ADR-007: Dependency Audit and Upgrade Decisions
On this page
Context
As part of pre-Phase 6 hardening, all workspace dependencies were audited against crates.io (March 2026). At that audit point, 30 direct workspace deps existed; 23 were already at their latest version. Seven required action: 4 upgrades, 1 removal, and 2 deferred with documented rationale.
Since March 2026, additional direct workspace deps have landed. As of 2026-04-20 the [workspace.dependencies] block carries ~40 direct crates. Notable additions not reflected in the 30-dep audit below:
-
tower-cookies(3) +aes-gcm-siv/aead— landed with ADR-013 (stateless encrypted session cookies, !81). -
thiserror(2) — typed error enums at service/SDK boundaries (EngineErrorin craig-rules,IntakeError::ResponseDecodein craig-intake-sdk; see CHANGELOG 2026-04-19). -
csv(1) — federal flat-file emission; replaces hand-rolledformat!()-based TSV in craig-reporting AFCARS export (CHANGELOG Step 8). -
ammonia(4) — HTML sanitization on public-intake narrative fields. -
p256+base64ct+sha2(ADR-010 JWS detached signatures) acrosscraig-intake-sdkandcraig-test-lib. -
craig-intake-sdk,craig-crypto,craig-referencepromoted to[workspace.dependencies]so downstream crates can reference viaworkspace = trueinstead of path deps. -
craig_common::build_shared_client(new module, not a separate dep) — single-source-of-truthreqwest::Clientbuilder landed 2026-04-20 to close four "per-call Client::new()" TODOs.
Refresh the full dep inventory as part of the next hardening plan; the list below is retained for historical traceability of the March 2026 decisions.
Decisions
Upgrades Applied
| Crate | From | To | Notes |
|---|---|---|---|
|
0.17 |
0.20 |
Zero code changes; our usage avoids all renamed APIs |
|
9 |
10 |
Added |
|
0.25 |
0.54 |
|
|
2 |
4 |
String params → |
Removed
| Crate | Version | Rationale |
|---|---|---|
|
0.9 |
Deprecated by author (dtolnay, March 2024). The community fork |
Deferred
| Crate | Current | Latest | Rationale |
|---|---|---|---|
|
0.8 |
1.0 |
toml 1.0 was released February 11, 2026 (3 weeks before this audit). Our usage is strictly |
|
0.12 |
0.13 |
reqwest 0.13 switches the default TLS crypto provider to |
jsonwebtoken Crypto Backend Choice
jsonwebtoken 10 requires selecting a crypto backend: aws_lc_rs or rust_crypto.
We chose rust_crypto (RustCrypto project: rsa, sha2, p256, p384) because:
-
Pure Rust — builds on all platforms without native toolchain dependencies (no NASM, no cmake)
-
Consistent with our decision to defer
aws-lc-rsadoption (see reqwest deferral above) -
Acceptable performance for JWT validation workloads (low volume, not a hot path)
If FIPS compliance becomes a requirement, switch to aws_lc_rs which provides FIPS-validated cryptography.
zen-engine LocalPoolHandle Decision
zen-engine’s evaluate() future is !Send (uses Rc internally). The upstream documentation recommends tokio_util::task::LocalPoolHandle for multi-threaded workloads.
We retain the existing manual approach: a dedicated OS thread running a single-threaded tokio runtime, communicating via mpsc channel. This is:
-
Explicit and easy to reason about (~20 lines of code)
-
Already proven in production testing (67+ ruleset evaluation tests)
-
Does not add a
tokio-utildependency
Revisit if zen-engine removes the !Send constraint in a future release.
Consequences
-
The workspace compiles and passes all tests with the upgraded dependencies
-
The
serde_yamlcrate is fully removed from the dependency tree -
The CLI
-f yamloutput format is no longer available; users should use-f jsoninstead -
Two dependencies (
toml,reqwest) remain pinned at older versions with documented upgrade paths -
The
jsonwebtokencrypto backend can be changed by modifying a single Cargo.toml feature flag