Files
bot-bottle/docs/prds/0038-smolmachines-env-contract.md
T
didericis 049103ac99
test / unit (pull_request) Successful in 50s
test / integration (pull_request) Successful in 17s
test / coverage (pull_request) Failing after 1m4s
docs: mark smolmachines-specific PRDs + research as superseded
Add a "Superseded (2026-07-11)" banner and flip Status: Active →
Superseded on the 8 smolmachines-specific docs (7 PRDs + the VM-backend
research). Bodies are left intact as a historical record; the banner
points at the removal commit and the landscape doc so a reader isn't
misled into thinking the backend still exists.

Incidental mentions in other PRDs (git-gate, cred-proxy, print-parity,
etc.) are left as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
2026-07-11 19:09:43 -04:00

105 lines
4.0 KiB
Markdown

# PRD 0038: smolmachines Env Contract and Secret-Safe Injection
> **Superseded (2026-07-11).** The smolmachines backend was removed — Linux now uses the Firecracker backend, macOS uses macos-container. Kept as a historical record; see the removal commit `c07ebca` and `docs/research/landscape-containerized-claude.md`.
- **Status:** Superseded (2026-07-11) — was Active
- **Author:** didericis-codex
- **Created:** 2026-06-02
- **Issue:** #135
## Summary
Make smolmachines env handling match Docker's contract: resolve manifest env
entries through `resolve_env()`, keep secret and interpolated values out of
host argv, and document or enforce an explicit env contract for the backend.
## Problem
`bot_bottle/backend/smolmachines/prepare.py` builds the guest env from
`bottle.env` directly, bypassing `resolve_env()`. Entries like `?prompt` and
`${HOST_VAR}` can reach the guest literally rather than being prompted or
resolved. In contrast, Docker resolves env through `resolve_env()` before
writing a mode-600 env file.
`smolmachines/smolvm.py` renders env as `-e KEY=VALUE` on `smolvm machine
create` argv, and `SmolmachinesBottle.agent_argv` / `exec` prepend
`env KEY=VALUE …` onto the `smolvm machine exec` argv. Any literal or resolved
secret value is therefore visible in the host process table.
The two backends have no shared env contract document. Divergence will silently
widen as new manifest env features are added.
## Goals / Success Criteria
- Manifest env entries are resolved through `resolve_env()` before being
injected into the smolmachines guest, matching Docker behaviour.
- No manifest env value (literal or resolved) appears on host argv during
machine creation or exec.
- Define and document an explicit smolmachines env contract covering literals,
`?prompt` secrets, and `${HOST_VAR}` interpolations.
- Unit tests cover: literal passthrough, prompted-secret resolution,
host-var interpolation, and the no-argv-leak invariant.
## Non-goals
- No changes to the Docker env path.
- No changes to manifest schema or `resolve_env()` itself.
- No changes to smolmachines networking or mount handling.
- No new runtime dependencies.
## Scope
In scope:
- `bot_bottle/backend/smolmachines/prepare.py` env resolution.
- `bot_bottle/backend/smolmachines/smolvm.py` machine-create argv.
- `bot_bottle/backend/smolmachines/bottle.py` `agent_argv` / `exec` env
injection.
- `bot_bottle/env.py` if helper changes are needed to support the smolmachines
path.
- Unit tests in `tests/unit/` covering the above.
Out of scope:
- Integration tests that start a live smolmachines VM.
- Docker backend changes.
- Dashboard or CLI changes.
## Design
Run smolmachines env through `resolve_env()` at prepare time, exactly as Docker
does. After resolution, inject env into the guest through a mechanism that does
not expose values on host argv — for example by writing a mode-600 env file
into the machine's state directory and loading it at exec time, or by passing
env through `smolvm`'s stdin if the tool supports it.
If `smolvm` provides no stdin or env-file injection path, document this as a
known limitation and at minimum move env values behind a per-invocation
tmpfile rather than inline argv.
The env contract for smolmachines should mirror Docker's:
- Literals: passed as-is after resolution.
- `?prompt` entries: prompted at prepare time; resolved value injected, never
on argv.
- `${HOST_VAR}` entries: interpolated from the operator's env at prepare time;
resolved value injected, never on argv.
## Testing Strategy
- Unit tests for `prepare.py` asserting `resolve_env()` is called and that
resolution results are used rather than raw `bottle.env` values.
- Unit tests for `smolvm.py` machine-create argv asserting no env value appears
inline.
- Unit tests for `bottle.py` exec path asserting the same argv invariant.
Run:
- `python3 -m unittest tests.unit.test_smolmachines_prepare`
- `python3 -m unittest discover -s tests/unit`
## Open Questions
- Does `smolvm machine create` support an env-file flag or stdin injection that
avoids `-e KEY=VALUE` argv?