Skip to content

Isolate gate command namespaces#134

Merged
chasebryan merged 2 commits into
mainfrom
agent/isolate-gate-command-namespaces
Jul 16, 2026
Merged

Isolate gate command namespaces#134
chasebryan merged 2 commits into
mainfrom
agent/isolate-gate-command-namespaces

Conversation

@chasebryan

@chasebryan chasebryan commented Jul 16, 2026

Copy link
Copy Markdown
Owner

What changed

  • run every copied Python and Rust command in private mount, PID, /proc, and network namespaces, with an unprivileged user namespace where supported
  • fall back on restricted hosts to non-interactive sudo for namespace creation, then restore the invoking UID/GID, clear supplementary groups, and set no_new_privs before copied code
  • make the copied command PID 1 with no host routes and no inherited capture descriptors
  • assert the invoking identity, zero effective capabilities, and no_new_privs at runtime
  • kill the namespace child if the unshare supervisor is interrupted
  • bind the exact isolation flags and runtime assertions into the protected Makefile contract
  • add mutation coverage for wrapper removal, user mapping drift, host /proc exposure, network restoration, lifecycle weakening, and assertion removal
  • document the new host-tool dependency, control boundary, and remaining kernel/same-account assumptions

Why

Closing capture descriptors 8 and 9 in copied commands prevented direct inheritance, but a same-account child could still enumerate the host /proc tree, find the trusted parent shell, and reopen those descriptors through /proc/<parent>/fd/{8,9}. Cargo's offline setting also did not prevent non-Cargo copied code from opening network connections.

Private PID and /proc namespaces remove the trusted parent from the child's process view. A private network namespace prevents new external connections at the kernel boundary. The preferred path creates these controls inside an unprivileged user namespace. GitHub's hosted Ubuntu policy rejects nested UID-map writes, so the fallback elevates only the namespace supervisor and drops back to the invoking identity before any copied command. --kill-child=KILL prevents interrupted supervision from leaving a detached namespace workload.

Impact

Orange language behavior is unchanged. The Linux repository gate now requires runner-provided unshare and setpriv; hosts that reject unprivileged user mapping also require non-interactive sudo permission for the fixed namespace setup. Those mutable host facilities remain explicit trust dependencies.

Validation

  • reproduced parent-descriptor access outside the namespace and rejection inside it
  • verified the wrapper with the foundation validator and pinned Cargo 1.96.1
  • git diff --check
  • policy 0.2.84
  • 10 focused ProtectedControlHardeningTests
  • three complete scripts/ci/check-repository runs after namespace integration, including the final privilege-drop fallback design
    • 287 Python tests
    • Rust debug and release suites: 162 + 74 + 32 + 9 each
    • 7 documentation tests
    • independent two-root reproducible release build
    • final policy, capture-identity, source-membership, mode, and byte comparisons
  • initial hosted Required CI exposed unshare: write failed /proc/self/uid_map: Operation not permitted; the follow-up commit adds the privilege-dropping restricted-host path

@chasebryan
chasebryan marked this pull request as ready for review July 16, 2026 00:18
@chasebryan
chasebryan merged commit cbe7ff8 into main Jul 16, 2026
6 checks passed
@chasebryan
chasebryan deleted the agent/isolate-gate-command-namespaces branch July 16, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant