Auto-degrade when jail setup is denied after the child starts, so consumers stop declaring CLIGUARD_NO_SANDBOX #277
Labels
No labels
burndown-2026-06
sunday-sprint
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/umbra#277
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Outcome
Every environment that cannot create the namespace jail degrades to an unsandboxed run on its own. No consumer repo, workflow, image, or test declares
CLIGUARD_NO_SANDBOX=1to make cli-guard usable.Cause
docs/sandbox.mdnames two field failure modes and covers only one.cmd.RunreturnsEPERM/EACCESwithcmd.ProcessState == nil,sandbox.SetupDeniedreturns true, andshell.Runner.Execretries unsandboxed with a one-time warning. Handled.prepareJailMountsfails atunix.Mount("", "/", "", MS_REC|MS_PRIVATE, "")withsandbox: make-rprivate: permission denied. The child ran, socmd.ProcessState != nilandSetupDeniedreturns false atcli/shell/shell.go:105. The verb dies. Not handled.Mode 2 is the live one. infrastructure#370 records it verbatim on ser8, where Ubuntu 24.04's
apparmor_restrict_unprivileged_userns=1denies the userns to an unprofiled Homebrewwardbinary, and it hard-failed everyward execincluding the silentfleet-convergetimer. Option 3 of that issue is exactly this fix and was never filed upstream here.Because mode 2 has no escape, the only remedy consumers have is the opt-out env, and it has spread as a standing declaration rather than a deliberate choice. cli-guard#256 is the same family from the other direction: a masking bug whose acceptance is "the explicit no-sandbox compatibility switch is no longer required for this case."
Why a retry is safe here
RunJailreaches the target only throughexecJailTarget, the last statement afterprepareJailMounts,installToolShims,setJailEnvironment,clearAmbientCaps, andlockdownSyscalls. Any error returned fromRunJailis pre-exec by construction, andexeceither replaces the process image or fails without running the target. So a mode-2 failure carries the same guarantee mode 1 already relies on: the wrapped tool never ran, and the retry cannot double an effect.The setup work that did happen lives in the child's private mount namespace and dies with it, so there is no host state to unwind.
Scope
ExtraFilessentinel fd fromshell.Runneris collision-free. A reserved exit code is cheaper but needs a stated argument about tool collision.EPERM/EACCESfrom mount, seccomp, or capability operations) from a genuine setup bug. A malformed spec or missing stash directory should still fail loudly rather than silently drop the boundary.sandbox.SetupDeniedto accept the mode-2 signal and letshell.Runner.Exectake the existing retry path and one-time warning.docs/sandbox.md: the "choosing" section currently tells container operators to set the opt-out because auto-degrade does not catch mode 2. After this, the env var is for deterministic opt-out with no per-exec retry cost, not a correctness requirement.Acceptance
ward execverb on a host withapparmor_restrict_unprivileged_userns=1completes, unsandboxed, with one warning, and noCLIGUARD_NO_SANDBOXset.make-rprivatedenial and asserts the command runs exactly once, unsandboxed, and succeeds.docs/sandbox.mdanddocs/FEATURES.mddescribe one automatic degrade path covering both modes.Fleet follow-through
The consumer-side removal of the declarations is tracked separately in coilysiren/inbox. Confirmed declarations today: agentic-os
ci.yml,promote.yml,docker/dev-base/verify-common.sh, andtests/test_aosguard.py, plus job-level env in deploy and agentic-os-xxx CI. Ward'scmd/ward/container_bootstrap.gosets it deliberately forward containerand stays as a legitimate opt-out either way.Filed from a native session that cannot land on main.