Skip to content

Commit 23a6365

Browse files
committed
docs: substantive CRG C annotation (EXPLAINME.adoc)
1 parent e1759e0 commit 23a6365

1 file changed

Lines changed: 120 additions & 8 deletions

File tree

EXPLAINME.adoc

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,146 @@
11
// SPDX-License-Identifier: PMPL-1.0-or-later
22
= ShellIntegration.jl — Show Me The Receipts
3+
Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
34
:toc:
45
:icons: font
56

6-
The README makes claims. This file backs them up.
7+
The README makes claims. This file backs them up with file paths, honest caveats,
8+
and a precise description of what the safety layer actually enforces.
79

810
[quote, README]
911
____
1012
ShellIntegration.jl bridges Julia with the wider operating system. It provides:
13+
(1) PowerShell Bridge — native execution of `pwsh` scripts for cross-platform
14+
admin tasks. (2) Valence Shell — a secure, capability-based shell environment for
15+
sensitive operations. (3) Safety Wrappers — middleware to prevent accidental
16+
destructive commands.
1117
____
1218

13-
== Technology Choices
19+
== What It Actually Does Today
20+
21+
=== Claim: Safety wrappers that block destructive commands
22+
23+
*True and enforced at the regex level.* `exec_safe(cmd::Cmd)` and the internal
24+
`_is_dangerous(cmd_str::String)` function in `src/ShellIntegration.jl` check every
25+
command against a nine-pattern blocklist:
26+
27+
- `rm -rf /` and `rm -f /path` patterns
28+
- `mkfs.*` (filesystem formatting)
29+
- `dd .*of=/dev/` (raw device writes)
30+
- `chmod -R 777` (world-writable recursion)
31+
- Fork bomb `:(){ :\|:& };:`
32+
- Block device overwrite via `>`
33+
- `curl | (ba)?sh` and `wget | (ba)?sh` (pipe-to-shell download attacks)
34+
35+
The test suite confirms `exec_safe(\`rm -rf /\`)` throws `ErrorException` with
36+
a message containing "Unsafe command blocked". It also confirms that plain `rm`
37+
without `-rf` passes the safety check (though the `rm` itself may then fail for
38+
other reasons).
39+
40+
=== Claim: Capability-based Valence shell restricting which commands are available
41+
42+
*Fully implemented.* `start_valence_shell(; capabilities, prompt, timeout_seconds)`
43+
runs an interactive REPL with a six-capability enum (`CAP_READ`, `CAP_WRITE`,
44+
`CAP_NETWORK_OUT`, `CAP_NETWORK_IN`, `CAP_EXEC`, `CAP_ENV`). The `_has_capability`
45+
function classifies every command by its first token (executable name) against
46+
hardcoded sets — e.g., `cat`/`ls`/`grep`/`rg`/`sha256sum` require `CAP_READ`;
47+
`curl`/`wget`/`ssh`/`rsync` require `CAP_NETWORK_OUT`; anything not classified
48+
requires `CAP_EXEC`. The dangerous-pattern check runs unconditionally before the
49+
capability check, so no capability grants access to `rm -rf /`.
50+
51+
*Honest caveat:* The capability classification is static keyword matching. It does
52+
not sandbox the subprocess via kernel namespaces or seccomp; a `CAP_EXEC`-permitted
53+
process could spawn further shells. The safety guarantee is best-effort for
54+
interactive accidental misuse, not adversarial containment.
55+
56+
=== Claim: PowerShell Bridge
57+
58+
`run_pwsh(script::String)` shells out to `pwsh -NoProfile -NonInteractive -Command`
59+
and returns stdout as a String. It requires `pwsh` (PowerShell Core) on the PATH.
60+
No Windows-specific code paths; works on Fedora with `pwsh` installed via the
61+
Microsoft repo.
62+
63+
== How It Works
64+
65+
Critical path for `exec_safe`:
66+
67+
. Caller provides a `Cmd` (e.g., `\`echo hello\``).
68+
. `exec_safe` calls `string(cmd)` to get a string representation.
69+
. `_is_dangerous(cmd_str)` scans against each of the nine `DANGEROUS_PATTERNS` regexes.
70+
. If any match, throws `ErrorException("Unsafe command blocked: $cmd_str")`.
71+
. Otherwise, calls `run(cmd)` and returns the `Process`.
72+
73+
Critical path for `start_valence_shell`:
74+
75+
. Enters a timed REPL loop (default timeout 300s).
76+
. Reads a line from stdin.
77+
. Calls `_is_dangerous` unconditionally.
78+
. Calls `_has_capability(input, capabilities)` to check the first token.
79+
. If both pass, executes via `read(\`sh -c $input\`, String)` and prints stdout.
80+
81+
== Dogfooded Across The Account
1482

1583
[cols="1,2"]
1684
|===
17-
| Technology | Learn More
85+
| Project | Connection
86+
87+
| `SoftwareSovereign.jl`
88+
| The `enforce_policy` path invokes shell commands (DNF, Flatpak, ASDF) through
89+
`exec_safe` to prevent policy enforcement from accidentally issuing destructive
90+
system commands.
91+
92+
| `ambientops` (volumod, personal-sysadmin)
93+
| ShellIntegration is the standard Julia shell bridge in the ambientops monorepo;
94+
admin automation scripts use `run_pwsh` for cross-platform tasks.
95+
96+
| `developer-ecosystem/julia-ecosystem/`
97+
| ShellIntegration is catalogued as the systems-integration bridge package.
98+
99+
| `game-server-admin` (zatty)
100+
| The zatty terminal detection utility shares the capability-flag mental model;
101+
ShellIntegration's `CAP_*` enum is the Julia-side analogue.
18102

19-
| **Julia** | https://julialang.org
103+
| `hypatia` CI scan
104+
| `hypatia-scan.yml` validates SPDX headers and checks for dangerous shell patterns
105+
in repository code, complementing ShellIntegration's runtime blocking.
20106
|===
21107

22108
== File Map
23109

24-
[cols="1,2"]
110+
[cols="1,3"]
25111
|===
26112
| Path | What's There
27113

28-
| `src/` | Source code
29-
| `test(s)/` | Test suite
114+
| `src/ShellIntegration.jl`
115+
| Entire module (~270 lines): `Capability` enum (6 values); `DANGEROUS_PATTERNS`
116+
constant (9 regexes); `run_pwsh`, `start_valence_shell`, `exec_safe` exports;
117+
`_is_dangerous`, `_has_capability`, `_valence_help` internal helpers.
118+
`_has_capability` classifies ~30 named executables into capability buckets.
119+
120+
| `test/runtests.jl`
121+
| 8 testsets: `exec_safe` blocks `rm -rf /` with correct error message; allows
122+
safe `echo`; allows plain `rm` (which may fail for process reasons); method
123+
signature checks for all three exports; `start_valence_shell` returns `nothing`.
124+
Chains to `e2e_test.jl` and `property_test.jl`.
125+
126+
| `test/e2e_test.jl`
127+
| End-to-end scenario: calls `exec_safe` on a sequence of safe and unsafe commands,
128+
verifying the correct subset is blocked.
129+
130+
| `test/property_test.jl`
131+
| Property-based checks: arbitrary strings matching dangerous patterns must always
132+
be blocked; arbitrary safe commands must never be blocked by `_is_dangerous`.
133+
134+
| `Project.toml`
135+
| Package identity (uuid `c3d4e5f6...`), stdlib `Libdl` only, Julia ≥ 1.10.
136+
No third-party runtime dependencies.
137+
138+
| `TOPOLOGY.md`
139+
| Dependency graph: ShellIntegration sits between the OS layer and higher-level
140+
packages (SoftwareSovereign, ambientops scripts).
30141
|===
31142

32143
== Questions?
33144

34-
Open an issue or reach out directly — happy to explain anything in more detail.
145+
Open an issue or reach out — happy to discuss capability model design choices
146+
or the regex blocklist rationale.

0 commit comments

Comments
 (0)