Repository navigation
fix(lsp): fail closed on malformed requests; extend aspect gate to panic family - #117
Conversation
…nic family The LSP server's request dispatcher panicked (crashing the server) when a request's method matched but its params failed JSON deserialization. The dispatcher now answers JSON-RPC Invalid params (-32602) naming the method and the error, via a new three-outcome Cast type that rescues the request id before extract() consumes it. The binary also gains #![deny(clippy::unwrap_used, clippy::expect_used)], mirroring vclt-gate. tests/aspect_tests.sh check 3 now also rejects panic!/unreachable!/todo!/ unimplemented! in production src/, matching the documented vcltotal-parse SPARK-grade lint set; a parser.rs doc comment is reworded (panic! -> panic, meaning unchanged) so the textual gate stays precise. Disposition of #49: SPDX headers complete; remaining unsafe is confined to // SAFETY:-justified FFI trust boundaries; remaining unwrap/expect is test-only; last production panic! removed. Gate passes 6/6. Closes #49. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing (4)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CI verification (for the merger)All checks covering this change pass: Aspect tests, vcltotal-parse (clippy/tests), license-policy, Licence consistency, Root workspace tests, attest / recompute-wasm clippy+tests, CodeQL, secret scanners, Semgrep, OpenSSF. The 5 remaining red checks were each verified pre-existing on
(These match the pre-existing reds already documented in #116. Backend-matrix Smoke jobs still pending at time of writing are unrelated to this change.) On merge, |
|
❌ Failed to create Coding Agent finishing-touch task. Please try again. |
|
Autopilot could not be updated. Open Coding to check access and billing. |
…49) (#121) Follow-up to #49 / #117. #117 allowed *documented* `unsafe` in `src/`; this PR enforces the stricter boundary #49 asked for: **no unsafe Rust under `src/` at all**, with the FFI boundary crates moved to `ffi/rust/`. ## Changes - `git mv src/interface/{attest,recompute-wasm} ffi/rust/`; path deps → `../../../src/interface/parse`; lockfiles unchanged. - `tests/aspect_tests.sh` (keeps #117's unwrap/expect/panic-family check): - no `unsafe {` / `unsafe fn|impl|trait|extern` / `#[unsafe(..)]` / `static mut` anywhere under `src/` (tests included) - `#![forbid(unsafe_code)]` on every `src/` crate root (`lib.rs`, `main.rs`, `src/bin/*.rs`) - SPDX identifier on line 1 of every `src/` Rust file - `target/` pruned from every scan; failures now name the offending file - Added `forbid(unsafe_code)` to 9 crate roots; moved misplaced SPDX headers (dap/fmt/lint/lsp); `rustfmt` on `vcltotal-parse`. - Paths followed in `ffi/zig/build.zig`, `satellite-crates-gate.yml`, `dependabot.yml`, `audits/assail-classifications.a2ml`, `REUSE.toml` (`ffi/**`), ADR-0002, VERIFICATION-STANCE, PROOF-NEEDS, Tier2/Foreign.idr; new `ffi/rust/README.adoc`. ## Verified locally (cargo 1.97.1, zig 0.16.0) - `tests/aspect_tests.sh`: 7/7 pass. Positive controls: a planted `unsafe {}`, `#[unsafe(no_mangle)]`, `static mut`, `unsafe impl`, a misplaced SPDX line, and a removed forbid each FAIL the right check; a comment mentioning `unsafe {` and an `unsafe_code` identifier do not. - `ffi/rust/attest`: clippy `-D warnings` clean, 9 tests pass. `ffi/rust/recompute-wasm`: clippy clean, 3 tests pass. - `src/interface/parse`: clippy clean, all tests pass with `RUST_MIN_STACK=32MiB` (as in `parse-gate.yml`). Without it, `wire::op_roundtrip` intermittently overflows the default stack: an existing proptest-depth issue that CI already handles. - Root workspace: clippy `-D warnings` clean, 102 tests pass; `cargo fmt --check` clean. - `ffi/zig`: `zig build test` passes, linking the attest staticlib from its new path. - `reuse lint`: compliant, 479/479. - `Dependency audit` (also red on main): bumped `crossbeam-epoch` 0.9.18 → 0.9.21 in the root `Cargo.lock` for RUSTSEC-2026-0204. `cargo audit` is now clean apart from the allowed `anyhow` warning RUSTSEC-2026-0190. - `governance / Workflow security linter` (also red on main): moved the SPDX header of `rhodibot.yml` to line 1, below which the actions-lock marker now sits. - CodeRabbit autofix commits `73c8a98` (split-line `unsafe` detection, confirmed with planted controls) and `a37ecf3` (docstrings) reviewed and kept. Recut of the 2026-10-03 patch `53e80b4` onto current main. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Closes #49.
What #49 asked, and where it stands
Re-audited all three items against the current tree (the gate has evolved since the issue was filed in June — it now scopes checks 2–3 to production code and accepts
// SAFETY:-justified FFI, both correct refinements):unsafeinsrc/// SAFETY:comment;attestandrecompute-wasm(the only crates withunsafe) both set#![deny(clippy::undocumented_unsafe_blocks)]. These are#[no_mangle] extern "C"FFI trust boundaries, which cannot be written withoutunsafe— elimination is impossible, documentation is the correct posture, and the gate enforces it.unwrap/expectinsrc/#[cfg(test)]module or undersrc/*/tests/(plustesting.expectin Zig test files, out of the Rust gate's scope by design). Production count is 0.The gate already passed 6/6 — but the audit found one genuine hole in the same SPARK-grade family that the gate didn't cover: a production
panic!.Changes
src/interface/lsp/src/main.rs— the request dispatcherpanic!'d (crashing the whole server) when a request's method matched but its params failed JSON deserialization. It now answers JSON-RPCInvalid params(-32602) naming the method and the error, via a new three-outcomeCasttype that rescues the request id beforeextract()consumes it. Also adds#![deny(clippy::unwrap_used, clippy::expect_used)], mirroringvclt-gate, and dedupes error responses through a newsend_errorhelper.tests/aspect_tests.sh— check 3 now also rejectspanic!/unreachable!/todo!/unimplemented!in productionsrc/, matching the documentedvcltotal-parseSPARK-grade lint set (the estate pattern perparse/src/lib.rs).src/interface/parse/src/parser.rs— one doc comment reworded (panic!→panic, meaning unchanged) so the textual gate stays precise.CHANGELOG.adoc—[Unreleased] / Fixedentries.Validation
bash tests/aspect_tests.sh→ 6 passed, 0 failed (before and after; the gate is now strictly stronger).panic!("boom")into productionsrc/makes the new check FAIL as intended; removed afterwards.bash -non the script andgit diff --checkclean.vcltotal-lspis not built by standalone CI (it needs the echidna sibling path-dep; only the estate e2e layout compiles it), and this sandbox has no Rust toolchain — so themain.rschange was verified by inspection against the lsp-server 0.7 API on docs.rs (Request { pub id, pub method, pub params },Request: Clone,extractsignature,ExtractError::{MethodMismatch, JsonError { method, error }}shapes all confirmed). Only previously-unused-but-public API surface (req.id.clone()) is introduced; every other construct mirrors adjacent existing code.Suggested follow-up (not in this PR)
Per-crate
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, …)]on the remaining lib crates (lsp,dap,fmt,lint,attest,echidna-client) withallows in their test modules, mirroringvcltotal-parse. Deliberately left out: it needscargo clippyvalidation per crate, which isn't available in this sandbox — and #49 itself warns against blind passes.