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