Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[ENV-A2] Introduce pluggable sandbox backend seam without changing Bubblewrap behavior

Open
#268 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
python

Research direction

Start with the accepted ADRs 0002, 0004, 0005, 0006 and 0008, then read #267 and the existing sandbox and executor boundaries in src/autoforge/sandbox.py, sandbox_bwrap.py, executor.py, executor_duplex.py, executor_supervised.py, and doctor_sandbox.py. Use the tests and offline fake executable/provider fixtures to trace backend selection, launch, streams, cancellation, and denial behavior. Done means all acceptance criteria hold, including unchanged bwrap behavior, no unsafe fallback, and parity across single-issue and scheduler launches; attach focused negative and crash-window tests or an auditable design-only test plan.

Written by the indexing model from the issue text.

Description

enhancement

Artifact: implementation-ready engineering issue. Parent EPIC: #266. Workstream: A. Size: L. Baseline: main 711ff09 (2026-10-21). No implementation is authorized by this planning action.

Objective / scoped deliverable

Extract narrowly typed backend selection/probe/launch lifecycle at the existing executor boundary while preserving bwrap as the default implementation. Keep the process supervisor responsible for termination, output, streams, timeouts and containment; no second agent orchestration stack. Distinguish unsupported, denied policy, setup failure, command failure and uncertain external lifecycle. No direct shell command strings or provider-dependent state transitions.

Existing foundations and boundaries

Read EPIC #266 and relevant accepted ADRs 0002, 0004, 0005, 0006, 0008. The deterministic controller retains every workflow transition, Git/GitHub write, read-back, ReviewCertificate and merge authorization. Do not embed Sandcastle's run(), replace the Python agent providers or introduce an arbitrary privileged mount. Preserve the Linux bwrap baseline. Coordinate session/interaction overlaps with #147/#126. If state schema must change, obtain protocol-number coordination on #23 before the migration.

Dependencies

  • Hard: #267 (ENV-A1)
  • This issue must not be considered complete by filing a follow-up for a core acceptance criterion; split decisions before implementation only if the EPIC ledger is updated.

Relevant implementation surfaces (starting points, not an exhaustive mandate)

src/autoforge/sandbox.py, sandbox_bwrap.py, executor.py, executor_duplex.py, executor_supervised.py, doctor_sandbox.py, tests

Acceptance criteria

  • Existing bwrap fixtures and real-backend semantics remain unchanged including required/preferred/disabled
  • Fake sandbox backend proves invocation, exact argv/stdin/env handling, streaming, cancellation and denial path
  • Prelaunch capability refusal leaves state and attempt counters untouched where current contract requires
  • Backend lifecycle errors never become success or permit automatic unsandboxed fallback
  • Parities across single-issue and scheduler worker launch, with no change to controller authority
  • Existing regression suite passes; focused negative and crash-window tests are attached to the PR, or a design-only issue includes an auditable test plan.
  • Update documentation and backend capability/rollout status when user-facing behavior changes; do not represent a skipped live test as a pass.

Exclusions / anti-goals

Do not weaken sandbox.mode: required, allow agent-held GitHub write credentials, expose host .git common-dir/state to isolated agents, silently apply raw REMOTE diffs, or invent a second lifecycle controller. EPIC #255 Public Alpha is not blocked by this task.

Verification guidance

Use offline fake executable/provider fixtures first, then explicitly gated disposable-repository real-backend tests when applicable. Record exact candidate/base SHAs and externally observed failures, ensure secure redaction, and demonstrate idempotent cleanup and resume.

Planning reconciliation (2026-10-23)

Artifact: planning update from the 2026-10-23 reconciliation of EPIC #266 with its architecture review (#266 comment). Baseline re-read: main 388ecb3. Planning only: nothing here implements a feature or checks off a criterion. The earlier sections stay authoritative where this one does not change them.

Why the seam needs a full lifecycle

On 388ecb3 the sandbox seam is hard-wired to bwrap. Each of these call sites must go through the new backend seam:

  • src/autoforge/executor.py:97 imports BwrapLaunch;
  • _spawn_sandboxed (executor.py:1322-1356) and _prepare_sandbox (executor.py:1359-1377) call sandbox_bwrap.prepare;
  • src/autoforge/executor_duplex.py:105,503,583 uses BwrapLaunch for duplex launches;
  • src/autoforge/engine.py:1260-1269 probes through sandbox_bwrap.probe;
  • src/autoforge/doctor_sandbox.py:42 uses sandbox_bwrap.ProbeResult.

A bwrap launch is one process whose death ends the sandbox. A container is not. So the seam must model a lifecycle, not only "prepare a command".

Backend-neutral lifecycle (the seam's contract)
  1. Capability probe. Prove capability with a real minimal launch and report the backend's identity (engine, version, rootless or rootful for containers), with no side effects outside a temporary area. Dry run derives a pure, inspectable launch plan from the existing LaunchDescription (src/autoforge/sandbox.py:222) and the launch class (sandbox_policy.py:99-105) and stops before step 2.
  2. Prepare resources. Allocate the isolated environment under run-scoped names: a container and its volume, or nothing for bwrap.
  3. Stage source and credentials. Present #292's staged source snapshot and workspace seed, and #290's credential projection, by role.
  4. Start and supervise execution. Start the command. Apply timeouts, stop, cancellation and liveness through a channel that is not the agent's stdin.
  5. Capture streams and agent result. Use the executor's existing stdin, stdout and stderr handling, including the duplex streams, then collect the exit status and the backend's teardown facts.
  6. Export candidate/artifacts. Hand the produced candidate artifact to the controller-owned export location. For bwrap, the candidate is still the worktree HEAD (ADR 0005 D6.3), and nothing is exported.
  7. Verify and import through Controller. Pass the artifact to #269's strict, bounded import and candidate-source abstraction. For bwrap this is today's strict import of the private object directory (ADR 0005 D6.5). The backend never imports or publishes anything itself.
  8. Stop and remove resources. Run idempotently on every exit path. Report uncertain cleanup as uncertain, never as done.
  9. Reconcile after interruption. Give #272's journal and reconciliation the hooks it needs to find and remove this run's leftovers by ownership label after a crash. For bwrap this is a no-op.

Steps 1 to 3 can refuse the launch before anything is saved, charged or spawned, following today's setup-failure rule (ADR 0005 D10.8). A failure at a later step is reported as a typed failure and never becomes success or an unsandboxed fallback.

Requirements added by this reconciliation
  • Preserve executor streaming, timeouts, cancellation, Pi RPC duplex stdin and OpenCode 2.x stdin exactly as today. A liveness mechanism for a container backend must not read from, write to, or close the agent's stdin.
  • Backend identity becomes part of SandboxFacts (sandbox.py:382) and of every diagnostic that says a launch was enforced, following ADR 0005 D1.2 as amended by #267. For the container backend, the identity includes the detected runtime: Docker Engine or Podman (#267 decision 8, 2026-10-23). Today's TEARDOWN_UNCOUNTED fact (sandbox.py:374) stays bwrap's. A container backend reports its own teardown fact and never borrows "removed by namespace teardown".
  • The seam stays reusable by a later SDK helper launch (#147's providers run through the same executor). This issue does not implement or change #147.
  • This issue lands with bwrap and a fake backend only. It adds no Docker code (#271) and makes no backend selectable (#273).
Additional acceptance criteria (planning reconciliation)
  • Every listed bwrap call site goes through the seam; a test fails if engine, executor or doctor imports sandbox_bwrap directly for a launch or probe
  • The fake backend exercises all nine lifecycle steps (probe, prepare, stage, start and supervise, capture, export, verify and import, stop and remove, reconcile), including a refusal at each step and a cleanup that reports "uncertain"
  • Pi RPC duplex and OpenCode 2.x stdin tests pass unchanged through the seam; a test proves the liveness hook never touches the agent's stdin
  • SandboxFacts carries backend identity; existing bwrap facts and doctor rows are unchanged in content
Dominant language
Python
Stars
0
Forks
0
Avg merge
5h 57m
Merged PRs (30d)
71

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from iceboundrock/AutoForge

All issues in iceboundrock/AutoForge

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.