Skip to content

PHAX: smolvm isolation spike - #60

Open
lbdremy wants to merge 7 commits into
mainfrom
phax/smolvm-isolation-spike--phase-05
Open

PHAX: smolvm isolation spike#60
lbdremy wants to merge 7 commits into
mainfrom
phax/smolvm-isolation-spike--phase-05

Conversation

@lbdremy

@lbdremy lbdremy commented Jun 29, 2026

Copy link
Copy Markdown
Owner

PHAX Run Review Handoff

Generated by PHAX.

Run Review Handoff

Run summary

  • Short Name: smolvm-isolation-spike
  • Run ID: smolvm-isolation-spike-1782738661332
  • Base Branch: phax/smolvm-isolation-spike
  • Final Phase Branch: phax/smolvm-isolation-spike--phase-05
  • Gate Profile: full
  • Phases: 5/5 passed
  • See final-report.md for security details and entry/resume instructions.

Global File Reconciliation

Run: phax.smolvm-isolation-spike

File Planned in Touched in Status Notes
docs/spikes/smolvm-isolation-findings.md phase-05 phase-05 matched
phax.json phase-01 unplanned unplanned in: phase-01
spikes/smolvm/00-preflight.sh phase-01 phase-01 matched
spikes/smolvm/01-filesystem.sh phase-02 phase-02 matched
spikes/smolvm/02-network.sh phase-03 phase-03 matched
spikes/smolvm/03-agents.sh phase-04 phase-04 matched
spikes/smolvm/findings/01-filesystem.md phase-02 phase-02 matched
spikes/smolvm/findings/02-network.md phase-03 phase-03 matched
spikes/smolvm/findings/03-agents.md phase-04 phase-04 matched
spikes/smolvm/findings/TEMPLATE.md phase-01 phase-01 matched
spikes/smolvm/README.md phase-01 phase-01, phase-05 extra-touch extra touch in: phase-05

Global unplanned changes

  • phax.json (touched in: phase-01)

Global missing planned changes

None.

Global review attention points

Deviations not explained in any handoff

None.

Plan compliance review

Compliance Review — smolvm isolation spike

Run-level verdict: conformant-with-deviations

All five phases delivered their planned artifacts with correct scope boundaries. The single deviation — an unplanned touch to phax.json in phase-01 — is fully explained in that phase's handoff (oxfmt reformatting of the pre-existing agentCommands array; content identical) and carries no behavioral consequence.


Per-phase findings

Phase phase-01 — Spike scaffold and smolvm preflight

Verdict: conformant-with-deviations

  • objective: Delivered. spikes/smolvm/README.md, spikes/smolvm/00-preflight.sh, and spikes/smolvm/findings/TEMPLATE.md are all present with correct content. The preflight script uses set -eu, confirms smolvm on PATH, prints version/arch, and exits non-zero if absent without booting a VM.
  • excluded-scope: Respected. No src/ changes, no VM boot, no package.json wiring.
  • files: One deviation — phax.json appears in the file reconciliation as "unplanned". The handoff explains it: oxfmt reformatted the pre-existing agentCommands array from multi-line to single-line; content (including the smolvm entry) is unchanged. The explanation is credible and the change is inconsequential.
  • tests: Correct — no automated tests planned; the fast gate confirms repo health.
  • boundaries: No architectural boundaries crossed; phase adds only docs/shell under spikes/.
  • commit: Subject chore(spike): scaffold smolvm isolation spike and preflight matches plan exactly.
  • handoff: Covers all required content: exact paths created, phax.json deviation explained, note that smolvm was already in agentCommands before this phase, and gate status.

Phase phase-02 — Filesystem isolation probe

Verdict: conformant

  • objective: Delivered. spikes/smolvm/01-filesystem.sh implements five named checks (workspace round-trip, host HOME invisible, host repo root invisible, host /etc isolation, read-only mount rejection). spikes/smolvm/findings/01-filesystem.md has a fully populated ## Procedure with ## Results/## Verdict intentionally left empty per the spike's execution-model caveat.
  • excluded-scope: Respected. No network behavior, no agent execution, no resource-limit assertions, no src/ changes.
  • files: All planned files created; no unplanned touches.
  • tests: Correct — no automated tests; shell harness is human-run.
  • boundaries: None to cross; phase adds only shell/docs under spikes/.
  • commit: Subject test(spike): add smolvm filesystem isolation probe matches plan exactly.
  • handoff: Covers mount flag syntax (-v HOST:CONTAINER[:ro]), host paths probed, empty Results/Verdict explained, note that --net must be explicit in phase-03.

Phase phase-03 — Network per-domain allowlist probe

Verdict: conformant

  • objective: Delivered. spikes/smolvm/02-network.sh implements the five-case matrix (allowed-by-name, denied-by-name, denied-by-hardcoded-IP, allowed-by-IP, ICMP). Case 3 is labelled the decisive test. IP resolution uses nslookup/dig with a hard-coded fallback. spikes/smolvm/findings/02-network.md frames both crux questions in ## Verdict; Results/Verdict left empty.
  • excluded-scope: Respected. No agent CLIs used (curl/wget only), no src/ changes, no attempt to patch smolvm if a bypass is found.
  • files: All planned files created; no unplanned touches.
  • tests: Correct — no automated tests; five-case matrix is the signal.
  • boundaries: None to cross.
  • commit: Subject test(spike): add smolvm per-domain network allowlist probe matches plan exactly.
  • handoff: Covers --allow-host syntax, all five cases documented, case 3 clearly identified as go/no-go signal, smolvm flags confirmed, note about apk add curl needed in guest.

Phase phase-04 — Agents-in-guest execution probe

Verdict: conformant

  • objective: Delivered. spikes/smolvm/03-agents.sh is parameterized over three providers (claude, codex, vibe). Step A runs with --net --allow-host <provider-api-domain> and env-injected keys; Step B runs with zero egress to capture denied-egress UX via a 60-second timeout wrapper. spikes/smolvm/findings/03-agents.md has a per-provider results table; Results/Verdict left empty.
  • excluded-scope: Respected. No phax provider adapter changes, no wiring into SecurityPolicy, no hard-coded secrets.
  • files: All planned files created; no unplanned touches.
  • tests: Correct — no automated tests; per-provider findings table is the signal.
  • boundaries: None to cross; script invokes CLIs inside the guest, does not touch src/infra/.
  • commit: Subject test(spike): add smolvm in-guest agent execution probe matches plan exactly.
  • handoff: Covers per-provider install method, executable names (including the vibe/@mistralai/vibe caveat), zero-egress design rationale for Step B, pre-baked image implication, no-secrets confirmation, empty results explained.

Phase phase-05 — Synthesis and go/no-go recommendation

Verdict: conformant

  • objective: Delivered. docs/spikes/smolvm-isolation-findings.md synthesizes all three probes, gives an explicit provisional go/no-go pinned to probe 02 case 3 (hard-coded-IP egress), provides a non-implementing integration sketch (adapter location, SecurityPolicy reuse, secure/isolated layering), specifies the widened mcp.allow shape with Array<{ name; domains }> and a "refuse to start" policy for undeclared MCP entries, defines the capability-preamble prompt template, lists seven residual risks, and specifies the recommended next step for both go and no-go outcomes. The provisional status is clearly stated at the top of the document.
  • excluded-scope: Respected. No src/ changes, no phax.json or package.json changes, no follow-up implementation plan written.
  • files: docs/spikes/smolvm-isolation-findings.md created (planned). spikes/smolvm/README.md updated with a synthesis link (listed as "optional" in the plan, present in the reconciliation as "extra-touch" for phase-05 — this is expected and permitted). No unplanned files.
  • tests: Correct — no tests planned for a decision document.
  • boundaries: Informational only; the synthesis describes a proposed contract without introducing code. No architectural boundary crossed.
  • commit: Subject docs(spike): synthesize smolvm isolation findings and go/no-go matches plan exactly.
  • handoff: Covers go/no-go decision and the single driving fact, pointer to follow-up plan location and surface-area change, provisional status explicit, no file-plan deviations.

Unplanned-change ledger

File Phase Description Justified?
phax.json phase-01 oxfmt reformatted the agentCommands array from multi-line to single-line; content unchanged Yes — explained in handoff; no behavioral change

Unmet-promise ledger

None. All planned artifacts are present. All ## Results / ## Verdict sections are intentionally empty per the spike's execution-model caveat (real VM runs are out-of-band), which is stated in both the plan and the phase handoffs.


Attention points

  1. Provisional go/no-go — The synthesis is explicitly conditional on probe 02 case 3 (non-allowed host by hard-coded IP) blocking on a real microVM run. No follow-up implementation plan should be written until the three probe docs have their ## Results and ## Verdict sections filled in from an actual run.
  2. @mistralai/vibe npm package unverified — The phase-04 harness flags this with a NOTE: comment. Before running 03-agents.sh, the correct npm package name for Mistral Vibe must be confirmed; an incorrect name will cause the install to fail and produce an inconclusive finding for that provider.
  3. Pre-baked guest image requirement — Step B of the agents probe exposes a structural gap: apk and npm install both need internet, so an isolated mode with zero egress cannot install the provider CLI at boot time. The synthesis captures this as residual risk 7 (image distribution). Any follow-up implementation plan must address this before shipping.
  4. phax.json formatter drift — The unplanned oxfmt reformat of phax.json in phase-01 is benign but indicates the formatter is running on files outside the changed set. Worth noting for future spike phases that touch only shell/docs.

Phase details

phase-01 — Spike scaffold and smolvm preflight

File reconciliation

PHAX File Reconciliation

Planned to create

  • spikes/smolvm/README.md
  • spikes/smolvm/00-preflight.sh
  • spikes/smolvm/findings/TEMPLATE.md

Unplanned files edited

Deviation — agent must explain in phase-handoff.md under "What the next phase needs to know".

  • phax.json

Summary: Deviations detected — see sections above.

Phase handoff

What was delivered

  • spikes/smolvm/README.md — spike overview: three unknowns (network/FS/agents-in-guest), isolated-mode context, execution-model caveat, and harness run order.
  • spikes/smolvm/00-preflight.sh — POSIX sh, set -eu; confirms smolvm is on PATH, prints version, host arch/OS, binary path; probes smolvm info then smolvm config for VMM backend; exits non-zero with a clear message if smolvm is absent.
  • spikes/smolvm/findings/TEMPLATE.md — findings skeleton with sections: Environment, Procedure, Results (raw output, filled from real run), Verdict (PASS/FAIL/PARTIAL + one-line conclusion), Open questions.

Key decisions and why

  • Preflight uses a try-smolvm info / try-smolvm config / env-var fallback for backend detection because smolvm's CLI surface is not pinned; the script degrades gracefully rather than failing if neither subcommand exists.
  • Shell scripts are not wired into package.json or any phax gate — by plan design; they are human-run harnesses only.
  • phax.json was not intentionally edited by this phase; the change detected is oxfmt reformatting the pre-existing agentCommands array (added in the prior commit 3537e7e) from multi-line to single-line. The array content — including smolvm — is unchanged.

Exact locations (file paths and exported names)

  • spikes/smolvm/README.md — human-facing spike overview and run instructions
  • spikes/smolvm/00-preflight.sh — preflight script (shell only, no exported symbols)
  • spikes/smolvm/findings/TEMPLATE.md — findings template to copy for each probe

What the next phase needs to know

  • Copy findings/TEMPLATE.md as the base shape for findings/01-filesystem.md; fill the Procedure section, leave Results/Verdict empty for the real run.
  • The preflight script does not boot a VM; phase-02 is the first script that does.
  • smolvm is already present in security.agentCommands in phax.json (added in commit 3537e7e, pre-dating this phase); no further phax.json change is needed.
  • phax.json deviation: phax flagged it as an unplanned edit. The only change is oxfmt collapsing the agentCommands array to one line — content is identical, no behavioral change.
  • smolvm CLI surface may not expose a backend info subcommand; the preflight handles this gracefully. Phase-02 should similarly not assume undocumented subcommands exist.
  • All gates pass clean (typecheck, lint, format:check, knip, 1980 unit tests, audit:architecture, build). The three pre-existing knip ignoreBinaries hints (claude, gh, usage) are unrelated to this phase.

phase-02 — Filesystem isolation probe

File reconciliation

PHAX File Reconciliation

Planned to create

  • spikes/smolvm/01-filesystem.sh
  • spikes/smolvm/findings/01-filesystem.md

Summary: No deviations from the planned file lists.

Phase handoff

What was delivered

  • spikes/smolvm/01-filesystem.sh — POSIX sh harness (set -eu) with five named checks: workspace mount + write-back, host HOME invisible, host repo root invisible, host /etc not leaking, read-only mount rejected. Prints PASS/FAIL per check and a final tally.
  • spikes/smolvm/findings/01-filesystem.md — findings doc based on TEMPLATE.md; ## Procedure fully populated for all five checks; ## Results and ## Verdict left empty for the real run.

Key decisions and why

  • Guest image is alpine: minimal, multi-arch (works on Apple Silicon arm64), standard shell available, no heavy pull. Phase-03 and phase-04 can reuse the same image for their initial probing.
  • Host HOME and repo root probed with unique per-PID marker files (.smolvm-probe-$$) written before boot, then accessed at their exact host paths from inside the guest. More robust than checking directory existence — Alpine's /home exists but is empty; macOS /Users/ simply doesn't exist in the Linux rootfs.
  • PASS/FAIL for the host-path invisibility checks (B and C) are textual only: the guest prints "NOT VISIBLE" or "VISIBLE". No programmatic exit-code assertion. Rationale: the deliverable is observable output to paste into the findings doc, not a CI gate.
  • Read-only mount tested with the documented -v HOST:CONTAINER:ro suffix (confirmed via smolvm machine run --help). The host side is also checked as secondary confirmation — a guest write-through would create the file on the host even if the guest shell masked the error.
  • smolvm machine run (ephemeral) used throughout. No persistent machine state. Each check is an independent VM lifecycle to avoid state leakage between checks.

Exact locations (file paths and exported names)

  • spikes/smolvm/01-filesystem.sh — shell harness (no exported symbols)
  • spikes/smolvm/findings/01-filesystem.md — findings doc (procedure filled, results empty)

What the next phase needs to know

  • Network is off by default in smolvm (security-first). Phase-03 must include --net explicitly even for the "allowed domain" case.
  • Relevant flags for phase-03 (confirmed via smolvm machine run --help): --net, --allow-host <HOSTNAME>, --allow-cidr <CIDR>.
  • ## Results and ## Verdict in findings/01-filesystem.md are intentionally empty — filled from a real run out-of-band per the spike's execution-model caveat.
  • No changes to src/, phax.json, or package.json in this phase.
  • All gates pass clean (1980 unit tests, typecheck, lint, format, knip, audit:architecture). Three pre-existing knip ignoreBinaries hints (claude, gh, usage) are unrelated to this phase.

phase-03 — Network per-domain allowlist probe

File reconciliation

PHAX File Reconciliation

Planned to create

  • spikes/smolvm/02-network.sh
  • spikes/smolvm/findings/02-network.md

Summary: No deviations from the planned file lists.

Phase handoff

What was delivered

  • spikes/smolvm/02-network.sh — POSIX sh harness (set -eu) with five named cases: (1) allowed domain reachable by name, (2) non-allowed domain blocked by name, (3) non-allowed host by hard-coded IP (the decisive test), (4) allowed host by raw IP (reveals enforcement mechanism), (5) ICMP probe for completeness. Blocked domain IP is resolved on the host before VM boot and injected via shell variable.
  • spikes/smolvm/findings/02-network.md — findings doc based on TEMPLATE.md; ## Procedure fully populated for all five cases including the two crux questions in ## Verdict; ## Results and ## Verdict left empty for the real run.

Key decisions and why

  • example.com / httpbin.org as probe domains. example.com is IANA-reserved and stable. httpbin.org is a real host with a distinct IP, confirmed reachable on the public internet, making the raw-IP bypass test meaningful.
  • IP resolved on host before VM boot. The script uses nslookup + dig fallback. If both fail it warns and uses a hard-coded fallback. This avoids a DNS dependency inside the guest (which may itself be filtered) for the decisive case 3.
  • apk add curl inside each ephemeral VM. Alpine minimal image does not ship curl. Installing it per-case is noisy but guarantees a clean, hermetic probe. Phase-04 can reuse the same pattern.
  • Case 3 labelled THE DECISIVE TEST. The plan names this the go/no-go signal. The label and explanatory comment appear in both the script and the findings ## Procedure.
  • Network off by default. Confirmed from phase-02 handoff: --net must be given explicitly even for the "allowed domain" case. All five cases include --net.

Exact locations (file paths and exported names)

  • spikes/smolvm/02-network.sh — shell harness (no exported symbols)
  • spikes/smolvm/findings/02-network.md — findings doc (procedure filled, results empty)

What the next phase needs to know

  • ## Results and ## Verdict in findings/02-network.md are intentionally empty — filled from a real run out-of-band per the spike's execution-model caveat.
  • The denied-egress UX (timeout vs. connection refused) observed in cases 2 and 3 is what motivates the capability-preamble prompt in phase-05. Phase-04 (agents-in-guest) should observe and record this UX, since the network probe only records exit code / HTTP code, not the exact error message or timing.
  • Case 3 (raw-IP) result is the go/no-go signal feeding phase-05 synthesis. If the result is REACHABLE, phase-05's synthesis must mark the network boundary as insufficient.
  • smolvm flags confirmed working: --net, --allow-host <HOSTNAME>. --allow-cidr <CIDR> is also documented and included in the flag reference comment.
  • Guest image alpine requires apk add curl before any HTTP probe. Phase-04 agent probes will need similar in-guest setup steps for non-interactive CLI invocations.
  • No changes to src/, phax.json, or package.json. All gates pass (1980 tests, typecheck, lint, format, knip, audit:architecture). Three pre-existing knip ignoreBinaries hints (claude, gh, usage) are unrelated to this phase.

phase-04 — Agents-in-guest execution probe

File reconciliation

PHAX File Reconciliation

Planned to create

  • spikes/smolvm/03-agents.sh
  • spikes/smolvm/findings/03-agents.md

Summary: No deviations from the planned file lists.

Phase handoff

What was delivered

  • spikes/smolvm/03-agents.sh — POSIX sh harness (set -eu) parameterized over
    three providers (claude, codex, vibe). Two steps per provider: STEP A boots
    with --net --allow-host <provider-api-domain> and an env-injected key, installs
    the CLI via npm, runs a trivial task (hello.txt in /workspace), and confirms
    write-back on the host; STEP B boots with zero egress (no --net) and captures
    denied-egress UX via a 60-second timeout wrapper.
  • spikes/smolvm/findings/03-agents.md — findings doc based on TEMPLATE.md; ## Procedure fully populated with per-provider invocation table, installation method,
    and key-handling notes; per-provider results table ready for filling; ## Results
    and ## Verdict left empty for the real run.

Key decisions and why

  • Executable names: claude (Claude Code), codex (Codex CLI), vibe (Mistral
    Vibe). Confirmed from src/domain/routing/defaults.ts — do not use mistral-vibe
    or mistral as the binary name for Mistral's provider.
  • vibe npm package @mistralai/vibe is unverified: flagged with a NOTE:
    comment in the script. Must be confirmed before running; if wrong, install fails
    and the findings table records it.
  • STEP B uses no --net (not a wrong allowlist): zero egress is the cleanest
    signal. Any connection attempt fails at the kernel level; no ambiguity about whether
    the allowlist is partially active.
  • Codex prompt via stdin: printf '<prompt>' | codex exec -C /workspace …. This
    matches how phax's own spawnCodex feeds the prompt (proc.stdin.write(prompt)).
  • 60-second timeout on STEP B: guards against silent CLI retry loops. If the
    timeout fires, the finding is "CLI hangs" — which is as important as a clean error.

Exact locations (file paths and exported names)

  • spikes/smolvm/03-agents.sh — shell harness (no exported symbols)
  • spikes/smolvm/findings/03-agents.md — findings doc (procedure filled, results empty)

What the next phase needs to know

  • ## Results and ## Verdict in findings/03-agents.md are intentionally empty —
    filled from a real run out-of-band per the spike's execution-model caveat.
  • The Step B denied-egress UX is the primary input phase-05 needs from this probe for
    the capability-preamble prompt design. Key question: does the CLI exit with a clear
    error, hang until timeout, or enter a retry loop?
  • The harness installs CLIs fresh each boot via apk add nodejs npm + npm install -g.
    In STEP B (no --net), apk itself needs internet → install fails before the CLI
    runs. This is a real finding: production isolated-mode likely needs a pre-baked
    guest image with the CLI already installed.
  • smolvm flags confirmed working in prior phases: --net, --allow-host, -v HOST:CONTAINER[:ro], -e KEY=VALUE. The -e flag takes KEY=VALUE pairs.
  • Three knip ignoreBinaries configuration hints (claude, gh, usage) pre-exist
    in knip.json and are unrelated to this phase. Knip still exits 0 (hints, not errors).
  • No changes to src/, phax.json, or package.json. All gates pass (1980 tests,
    typecheck, lint, format, knip, architecture, build).

phase-05 — Synthesis and go/no-go recommendation

File reconciliation

PHAX File Reconciliation

Planned to create

  • docs/spikes/smolvm-isolation-findings.md

Optional files touched

  • spikes/smolvm/README.md

Summary: No deviations from the planned file lists.

Phase handoff

What was delivered

  • docs/spikes/smolvm-isolation-findings.md — single synthesis doc: per-probe
    summaries (filesystem / network / agents), a provisional go/no-go pinned to probe
    02 case 3 (hard-coded-IP egress), a non-implementing integration sketch for a
    future isolatedSandbox adapter under src/infra/providers/, the proposed
    widened mcp.allow shape, the capability-preamble prompt motivated by probe 03's
    denied-egress UX, residual risks, and the recommended next step.
  • spikes/smolvm/README.md — link to the synthesis added with a provisional-status
    note (optional edit listed in the plan).

Key decisions and why

  • Verdict is provisional. Every probe's ## Results / ## Verdict is still
    empty per the spike's execution-model caveat; the doc states this at the top and
    in the conclusion. Treat go/no-go as unresolved until a real microVM run fills
    those sections.
  • Probe 02 case 3 is the single decision point. Hard-coded-IP egress alone
    decides "real boundary" vs "DNS-name filtering". The synthesis binds the go/no-go
    to that one fact so a follow-up plan cannot start from a misread.
  • Reuse, don't extend, the domain types. No new SecurityMode, no new
    SecurityPolicy field. isolated already exists in src/domain/security/types.ts
    and src/schemas/securityConfig.ts; the stub at src/cli/commands/run.ts:152-158
    is the entire swap point.
  • mcp.allow widening is deliberately breaking. Per the project's "no
    back-compat shims in persisted schemas" rule, the proposed shape is
    Array<{ name; domains }>, and isolated mode refuses to start if any allowed
    MCP entry has no declared domains. Silent allow-everything would defeat the VM.
  • secure and isolated are layered. Defence-in-depth — isolated still
    applies the provider-native flags secure uses, inside the VM.

Exact locations (file paths and exported names)

  • docs/spikes/smolvm-isolation-findings.md — Markdown synthesis (no exports)
  • spikes/smolvm/README.md — Markdown (no exports)
  • Read-only anchors referenced by the synthesis:
    • src/domain/security/types.tsSecurityMode already includes "isolated"
    • src/schemas/securityConfig.ts:4SecurityProfileSchema accepts it
    • src/cli/commands/run.ts:152-158 — current isolated-rejection stub
    • src/infra/providers/{claudeCode,codexCli,mistralVibe,dispatcher}.ts — spawn
      surface a future isolatedSandbox.ts would wrap
    • spikes/smolvm/findings/{01-filesystem,02-network,03-agents}.md — source probes

What the next phase needs to know

  • This is the final phase of the spike; there is no next phase. The synthesis names
    what comes after: if probe 02 case 3 blocks on the real run, write the
    isolated-mode implementation plan (adapter, mcp.allow widening,
    capability-preamble builder, pre-baked guest-image recipe, e2e test under
    pnpm test:e2e:real); if it succeeds (IP literal escapes), stop and re-scope.
  • Until that real run, the per-probe verdicts and the go/no-go must remain marked
    provisional in the synthesis.
  • No changes under src/, phax.json, or package.json — strictly doc-only.
  • No file-plan deviations.

lbdremy and others added 7 commits June 29, 2026 15:14
Add the spikes/smolvm harness directory: a README stating the three unknowns (network/filesystem/agents-in-guest) and the execution-model caveat, a preflight script that verifies a smolvm install and reports backend/arch, and a findings template. No src/ changes; this is groundwork for the isolation probes.

---

Run-Id: smolvm-isolation-spike-1782738661332
Short-Name: smolvm-isolation-spike
Phase-Id: phase-01
Phase-Title: Spike scaffold and smolvm preflight
Model: claude-sonnet-4-6
Effort: low
Worktree: /Users/remyloubradou/.phax/worktrees/phax.smolvm-isolation-spike/phase-01
Session-Id: 0c33a1a2-8b3f-405d-aabd-e526821889c0
Gate-Log: /Users/remyloubradou/.phax/runs/phax.smolvm-isolation-spike/phase-01/checks-attempt-01.log
Add a harness that mounts one host dir as /workspace and asserts the rest of the host FS (HOME, repo root, /etc) is invisible to the guest, plus a read-only-mount check. Findings doc captures procedure; Results/Verdict are filled from a real run out-of-band per the spike's execution-model caveat.

---

Run-Id: smolvm-isolation-spike-1782738661332
Short-Name: smolvm-isolation-spike
Phase-Id: phase-02
Phase-Title: Filesystem isolation probe
Model: claude-sonnet-4-6
Effort: medium
Worktree: /Users/remyloubradou/.phax/worktrees/phax.smolvm-isolation-spike/phase-02
Session-Id: 2e26a154-2c61-42d1-93d2-e6b266001b6c
Gate-Log: /Users/remyloubradou/.phax/runs/phax.smolvm-isolation-spike/phase-02/checks-attempt-01.log
Add the decisive network harness: a five-case matrix (allowed-by-name, denied-by-name, denied-by-hardcoded-IP, allowed-by-IP, ICMP) that determines whether smolvm's --allow-host is deny-by-default and a real egress boundary versus DNS-name filtering. Findings doc frames the two crux questions; Results/Verdict filled from a real run out-of-band.

---

Run-Id: smolvm-isolation-spike-1782738661332
Short-Name: smolvm-isolation-spike
Phase-Id: phase-03
Phase-Title: Network per-domain allowlist probe
Model: claude-sonnet-4-6
Effort: medium
Worktree: /Users/remyloubradou/.phax/worktrees/phax.smolvm-isolation-spike/phase-03
Session-Id: f5a8c7d9-6a2f-4972-a851-4489a77b16f2
Gate-Log: /Users/remyloubradou/.phax/runs/phax.smolvm-isolation-spike/phase-03/checks-attempt-01.log
Add a parameterized harness that runs Claude Code, Codex, and Mistral Vibe inside the libkrun Linux guest with env-injected creds and a per-provider network allowlist, confirming each edits the mounted worktree and observing denied-egress UX. Secrets are read from host env only. Per-provider findings table filled from a real run.

---

Run-Id: smolvm-isolation-spike-1782738661332
Short-Name: smolvm-isolation-spike
Phase-Id: phase-04
Phase-Title: Agents-in-guest execution probe
Model: claude-sonnet-4-6
Effort: medium
Worktree: /Users/remyloubradou/.phax/worktrees/phax.smolvm-isolation-spike/phase-04
Session-Id: 7803253c-40ba-480b-97f8-287f8a05a2f6
Gate-Log: /Users/remyloubradou/.phax/runs/phax.smolvm-isolation-spike/phase-04/checks-attempt-01.log
Add the synthesis doc: per-probe verdicts (filesystem, per-domain network, agents-in-guest), an explicit go/no-go on smolvm for phax's isolated mode driven by the hard-coded-IP egress result, and a non-implementing integration sketch (infra wrapper adapter, SecurityPolicy reuse, MCP domain declaration, capability-preamble prompt) plus residual risks and the recommended next step.

---

Run-Id: smolvm-isolation-spike-1782738661332
Short-Name: smolvm-isolation-spike
Phase-Id: phase-05
Phase-Title: Synthesis and go/no-go recommendation
Model: claude-opus-4-8
Effort: high
Worktree: /Users/remyloubradou/.phax/worktrees/phax.smolvm-isolation-spike/phase-05
Session-Id: 4410fda5-e889-40dd-b5d7-47eadcf5ffb4
Gate-Log: /Users/remyloubradou/.phax/runs/phax.smolvm-isolation-spike/phase-05/checks-attempt-01.log
Ran the filesystem and network probes on smolvm 1.3.2 (macOS/arm64) and
filled in the findings docs and synthesis with actual results:

- Probe 01 (filesystem): PASS — clean guest, :ro enforced at hypervisor layer.
- Probe 02 (network): PASS — case 3 (raw IP to non-allowed host) is refused at
  L4, so --allow-host is a real IP-based egress boundary, not DNS filtering. GO.
- Probe 03 (agents): BLOCKED — no API keys; recorded the infrastructure facts.

Synthesis go/no-go is now a confirmed GO on the security question. Folds in two
run findings: scripts don't run verbatim (pull/apk blocked by the allowlist), and
a pre-baked image + --allow-host do not compose in smolvm 1.3.2 (new risk 8).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the bugs that stopped the probe scripts from running as written; all four
now run end-to-end on smolvm 1.3.2 (verified):

- 00-preflight: printf header starting with "--" was parsed as an option; use
  '%s\n'.
- 01-filesystem: omitted --net so the image pull failed. Bake a --from artifact
  once (cached) and boot every check from it — no network, no allowlist. Marker
  cleanup is now interrupt-safe via the trap.
- 02-network: apk add curl is blocked by the allowlist (would falsely report
  every case blocked) and the image pull is itself subject to the allowlist.
  Use busybox wget with a block-vs-HTTP-error classifier, allowlist the Docker
  registry hosts so the pull succeeds, run the matrix in a single boot under
  smolvm --timeout.
- 03-agents: replace the host `timeout` (absent on macOS, always false-positive)
  with smolvm --timeout; boot Step B offline from the --from artifact; allowlist
  package mirrors + registry for Step A install; make Vibe package overridable
  via VIBE_NPM_PKG (@mistralai/vibe 404s). Still requires API keys to produce a
  provider verdict.

Findings docs and synthesis updated to note the fixes are now in the scripts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant