Skip to content

Commit e1d8abc

Browse files
committed
feat(builtins): make, a GNU make subset run in the sandbox shell
Driver-based make: parses makefiles (assignments, conditionals, define, include, explicit/pattern/static/suffix rules, target-specific vars, special targets), expands functions incl. $(shell)/$(wildcard), and runs recipes as sh -c in the interpreter. New PlanStep::Capture/Emit keep $(shell) output captured and make's messages ordered with recipe output. Gaps L-MAKE-001..003, caps TM-DOS-126. Claude-Session: https://claude.ai/code/session_019aFikmptPc91Fj4N2iDXQA
1 parent 1ea4653 commit e1d8abc

17 files changed

Lines changed: 3779 additions & 13 deletions

File tree

‎crates/bashkit/docs/compatibility.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ for sandbox security reasons. See the compliance spec for details.
9999
| `disown`, `fg`, `bg` | `[JOBSPEC]` | `fg` waits; `bg` is a no-op (jobs already run) |
100100
| `uuidgen` | `-r` | Random (v4) UUID from the OS CSPRNG |
101101
| `openssl` | `rand [-hex\|-base64] [-out FILE] NUM` | Only `rand`; other subcommands fail with `Invalid command` |
102+
| `make` | `-f`, `-C`, `-n`, `-k`, `-q`, `-s`, `-i`, `-B`, `-e`, `-j` (sequential), `VAR=value` | GNU make subset; recipes run in the sandbox shell; no built-in implicit rules, `$(eval)` or `vpath` (L-MAKE-001..003) |
102103
| `curl` | `-s`, `-o`, `-X`, `-d`/`--data`, `--data-raw`, `--data-binary`, `--data-urlencode`, `-G`/`--get`, `-H`, `-I`, `-f`, `-L`, `-w`, `--compressed`, `-u`, `-A`, `-e`, `-v`, `-m` | HTTP client (requires http_client feature) |
103104
| `wget` | `-q`, `-O`, `--spider`, `--header`, `-U`, `--post-data`, `-t` | Download files (requires http_client feature) |
104105
| `time` | `[-p] [-f FORMAT] [-o FILE] [-a] [-v] [--] PIPELINE` | Reserved-word timing; elapsed/status/Bashkit counters are truthful, host CPU/RSS fields say `unavailable` |

‎crates/bashkit/docs/threat-model.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ through configurable limits.
115115
| Interactive terminal flooding (TM-DOS-119) | Unbounded type-ahead, undrained output, or a `vi` buffer grown by pastes | Caps on unread input (1 MiB), retained output (4 MiB), scrollback (1000 rows), transcript (1 MiB), line length, `vi` buffer (8 MiB) and undo history; `:w` goes through VFS limits | MITIGATED |
116116
| Input wait vs. timeout (TM-DOS-120) | Abusing the keyboard-wait exclusion to run work past the deadline | Only time blocked reading the terminal is excluded; CPU work and `sleep` still count | MITIGATED |
117117
| Concurrent pipeline amplification (TM-DOS-124) | An endless loop piped into `head`, a producer whose reader quit, or recursive pipelines `f() { f \| f; }` | 4 KiB pipes with backpressure; a writer whose reader is gone ends with 141 (SIGPIPE); streaming nesting counts toward `max_subshell_depth` and falls back to sequential stages past 4 levels; stages share the session budget, timeout and cancellation | MITIGATED |
118+
| make amplification (TM-DOS-126) | Exponential recursive variables, self-including makefiles, deep `$(MAKE)` recursion, huge graphs | Expansion depth 200 and 4 MiB per expansion; include depth 16; target, query and glob caps per run; `$(MAKE)` stops at level 8; recipes run under the session budget and timeout | MITIGATED |
118119
| Random generator amplification (TM-DOS-123) | `openssl rand` asked for gigabytes | Requests capped at 1 MiB; fixed-size `uuidgen`/`$SRANDOM` | MITIGATED |
119120
| Unbounded builtin output (TM-DOS-058) | `seq 1 1000000` produces 1M lines | Add `max_stdout_bytes` limit | **MITIGATED** |
120121
| Silent truncation at builtin caps (TM-DOS-109) | `seq 200000`, an awk loop past its cap, or an oversized `sprintf` expression returns incomplete output with exit 0 | Caps report `<cmd>: <what> limit (<N>) exceeded` on stderr and exit non-zero; awk caps and formatting errors are fatal | **MITIGATED** |

‎crates/bashkit/src/builtins/find/mod.rs‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,10 +1003,12 @@ impl Builtin for Find {
10031003
match run.next(None).await? {
10041004
PlanStep::Done(result) => Ok(result),
10051005
// Only reachable if the plan path was skipped; -exec needs it.
1006-
PlanStep::Run { .. } => Ok(ExecResult::err(
1007-
"find: -exec is not available in this context\n".to_string(),
1008-
1,
1009-
)),
1006+
PlanStep::Run { .. } | PlanStep::Capture { .. } | PlanStep::Emit { .. } => {
1007+
Ok(ExecResult::err(
1008+
"find: -exec is not available in this context\n".to_string(),
1009+
1,
1010+
))
1011+
}
10101012
}
10111013
}
10121014

‎crates/bashkit/src/builtins/ls/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Directory listing builtins - ls, rmdir, and shared glob matching.
22
3-
mod glob;
3+
pub(crate) mod glob;
44
mod list;
55
mod rmdir;
66

0 commit comments

Comments
 (0)