diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8d92209..b608133 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -164,7 +164,7 @@ capsec provides four macros that work together: | Macro | Purpose | |-------|---------| -| `#[capsec::context]` | Generates `Has

` impls on a struct, turning it into a capability context | +| `#[capsec::context]` | Generates `Has

` and `CapProvider

` impls on a struct, turning it into a capability context | | `#[capsec::main]` | Injects `CapRoot` creation into a function entry point | | `#[capsec::requires]` | Validates that a function's parameters satisfy declared permissions | | `#[capsec::deny]` | Marks a function as capability-free; violations are promoted to critical by the audit tool | diff --git a/Cargo.lock b/Cargo.lock index 3acfab0..e4a1422 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "capsec" -version = "0.1.9" +version = "0.2.0" dependencies = [ "capsec-core", "capsec-macro", @@ -124,14 +124,14 @@ dependencies = [ [[package]] name = "capsec-core" -version = "0.1.9" +version = "0.2.0" dependencies = [ "thiserror", ] [[package]] name = "capsec-macro" -version = "0.1.9" +version = "0.2.0" dependencies = [ "proc-macro2", "quote", @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "capsec-proof" -version = "0.1.9" +version = "0.2.0" dependencies = [ "proptest", "toml", @@ -148,14 +148,14 @@ dependencies = [ [[package]] name = "capsec-std" -version = "0.1.9" +version = "0.2.0" dependencies = [ "capsec-core", ] [[package]] name = "capsec-tests" -version = "0.1.9" +version = "0.2.0" dependencies = [ "capsec", "capsec-core", @@ -167,7 +167,7 @@ dependencies = [ [[package]] name = "capsec-tokio" -version = "0.1.9" +version = "0.2.0" dependencies = [ "capsec-core", "capsec-macro", @@ -176,7 +176,7 @@ dependencies = [ [[package]] name = "cargo-capsec" -version = "0.1.9" +version = "0.2.0" dependencies = [ "capsec-core", "capsec-std", diff --git a/Cargo.toml b/Cargo.toml index 859b901..88285e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ exclude = [ ] [workspace.package] -version = "0.1.9" +version = "0.2.0" edition = "2024" rust-version = "1.85.0" readme = "README.md" @@ -51,7 +51,7 @@ trybuild = "1" insta = { version = "1", features = ["yaml"] } # Internal crates -capsec-core = { path = "crates/capsec-core", version = "0.1.0" } -capsec-macro = { path = "crates/capsec-macro", version = "0.1.0" } -capsec-std = { path = "crates/capsec-std", version = "0.1.0" } -capsec-tokio = { path = "crates/capsec-tokio", version = "0.1.0" } +capsec-core = { path = "crates/capsec-core", version = "0.2.0" } +capsec-macro = { path = "crates/capsec-macro", version = "0.2.0" } +capsec-std = { path = "crates/capsec-std", version = "0.2.0" } +capsec-tokio = { path = "crates/capsec-tokio", version = "0.2.0" } diff --git a/README.md b/README.md index c34a655..4814fd4 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ cargo capsec audit capsec fills that gap with three layers: 1. **`cargo capsec audit`** — a static audit tool that scans your code and reports every I/O call. Drop it into CI and know exactly what your dependencies do. -2. **Compile-time type system** — functions declare their I/O permissions via `Has

` trait bounds, and the compiler rejects anything that exceeds them. Zero runtime cost. +2. **Compile-time type system** — functions declare their I/O permissions via `CapProvider

` trait bounds, and the compiler rejects anything that exceeds them. Zero runtime cost. Scoped capabilities (`Attenuated`) enforce *where* a capability can act. 3. **Runtime capability control** — `RuntimeCap` (revocable) and `TimedCap` (expiring) wrap static capabilities with runtime validity checks for dynamic scenarios like server init or migration windows. The audit tool finds the problems. The type system prevents them at compile time. Runtime caps handle the cases where permissions need to change dynamically. @@ -120,15 +120,15 @@ Functions declare their I/O requirements in the type signature. The compiler enf use capsec::prelude::*; // Define a context with exactly the permissions your app needs. -// The macro generates Cap fields, constructor, and Has

impls. +// The macro generates Cap fields, constructor, Has

impls, and CapProvider

impls. #[capsec::context] struct AppCtx { fs: FsRead, net: NetConnect, } -// Leaf functions take &impl Has

— works with raw caps AND context structs. -pub fn load_config(path: &str, cap: &impl Has) -> Result { +// Leaf functions take &impl CapProvider

— works with raw caps, context structs, AND scoped caps. +pub fn load_config(path: &str, cap: &impl CapProvider) -> Result { capsec::fs::read_to_string(path, cap) } @@ -157,11 +157,11 @@ let _ = capsec::fs::read_to_string("/etc/passwd", &net_cap); ``` ``` -error[E0277]: the trait bound `Cap: Has` is not satisfied +error[E0277]: the trait bound `Cap: CapProvider` is not satisfied --> src/main.rs:4:55 | 4 | let _ = capsec::fs::read_to_string("/etc/passwd", &net_cap); - | -------------------------- ^^^^^^^^ the trait `Has` is not implemented for `Cap` + | -------------------------- ^^^^^^^^ the trait `CapProvider` is not implemented for `Cap` | | | required by a bound introduced by this call ``` @@ -189,15 +189,15 @@ help: provide the argument ```rust let fs_all = root.grant::(); -needs_net(&fs_all); // fn needs_net(_: &impl Has) {} +needs_net(&fs_all); // fn needs_net(_: &impl CapProvider) {} ``` ``` -error[E0277]: the trait bound `Cap: Has` is not satisfied +error[E0277]: the trait bound `Cap: CapProvider` is not satisfied --> src/main.rs:3:15 | 3 | needs_net(&fs_all); - | --------- ^^^^^^^ the trait `Has` is not implemented for `Cap` + | --------- ^^^^^^^ the trait `CapProvider` is not implemented for `Cap` | | | required by a bound introduced by this call ``` @@ -210,7 +210,7 @@ These are real `rustc` errors — no custom error framework, no runtime panics. |--|--------|-------| | Can any function read files? | Yes | Only if it has `Cap` | | Can any function open sockets? | Yes | Only if it has `Cap` | -| Can you audit who has what access? | Grep and pray | Grep for `Has` | +| Can you audit who has what access? | Grep and pray | Grep for `CapProvider` | | Runtime cost? | N/A | Zero — all types are erased at compile time | ### Security model @@ -347,7 +347,7 @@ fn main(root: CapRoot) -> Result<(), Box> { ### Key properties -- `RuntimeCap`, `TimedCap`, `LoggedCap`, and `DualKeyCap` do **not** implement `Has

` — fallibility is explicit via `try_cap()` at every call site +- `RuntimeCap`, `TimedCap`, `LoggedCap`, and `DualKeyCap` do **not** implement `Has

` but they do implement `CapProvider

` — so they can be passed directly to capsec-std/tokio functions. Fallibility is handled transparently by `provide_cap()` - All are `!Send` by default — use `make_send()` to opt into cross-thread transfer - Cloning a `RuntimeCap` shares the revocation flag — revoking one revokes all clones - Cloning a `LoggedCap` shares the audit log — entries from any clone appear in the same log @@ -379,7 +379,7 @@ capsec's design draws from three foundational papers in capability-based securit - **Saltzer & Schroeder (1975)** — [The Protection of Information in Computer Systems](https://www.cs.virginia.edu/~evans/cs551/saltzer/). Defined the eight design principles for protection mechanisms. capsec implements six: economy of mechanism (zero-sized types), fail-safe defaults (no cap = no access), least privilege (the core mission), open design (open source + adversarial test suite), separation of privilege (`DualKeyCap`), and compromise recording (`LoggedCap`). The two partially met — complete mediation and least common mechanism — are inherent limitations of a library-level approach. -- **Melicher et al. (2017)** — [A Capability-Based Module System for Authority Control](https://www.cs.cmu.edu/~aldrich/papers/ecoop17modules.pdf) (ECOOP 2017). Formalized non-transitive authority in the Wyvern language, proving that a module's authority can be determined by inspecting only its interface. capsec achieves the same property: `Has

` bounds make a function's authority visible in its signature, and `Attenuated` / runtime cap types that don't implement `Has

` enforce non-transitivity. +- **Melicher et al. (2017)** — [A Capability-Based Module System for Authority Control](https://www.cs.cmu.edu/~aldrich/papers/ecoop17modules.pdf) (ECOOP 2017). Formalized non-transitive authority in the Wyvern language, proving that a module's authority can be determined by inspecting only its interface. capsec achieves the same property: `CapProvider

` bounds make a function's authority visible in its signature, and `Attenuated` enforces non-transitivity through scope checks embedded in `provide_cap()`. --- diff --git a/crates/capsec-core/src/attenuate.rs b/crates/capsec-core/src/attenuate.rs index 68f1d29..4740718 100644 --- a/crates/capsec-core/src/attenuate.rs +++ b/crates/capsec-core/src/attenuate.rs @@ -58,6 +58,7 @@ impl Cap

{ impl Attenuated { /// Checks whether `target` is within this capability's scope. + #[must_use = "ignoring a scope check silently discards scope violations"] pub fn check(&self, target: &str) -> Result<(), CapSecError> { self.scope.check(target) } diff --git a/crates/capsec-core/src/cap.rs b/crates/capsec-core/src/cap.rs index ee7825b..1009a69 100644 --- a/crates/capsec-core/src/cap.rs +++ b/crates/capsec-core/src/cap.rs @@ -30,6 +30,7 @@ use std::marker::PhantomData; /// // cap is a proof token — zero bytes at runtime /// assert_eq!(std::mem::size_of_val(&cap), 0); /// ``` +#[must_use = "capability tokens are proof of permission — discarding one wastes a grant"] pub struct Cap { _phantom: PhantomData

, // PhantomData<*const ()> makes Cap !Send + !Sync @@ -68,6 +69,7 @@ impl Cap

{ /// /// This is an explicit opt-in — you're acknowledging that this capability /// will be used in a multi-threaded context (e.g., passed into `tokio::spawn`). + #[must_use = "make_send consumes the original Cap and returns a SendCap"] pub fn make_send(self) -> SendCap

{ SendCap { _phantom: PhantomData, @@ -100,6 +102,7 @@ impl Clone for Cap

{ /// // use cap in this thread /// }).join().unwrap(); /// ``` +#[must_use = "capability tokens are proof of permission — discarding one wastes a grant"] pub struct SendCap { _phantom: PhantomData

, } diff --git a/crates/capsec-core/src/cap_provider.rs b/crates/capsec-core/src/cap_provider.rs index c8b36a9..de1770b 100644 --- a/crates/capsec-core/src/cap_provider.rs +++ b/crates/capsec-core/src/cap_provider.rs @@ -14,6 +14,7 @@ use crate::permission::Permission; pub trait CapProvider { /// Provides a `Cap

` for the given target, or returns an error if the /// target is outside the capability's scope. + #[must_use = "ignoring a capability check silently discards scope violations"] fn provide_cap(&self, target: &str) -> Result, CapSecError>; } @@ -63,7 +64,7 @@ impl CapProvider

for crate::cap::SendCap

{ } } -// ── Subsumption ───────────────────────────────────────────────────── +// ── Subsumption (Cap) ──────────────────────────────────────────────── macro_rules! impl_cap_provider_subsumes { ($super:ty => $($sub:ty),+) => { @@ -82,7 +83,24 @@ use crate::permission::*; impl_cap_provider_subsumes!(FsAll => FsRead, FsWrite); impl_cap_provider_subsumes!(NetAll => NetConnect, NetBind); -// ── Ambient ───────────────────────────────────────────────────────── +// ── Subsumption (SendCap) ─────────────────────────────────────────── + +macro_rules! impl_cap_provider_sendcap_subsumes { + ($super:ty => $($sub:ty),+) => { + $( + impl CapProvider<$sub> for crate::cap::SendCap<$super> { + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + Ok(Cap::new()) + } + } + )+ + } +} + +impl_cap_provider_sendcap_subsumes!(FsAll => FsRead, FsWrite); +impl_cap_provider_sendcap_subsumes!(NetAll => NetConnect, NetBind); + +// ── Ambient (Cap) ─────────────────────────────────────────────────── macro_rules! impl_cap_provider_ambient { ($($perm:ty),+) => { @@ -100,7 +118,25 @@ impl_cap_provider_ambient!( FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn ); -// ── Tuples ────────────────────────────────────────────────────────── +// ── Ambient (SendCap) ─────────────────────────────────────────────── + +macro_rules! impl_cap_provider_sendcap_ambient { + ($($perm:ty),+) => { + $( + impl CapProvider<$perm> for crate::cap::SendCap { + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + Ok(Cap::new()) + } + } + )+ + } +} + +impl_cap_provider_sendcap_ambient!( + FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn +); + +// ── Tuples (Cap) ──────────────────────────────────────────────────── macro_rules! impl_cap_provider_tuple_first { ([$($a:ident),+]; $all:tt) => { @@ -145,6 +181,101 @@ impl_cap_provider_tuple_second!( FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient ); +// ── Tuples (SendCap) ──────────────────────────────────────────────── + +macro_rules! impl_cap_provider_sendcap_tuple_first { + ([$($a:ident),+]; $all:tt) => { + $( impl_cap_provider_sendcap_tuple_first!(@inner $a; $all); )+ + }; + (@inner $a:ident; [$($b:ident),+]) => { + $( + impl CapProvider<$a> for crate::cap::SendCap<($a, $b)> { + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + Ok(Cap::new()) + } + } + )+ + }; +} + +macro_rules! impl_cap_provider_sendcap_tuple_second { + ($first:ident $(, $rest:ident)+) => { + $( + impl CapProvider<$first> for crate::cap::SendCap<($rest, $first)> { + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + Ok(Cap::new()) + } + } + impl CapProvider<$rest> for crate::cap::SendCap<($first, $rest)> { + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + Ok(Cap::new()) + } + } + )+ + impl_cap_provider_sendcap_tuple_second!($($rest),+); + }; + ($single:ident) => {}; +} + +impl_cap_provider_sendcap_tuple_first!( + [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient]; + [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient] +); + +impl_cap_provider_sendcap_tuple_second!( + FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient +); + +// ── Runtime / Prescript types ─────────────────────────────────────── + +impl CapProvider

for crate::runtime::RuntimeCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::runtime::RuntimeSendCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::runtime::TimedCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::runtime::TimedSendCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::prescript::LoggedCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::prescript::LoggedSendCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::prescript::DualKeyCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + +impl CapProvider

for crate::prescript::DualKeySendCap

{ + fn provide_cap(&self, _target: &str) -> Result, CapSecError> { + self.try_cap() + } +} + #[cfg(test)] mod tests { use super::*; @@ -186,4 +317,79 @@ mod tests { assert!(CapProvider::::provide_cap(&cap, "/any").is_ok()); assert!(CapProvider::::provide_cap(&cap, "host").is_ok()); } + + #[test] + fn sendcap_subsumption_provides() { + let root = crate::root::test_root(); + let cap = root.grant::().make_send(); + let result: Result, _> = cap.provide_cap("/any"); + assert!(result.is_ok()); + } + + #[test] + fn sendcap_ambient_provides() { + let root = crate::root::test_root(); + let cap = root.grant::().make_send(); + let result: Result, _> = cap.provide_cap("/any"); + assert!(result.is_ok()); + } + + #[test] + fn sendcap_tuple_provides() { + let root = crate::root::test_root(); + let cap = root.grant::<(FsRead, NetConnect)>().make_send(); + assert!(CapProvider::::provide_cap(&cap, "/any").is_ok()); + assert!(CapProvider::::provide_cap(&cap, "host").is_ok()); + } + + #[test] + fn runtime_cap_provides() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let (rcap, _revoker) = crate::runtime::RuntimeCap::new(cap); + assert!(rcap.provide_cap("/any").is_ok()); + } + + #[test] + fn runtime_cap_provides_fails_after_revocation() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let (rcap, revoker) = crate::runtime::RuntimeCap::new(cap); + revoker.revoke(); + assert!(rcap.provide_cap("/any").is_err()); + } + + #[test] + fn timed_cap_provides() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let tcap = crate::runtime::TimedCap::new(cap, std::time::Duration::from_secs(60)); + assert!(tcap.provide_cap("/any").is_ok()); + } + + #[test] + fn logged_cap_provides() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let lcap = crate::prescript::LoggedCap::new(cap); + assert!(lcap.provide_cap("/any").is_ok()); + } + + #[test] + fn dual_key_cap_provides() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let (dcap, a, b) = crate::prescript::DualKeyCap::new(cap); + a.approve(); + b.approve(); + assert!(dcap.provide_cap("/any").is_ok()); + } + + #[test] + fn dual_key_cap_provides_fails_without_approvals() { + let root = crate::root::test_root(); + let cap = root.grant::(); + let (dcap, _a, _b) = crate::prescript::DualKeyCap::new(cap); + assert!(dcap.provide_cap("/any").is_err()); + } } diff --git a/crates/capsec-core/src/lib.rs b/crates/capsec-core/src/lib.rs index 4941833..c2452be 100644 --- a/crates/capsec-core/src/lib.rs +++ b/crates/capsec-core/src/lib.rs @@ -8,7 +8,8 @@ //! //! - [`Permission`](permission::Permission) — marker trait for capability categories //! - [`Cap

`](cap::Cap) — zero-sized proof token that the holder has permission `P` -//! - [`Has

`](has::Has) — trait for checking and composing capabilities +//! - [`Has

`](has::Has) — trait for infallible capability proof extraction +//! - [`CapProvider

`](cap_provider::CapProvider) — trait for capability access with scope checking //! - [`CapRoot`](root::CapRoot) — the singleton root of all capability grants //! - [`Attenuated`](attenuate::Attenuated) — scope-restricted capabilities //! - [`CapSecError`](error::CapSecError) — error types for scope violations and I/O diff --git a/crates/capsec-core/src/root.rs b/crates/capsec-core/src/root.rs index 47229d0..c43371f 100644 --- a/crates/capsec-core/src/root.rs +++ b/crates/capsec-core/src/root.rs @@ -35,6 +35,7 @@ static ROOT_CREATED: AtomicBool = AtomicBool::new(false); /// let root = test_root(); /// let fs_cap = root.grant::(); /// ``` +#[must_use = "CapRoot is a singleton — discarding it means no capabilities can be granted"] pub struct CapRoot { _private: (), } diff --git a/crates/capsec-example-db/Cargo.lock b/crates/capsec-example-db/Cargo.lock new file mode 100644 index 0000000..c149bcb --- /dev/null +++ b/crates/capsec-example-db/Cargo.lock @@ -0,0 +1,2601 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e833808ff2d94ed40d9379848a950d995043c7fb3e81a30b383f4c6033821cc" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad08897b81588f60ba983e3ca39bda2b179bdd84dced378e7df81a5313802ef8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num", +] + +[[package]] +name = "arrow-array" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8548ca7c070d8db9ce7aa43f37393e4bfcf3f2d3681df278490772fd1673d08d" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e003216336f70446457e280807a73899dd822feaf02087d31febca1363e2fccc" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919418a0681298d3a77d1a315f625916cb5678ad0d74b9c60108eb15fd083023" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5c64fff1d142f833d78897a772f2e5b55b36cb3e6320376f0961ab0db7bd6d0" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ord" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8f82583eb4f8d84d4ee55fd1cb306720cddead7596edce95b50ee418edf66f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d07ba24522229d9085031df6b94605e0f4b26e099fb7cdeec37abd941a73753" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3aa9e59c611ebc291c28582077ef25c97f1975383f1479b12f3b9ffee2ffabe" +dependencies = [ + "bitflags", +] + +[[package]] +name = "arrow-select" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c41dbbd1e97bfcaee4fcb30e29105fb2c75e4d82ae4de70b792a5d3f66b2e7a" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5183c150fbc619eede22b861ea7c0eebed8eaac0333eaa7f6da5205fd504d" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "capsec" +version = "0.2.0" +dependencies = [ + "capsec-core", + "capsec-macro", + "capsec-std", +] + +[[package]] +name = "capsec-core" +version = "0.2.0" +dependencies = [ + "thiserror", +] + +[[package]] +name = "capsec-example-db" +version = "0.2.0" +dependencies = [ + "capsec", + "capsec-core", + "duckdb", +] + +[[package]] +name = "capsec-macro" +version = "0.2.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "capsec-std" +version = "0.2.0" +dependencies = [ + "capsec-core", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "comfy-table" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d05af1e006a2407bedef5af410552494ce5be9090444dbbcb57258c1af3d56" +dependencies = [ + "strum 0.26.3", + "strum_macros 0.26.4", + "unicode-width", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "duckdb" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8685352ce688883098b61a361e86e87df66fc8c444f4a2411e884c16d5243a65" +dependencies = [ + "arrow", + "cast", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "num-integer", + "rust_decimal", + "strum 0.27.2", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libduckdb-sys" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78bacb8933586cee3b550c39b610d314f9b7a48701ac7a914a046165a4ad8da" +dependencies = [ + "cc", + "flate2", + "pkg-config", + "reqwest", + "serde", + "serde_json", + "tar", + "vcpkg", + "zip", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "1.0.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.10+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[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 = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] diff --git a/crates/capsec-example-db/Cargo.toml b/crates/capsec-example-db/Cargo.toml index c51a10c..8450cb4 100644 --- a/crates/capsec-example-db/Cargo.toml +++ b/crates/capsec-example-db/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "capsec-example-db" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true +version = "0.2.0" +edition = "2024" +license = "Apache-2.0" +repository = "https://github.com/auths-dev/capsec" description = "Example: user-defined database permissions with capsec" publish = false +rust-version = "1.85.0" [dependencies] capsec = { path = "../capsec" } diff --git a/crates/capsec-macro/README.md b/crates/capsec-macro/README.md index 6eeb180..f7924f2 100644 --- a/crates/capsec-macro/README.md +++ b/crates/capsec-macro/README.md @@ -28,7 +28,7 @@ async fn main(root: CapRoot) { ... } ### `#[capsec::context]` -Transforms a struct with permission-type fields into a capability context. Generates `Cap

` fields, a `new(root)` constructor, and `Has

` impls for each field. +Transforms a struct with permission-type fields into a capability context. Generates `Cap

` fields, a `new(root)` constructor, `Has

` impls, and `CapProvider

` impls for each field. ```rust,ignore #[capsec::context] @@ -37,7 +37,7 @@ struct AppCtx { net: NetConnect, } -// Generated: AppCtx::new(&root), impl Has for AppCtx, impl Has for AppCtx +// Generated: AppCtx::new(&root), impl Has

+ CapProvider

for AppCtx (for each field) ``` For async/threaded code, use the `send` variant to generate `SendCap

` fields: @@ -63,7 +63,7 @@ fn sync_data(fs: &impl Has, net: &impl Has) -> Result<()> { } ``` -With concrete context types, use `on = param` to emit a compile-time assertion that the parameter type implements `Has

`: +With concrete context types, use `on = param` to emit a compile-time assertion that the parameter type implements `CapProvider

`: ```rust,ignore #[capsec::requires(fs::read, net::connect, on = ctx)] @@ -72,7 +72,7 @@ fn sync_data(config: &Config, ctx: &AppCtx) -> Result<()> { } ``` -With generic type parameters, `on = param` auto-generates `Has

` bounds — write your requirements once in the attribute, and the macro adds the `where` clause: +With generic type parameters, `on = param` auto-generates `CapProvider

` bounds — write your requirements once in the attribute, and the macro adds the `where` clause: ```rust,ignore // You write: @@ -81,7 +81,7 @@ fn sync_data(config: &Config, ctx: &C) -> Result<()> { // ... } -// Macro generates: where C: Has + Has +// Macro generates: where C: CapProvider + CapProvider ``` ### `#[capsec::deny(...)]` diff --git a/crates/capsec-macro/src/lib.rs b/crates/capsec-macro/src/lib.rs index 90283bb..6a90add 100644 --- a/crates/capsec-macro/src/lib.rs +++ b/crates/capsec-macro/src/lib.rs @@ -117,7 +117,7 @@ fn permission_inner( // impl Has

for SendCap

// So we only need to generate Subsumes-related Has impls. - // Generate Subsumes impls + Has for Cap/SendCap + // Generate Subsumes impls + Has + CapProvider for Cap/SendCap let subsumes_impls: Vec<_> = subsumes .iter() .map(|sub| { @@ -135,6 +135,18 @@ fn permission_inner( capsec_core::cap::Cap::__capsec_new_derived(capsec_core::__private::__capsec_seal()) } } + + impl capsec_core::cap_provider::CapProvider<#sub> for capsec_core::cap::Cap<#struct_name> { + fn provide_cap(&self, _target: &str) -> Result, capsec_core::error::CapSecError> { + Ok(capsec_core::cap::Cap::__capsec_new_derived(capsec_core::__private::__capsec_seal())) + } + } + + impl capsec_core::cap_provider::CapProvider<#sub> for capsec_core::cap::SendCap<#struct_name> { + fn provide_cap(&self, _target: &str) -> Result, capsec_core::error::CapSecError> { + Ok(capsec_core::cap::Cap::__capsec_new_derived(capsec_core::__private::__capsec_seal())) + } + } } }) .collect(); @@ -314,12 +326,12 @@ fn requires_inner( }); if let Some(ref gen_ident) = generic_ident { - // Mode 4: Auto-generate Has

bounds on the generic type parameter + // Mode 4: Auto-generate CapProvider

bounds on the generic type parameter let mut sig = func.sig.clone(); let where_clause = sig.generics.make_where_clause(); let bounds: Vec<_> = cap_types .iter() - .map(|perm_ty| quote! { capsec_core::has::Has<#perm_ty> }) + .map(|perm_ty| quote! { capsec_core::cap_provider::CapProvider<#perm_ty> }) .collect(); where_clause .predicates @@ -334,7 +346,7 @@ fn requires_inner( .map(|(i, perm_ty)| { let fn_name = format_ident!("_assert_has_{}", i); quote! { - fn #fn_name>() {} + fn #fn_name>() {} } }) .collect(); @@ -758,6 +770,20 @@ fn context_inner( }) .collect(); + // Generate CapProvider

impls (delegates to Has

) + let cap_provider_impls: Vec<_> = field_infos + .iter() + .map(|(_name, perm)| { + quote! { + impl capsec_core::cap_provider::CapProvider<#perm> for #struct_name { + fn provide_cap(&self, _target: &str) -> Result, capsec_core::error::CapSecError> { + Ok(>::cap_ref(self)) + } + } + } + }) + .collect(); + Ok(quote! { #(#struct_attrs)* #struct_vis struct #struct_name { @@ -774,5 +800,6 @@ fn context_inner( } #(#has_impls)* + #(#cap_provider_impls)* }) } diff --git a/crates/capsec-std/README.md b/crates/capsec-std/README.md index e7d2ce4..91256a6 100644 --- a/crates/capsec-std/README.md +++ b/crates/capsec-std/README.md @@ -16,7 +16,7 @@ let cap = root.grant::(); // This works — we have a Cap: let data = capsec_std::fs::read("/tmp/data.bin", &cap).unwrap(); -// This won't compile — NetConnect can't satisfy Has: +// This won't compile — NetConnect can't satisfy CapProvider: // let net = root.grant::(); // let data = capsec_std::fs::read("/tmp/data.bin", &net); ``` diff --git a/crates/capsec-std/src/env.rs b/crates/capsec-std/src/env.rs index e64d0ed..e5b61f2 100644 --- a/crates/capsec-std/src/env.rs +++ b/crates/capsec-std/src/env.rs @@ -3,21 +3,22 @@ //! Drop-in replacements for `std::env` functions that require a capability token. use capsec_core::cap::Cap; -use capsec_core::has::Has; +use capsec_core::cap_provider::CapProvider; +use capsec_core::error::CapSecError; use capsec_core::permission::{EnvRead, EnvWrite}; /// Reads an environment variable. /// Requires [`EnvRead`] permission. -pub fn var(key: &str, cap: &impl Has) -> Result { - let _proof: Cap = cap.cap_ref(); - std::env::var(key) +pub fn var(key: &str, cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap(key)?; + Ok(std::env::var(key)?) } /// Returns an iterator of all environment variables. /// Requires [`EnvRead`] permission. -pub fn vars(cap: &impl Has) -> std::env::Vars { - let _proof: Cap = cap.cap_ref(); - std::env::vars() +pub fn vars(cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap("*")?; + Ok(std::env::vars()) } /// Sets an environment variable. @@ -35,13 +36,19 @@ pub fn vars(cap: &impl Has) -> std::env::Vars { /// function concurrently from multiple threads is undefined behavior. The /// capability system tracks *permission*, not *exclusivity* — synchronization /// is the caller's responsibility. +/// +/// # Errors +/// +/// The underlying `std::env::set_var` is infallible (panics on failure). +/// The `Err` path only triggers from `CapProvider` scope checks. pub fn set_var( key: impl AsRef, value: impl AsRef, - cap: &impl Has, -) { - let _proof: Cap = cap.cap_ref(); + cap: &impl CapProvider, +) -> Result<(), CapSecError> { + let _proof: Cap = cap.provide_cap(&key.as_ref().to_string_lossy())?; unsafe { std::env::set_var(key, value); } + Ok(()) } diff --git a/crates/capsec-std/src/fs.rs b/crates/capsec-std/src/fs.rs index 6df03a1..e4045f6 100644 --- a/crates/capsec-std/src/fs.rs +++ b/crates/capsec-std/src/fs.rs @@ -8,7 +8,7 @@ //! ```no_run //! # use capsec_core::root::test_root; //! # use capsec_core::permission::FsRead; -//! # use capsec_core::has::Has; +//! # use capsec_core::cap_provider::CapProvider; //! let root = test_root(); //! let cap = root.grant::(); //! let data = capsec_std::fs::read("/tmp/data.bin", &cap).unwrap(); @@ -16,15 +16,18 @@ use crate::file::{ReadFile, WriteFile}; use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::{FsRead, FsWrite}; use std::path::Path; /// Reads the entire contents of a file into a byte vector. /// Requires [`FsRead`] permission. -pub fn read(path: impl AsRef, cap: &impl Has) -> Result, CapSecError> { - let _proof: Cap = cap.cap_ref(); +pub fn read( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result, CapSecError> { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::read(path)?) } @@ -32,9 +35,9 @@ pub fn read(path: impl AsRef, cap: &impl Has) -> Result, C /// Requires [`FsRead`] permission. pub fn read_to_string( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::read_to_string(path)?) } @@ -42,9 +45,9 @@ pub fn read_to_string( /// Requires [`FsRead`] permission. pub fn read_dir( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::read_dir(path)?) } @@ -52,9 +55,9 @@ pub fn read_dir( /// Requires [`FsRead`] permission. pub fn metadata( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::metadata(path)?) } @@ -63,69 +66,90 @@ pub fn metadata( pub fn write( path: impl AsRef, contents: impl AsRef<[u8]>, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::write(path, contents)?) } /// Creates all directories in the given path if they don't exist. /// Requires [`FsWrite`] permission. -pub fn create_dir_all(path: impl AsRef, cap: &impl Has) -> Result<(), CapSecError> { - let _proof: Cap = cap.cap_ref(); +pub fn create_dir_all( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result<(), CapSecError> { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::create_dir_all(path)?) } /// Deletes a file. /// Requires [`FsWrite`] permission. -pub fn remove_file(path: impl AsRef, cap: &impl Has) -> Result<(), CapSecError> { - let _proof: Cap = cap.cap_ref(); +pub fn remove_file( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result<(), CapSecError> { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::remove_file(path)?) } /// Recursively deletes a directory and all its contents. /// Requires [`FsWrite`] permission. -pub fn remove_dir_all(path: impl AsRef, cap: &impl Has) -> Result<(), CapSecError> { - let _proof: Cap = cap.cap_ref(); +pub fn remove_dir_all( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result<(), CapSecError> { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(std::fs::remove_dir_all(path)?) } /// Renames a file or directory. /// Requires [`FsWrite`] permission. +/// +/// Both source and destination paths are checked against the capability's scope. pub fn rename( from: impl AsRef, to: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(&from.as_ref().to_string_lossy())?; + let _proof2: Cap = cap.provide_cap(&to.as_ref().to_string_lossy())?; Ok(std::fs::rename(from, to)?) } /// Copies a file. Requires both [`FsRead`] and [`FsWrite`] permissions /// (passed as separate capability tokens). +/// +/// The read capability is checked against the source path, and the write +/// capability is checked against the destination path. pub fn copy( from: impl AsRef, to: impl AsRef, - read_cap: &impl Has, - write_cap: &impl Has, + read_cap: &impl CapProvider, + write_cap: &impl CapProvider, ) -> Result { - let _read_proof: Cap = read_cap.cap_ref(); - let _write_proof: Cap = write_cap.cap_ref(); + let _read_proof: Cap = read_cap.provide_cap(&from.as_ref().to_string_lossy())?; + let _write_proof: Cap = write_cap.provide_cap(&to.as_ref().to_string_lossy())?; Ok(std::fs::copy(from, to)?) } /// Opens a file for reading. Returns a [`ReadFile`] that implements `Read` + `Seek` /// but NOT `Write`, enforcing the capability boundary beyond the function call. /// Requires [`FsRead`] permission. -pub fn open(path: impl AsRef, cap: &impl Has) -> Result { - let _proof: Cap = cap.cap_ref(); +pub fn open( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(ReadFile::new(std::fs::File::open(path)?)) } /// Creates or truncates a file for writing. Returns a [`WriteFile`] that implements /// `Write` + `Seek` but NOT `Read`, enforcing the capability boundary beyond the function call. /// Requires [`FsWrite`] permission. -pub fn create(path: impl AsRef, cap: &impl Has) -> Result { - let _proof: Cap = cap.cap_ref(); +pub fn create( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(WriteFile::new(std::fs::File::create(path)?)) } diff --git a/crates/capsec-std/src/lib.rs b/crates/capsec-std/src/lib.rs index 9b6e642..8106182 100644 --- a/crates/capsec-std/src/lib.rs +++ b/crates/capsec-std/src/lib.rs @@ -4,7 +4,7 @@ //! //! Every function in this crate mirrors a `std` function but requires a capability //! token proving the caller has the appropriate permission. For example, -//! [`fs::read`] requires `&impl Has`. +//! [`fs::read`] requires `&impl CapProvider`. //! //! This is the enforcement layer of `capsec` — by using these wrappers instead of //! raw `std` calls, you get compile-time verification that your code only exercises diff --git a/crates/capsec-std/src/net.rs b/crates/capsec-std/src/net.rs index 4df54b7..fb4deab 100644 --- a/crates/capsec-std/src/net.rs +++ b/crates/capsec-std/src/net.rs @@ -3,37 +3,31 @@ //! Drop-in replacements for `std::net` functions that require a capability token. use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::{NetBind, NetConnect}; -use std::net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; +use std::net::{TcpListener, TcpStream, UdpSocket}; /// Opens a TCP connection to the given address. /// Requires [`NetConnect`] permission. pub fn tcp_connect( - addr: impl ToSocketAddrs, - cap: &impl Has, + addr: &str, + cap: &impl CapProvider, ) -> Result { - let _proof: Cap = cap.cap_ref(); + let _proof: Cap = cap.provide_cap(addr)?; Ok(TcpStream::connect(addr)?) } /// Binds a TCP listener to the given address. /// Requires [`NetBind`] permission. -pub fn tcp_bind( - addr: impl ToSocketAddrs, - cap: &impl Has, -) -> Result { - let _proof: Cap = cap.cap_ref(); +pub fn tcp_bind(addr: &str, cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap(addr)?; Ok(TcpListener::bind(addr)?) } /// Binds a UDP socket to the given address. /// Requires [`NetBind`] permission. -pub fn udp_bind( - addr: impl ToSocketAddrs, - cap: &impl Has, -) -> Result { - let _proof: Cap = cap.cap_ref(); +pub fn udp_bind(addr: &str, cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap(addr)?; Ok(UdpSocket::bind(addr)?) } diff --git a/crates/capsec-std/src/process.rs b/crates/capsec-std/src/process.rs index cab14ed..f3595d5 100644 --- a/crates/capsec-std/src/process.rs +++ b/crates/capsec-std/src/process.rs @@ -3,8 +3,8 @@ //! Drop-in replacements for `std::process` functions that require a capability token. use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::Spawn; use std::process::{Command, Output}; @@ -12,14 +12,18 @@ use std::process::{Command, Output}; /// Requires [`Spawn`] permission. /// /// Returns a `std::process::Command` that can be further configured before execution. -pub fn command(program: &str, cap: &impl Has) -> Command { - let _proof: Cap = cap.cap_ref(); - Command::new(program) +pub fn command(program: &str, cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap(program)?; + Ok(Command::new(program)) } /// Runs a program with arguments and returns its output. /// Requires [`Spawn`] permission. -pub fn run(program: &str, args: &[&str], cap: &impl Has) -> Result { - let _proof: Cap = cap.cap_ref(); +pub fn run( + program: &str, + args: &[&str], + cap: &impl CapProvider, +) -> Result { + let _proof: Cap = cap.provide_cap(program)?; Ok(Command::new(program).args(args).output()?) } diff --git a/crates/capsec-tests/tests/type_system.rs b/crates/capsec-tests/tests/type_system.rs index 36d8b9e..ae1d77d 100644 --- a/crates/capsec-tests/tests/type_system.rs +++ b/crates/capsec-tests/tests/type_system.rs @@ -416,7 +416,7 @@ fn requires_impl_still_works() { #[capsec_macro::requires(fs::read, on = ctx)] fn fn_with_requires_generic(ctx: &C) { - let _: Cap = ctx.cap_ref(); + let _: Cap = ctx.provide_cap("test").unwrap(); } #[test] @@ -428,8 +428,8 @@ fn requires_auto_bounds_single() { #[capsec_macro::requires(fs::read, net::connect, on = ctx)] fn fn_with_requires_generic_multi(ctx: &C) { - let _: Cap = ctx.cap_ref(); - let _: Cap = ctx.cap_ref(); + let _: Cap = ctx.provide_cap("test").unwrap(); + let _: Cap = ctx.provide_cap("test").unwrap(); } #[test] @@ -441,7 +441,7 @@ fn requires_auto_bounds_multiple() { #[capsec_macro::requires(fs::read, on = ctx)] fn fn_with_requires_generic_existing_bounds(ctx: &C) { - let _: Cap = ctx.cap_ref(); + let _: Cap = ctx.provide_cap("test").unwrap(); } #[test] @@ -495,7 +495,13 @@ impl Has for PanicForge { } } -/// Proves: a diverging Has

impl (panic) fires BEFORE std::fs::read executes. +impl capsec_core::cap_provider::CapProvider for PanicForge { + fn provide_cap(&self, _target: &str) -> Result, capsec_core::error::CapSecError> { + panic!("forged capability — this should fire before I/O"); + } +} + +/// Proves: a diverging CapProvider

impl (panic) fires BEFORE std::fs::read executes. /// If the _proof pattern were missing or incorrect, the I/O would run first. #[test] #[should_panic(expected = "forged capability")] diff --git a/crates/capsec-tokio/README.md b/crates/capsec-tokio/README.md index 092283a..6c4b99c 100644 --- a/crates/capsec-tokio/README.md +++ b/crates/capsec-tokio/README.md @@ -19,7 +19,7 @@ There are three common patterns for using capabilities in async code. When your async code runs on the current task (no `tokio::spawn`), pass capabilities by reference. The scope-before-await pattern inside each wrapper keeps futures `Send` automatically. ```rust,ignore -async fn handle_request(cap: &impl Has) { +async fn handle_request(cap: &impl CapProvider) { let data = capsec::tokio::fs::read("/tmp/config.toml", cap).await?; // use data... } diff --git a/crates/capsec-tokio/src/fs.rs b/crates/capsec-tokio/src/fs.rs index 105dc26..44f07b6 100644 --- a/crates/capsec-tokio/src/fs.rs +++ b/crates/capsec-tokio/src/fs.rs @@ -5,17 +5,18 @@ use crate::file::{AsyncReadFile, AsyncWriteFile}; use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::{FsRead, FsWrite}; use std::path::Path; /// Reads the entire contents of a file into a byte vector. /// Requires [`FsRead`] permission. -pub async fn read(path: impl AsRef, cap: &impl Has) -> Result, CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } +pub async fn read( + path: impl AsRef, + cap: &impl CapProvider, +) -> Result, CapSecError> { + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::read(path).await?) } @@ -23,11 +24,9 @@ pub async fn read(path: impl AsRef, cap: &impl Has) -> Result, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::read_to_string(path).await?) } @@ -35,11 +34,9 @@ pub async fn read_to_string( /// Requires [`FsRead`] permission. pub async fn read_dir( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::read_dir(path).await?) } @@ -47,11 +44,9 @@ pub async fn read_dir( /// Requires [`FsRead`] permission. pub async fn metadata( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::metadata(path).await?) } @@ -60,11 +55,9 @@ pub async fn metadata( pub async fn write( path: impl AsRef, contents: impl AsRef<[u8]>, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::write(path, contents).await?) } @@ -72,11 +65,9 @@ pub async fn write( /// Requires [`FsWrite`] permission. pub async fn create_dir_all( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::create_dir_all(path).await?) } @@ -84,11 +75,9 @@ pub async fn create_dir_all( /// Requires [`FsWrite`] permission. pub async fn remove_file( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::remove_file(path).await?) } @@ -96,38 +85,38 @@ pub async fn remove_file( /// Requires [`FsWrite`] permission. pub async fn remove_dir_all( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(tokio::fs::remove_dir_all(path).await?) } /// Renames a file or directory. /// Requires [`FsWrite`] permission. +/// +/// Both source and destination paths are checked against the capability's scope. pub async fn rename( from: impl AsRef, to: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result<(), CapSecError> { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&from.as_ref().to_string_lossy())?; + let _proof2: Cap = cap.provide_cap(&to.as_ref().to_string_lossy())?; Ok(tokio::fs::rename(from, to).await?) } /// Copies a file. Requires both [`FsRead`] and [`FsWrite`] permissions. +/// +/// The read capability is checked against the source path, and the write +/// capability is checked against the destination path. pub async fn copy( from: impl AsRef, to: impl AsRef, - read_cap: &impl Has, - write_cap: &impl Has, + read_cap: &impl CapProvider, + write_cap: &impl CapProvider, ) -> Result { - { - let _read_proof: Cap = read_cap.cap_ref(); - let _write_proof: Cap = write_cap.cap_ref(); - } + let _read_proof: Cap = read_cap.provide_cap(&from.as_ref().to_string_lossy())?; + let _write_proof: Cap = write_cap.provide_cap(&to.as_ref().to_string_lossy())?; Ok(tokio::fs::copy(from, to).await?) } @@ -136,11 +125,9 @@ pub async fn copy( /// Requires [`FsRead`] permission. pub async fn open( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(AsyncReadFile::new(tokio::fs::File::open(path).await?)) } @@ -149,10 +136,8 @@ pub async fn open( /// Requires [`FsWrite`] permission. pub async fn create( path: impl AsRef, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(&path.as_ref().to_string_lossy())?; Ok(AsyncWriteFile::new(tokio::fs::File::create(path).await?)) } diff --git a/crates/capsec-tokio/src/lib.rs b/crates/capsec-tokio/src/lib.rs index d71133b..ec653ce 100644 --- a/crates/capsec-tokio/src/lib.rs +++ b/crates/capsec-tokio/src/lib.rs @@ -11,7 +11,7 @@ //! //! Enable via feature flags: //! -//! - `rt` — task spawning with capability transfer ([`task::spawn_with`]) +//! - `rt` — task spawning with capability transfer (`task::spawn_with`) //! - `fs` — async filesystem operations (`tokio::fs`) //! - `net` — async network operations (`tokio::net`) //! - `process` — async subprocess execution (`tokio::process`) @@ -30,10 +30,10 @@ //! wrapper keeps futures `Send` automatically. //! //! ```no_run -//! use capsec_core::has::Has; +//! use capsec_core::cap_provider::CapProvider; //! use capsec_core::permission::FsRead; //! -//! async fn handle_request(cap: &impl Has) { +//! async fn handle_request(cap: &impl CapProvider) { //! let data = capsec_tokio::fs::read("/tmp/config.toml", cap).await.unwrap(); //! // ... //! } @@ -42,7 +42,7 @@ //! ## Pattern 2: `spawn_with` (single capability) //! //! When spawning a task that needs one capability, use -//! [`task::spawn_with`]. It converts `Cap

` to `SendCap

` for you — +//! `task::spawn_with`. It converts `Cap

` to `SendCap

` for you — //! no need to call `.make_send()` manually. //! //! ```no_run diff --git a/crates/capsec-tokio/src/net.rs b/crates/capsec-tokio/src/net.rs index f427530..f0765b9 100644 --- a/crates/capsec-tokio/src/net.rs +++ b/crates/capsec-tokio/src/net.rs @@ -4,43 +4,37 @@ //! capability token. use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::{NetBind, NetConnect}; -use tokio::net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket}; +use tokio::net::{TcpListener, TcpStream, UdpSocket}; /// Opens an async TCP connection to the given address. /// Requires [`NetConnect`] permission. pub async fn tcp_connect( - addr: impl ToSocketAddrs, - cap: &impl Has, + addr: &str, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(addr)?; Ok(TcpStream::connect(addr).await?) } /// Binds an async TCP listener to the given address. /// Requires [`NetBind`] permission. pub async fn tcp_bind( - addr: impl ToSocketAddrs, - cap: &impl Has, + addr: &str, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(addr)?; Ok(TcpListener::bind(addr).await?) } /// Binds an async UDP socket to the given address. /// Requires [`NetBind`] permission. pub async fn udp_bind( - addr: impl ToSocketAddrs, - cap: &impl Has, + addr: &str, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(addr)?; Ok(UdpSocket::bind(addr).await?) } diff --git a/crates/capsec-tokio/src/process.rs b/crates/capsec-tokio/src/process.rs index b42c5bf..b6fd0e0 100644 --- a/crates/capsec-tokio/src/process.rs +++ b/crates/capsec-tokio/src/process.rs @@ -4,8 +4,8 @@ //! capability token. use capsec_core::cap::Cap; +use capsec_core::cap_provider::CapProvider; use capsec_core::error::CapSecError; -use capsec_core::has::Has; use capsec_core::permission::Spawn; use std::process::Output; use tokio::process::Command; @@ -14,9 +14,9 @@ use tokio::process::Command; /// Requires [`Spawn`] permission. /// /// Returns a `tokio::process::Command` that can be further configured before execution. -pub fn command(program: &str, cap: &impl Has) -> Command { - let _proof: Cap = cap.cap_ref(); - Command::new(program) +pub fn command(program: &str, cap: &impl CapProvider) -> Result { + let _proof: Cap = cap.provide_cap(program)?; + Ok(Command::new(program)) } /// Runs a program with arguments and returns its output. @@ -24,10 +24,8 @@ pub fn command(program: &str, cap: &impl Has) -> Command { pub async fn run( program: &str, args: &[&str], - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { - { - let _proof: Cap = cap.cap_ref(); - } + let _proof: Cap = cap.provide_cap(program)?; Ok(Command::new(program).args(args).output().await?) } diff --git a/crates/capsec-tokio/tests/async_io.rs b/crates/capsec-tokio/tests/async_io.rs index 60e8a57..2914292 100644 --- a/crates/capsec-tokio/tests/async_io.rs +++ b/crates/capsec-tokio/tests/async_io.rs @@ -113,7 +113,7 @@ async fn async_run_echo() { async fn async_command_returns_tokio_command() { let root = test_root(); let cap = root.spawn(); - let mut cmd = capsec_tokio::process::command("echo", &cap); + let mut cmd = capsec_tokio::process::command("echo", &cap).unwrap(); let output = cmd.arg("test").output().await.unwrap(); assert!(output.status.success()); } diff --git a/crates/capsec/README.md b/crates/capsec/README.md index 73f69e9..9c4cf95 100644 --- a/crates/capsec/README.md +++ b/crates/capsec/README.md @@ -30,8 +30,8 @@ fn main(root: CapRoot) { let data = load_data("/tmp/data.csv", &ctx).unwrap(); } -// Leaf functions take &impl Has

— works with raw caps AND context structs -fn load_data(path: &str, cap: &impl Has) -> Result { +// Leaf functions take &impl CapProvider

— works with raw caps, context structs, AND scoped caps +fn load_data(path: &str, cap: &impl CapProvider) -> Result { capsec::fs::read_to_string(path, cap) } ``` diff --git a/crates/capsec/examples/context_struct.rs b/crates/capsec/examples/context_struct.rs index 41ca914..0a1128f 100644 --- a/crates/capsec/examples/context_struct.rs +++ b/crates/capsec/examples/context_struct.rs @@ -8,7 +8,7 @@ //! Key concepts: //! - `#[capsec::context]` generates Cap fields, constructor, and Has impls //! - Context structs are ZSTs (all fields are zero-sized caps) -//! - Pass `&ctx` directly to leaf functions that take `&impl Has

` +//! - Pass `&ctx` directly to leaf functions that take `&impl CapProvider

` //! - For multi-threaded contexts, use `#[capsec::context(send)]` use capsec::prelude::*; @@ -43,17 +43,17 @@ fn run_app(ctx: &AppCtx) { println!("Would send {} bytes to metrics server", processed.len()); } -// ─── Leaf functions: take `&impl Has

`, not the context ──────── +// ─── Leaf functions: take `&impl CapProvider

`, not the context ──────── -fn get_config_path(cap: &impl Has) -> String { +fn get_config_path(cap: &impl CapProvider) -> String { capsec::env::var("APP_CONFIG", cap).unwrap_or_else(|_| "/etc/app/config.toml".into()) } -fn load_file(path: &str, cap: &impl Has) -> String { +fn load_file(path: &str, cap: &impl CapProvider) -> String { capsec::fs::read_to_string(path, cap).unwrap_or_else(|_| "# default config".into()) } -fn save_output(path: &str, data: &str, cap: &impl Has) { +fn save_output(path: &str, data: &str, cap: &impl CapProvider) { if let Err(e) = capsec::fs::write(path, data.as_bytes(), cap) { eprintln!("Warning: could not write {path}: {e}"); } diff --git a/crates/capsec/examples/incremental_migration.rs b/crates/capsec/examples/incremental_migration.rs index a93a188..84ee05c 100644 --- a/crates/capsec/examples/incremental_migration.rs +++ b/crates/capsec/examples/incremental_migration.rs @@ -16,12 +16,16 @@ use capsec::prelude::*; /// This function has been migrated to capsec. /// The `Has` bound makes the filesystem access explicit. -fn load_config(path: &str, cap: &impl Has) -> Result { +fn load_config(path: &str, cap: &impl CapProvider) -> Result { capsec::fs::read_to_string(path, cap) } /// Also migrated — network access is now visible in the type signature. -fn send_metrics(addr: &str, data: &str, cap: &impl Has) -> Result<(), CapSecError> { +fn send_metrics( + addr: &str, + data: &str, + cap: &impl CapProvider, +) -> Result<(), CapSecError> { let mut stream = capsec::net::tcp_connect(addr, cap)?; std::io::Write::write_all(&mut stream, data.as_bytes())?; Ok(()) diff --git a/crates/capsec/examples/layered_app.rs b/crates/capsec/examples/layered_app.rs index 3877708..5610a8b 100644 --- a/crates/capsec/examples/layered_app.rs +++ b/crates/capsec/examples/layered_app.rs @@ -106,8 +106,8 @@ fn sync_workflow( /// Business logic for the status check. /// /// Also zero capsec imports. Takes domain wrappers + a single cap -/// for env access (leaf-level, so `&impl Has

` is appropriate). -fn status_check(config: &ConfigService, env_cap: &impl Has) -> String { +/// for env access (leaf-level, so `&impl CapProvider

` is appropriate). +fn status_check(config: &ConfigService, env_cap: &impl CapProvider) -> String { let version = capsec::env::var("APP_VERSION", env_cap).unwrap_or_else(|_| "dev".into()); let config_ok = config.get("app").is_some(); diff --git a/crates/capsec/examples/scoped_capabilities.rs b/crates/capsec/examples/scoped_capabilities.rs index 2cbfee1..d0b4243 100644 --- a/crates/capsec/examples/scoped_capabilities.rs +++ b/crates/capsec/examples/scoped_capabilities.rs @@ -12,7 +12,7 @@ //! 2. **Capability check** — `capsec::fs::read(path, &cap)?` verifies permission //! //! Both must pass before I/O happens. This keeps capsec-std wrappers simple -//! (`&impl Has

`) while still supporting fine-grained restrictions. +//! (`&impl CapProvider

`) while still supporting fine-grained restrictions. use capsec::prelude::*; @@ -24,7 +24,7 @@ use capsec::prelude::*; fn read_scoped( path: &str, scope: &Attenuated, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { // Step 1: scope gate — is this path within bounds? scope.check(path)?; @@ -39,7 +39,7 @@ fn read_scoped( /// an unscoped copy for passing to capsec-std functions. fn read_from_dir( path: &str, - raw_cap: &impl Has, + raw_cap: &impl CapProvider, scope: &Attenuated, ) -> Result { scope.check(path)?; @@ -50,7 +50,7 @@ fn read_from_dir( fn connect_scoped( addr: &str, scope: &Attenuated, - cap: &impl Has, + cap: &impl CapProvider, ) -> Result { scope.check(addr)?; capsec::net::tcp_connect(addr, cap) diff --git a/crates/capsec/examples/type_enforcement.rs b/crates/capsec/examples/type_enforcement.rs index 0379719..91500b0 100644 --- a/crates/capsec/examples/type_enforcement.rs +++ b/crates/capsec/examples/type_enforcement.rs @@ -7,7 +7,7 @@ //! Key concepts shown here: //! - `#[capsec::main]` — injects the capability root automatically //! - Convenience methods (`root.fs_read()`) — discoverable via IDE autocomplete -//! - `&impl Has

` — function bounds that declare required permissions +//! - `&impl CapProvider

` — function bounds that declare required permissions //! - `capsec::fs::*`, `capsec::net::*`, `capsec::process::*` — drop-in //! replacements for std that require a capability argument //! @@ -19,19 +19,23 @@ use std::io::Write; /// Reads configuration from disk. /// The `Has` bound makes the filesystem access visible in the signature. -fn load_config(path: &str, cap: &impl Has) -> Result { +fn load_config(path: &str, cap: &impl CapProvider) -> Result { capsec::fs::read_to_string(path, cap) } /// Writes a result file to disk. /// Requires `FsWrite` — cannot read files, only write them. -fn save_result(path: &str, data: &str, cap: &impl Has) -> Result<(), CapSecError> { +fn save_result(path: &str, data: &str, cap: &impl CapProvider) -> Result<(), CapSecError> { capsec::fs::write(path, data.as_bytes(), cap) } /// Opens a TCP connection and sends data. /// Requires `NetConnect` — cannot bind a listener or do filesystem I/O. -fn send_report(addr: &str, data: &str, cap: &impl Has) -> Result<(), CapSecError> { +fn send_report( + addr: &str, + data: &str, + cap: &impl CapProvider, +) -> Result<(), CapSecError> { let mut stream = capsec::net::tcp_connect(addr, cap)?; stream.write_all(data.as_bytes())?; Ok(()) @@ -39,7 +43,7 @@ fn send_report(addr: &str, data: &str, cap: &impl Has) -> Result<(), /// Spawns a subprocess to run cleanup. /// Requires `Spawn` — the most dangerous permission, isolated to just this function. -fn run_cleanup(dir: &str, cap: &impl Has) -> Result<(), CapSecError> { +fn run_cleanup(dir: &str, cap: &impl CapProvider) -> Result<(), CapSecError> { let output = capsec::process::run("rm", &["-rf", dir], cap)?; if !output.status.success() { eprintln!("cleanup failed"); diff --git a/crates/capsec/src/lib.rs b/crates/capsec/src/lib.rs index 25584e1..dfbcc4b 100644 --- a/crates/capsec/src/lib.rs +++ b/crates/capsec/src/lib.rs @@ -15,7 +15,7 @@ //! let data = load_data("/tmp/data.csv", &fs_cap).unwrap(); //! } //! -//! fn load_data(path: &str, cap: &impl Has) -> Result { +//! fn load_data(path: &str, cap: &impl CapProvider) -> Result { //! capsec::fs::read_to_string(path, cap) //! } //! ``` @@ -122,8 +122,9 @@ pub mod tokio { /// ``` pub mod prelude { pub use crate::{ - Ambient, ApproverA, ApproverB, Attenuated, Cap, CapProvider, CapRoot, CapSecError, DirScope, - DualKeyCap, EnvRead, EnvWrite, FsAll, FsRead, FsWrite, Has, HostScope, LoggedCap, NetAll, - NetBind, NetConnect, Permission, Revoker, RuntimeCap, Spawn, Subsumes, TimedCap, + Ambient, ApproverA, ApproverB, Attenuated, Cap, CapProvider, CapRoot, CapSecError, + DirScope, DualKeyCap, DualKeySendCap, EnvRead, EnvWrite, FsAll, FsRead, FsWrite, Has, + HostScope, LoggedCap, LoggedSendCap, NetAll, NetBind, NetConnect, Permission, Revoker, + RuntimeCap, RuntimeSendCap, Scope, SendCap, Spawn, Subsumes, TimedCap, TimedSendCap, }; } diff --git a/crates/capsec/tests/compile_fail/capsec_std_wrong_cap.stderr b/crates/capsec/tests/compile_fail/capsec_std_wrong_cap.stderr index 24c7e4f..c440ad5 100644 --- a/crates/capsec/tests/compile_fail/capsec_std_wrong_cap.stderr +++ b/crates/capsec/tests/compile_fail/capsec_std_wrong_cap.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `Cap: Has` is not satisfied +error[E0277]: the trait bound `Cap: CapProvider` is not satisfied --> tests/compile_fail/capsec_std_wrong_cap.rs:8:55 | 8 | let _ = capsec::fs::read_to_string("/etc/passwd", &net_cap); - | -------------------------- ^^^^^^^^ the trait `Has` is not implemented for `Cap` + | -------------------------- ^^^^^^^^ the trait `CapProvider` is not implemented for `Cap` | | | required by a bound introduced by this call | - = help: the following other types implement trait `Has

`: - `Cap<(Ambient, Ambient)>` implements `Has` - `Cap<(Ambient, EnvRead)>` implements `Has` - `Cap<(Ambient, EnvRead)>` implements `Has` - `Cap<(Ambient, EnvWrite)>` implements `Has` - `Cap<(Ambient, EnvWrite)>` implements `Has` - `Cap<(Ambient, FsAll)>` implements `Has` - `Cap<(Ambient, FsAll)>` implements `Has` - `Cap<(Ambient, FsRead)>` implements `Has` + = help: the following other types implement trait `CapProvider

`: + `Cap<(Ambient, Ambient)>` implements `CapProvider` + `Cap<(Ambient, EnvRead)>` implements `CapProvider` + `Cap<(Ambient, EnvRead)>` implements `CapProvider` + `Cap<(Ambient, EnvWrite)>` implements `CapProvider` + `Cap<(Ambient, EnvWrite)>` implements `CapProvider` + `Cap<(Ambient, FsAll)>` implements `CapProvider` + `Cap<(Ambient, FsAll)>` implements `CapProvider` + `Cap<(Ambient, FsRead)>` implements `CapProvider` and $N others note: required by a bound in `capsec::fs::read_to_string` --> $WORKSPACE/crates/capsec-std/src/fs.rs @@ -22,5 +22,5 @@ note: required by a bound in `capsec::fs::read_to_string` | pub fn read_to_string( | -------------- required by a bound in this function | path: impl AsRef, - | cap: &impl Has, - | ^^^^^^^^^^^ required by this bound in `read_to_string` + | cap: &impl CapProvider, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `read_to_string` diff --git a/crates/capsec/tests/compile_fail/context_bad_field.stderr b/crates/capsec/tests/compile_fail/context_bad_field.stderr index 73403ac..cb1e1fc 100644 --- a/crates/capsec/tests/compile_fail/context_bad_field.stderr +++ b/crates/capsec/tests/compile_fail/context_bad_field.stderr @@ -44,6 +44,29 @@ note: required by a bound in `capsec::Has` | ^^^^^^^^^^ required by this bound in `Has` = note: this error originates in the attribute macro `capsec::context` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `String: Permission` is not satisfied + --> tests/compile_fail/context_bad_field.rs:4:1 + | +4 | #[capsec::context] + | ^^^^^^^^^^^^^^^^^^ the trait `Permission` is not implemented for `String` + | + = help: the following other types implement trait `Permission`: + (A, B) + Ambient + EnvRead + EnvWrite + FsAll + FsRead + FsWrite + NetAll + and $N others +note: required by a bound in `CapProvider` + --> $WORKSPACE/crates/capsec-core/src/cap_provider.rs + | + | pub trait CapProvider { + | ^^^^^^^^^^ required by this bound in `CapProvider` + = note: this error originates in the attribute macro `capsec::context` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `String: Permission` is not satisfied --> tests/compile_fail/context_bad_field.rs:6:8 | @@ -89,3 +112,28 @@ error[E0599]: the method `cap_ref` exists for struct `Cap`, but its trai `String: Permission` which is required by `Cap: capsec::Has` = note: this error originates in the attribute macro `capsec::context` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `String: Permission` is not satisfied + --> tests/compile_fail/context_bad_field.rs:6:8 + | +6 | x: String, + | ^^^^^^ the trait `Permission` is not implemented for `String` + | + = help: the following other types implement trait `Permission`: + (A, B) + Ambient + EnvRead + EnvWrite + FsAll + FsRead + FsWrite + NetAll + and $N others +note: required by a bound in `cap_ref` + --> $WORKSPACE/crates/capsec-core/src/has.rs + | + | pub trait Has { + | ^^^^^^^^^^ required by this bound in `Has::cap_ref` + | /// Returns a new `Cap

` proving the permission is available. + | fn cap_ref(&self) -> Cap

; + | ------- required by a bound in this associated function diff --git a/crates/capsec/tests/compile_fail/requires_on_wrong_type.stderr b/crates/capsec/tests/compile_fail/requires_on_wrong_type.stderr index 3d4f878..d8330e2 100644 --- a/crates/capsec/tests/compile_fail/requires_on_wrong_type.stderr +++ b/crates/capsec/tests/compile_fail/requires_on_wrong_type.stderr @@ -6,26 +6,26 @@ warning: unused import: `capsec::prelude::*` | = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default -error[E0277]: the trait bound `NoHas: Has` is not satisfied +error[E0277]: the trait bound `NoHas: CapProvider` is not satisfied --> tests/compile_fail/requires_on_wrong_type.rs:7:18 | 7 | fn process(ctx: &NoHas) {} | ^^^^^ unsatisfied trait bound | -help: the trait `Has` is not implemented for `NoHas` +help: the trait `CapProvider` is not implemented for `NoHas` --> tests/compile_fail/requires_on_wrong_type.rs:4:1 | 4 | struct NoHas; | ^^^^^^^^^^^^ - = help: the following other types implement trait `Has

`: - `Cap<(Ambient, Ambient)>` implements `Has` - `Cap<(Ambient, EnvRead)>` implements `Has` - `Cap<(Ambient, EnvRead)>` implements `Has` - `Cap<(Ambient, EnvWrite)>` implements `Has` - `Cap<(Ambient, EnvWrite)>` implements `Has` - `Cap<(Ambient, FsAll)>` implements `Has` - `Cap<(Ambient, FsAll)>` implements `Has` - `Cap<(Ambient, FsRead)>` implements `Has` + = help: the following other types implement trait `CapProvider

`: + `Attenuated` implements `CapProvider

` + `Cap<(Ambient, Ambient)>` implements `CapProvider` + `Cap<(Ambient, EnvRead)>` implements `CapProvider` + `Cap<(Ambient, EnvRead)>` implements `CapProvider` + `Cap<(Ambient, EnvWrite)>` implements `CapProvider` + `Cap<(Ambient, EnvWrite)>` implements `CapProvider` + `Cap<(Ambient, FsAll)>` implements `CapProvider` + `Cap<(Ambient, FsAll)>` implements `CapProvider` and $N others note: required by a bound in `_assert_has_0` --> tests/compile_fail/requires_on_wrong_type.rs:6:1 diff --git a/crates/cargo-capsec/src/baseline.rs b/crates/cargo-capsec/src/baseline.rs index e55c9c9..0841b88 100644 --- a/crates/cargo-capsec/src/baseline.rs +++ b/crates/cargo-capsec/src/baseline.rs @@ -87,7 +87,7 @@ pub struct DiffResult { /// Returns `None` if the file doesn't exist or can't be parsed. pub fn load_baseline( workspace_root: &Path, - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) -> Option> { let path = workspace_root.join(BASELINE_FILE); let data = capsec_std::fs::read_to_string(path, cap).ok()?; @@ -98,7 +98,7 @@ pub fn load_baseline( pub fn save_baseline( workspace_root: &Path, findings: &[Finding], - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) -> Result<(), String> { let entries: Vec = findings.iter().map(BaselineEntry::from).collect(); let json = serde_json::to_string_pretty(&entries) diff --git a/crates/cargo-capsec/src/config.rs b/crates/cargo-capsec/src/config.rs index 43f3507..88d6016 100644 --- a/crates/cargo-capsec/src/config.rs +++ b/crates/cargo-capsec/src/config.rs @@ -162,7 +162,7 @@ impl DenyConfig { /// if the file exists but contains invalid TOML. pub fn load_config( workspace_root: &Path, - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) -> Result { let config_path = workspace_root.join(CONFIG_FILE); diff --git a/crates/cargo-capsec/src/discovery.rs b/crates/cargo-capsec/src/discovery.rs index 66cdd3d..6250dc1 100644 --- a/crates/cargo-capsec/src/discovery.rs +++ b/crates/cargo-capsec/src/discovery.rs @@ -79,8 +79,8 @@ pub struct DiscoveryResult { pub fn discover_crates( workspace_root: &Path, include_deps: bool, - spawn_cap: &impl capsec_core::has::Has, - _fs_cap: &impl capsec_core::has::Has, + spawn_cap: &impl capsec_core::cap_provider::CapProvider, + _fs_cap: &impl capsec_core::cap_provider::CapProvider, ) -> Result { // Use --no-deps by default for speed (avoids resolving 300+ transitive deps). // Drop it when --include-deps is set so path dependencies and registry crates appear. @@ -90,6 +90,7 @@ pub fn discover_crates( } let output = capsec_std::process::command("cargo", spawn_cap) + .map_err(|e| format!("Failed to create command: {e}"))? .args(&args) .current_dir(workspace_root) .output() @@ -138,7 +139,7 @@ pub fn discover_crates( /// crate root (the parent of the `src/` directory). pub fn discover_source_files( dir: &Path, - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) -> Vec { let mut files = Vec::new(); discover_recursive(dir, &mut files, cap); @@ -157,7 +158,7 @@ pub fn discover_source_files( fn discover_recursive( dir: &Path, files: &mut Vec, - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) { let entries = match capsec_std::fs::read_dir(dir, cap) { Ok(e) => e, diff --git a/crates/cargo-capsec/src/parser.rs b/crates/cargo-capsec/src/parser.rs index f7687dc..a3ff87a 100644 --- a/crates/cargo-capsec/src/parser.rs +++ b/crates/cargo-capsec/src/parser.rs @@ -120,7 +120,7 @@ pub struct ExternBlock { /// ``` pub fn parse_file( path: &Path, - cap: &impl capsec_core::has::Has, + cap: &impl capsec_core::cap_provider::CapProvider, ) -> Result { let source = capsec_std::fs::read_to_string(path, cap) .map_err(|e| format!("Failed to read {}: {e}", path.display()))?;