Skip to content

acq: host-authoritative sandbox config — migrate guest-writable state off /var/lib/acq (ADR-0030) #503

Description

@mogul

Summary

Implement the mechanism defined in ADR-0030 (Host-Authoritative Sandbox Configuration): acq must not rely on guest-generated or guest-tamperable state to configure the sandbox. Because the in-sandbox agent has passwordless sudo, guest root-ownership is not a trust boundary against a prompt-injected agent. Every input acq trusts to make a configuration or lifecycle decision — data and code — must be host-resident and mounted read-only into the guest, or held on the host and injected at exec time.

This issue tracks the acq-side implementation and the staged migration of the existing /var/lib/acq/* markers off guest-writable paths. One PR, a commit per change below.

See docs/adr/0030-host-authoritative-sandbox-config.md (branch docs/adr-host-authoritative-config) for the principle, threat model, considered options (option 1 — mount kit code/data read-only and invoke code from the :ro path — selected), and the migration plan.

Background (why)

Today acq writes markers under the guest path /var/lib/acq/ via msb exec -u 0 and reads them back later to configure the sandbox. Four of them carry content acq acts on:

Marker Read-back effect
agent selects which binary the re-attach launches
workspace sets the session working directory (-w)
ssh-auth-sock sets -e SSH_AUTH_SOCK=…
kit-env replays kit environment[] as -e NAME=value every session

Reads are hardened against shell injection, but not against a sudo-capable guest setting a valid-but-malicious value. Four others (install-<cksum>, agent-installed-<agent>, agent-user-ready, oci-ready) are presence-only gates a guest can forge to suppress provisioning. Separately, acq's restart heal re-runs guest-resident kit startup code, which a sudo agent can tamper between restarts.

First external consumer: GSA-TTS/agentic-coding-patterns#423 ADR 0003 (neutral model-provider discovery) — its provider-facts channel needs the read-only mount this issue delivers.

Tasks (commit per change)

  • Facts + :ro mount plumbing. Per-sandbox host config dir under ${ACQ_STATE_DIR}/config/<backend>.<sandbox>.<sum>/ (mirroring the existing clones//ports//provenance conventions in acq.backends/common.sh); mount it read-only into the guest at /var/lib/acq/host/ on both backends (--volume host:guest:ro on msb; :ro positional on sbx). Honor Windows host/guest path forms (ADR-0029).
  • agent, workspace. acq authors these already — write to the host config dir; stop reading them back from the guest.
  • ssh-auth-sock. acq already knows the value (its own constant) — hold host-side and inject at exec; stop reading it back.
  • kit-env. acq already parses each kit's environment[] on the host at apply — persist the validated env to the host config dir and replay from there; stop reading the guest marker.
  • Presence gates (install-*, agent-installed-*, agent-user-ready, oci-ready). Move to the host config dir so a guest cannot forge them to suppress provisioning.
  • Trusted startup execution (ADR-0030 Mechanism 2). Stage kit startup code acq re-runs across restarts into the :ro config dir and invoke it from there, so a restart executes the host-authoritative (pinned) copy, not a guest-tampered one.

Constraints

  • Preserve the current best-effort fail-soft behavior of the marker writes (|| true): a state-dir hiccup must not turn a previously-survivable provision into a hard abort.
  • No code execution on the host — acq reads static data from the pinned kit dir on the host; it does not execute kit-shipped code there.
  • Do not remove passwordless sudo. This narrows what acq trusts, not what the agent can do in its sandbox.
  • Add/extend bats coverage (offline stubbed) for the new host-config-dir + :ro mount paths and for each migrated marker.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions