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

[ENV-A5] Host-side exact-SHA source snapshot and private-workspace seed staging (backend-neutral; Docker mount enforcement in #271)

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

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
docker, git, python
Domain
backend, devtools

Research direction

Start with src/autoforge/materialize.py and its materialize() implementation and proof, then read src/autoforge/safefs.py and the existing sandbox tests. Trace how the exact base SHA is staged and how #269’s minimal Git input seeds a private workspace; the fake staging backend tests should show the interface and failure cases. Done means staging is re-proved at hand-off, paths and snapshot contents are validated, reuse and cleanup are run-scoped, and the documented invariants are covered.

Written by the indexing model from the issue text.

Description

enhancement

Artifact: implementation-ready child of EPIC #266. Wave A (workspace isolation and staging). Size: M (reduced from L on 2026-10-23; see the scope note). Target is REMOTE CLI agents: Claude Code, OpenCode 2.x, Pi; Codex and SDK rollout are not part of this gate.

Scope after the 2026-10-23 planning reconciliation (review: #266 comment). The architecture below is still the Docker MVP's target. This issue now owns only its host-side, backend-neutral part: building the exact-SHA source snapshot by reusing materialize(), keeping the proven tree staged for the launch, validating paths, and preparing the private-workspace seed. It is proven with fakes. Enforcing the mounts in Docker, launching anything, and every real-Docker proof moved to #271, #272 and #274 (see "Acceptance criteria moved" below). This removes the cycle in which #292's acceptance needed #271's Docker backend while #271 was blocked by #292. Size reduced from L to M.

Objective

Implement the host source → container-private writable workspace boundary so the sandbox can read a host-owned, exact-SHA code snapshot via read-only bind mount but all AI-agent code changes, dependency installation, compilation, validation and local Git commits happen inside a private sandbox workspace. The operator's checkout, HOME, controller state, Git common-dir and GitHub credentials are never writable/exposed inside the agent container. The container is disposable; an exact verified Git candidate returns through #269, not through a write to the host checkout.

Required architecture

  • Controller (host): choose expected repository + issue/run + base commit SHA, create an immutable per-run source snapshot from that exact tree, check staging integrity, manage source/root identities and bind rules; the read-only source may be a host-owned staging directory under AutoForge runtime (prefer this to the user's dirty main checkout). A user-provided checkout path is not automatically trusted: never bind arbitrary host paths based on repository YAML.
  • Source bind: only approved source snapshot, mapped read-only to /source. No bind of host $HOME, .git file, linked-worktree admin, common-dir, Docker socket, gh/SSH/keychain sockets, agent authentication store or Controller config. No unrelated untracked/ignored/secret files; snapshot content must match the expected Git tree (allow explicit audited non-Git inputs in a future separate design, not MVP).
  • Workspace: per issue/run writable Docker volume or other sandbox-private storage at /workspace, with a private self-contained Git repository initialized/seeded using #269's minimal object transport; not a writable bind of the host checkout nor the controller-owned linked worktree. Make snapshot-to-workspace copy/materialization reproducible, ownership-safe and idempotent after lifecycle interruption; preserve tracked executable bits/symlinks, submodules and LFS with explicit supported/unsupported diagnostics.
  • Runtime: launch all existing supported CLI providers and commands from /workspace; HOME is a fresh restricted container home distinct from /source and /workspace. Build tools/compilers/test runners execute only inside the container, using private temp/cache/build artifact paths. Image must carry the required toolchains; do not run setup scripts on the host as a fallback.
  • Output: export only a bounded, complete, verifiable candidate commit/pack+manifest via #269. The Host Controller strictly imports and validates before any host git push, gh operation or candidate publication. Build output/logs have explicit artifact budget and confidentiality rules.
  • Permissions: no Docker socket, privileged mode, arbitrary mount flags, host PID/namespace, --network host or writable repository/Controller paths. Use #270's security/capability policy and #290's separate model credential projection; no LLM credential is bundled in source snapshot.
  • Compatibility: preserve existing bwrap and LOCAL behavior. Any different optional writable bind of a dedicated issue staging directory must be explicitly designed and independently security-reviewed later; not the Docker MVP default.

Hard dependencies

  • #267 — accepted backend/workspace ADR (host/container ownership)
  • #269 — minimal Git source/candidate artifact protocol
  • #270 — container mount policy and enforceable capability model
  • Consumed by: #271 Docker backend and #274 Docker E2E; #273 config/doctor and #272 recovery must reflect workspace semantics.

Acceptance criteria

Rewritten 2026-10-23 (planning reconciliation). The original criteria are quoted verbatim, with their new owners, under "Acceptance criteria moved (ownership transfer)" below. None of them was dropped.

  • The source snapshot is produced by reusing materialize() (src/autoforge/materialize.py:690) and its proof (ADR 0006 D6.3) for the exact base SHA, with no second tree-export path. The candidate-validation path (ADR 0006 D6.4) is unchanged.
  • materialize() removes its temporary tree on exit, so staging either keeps the proven tree under a controller-owned, run-scoped staging directory for the launch's lifetime or holds the context open across it. Either way the tree is re-proved against the expected tree immediately before it is handed to a backend, the trust boundary. A tree changed between proof and hand-off is refused. A read-only bind alone is not treated as protection against host-side mutation.
  • Every staging and seed path is validated with the existing safefs primitives before use: no symlink or path traversal, no mount nesting, no source-path substitution, and no path outside the controller-owned staging root. The snapshot contains no host .git file or admin dir, no common dir, no HOME content, and no untracked or ignored file.
  • Two stagings from the same base SHA give byte-identical tracked trees (modes and symlinks included), and the operator's checkout is not changed by staging.
  • The private-workspace seed is prepared from #269's minimal Git input for the exact base SHA. It has no alternates to the host store, no host refs, no remote that carries a credential, and no enabled hooks. Its history depth follows #267's decision 11. Submodules, LFS, Git filters and sparse or partial clones each get an explicit supported or unsupported diagnostic, and no repository hook or filter runs on the host.
  • The file modes and the UID/GID ownership the container needs are recorded as data and handed to #271. This issue does not change ownership for any backend.
  • A backend-neutral staging and volume interface has a fake implementation. Fake-backend tests prove that /source is presented read-only and /workspace writable at the interface level. Real Docker volumes and mounts are #271's.
  • Cleanup is idempotent and scoped by run identity. A crash before or after snapshot staging or seed preparation leaves at most a run-scoped directory, which a later step re-proves before reuse or removes. Staging never mixes issues or runs. Container, volume and secret-projection cleanup belongs to #272.
  • Docs explain source snapshot vs live host bind: host checkout edits do not automatically become container input unless the controller explicitly snapshots an approved commit; no direct main-checkout writable mount in MVP. (Original criterion 10, kept here.)
  • Existing tests pass, and each invariant of ADRs 0002/0004/0005/0006/0008 is preserved or amended per #267's invariant map. (Original criterion 11, revised: the Docker backend amends some ADR 0005 decisions explicitly, see #267.)
Acceptance criteria moved (ownership transfer, 2026-10-23)

These are the original criteria, quoted verbatim, with where each one now lives. Their substance is unchanged. Those that need a real Docker backend or a launch moved, because this issue no longer has one. Each destination issue lists the criteria it received.

  1. /source is mounted read-only from the controller-prepared host snapshot; /workspace is private and writable; a deliberate write to /source fails and does not mutate host bytes.

    → #271 (mount enforcement), proven on real Docker in #274

  2. Preparing two independent sandboxes from the same base SHA yields byte-identical tracked file trees, independent writable workspaces, and no host checkout drift.

    → first half (byte-identical tracked trees, no host checkout drift) stays here; second half (independent writable workspaces) → #271, proven in #274

  3. Agent changes, git add/commit, compiler writes and test-generated artifacts are confined to private /workspace, temp or explicitly approved private volumes. No build command from a repository can execute on host as a fallback.

    → #274 (proof); the no-host-fallback rule for repository commands is enforced by #271's EXPORT_COMMAND ownership

  4. Snapshot contains no host .git admin/common-dir, HOME or nontracked/ignored credential files; reject symlink/path traversal, mount nesting and source path substitution attacks before launch.

    → stays here (rewritten above as the snapshot-content and safefs criteria)

  5. Rootless/userns and non-root launch permissions checked; no raw user-provided host mount paths or repo-controlled Docker run flags accepted. Unsupported Docker features fail closed in sandbox.mode: required.

    → #271 (launch permissions, no raw mounts or flags) and #273 (fail-closed selection and diagnostics)

  6. Git candidate produced from private workspace preserves exact base/candidate SHA relationship, imports only through #269's controller-side verified path, and never changes host shared Git refs without controller authorization.

    → split: the exact-base seed stays here; candidate import semantics → #269; real-workspace proof → #274

  7. Host crash before/after source staging, workspace seeding, snapshot copy, export and container cleanup reconciles safely without mixing issues; abandoned volumes/snapshots are scoped by run identity.

    → split: snapshot staging and seed crash recovery stay here; export and container cleanup → #272

  8. Two concurrent worker containers cannot access each other's code, volumes, build caches, secret leases or artifacts; tests cover host HOME/GitHub token absolute paths and Docker socket denial.

    → #274

  9. Fake and real-Docker tests verify read-only source and writable container workspace; record skips as untested, never as success.

    → split: fake tests stay here; real-Docker tests → #271 (backend tests) and #274 (E2E)

  10. Docs explain source snapshot vs live host bind: host checkout edits do not automatically become container input unless the controller explicitly snapshots an approved commit; no direct main-checkout writable mount in MVP.

    → stays here, unchanged

  11. Existing tests pass and ADRs 0002/0004/0005/0006/0008 remain intact.

    → stays here, revised as above

Implementation surface

src/autoforge/agent_worktree.py, git_transport.py, materialize.py, sandbox_policy.py, sandbox.py, safefs.py, sandbox tests with a fake staging backend (no Docker module: that is #271's), docs/configuration.md and autoforge.example.yaml.

Out of scope

Do not create GitHub PRs, run gh, grant GitHub credentials to the agent, ship user-selectable unrestricted bind mounts, implement model auth (owned by #290), rewrite controller Git transport, or gate Public Alpha #255.

Source delivery per runtime (owner decision, 2026-10-23)

#267 decision 12 makes the choice between a /source bind and copy-in per runtime, decided by proven capability.

  • A runtime proven to share the controller's filesystem (local rootless Docker or Podman): the staging keeps the re-proved snapshot for a read-only bind, as above.
  • Any other runtime (a remote sandbox, a VM-hosted daemon, a DOCKER_HOST or docker context that points elsewhere): only the workspace seed is prepared, and nothing is kept for /source, because the seed pack already carries the exact tree.

The backend-neutral staging interface and its fake cover both cases.

  • The staging interface supports both delivery modes; fake tests show that a copy-in runtime gets the seed only and no retained snapshot, and that a bind runtime gets the re-proved snapshot
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.