Summary
When one of the AllowedPaths configured by the caller cannot be opened (e.g. C:\var\log on a Windows host, where /var/log exists on Linux but its Windows counterpart does not), the sandbox emits a diagnostic warning to stderr. Because the warning is flushed to r.stderr during Runner construction, every script execution in that session ends up with a non-empty stderr, which makes the output look like the command itself failed even though exitCode is 0.
Repro
Run ss (or any command) with AllowedPaths including a path that does not exist on the host.
Windows (par-in-windows-smoke-test-remote-action, AllowedPaths contains C:\var\log):
{
"exitCode": 0,
"stderr": "AllowedPaths: skipping \"C:\\\\var\\\\log\": open C:\\var\\log: The system cannot find the path specified.\n",
"stdout": "Netid State ... (tcp entries) ..."
}
Linux (same command, /var/log exists):
{
"exitCode": 0,
"stderr": "",
"stdout": "Netid State ... (tcp + udp + unix entries) ..."
}
Root cause
allowedpaths/sandbox.go:60-68 — allowedpaths.New() records a warning whenever os.OpenRoot(abs) fails (missing path, not a directory, no permission, etc.):
r, err := os.OpenRoot(abs)
if err != nil {
fmt.Fprintf(&buf, "AllowedPaths: skipping %q: %v\n", abs, err)
continue
}
interp/api.go:255-258 — the buffered warnings are flushed to r.stderr once during New():
if len(r.sandboxWarnings) > 0 {
r.stderr.Write(r.sandboxWarnings)
r.sandboxWarnings = nil
}
This is by design — AllowedPaths is advisory and missing paths must not fail the Runner — but it makes stderr noisy for every caller that ships a cross-platform allowlist containing paths that only exist on one OS.
Impact
- Callers that inspect
stderr to detect command failure see false positives (exit code is 0 but stderr is non-empty).
- Integrations that pipe
stderr into structured output (e.g. the remote-action UI in the screenshots) display the warning on every invocation.
- On a correctly-configured host (e.g. Linux with
/var/log) the stderr is empty, so the noise is purely a platform-skew artefact, not a real operational problem.
Proposals
Pick one (or combine):
- Route sandbox diagnostics to a dedicated sink — a
SandboxWarnings(io.Writer) option or an accessor (r.Warnings()) so callers can opt in to displaying them without them contaminating command stderr.
- Log only once, demote to debug — write to a logger at debug level rather than stderr; still surface via an accessor for tests/diagnostics.
- Silently drop missing paths — since the warning content does not change command behaviour, and most deployments will configure cross-platform allowlists, simply omit the
fmt.Fprintf for os.OpenRoot failures. Keep the warning for genuinely unexpected errors (e.g. filepath.Abs failure).
- Gate behind an env var / option — e.g.
RSHELL_VERBOSE_SANDBOX=1, off by default.
Option 1 or 2 preserves the diagnostic for operators who want it; option 3 is simplest if the warning is judged to be more noise than signal in practice.
Workaround for callers today
Strip/replace Unix-shaped paths (/var/log, /etc, /tmp, ...) before sending the allowlist to rshell on Windows — pick platform-appropriate equivalents (C:\ProgramData\Datadog\logs, C:\Windows\Temp, etc.).
Summary
When one of the
AllowedPathsconfigured by the caller cannot be opened (e.g.C:\var\logon a Windows host, where/var/logexists on Linux but its Windows counterpart does not), the sandbox emits a diagnostic warning tostderr. Because the warning is flushed tor.stderrduringRunnerconstruction, every script execution in that session ends up with a non-emptystderr, which makes the output look like the command itself failed even thoughexitCodeis0.Repro
Run
ss(or any command) withAllowedPathsincluding a path that does not exist on the host.Windows (
par-in-windows-smoke-test-remote-action,AllowedPathscontainsC:\var\log):{ "exitCode": 0, "stderr": "AllowedPaths: skipping \"C:\\\\var\\\\log\": open C:\\var\\log: The system cannot find the path specified.\n", "stdout": "Netid State ... (tcp entries) ..." }Linux (same command,
/var/logexists):{ "exitCode": 0, "stderr": "", "stdout": "Netid State ... (tcp + udp + unix entries) ..." }Root cause
allowedpaths/sandbox.go:60-68—allowedpaths.New()records a warning wheneveros.OpenRoot(abs)fails (missing path, not a directory, no permission, etc.):interp/api.go:255-258— the buffered warnings are flushed tor.stderronce duringNew():This is by design —
AllowedPathsis advisory and missing paths must not fail the Runner — but it makesstderrnoisy for every caller that ships a cross-platform allowlist containing paths that only exist on one OS.Impact
stderrto detect command failure see false positives (exit code is 0 but stderr is non-empty).stderrinto structured output (e.g. the remote-action UI in the screenshots) display the warning on every invocation./var/log) the stderr is empty, so the noise is purely a platform-skew artefact, not a real operational problem.Proposals
Pick one (or combine):
SandboxWarnings(io.Writer)option or an accessor (r.Warnings()) so callers can opt in to displaying them without them contaminating command stderr.fmt.Fprintfforos.OpenRootfailures. Keep the warning for genuinely unexpected errors (e.g.filepath.Absfailure).RSHELL_VERBOSE_SANDBOX=1, off by default.Option 1 or 2 preserves the diagnostic for operators who want it; option 3 is simplest if the warning is judged to be more noise than signal in practice.
Workaround for callers today
Strip/replace Unix-shaped paths (
/var/log,/etc,/tmp, ...) before sending the allowlist to rshell on Windows — pick platform-appropriate equivalents (C:\ProgramData\Datadog\logs,C:\Windows\Temp, etc.).