capsec_core/permission.rs
1//! The sealed [`Permission`] trait and all built-in permission types.
2//!
3//! Permissions are zero-sized marker types that encode what kind of I/O a
4//! capability token grants. They form a sealed hierarchy — external crates
5//! cannot define new permissions, ensuring the set is auditable.
6//!
7//! # Built-in permissions
8//!
9//! | Type | Category | What it grants |
10//! |------|----------|----------------|
11//! | [`FsRead`] | Filesystem | Read files, list directories, check metadata |
12//! | [`FsWrite`] | Filesystem | Write, create, delete files and directories |
13//! | [`FsAll`] | Filesystem | All filesystem operations (subsumes `FsRead` + `FsWrite`) |
14//! | [`NetConnect`] | Network | Open outbound TCP/UDP connections |
15//! | [`NetBind`] | Network | Bind listeners and sockets to local ports |
16//! | [`NetAll`] | Network | All network operations (subsumes `NetConnect` + `NetBind`) |
17//! | [`EnvRead`] | Environment | Read environment variables |
18//! | [`EnvWrite`] | Environment | Modify or remove environment variables |
19//! | [`Spawn`] | Process | Execute subprocesses |
20//! | [`Ambient`] | Everything | Full ambient authority — the "god token" |
21//!
22//! # Tuples
23//!
24//! Two permissions can be bundled via a tuple: `(FsRead, NetConnect)` is itself
25//! a `Permission`, and `Cap<(FsRead, NetConnect)>` satisfies both `Has<FsRead>`
26//! and `Has<NetConnect>`. All 2-tuple combinations of built-in permissions are
27//! supported.
28//!
29//! # Subsumption
30//!
31//! Some permissions imply others. [`FsAll`] subsumes both [`FsRead`] and [`FsWrite`],
32//! meaning a `Cap<FsAll>` can be used anywhere a `Cap<FsRead>` is required.
33//! [`Ambient`] subsumes everything.
34
35/// Marker trait for all capability permissions. Sealed to prevent external implementation.
36///
37/// Every permission type is a zero-sized struct that implements this trait.
38/// The sealed pattern ensures that only the permissions defined in this crate
39/// can be used as capability tokens — external crates cannot forge new permissions.
40pub trait Permission: sealed::Sealed + 'static {}
41
42// Filesystem
43
44/// Permission to read files, list directories, and check metadata.
45pub struct FsRead;
46
47/// Permission to write, create, rename, and delete files and directories.
48pub struct FsWrite;
49
50/// Permission for all filesystem operations. Subsumes [`FsRead`] and [`FsWrite`].
51pub struct FsAll;
52
53// Network
54
55/// Permission to open outbound TCP and UDP connections.
56pub struct NetConnect;
57
58/// Permission to bind TCP listeners and UDP sockets to local ports.
59pub struct NetBind;
60
61/// Permission for all network operations. Subsumes [`NetConnect`] and [`NetBind`].
62pub struct NetAll;
63
64// Environment
65
66/// Permission to read environment variables.
67pub struct EnvRead;
68
69/// Permission to modify or remove environment variables.
70pub struct EnvWrite;
71
72// Process
73
74/// Permission to spawn and execute subprocesses via `std::process::Command`.
75pub struct Spawn;
76
77// Ambient
78
79/// Full ambient authority — grants every permission.
80///
81/// This is the "god token." A `Cap<Ambient>` satisfies any `Has<P>` bound.
82/// Use sparingly and only at the capability root.
83pub struct Ambient;
84
85// Permission impls
86
87impl Permission for FsRead {}
88impl Permission for FsWrite {}
89impl Permission for FsAll {}
90impl Permission for NetConnect {}
91impl Permission for NetBind {}
92impl Permission for NetAll {}
93impl Permission for EnvRead {}
94impl Permission for EnvWrite {}
95impl Permission for Spawn {}
96impl Permission for Ambient {}
97
98// Tuple permissions
99
100impl<A: Permission, B: Permission> Permission for (A, B) {}
101
102// Subsumption
103
104/// Indicates that `Self` implies permission `P`.
105///
106/// When `Super: Subsumes<Sub>`, a `Cap<Super>` can satisfy `Has<Sub>`.
107/// For example, `FsAll: Subsumes<FsRead>` means `Cap<FsAll>` works
108/// anywhere `Has<FsRead>` is required.
109pub trait Subsumes<P: Permission>: Permission {}
110
111impl Subsumes<FsRead> for FsAll {}
112impl Subsumes<FsWrite> for FsAll {}
113impl Subsumes<NetConnect> for NetAll {}
114impl Subsumes<NetBind> for NetAll {}
115impl<P: Permission> Subsumes<P> for Ambient {}
116
117// Sealed
118
119mod sealed {
120 pub trait Sealed {}
121 impl Sealed for super::FsRead {}
122 impl Sealed for super::FsWrite {}
123 impl Sealed for super::FsAll {}
124 impl Sealed for super::NetConnect {}
125 impl Sealed for super::NetBind {}
126 impl Sealed for super::NetAll {}
127 impl Sealed for super::EnvRead {}
128 impl Sealed for super::EnvWrite {}
129 impl Sealed for super::Spawn {}
130 impl Sealed for super::Ambient {}
131 impl<A: Sealed, B: Sealed> Sealed for (A, B) {}
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use std::mem::size_of;
138
139 #[test]
140 fn all_permissions_are_zst() {
141 assert_eq!(size_of::<FsRead>(), 0);
142 assert_eq!(size_of::<FsWrite>(), 0);
143 assert_eq!(size_of::<FsAll>(), 0);
144 assert_eq!(size_of::<NetConnect>(), 0);
145 assert_eq!(size_of::<NetBind>(), 0);
146 assert_eq!(size_of::<NetAll>(), 0);
147 assert_eq!(size_of::<EnvRead>(), 0);
148 assert_eq!(size_of::<EnvWrite>(), 0);
149 assert_eq!(size_of::<Spawn>(), 0);
150 assert_eq!(size_of::<Ambient>(), 0);
151 }
152
153 // Compile-time proof that subsumption relationships hold:
154 fn _assert_subsumes<Super: Subsumes<Sub>, Sub: Permission>() {}
155
156 #[test]
157 fn tuple_permission_is_zst() {
158 assert_eq!(size_of::<(FsRead, NetConnect)>(), 0);
159 }
160
161 #[test]
162 fn subsumption_relationships() {
163 _assert_subsumes::<FsAll, FsRead>();
164 _assert_subsumes::<FsAll, FsWrite>();
165 _assert_subsumes::<NetAll, NetConnect>();
166 _assert_subsumes::<NetAll, NetBind>();
167 _assert_subsumes::<Ambient, FsRead>();
168 _assert_subsumes::<Ambient, NetConnect>();
169 _assert_subsumes::<Ambient, Spawn>();
170 }
171}