feat(smolmachines): resolve manifest env through resolve_env() (PRD 0038)

Before this change smolmachines prepare.py spliced bottle.env directly
into guest_env, so ?prompt and ${HOST_VAR} entries reached the VM as
raw sentinels rather than being prompted or interpolated.

After this change prepare.py calls resolve_env(), matching the Docker
backend's contract. Forwarded (secret/interpolated) values still flow
through smolvm -e K=V argv — the known exposure gap documented in PRD
0038's open question.

Closes #135
This commit is contained in:
2026-06-02 14:38:36 +00:00
parent 1c242b0ad9
commit 8830306101
2 changed files with 145 additions and 11 deletions
+12 -11
View File
@@ -28,6 +28,7 @@ from ...backend.docker.bottle_state import (
write_metadata,
)
from ...egress import Egress
from ...env import resolve_env
from ...git_gate import GitGate
from ...pipelock import PipelockProxy
from ...supervise import Supervise
@@ -77,18 +78,18 @@ def resolve_plan(
subnet, gateway, bundle_ip = smolmachines_bundle_subnet(slug)
# Agent's env: the prepare-time view doesn't yet know the
# host loopback ports the bundle's daemons get published on
# (those come from docker AFTER `docker run` returns), so
# HTTPS_PROXY / GIT_GATE_URL / MCP_SUPERVISE_URL are
# populated in launch.py and stamped onto guest_env there.
# What we set here is the part that doesn't depend on
# bundle bringup — bottle.env literals, the empty-NO_PROXY
# safe default, and the TLS trust env trio
# (NODE_EXTRA_CA_CERTS / SSL_CERT_FILE / REQUESTS_CA_BUNDLE)
# pointing at Debian's update-ca-certificates output bundle.
# Agent's env: resolve through resolve_env() so ?prompt entries
# are prompted and ${HOST_VAR} entries are interpolated — matching
# the Docker backend's contract. Forwarded (secret/interpolated)
# values still reach the guest as -e K=V smolvm flags because
# smolvm 0.8.0 has no env-file or stdin injection path; this is
# the known argv-exposure gap documented in PRD 0038.
# HTTPS_PROXY / GIT_GATE_URL / MCP_SUPERVISE_URL are populated
# in launch.py after bundle bringup.
resolved = resolve_env(manifest, spec.agent_name)
guest_env: dict[str, str] = {
**bottle.env,
**resolved.literals,
**resolved.forwarded,
"NO_PROXY": "localhost,127.0.0.1",
"NODE_EXTRA_CA_CERTS": "/etc/ssl/certs/ca-certificates.crt",
"SSL_CERT_FILE": "/etc/ssl/certs/ca-certificates.crt",