ready_set_sdk/sandbox.rs
1//! Sandbox abstraction for plugins.
2//!
3//! In v0.1.0 the per-platform implementations are no-op stubs that record
4//! declared capabilities only. The trait surface is `stable`; implementations
5//! are `experimental` and will gain real enforcement post-v0.1.0.
6
7use crate::error::Result;
8
9/// Capability a plugin may declare to its sandbox.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[non_exhaustive]
12pub enum Capability {
13 /// Read files within the project root.
14 ReadProject,
15 /// Write files within the project root.
16 WriteProject,
17 /// Read files within the user's home directory.
18 ReadHome,
19 /// Write files within the user's home directory.
20 WriteHome,
21 /// Network access.
22 Network,
23 /// Spawn subprocesses.
24 Subprocess,
25}
26
27/// A platform sandbox. Plugins declare the capabilities they need, then
28/// `enter` to commit to the sandbox.
29pub trait Sandbox {
30 /// Declare the capabilities this plugin needs.
31 fn declare(&mut self, capabilities: &[Capability]);
32 /// Enter the sandbox. After this returns, attempts to use undeclared
33 /// capabilities should fail.
34 ///
35 /// # Errors
36 ///
37 /// Implementation-specific. The v0.1.0 stub never errors.
38 fn enter(&self) -> Result<()>;
39}
40
41/// A no-op sandbox that records declarations and does not enforce anything.
42#[derive(Debug, Default, Clone)]
43pub struct NoopSandbox {
44 declared: Vec<Capability>,
45}
46
47impl NoopSandbox {
48 /// Capabilities recorded so far.
49 #[must_use]
50 pub fn declared(&self) -> &[Capability] {
51 &self.declared
52 }
53}
54
55impl Sandbox for NoopSandbox {
56 fn declare(&mut self, capabilities: &[Capability]) {
57 self.declared.extend_from_slice(capabilities);
58 }
59
60 fn enter(&self) -> Result<()> {
61 Ok(())
62 }
63}
64
65/// Return the sandbox for the current platform.
66///
67/// In v0.1.0 every platform returns a [`NoopSandbox`].
68#[must_use]
69pub fn for_current_platform() -> Box<dyn Sandbox> {
70 Box::new(NoopSandbox::default())
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn noop_sandbox_records_declarations() {
79 let mut sb = NoopSandbox::default();
80 sb.declare(&[Capability::ReadProject, Capability::Subprocess]);
81 sb.enter().unwrap();
82 assert_eq!(
83 sb.declared(),
84 &[Capability::ReadProject, Capability::Subprocess]
85 );
86 }
87}