In-Sandbox Tooling Secrets and Setup Script Staging¶
Previously, shared/startup.sh attempted to run scripts/setup.sh from the cloned target repository ($TARGET_DIR). Because external guest repositories do not track the factory's setup script and the image builder (shared/image.py) never staged tooling secrets (secrets/opencode.env, secrets/antigravity-oauth-token.json, secrets/modal.toml), sandboxes launched with --opencode, --agy, or --modal silently skipped credential decryption, resulting in missing API key errors. We decided to decouple factory tooling setup from the cloned repository: scripts/setup.sh is staged into the image at /root/scripts/setup.sh and dynamically resolves secrets relative to its own script location, build_sandbox_image stages only the specific encrypted tooling secrets matching requested flags into /root/secrets/, shared/startup.sh invokes /root/scripts/setup.sh via absolute path, and all staged encrypted tooling secrets are purged immediately following decryption alongside ~/.config/sops.
Considered Options¶
- Inline tooling decryption directly in
shared/startup.sh: Performsops decryptfor each tooling secret directly insideshared/startup.sh, retiringscripts/setup.shfrom sandbox bootstrap. Rejected becausescripts/setup.shalready encapsulates environment propagation (/etc/environment,~/.bashrc) and maintaining two divergent credential provisioning implementations between host workstations and sandboxes leads to behavioral drift. - Unconditionally stage all tooling secrets in
base_image: Bakeopencode.env,antigravity-oauth-token.json, andmodal.tomlinto/root/secrets/on every image build, decrypting only active flags. Rejected because it violates least privilege by leaving unnecessary encrypted credential files at rest in containers that only need a subset of tooling. - Dedicated staged setup script with granular secret staging: Stage
scripts/setup.shat/root/scripts/setup.sh, stage only the requested tooling secrets into/root/secrets/inbuild_sandbox_image, execute/root/scripts/setup.shvia absolute path fromshared/startup.sh, and purge staged encrypted secrets immediately after decryption. Accepted because it maintains execution parity between host workstations and sandboxes, enforces strict least privilege across image layers, guarantees zero residual encrypted files after boot, and decouples infrastructure setup from guest repositories.
Consequences¶
shared/image.pystagesscripts/setup.shinto the container at/root/scripts/setup.sh.build_sandbox_imageinshared/image.pycopiessecrets/opencode.envwhenopencode=True,secrets/antigravity-oauth-token.jsonwhenagy=True, andsecrets/modal.tomlwhenmodal_tooling=Trueto/root/secrets/.scripts/setup.shcomputesSECRETS_DIR="${SECRETS_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/secrets}", running identically on host workstations and in sandboxes.shared/startup.shexecutesbash /root/scripts/setup.sh "${setup_args[@]}"independently ofcd "$TARGET_DIR".- Ephemeral cleanup in
shared/startup.shdeletes/root/secrets/opencode.env,/root/secrets/antigravity-oauth-token.json, and/root/secrets/modal.tomlright after SOPS decryption completes.