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