From 9f0a913c5ecd573c944475a24abfbf7012f75b2b Mon Sep 17 00:00:00 2001 From: Rick Crawford Date: Tue, 5 May 2026 22:00:29 -0700 Subject: [PATCH] fix: add unsafe code guardrails Forbid unsafe in crates that do not require it and document the vault crate's explicit zeroization exception so future unsafe drift fails at compile time. Co-authored-by: Cursor --- CHANGELOG.md | 6 ++++++ crates/sbproxy-ai/src/lib.rs | 1 + crates/sbproxy-cache/src/lib.rs | 1 + crates/sbproxy-classifiers/src/lib.rs | 1 + crates/sbproxy-config/src/lib.rs | 1 + crates/sbproxy-core/src/lib.rs | 1 + crates/sbproxy-extension/src/lib.rs | 1 + crates/sbproxy-httpkit/src/lib.rs | 1 + crates/sbproxy-k8s-operator/src/lib.rs | 1 + crates/sbproxy-k8s-operator/src/main.rs | 1 + crates/sbproxy-middleware/src/lib.rs | 1 + crates/sbproxy-modules/src/lib.rs | 1 + crates/sbproxy-observe/src/lib.rs | 1 + crates/sbproxy-openapi/src/lib.rs | 1 + crates/sbproxy-platform/src/lib.rs | 1 + crates/sbproxy-plugin/src/lib.rs | 1 + crates/sbproxy-security/src/lib.rs | 1 + crates/sbproxy-tls/src/lib.rs | 1 + crates/sbproxy-transport/src/lib.rs | 1 + crates/sbproxy-vault/src/lib.rs | 2 ++ crates/sbproxy/src/main.rs | 1 + 21 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dff573e..65db66bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -149,6 +149,12 @@ of the new YAML fields below until the version that ships them. snippets instead of illustrative API fragments. ([docs/architecture.md], [docs/audit-log.md], [docs/cache-reserve.md]) +- **Unsafe-code drift guardrails.** Crates that do not need unsafe now + forbid it at the crate root, while `sbproxy-vault` explicitly allows + its narrowly-scoped volatile zeroization unsafe with an inline + justification. + ([crates/sbproxy-*/src/lib.rs]) + - **AI client retry resilience.** `MemoryBatchStore` now uses `parking_lot::Mutex` so a panic in one worker cannot poison the in-memory batch map for every later operation. Provider retries now diff --git a/crates/sbproxy-ai/src/lib.rs b/crates/sbproxy-ai/src/lib.rs index 35f026ce..e94db161 100644 --- a/crates/sbproxy-ai/src/lib.rs +++ b/crates/sbproxy-ai/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-ai: AI gateway with provider routing, streaming, and guardrails. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod ai_metrics; diff --git a/crates/sbproxy-cache/src/lib.rs b/crates/sbproxy-cache/src/lib.rs index f53d454d..852f1f6b 100644 --- a/crates/sbproxy-cache/src/lib.rs +++ b/crates/sbproxy-cache/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-cache: Response cache and object cache management. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod reserve; diff --git a/crates/sbproxy-classifiers/src/lib.rs b/crates/sbproxy-classifiers/src/lib.rs index dbed68b5..01fad7b8 100644 --- a/crates/sbproxy-classifiers/src/lib.rs +++ b/crates/sbproxy-classifiers/src/lib.rs @@ -32,6 +32,7 @@ //! place it behind an [`std::sync::Arc`] and share it across worker //! threads without an outer lock. +#![forbid(unsafe_code)] #![deny(missing_docs)] pub mod agent_class; diff --git a/crates/sbproxy-config/src/lib.rs b/crates/sbproxy-config/src/lib.rs index a3cf7db1..308fea9a 100644 --- a/crates/sbproxy-config/src/lib.rs +++ b/crates/sbproxy-config/src/lib.rs @@ -5,6 +5,7 @@ //! - Intermediate representation ([`raw`]) //! - Compiling configs into immutable, performance-optimized snapshots ([`snapshot`], [`compiler`]) +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod compiler; diff --git a/crates/sbproxy-core/src/lib.rs b/crates/sbproxy-core/src/lib.rs index 87de214b..487d84b8 100644 --- a/crates/sbproxy-core/src/lib.rs +++ b/crates/sbproxy-core/src/lib.rs @@ -8,6 +8,7 @@ //! - [`server::SbProxy`] - Pingora `ProxyHttp` implementation //! - [`server::run`] - Server entry point +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod admin; diff --git a/crates/sbproxy-extension/src/lib.rs b/crates/sbproxy-extension/src/lib.rs index c893679b..cdbc9d24 100644 --- a/crates/sbproxy-extension/src/lib.rs +++ b/crates/sbproxy-extension/src/lib.rs @@ -4,6 +4,7 @@ //! sbproxy for conditional logic in routing, access control, and policy //! enforcement. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod cel; diff --git a/crates/sbproxy-httpkit/src/lib.rs b/crates/sbproxy-httpkit/src/lib.rs index 54e7b320..a1e338a7 100644 --- a/crates/sbproxy-httpkit/src/lib.rs +++ b/crates/sbproxy-httpkit/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-httpkit: HTTP utilities, buffer pool, and compression. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod bufferpool; diff --git a/crates/sbproxy-k8s-operator/src/lib.rs b/crates/sbproxy-k8s-operator/src/lib.rs index 37b23faa..b43f2c9b 100644 --- a/crates/sbproxy-k8s-operator/src/lib.rs +++ b/crates/sbproxy-k8s-operator/src/lib.rs @@ -24,6 +24,7 @@ //! triple and applies it server-side. Config changes trigger a rollout-restart //! by stamping `sbproxy.dev/config-hash` on the Deployment's pod template. +#![forbid(unsafe_code)] #![deny(missing_docs)] /// CRD type definitions. diff --git a/crates/sbproxy-k8s-operator/src/main.rs b/crates/sbproxy-k8s-operator/src/main.rs index 416823d8..0ec63776 100644 --- a/crates/sbproxy-k8s-operator/src/main.rs +++ b/crates/sbproxy-k8s-operator/src/main.rs @@ -6,6 +6,7 @@ //! //! See `docs/kubernetes.md` for end-user instructions. +#![forbid(unsafe_code)] #![deny(missing_docs)] use std::sync::Arc; diff --git a/crates/sbproxy-middleware/src/lib.rs b/crates/sbproxy-middleware/src/lib.rs index bc5a1424..b7915a06 100644 --- a/crates/sbproxy-middleware/src/lib.rs +++ b/crates/sbproxy-middleware/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-middleware: CORS, HSTS, compression, callback, and header modifier middleware. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod callback; diff --git a/crates/sbproxy-modules/src/lib.rs b/crates/sbproxy-modules/src/lib.rs index 3d84110e..c223a3a6 100644 --- a/crates/sbproxy-modules/src/lib.rs +++ b/crates/sbproxy-modules/src/lib.rs @@ -5,6 +5,7 @@ //! The `Plugin` variant on each enum is the only case that falls back to //! dynamic dispatch for third-party extensions. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod action; diff --git a/crates/sbproxy-observe/src/lib.rs b/crates/sbproxy-observe/src/lib.rs index fc4539f6..afc8dd28 100644 --- a/crates/sbproxy-observe/src/lib.rs +++ b/crates/sbproxy-observe/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-observe: Observability - logging, metrics, and events. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod access_log; diff --git a/crates/sbproxy-openapi/src/lib.rs b/crates/sbproxy-openapi/src/lib.rs index 50cb1a99..7d9fbe50 100644 --- a/crates/sbproxy-openapi/src/lib.rs +++ b/crates/sbproxy-openapi/src/lib.rs @@ -26,6 +26,7 @@ //! `x-sbproxy-auth-type` extension and skip the `security` requirement so //! the doc still validates. +#![forbid(unsafe_code)] #![warn(missing_docs)] use sbproxy_config::{CompiledConfig, RawForwardRule}; diff --git a/crates/sbproxy-platform/src/lib.rs b/crates/sbproxy-platform/src/lib.rs index 04e7ff43..222d57f1 100644 --- a/crates/sbproxy-platform/src/lib.rs +++ b/crates/sbproxy-platform/src/lib.rs @@ -1,6 +1,7 @@ //! sbproxy-platform: Storage, messenger, circuit breaker, DNS, health checks, //! and network protocol utilities. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod adaptive_breaker; diff --git a/crates/sbproxy-plugin/src/lib.rs b/crates/sbproxy-plugin/src/lib.rs index 60401dd2..87fe4bc1 100644 --- a/crates/sbproxy-plugin/src/lib.rs +++ b/crates/sbproxy-plugin/src/lib.rs @@ -9,6 +9,7 @@ //! - [`identity`] - Identity, classification, and anomaly hook surface. //! - [`audit`] - Admin-action audit emitter trait surface. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod audit; diff --git a/crates/sbproxy-security/src/lib.rs b/crates/sbproxy-security/src/lib.rs index c012ac2b..2730e292 100644 --- a/crates/sbproxy-security/src/lib.rs +++ b/crates/sbproxy-security/src/lib.rs @@ -1,5 +1,6 @@ //! sbproxy-security: Cryptography, IP utilities, host filtering, PII masking, and SSRF protection. +#![forbid(unsafe_code)] #![warn(missing_docs)] #[cfg(feature = "agent-class")] diff --git a/crates/sbproxy-tls/src/lib.rs b/crates/sbproxy-tls/src/lib.rs index f0822ee2..39166640 100644 --- a/crates/sbproxy-tls/src/lib.rs +++ b/crates/sbproxy-tls/src/lib.rs @@ -1,5 +1,6 @@ //! TLS, ACME auto-cert, and HTTP/3 support for sbproxy. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod acme; diff --git a/crates/sbproxy-transport/src/lib.rs b/crates/sbproxy-transport/src/lib.rs index 139266ae..68c8f890 100644 --- a/crates/sbproxy-transport/src/lib.rs +++ b/crates/sbproxy-transport/src/lib.rs @@ -4,6 +4,7 @@ //! rate limiting, self-tuning connection pools, and request deduplication //! for the proxy transport layer. +#![forbid(unsafe_code)] #![warn(missing_docs)] pub mod auto_pool; diff --git a/crates/sbproxy-vault/src/lib.rs b/crates/sbproxy-vault/src/lib.rs index a8d90458..c90d79dc 100644 --- a/crates/sbproxy-vault/src/lib.rs +++ b/crates/sbproxy-vault/src/lib.rs @@ -1,5 +1,7 @@ //! sbproxy-vault: Secret management and secure variable interpolation. +#![allow(unsafe_code)] +// Volatile zeroization uses narrowly-scoped unsafe writes so secrets are not optimized away. #![warn(missing_docs)] pub mod convergent; diff --git a/crates/sbproxy/src/main.rs b/crates/sbproxy/src/main.rs index e1953a97..47b97b7c 100644 --- a/crates/sbproxy/src/main.rs +++ b/crates/sbproxy/src/main.rs @@ -4,6 +4,7 @@ //! mimalloc allocator, parses CLI args, and hands the config path to //! [`sbproxy_core::run`]. All real work happens in the workspace crates. +#![forbid(unsafe_code)] #![warn(missing_docs)] use std::env;