Skip to main content

basis/
shell.rs

1//! Whether a run may execute commands.
2//!
3//! Per [ADR-0013] the host owns the boundary. Commands are enabled by default:
4//! a harness that cannot run `cargo test` does very little real work, and the
5//! flag that used to gate them was theater once a process spawned — an
6//! in-process path check cannot confine a command that is already running.
7//!
8//! So basis claims nothing. The process holds whatever authority the user who
9//! started it holds, and confinement, where it is wanted, comes from the OS —
10//! `docs/containerization.md` has the patterns. Denying is one line for a run
11//! that is meant to read and report.
12//!
13//! [ADR-0013]: https://github.com/oops-rs/basis/blob/main/docs/adr/0013-the-host-owns-the-boundary.md
14
15/// Whether the agent may run commands.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub enum ShellAccess {
18    /// No command execution.
19    ///
20    /// For a run that inspects a workspace and reports on it. Worth being
21    /// precise about what this is: one route closed, not a boundary. The file
22    /// tools still write, and the process still runs as its user — see
23    /// [`DenyAll`](crate::DenyAll) for a run that changes nothing at all.
24    Denied,
25    /// Commands allowed.
26    ///
27    /// The default. A command reaches whatever the user account running basis
28    /// can reach, which is the honest description of a process on a host and
29    /// is why basis neither warns about it per run nor pretends otherwise.
30    #[default]
31    Granted,
32}
33
34impl ShellAccess {
35    pub fn is_granted(self) -> bool {
36        matches!(self, Self::Granted)
37    }
38
39    /// Maps a yes-or-no answer onto the enum, for a caller holding a bool —
40    /// a CLI flag, a config field, an environment variable of its own.
41    pub fn from_flag(granted: bool) -> Self {
42        if granted { Self::Granted } else { Self::Denied }
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn commands_are_the_default() {
52        // ADR-0013: the first `basis "run the tests"` has to work, and a default
53        // of denied made the tool's purpose opt-in.
54        assert_eq!(ShellAccess::default(), ShellAccess::Granted);
55        assert!(ShellAccess::default().is_granted());
56    }
57
58    #[test]
59    fn a_flag_maps_both_ways() {
60        assert_eq!(ShellAccess::from_flag(true), ShellAccess::Granted);
61        assert_eq!(ShellAccess::from_flag(false), ShellAccess::Denied);
62    }
63}