Review the safety boundary

Updated Sep 02, 2026

Netsuke reduces some common quoting mistakes, but it is not a sandbox:

  • {{ ins }} and {{ outs }} are quoted as path arguments.
  • Arbitrary Jinja values in command and script are not automatically shell-quoted.
  • On Windows, legacy recipes use the PowerShell contract above unless NETSUKE_WINDOWS_SHELL=bash selects the explicit Bash compatibility route. On Unix, scripts use /bin/sh -e.
  • shell, grep, fetch, filesystem helpers, and ordinary recipes interact with the host.
  • glob restricts its filesystem metadata access to a capability handle scoped to the pattern's literal directory prefix, so it cannot inspect anything outside the subtree the pattern can match; the pattern match walk itself still uses ambient filesystem access.
  • Verbose glob tracing replaces every caller-controlled path field — patterns, prefixes, and sampled relative matches — with the stable <redacted> marker. Aggregate metrics retain only bounded status and reason data. Error messages may retain the original input so invalid patterns can be explained.
  • raw template output and handwritten shell fragments remain the manifest author's responsibility.
  • On Unix and in the explicit Windows Bash compatibility route, each command list entry is joined into a single shell chain; a later entry inherits the working directory, environment, and shell variables left by an earlier entry, and runs only when that earlier entry exits with status zero. A failed entry may still leave side effects behind before it halts the chain. The generated brace/eval boundary keeps comments and trailing control operators inside an entry from changing the chain's structure. An entry may start at most one background job; Netsuke waits for that job before moving to a later entry, and rejects an entry that starts more than one background job during Ninja generation. It also rejects an entry whose nested eval payload makes the background-job count dynamic because the wrapper cannot safely determine which jobs to wait for. A direct simple exec, optionally prefixed by shell assignments, is supervised so its success or failure retains the list's status semantics: a successful exec ends the remaining chain, while structured or nested exec forms are rejected during Ninja generation. Failure diagnostics include the action fingerprint and one-based entry position when Netsuke can attribute the failed list entry.
  • On Windows in the default PowerShell route, each command list shares one PowerShell process. Netsuke checks $LASTEXITCODE immediately after every generated list entry and stops before a later entry can overwrite a failure. Multiple native commands inside one entry are not individually instrumented; terminating PowerShell errors also stop the list. The POSIX brace-group, eval, background-job, and exec restrictions do not apply to this route.
  • Write shell dollar expressions normally. $PATH, $RUSTFLAGS, $ins, and $outs are literal shell variables; PowerShell routes use $name or $env:NAME. Netsuke escapes those dollars as $$ only in generated Ninja so the shell receives them unchanged. {{ ins }} and {{ outs }} are the only Netsuke markers for input and output paths. On POSIX and Bash routes, Netsuke encodes a marker for its unquoted, single-quoted, or double-quoted shell context, and rejects one in a command substitution or backticks. In PowerShell, use markers unquoted; Netsuke rejects quoted and command-substitution marker sites rather than risking a context escape. PowerShell uses backticks as its native escape syntax, so they do not suppress marker interpolation.
  • Build and default-target paths reject $, spaces, colons, |, and control characters because Ninja cannot represent them without ambiguity. Generation also rejects newline, carriage-return, and NUL characters in emitted metadata such as descriptions, depfile, deps, and pool.
  • Migration: replace the historical manifest spelling $$PATH with $PATH. On POSIX and Bash routes, $$ is the shell's process identifier; PowerShell interprets $$ as its automatic variable containing the last token received by the session. Keeping the extra dollar can therefore change the command's result. Replace any former $in or $out path placeholder with {{ ins }} or {{ outs }} respectively; literal $ins and $outs remain shell variables.

Do not run an untrusted Netsukefile. Prefer explicit inputs, avoid embedding secrets in commands or URLs, and pin dependencies used by recipes.