docs(prd-0023): pivot to smolvm + TSI single-IP allowlist #63
Reference in New Issue
Block a user
Delete Branch "prd-0023-revise-option-b"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Reverses the network design in PRD 0023 after chunk-1's empirical spike against smolvm 0.8.0 contradicted the research note that motivated the gvproxy path. New design uses smolvm's TSI allowlist with a single /32 (the per-bottle sidecar bundle's pinned docker IP) instead of gvproxy + VZFileHandleNetworkDeviceAttachment.
What changed and why
The original PRD's "why gvproxy, not TSI" argument hinged on TSI's
--outbound-localhost-onlyflag — which is permissive on the whole127.0.0.0/8range. Re-examining TSI with the actual smolvm 0.8.0 CLI surface in hand,--allow-cidr <bundle-ip>/32(without--outbound-localhost-only) gives the same security property: agent can reach exactly one IP, nothing else. Host loopback, LAN, public internet directly are all denied at the VMM layer.Smolvm doesn't expose a virtio-net-over-unixgram attachment that the gvproxy design needs anyway, so the spike forced a choice between dropping smolvm (DIY VM lifecycle via PyObjC + Virtualization.framework — ~100+ lines of code, no
machine exec, no OCI image story) and dropping gvproxy. This PRD chooses to drop gvproxy.One concession TSI doesn't directly address
TSI's allowlist is IP-granular, not port-granular. So the agent CAN reach any port on the bundle's IP — including egress (
:9099), which is supposed to be pipelock's internal upstream. Mitigation: bind egress on127.0.0.1:9099inside the bundle (pipelock-only), bind pipelock / git-gate / supervise on0.0.0.0. The agent's connect to<bundle-ip>:9099refuses at the socket level even though TSI permits the IP. New acceptance test (egress-port-bypass probe) locks this in.Backend layout impact
gvproxy_config.py,gvproxy.py,vfkit_attach.py. No gvproxy lifecycle, no VZFileHandle plumbing.gvproxydep,pyobjc-framework-Virtualizationdep.Chunk shape impact
name = …/[[net]]instead of smolvm 0.8.0'simage/[network] allow_cidrs. Thegvproxy_config.pyrenderer is dead. Both get rewritten / deleted as part of chunk 2's work.smolvm pack create→.smolmachineartifact, per-bottle docker bridge + bundle with pinned IP, VM lifecycle, Smolfile renderer rewrite, the two acceptance probes (localhost-reach + egress-port-bypass).Open questions resolved
bottle.execexit-code fidelity probe (verify in chunk 2).Followup
I'll leave a comment on the merged PR #53 pointing at this revision so anyone landing on the old PR sees the design pivot.