Commit graph

287 commits

Author SHA1 Message Date
Evgeny Boger
96ef07fecf Strip Accept-Encoding from proxied API requests to prevent gzip corruption
Cloudflare was honoring the VM client's Accept-Encoding: gzip header and
returning compressed responses, but the proxy didn't forward the
Content-Encoding header, causing Claude Code to fail with "Failed to
parse JSON" when trying to parse raw gzip bytes as JSON.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:04:21 +03:00
Evgeny Boger
21e1c65226 Add cross-arch, MQTT packages and auto-update agents before launch
- Add qemu-user-static, binfmt-support, and mosquitto-clients to template
- Auto-update Claude Code or OpenCode to latest version before each session
- Add LSP plugins, ENABLE_LSP_TOOL support, and clangd/gopls/pyright/ts-lsp

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 05:13:20 +03:00
Evgeny Boger
27eeaef437 Support repos with no remote but with GitHub submodules
Previously _claude_vm_start_github_mcp bailed out immediately if the
repo had no origin remote. Now the main repo is optional — if there's
no remote, we still scan .gitmodules for GitHub submodule URLs and
request tokens for those. Also show all configured repos in the scope
message instead of just the main repo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:48:30 +03:00
Evgeny Boger
9d2bff5e2b Add cleanup fallback for broken Lima VM directories
If limactl delete leaves behind a directory with a missing lima.yaml
(e.g. after a Lima crash), all future limactl commands for that
instance break. Fall back to rm -rf to ensure the next VM creation
starts clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 04:14:05 +03:00
Evgeny Boger
1fd618b7db Support multi-repo credentials for git and MCP proxies
Detect GitHub submodules from .gitmodules, request a token for each,
and pass a JSON dict of {repo: token} to both proxies. The git proxy
injects per-repo Basic auth based on request path. The MCP proxy
selects the correct Bearer token based on owner/repo in tool call
arguments. Both proxies fall back to single-repo env vars for
backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 04:13:31 +03:00
Evgeny Boger
5e2fd69f51 Add USB passthrough and install non-cloud kernel
USB passthrough (--usb flag) resolves /dev/ttyACM0 or VID:PID to sysfs,
unbinds host drivers, wraps QEMU to inject -device usb-host args, and
rebinds on cleanup. The non-cloud kernel (linux-image-amd64) is needed
because the default cloud kernel lacks USB/serial drivers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 04:08:46 +03:00
Evgeny Boger
c6f25096cb Increase default VM disk size from 20 to 30 GB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 04:06:55 +03:00
Evgeny Boger
ca5be5bf71 Remove token refresh logic, use non-expiring tokens
Expiring user tokens with refresh broke when multiple repos were used:
each device flow revoked previous refresh tokens, causing 500 errors
on every refresh attempt. Switched to non-expiring tokens (opt out of
"User-to-server token expiration" in the GitHub App settings) which
coexist across multiple device flows without revoking each other.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:00:46 +03:00
Evgeny Boger
e3492eae4c Intercept Ctrl+V to forward host clipboard images into the VM
Add clipboard-pty.py, a pty wrapper that detects Ctrl+V (0x16) in the
host terminal input stream and saves the host clipboard image as a PNG
to the shared mount. Inside the VM, xclip and wl-paste shims read that
file, so Claude Code and OpenCode pick up pasted images transparently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 21:23:11 +03:00
Evgeny Boger
3e0b2f297f Improve token refresh log messages for better visibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:50:38 +03:00
Evgeny Boger
a4e45172ff Copy device flow user code to clipboard automatically
Uses pbcopy/xclip/xsel/wl-copy if available. Only shows
"(copied to clipboard)" when a tool was found and succeeded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 02:49:36 +03:00
Evgeny Boger
e0e3e93d77 Retry GitHub 5xx errors and save HTML error pages to disk
Instead of forwarding raw HTML error pages from GitHub to the client
(which dumps unreadable HTML on screen), save them to timestamped files
and retry with exponential backoff (1s, 2s, 4s, up to 4 attempts).
After exhausting retries, return a clean short error message.

Applies to all three GitHub-facing scripts:
- github-mcp-proxy.py (MCP tool calls)
- github-git-proxy.py (git push/pull)
- github_app_token_demo.py (OAuth token generation)

Also fixes connection leaks on exception paths in both proxy files
and adds URLError handling in the token demo for network-level failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 02:45:03 +03:00
Evgeny Boger
4f768eb5b1 Fix shell --no-git parsing and sync minimal docs 2026-02-21 14:29:26 +03:00
Evgeny Boger
7442c2836f Update agent-vm docs, harden streaming proxy, and remove Claude priming 2026-02-21 14:21:03 +03:00
Evgeny Boger
5b39ab5cfc Mount external state dir for VM session persistence 2026-02-21 03:47:52 +03:00
Evgeny Boger
e8f48bc237 Auto-accept project trust in VM Claude config 2026-02-20 21:41:42 +03:00
Evgeny Boger
e584cf8da9 Set high effort default in VM Claude settings 2026-02-20 21:05:39 +03:00
Evgeny Boger
de0c645e5a Set bypass warning skip flag in claude-vm 2026-02-20 20:37:14 +03:00
Evgeny Boger
5a4945579a Persist Claude config and bypass first-run onboarding 2026-02-20 20:36:27 +03:00
Evgeny Boger
12c7378caa Disable SO_REUSEADDR since proxy binds to random port
On a random port (bind to 0), there is no TIME_WAIT issue, so
SO_REUSEADDR is unnecessary and could allow another process to
bind to the same port and intercept traffic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:28:07 +03:00
Evgeny Boger
0fbbf2c6fa Harden API proxy against adversarial VM requests
Security fixes from comprehensive audit:
- CRITICAL: Add path allowlist (/v1/ only) to prevent VM accessing
  arbitrary endpoints on api.anthropic.com with injected credentials
- HIGH: Sanitize upstream error messages (no exception details to VM)
- HIGH: Add 32MB request body size limit to prevent memory exhaustion
- HIGH: Restrict log file permissions to 0o600
- MEDIUM: Allowlist upstream response headers forwarded to VM (strip
  Set-Cookie, Server, and other potentially sensitive headers)
- MEDIUM: Restrict HTTP methods to GET and POST only
- LOW: Validate Content-Length (reject negative/non-numeric values)
- LOW: Add 60s inbound connection timeout (Slowloris defense)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:26:14 +03:00
Evgeny Boger
7f4d9bcf13 Add OAuth token auto-refresh to API proxy using stdlib
Replace curl_cffi dependency with Python stdlib http.client for OAuth
token refresh against platform.claude.com. Verified reliable over 10
consecutive refreshes with token rotation.

Security hardening from code review:
- Fix connection leak: use try/finally for conn.close()
- Fix permission window: chmod temp file before atomic replace
- Fix credential leak: generic error messages to VM, details to logs only
- Fix lock contention: fast-path token check outside refresh lock
- Replace fragile ":" in host heuristic with explicit _token_use_tls flag
- Log credential save failures to stderr (not just debug)

Also adds test_proxy_refresh.py with 32 unit tests covering token
expiry, refresh flow, credential save/restore, and error paths.
Real endpoint test gated behind RUN_REAL_TESTS=1 env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:23:57 +03:00
Evgeny Boger
0f1f73e67c Add Git HTTP proxy for VM git push/pull
- github-git-proxy.py: host-side HTTP proxy that injects GitHub token
  (Basic auth) for the configured repo, forwards to github.com over HTTPS.
  Other repos are forwarded without credentials.
- Integrate into claude-vm.sh: starts alongside MCP proxy, configures
  git url.insteadOf (scoped to repo only), copies user.name/email from host
- Writes CLAUDE.md instructions in VM so Claude knows git push/pull works
- Logs to file (not stderr), with GITHUB_GIT_PROXY_DEBUG env var
- Update README with full GitHub integration docs (token generation,
  git proxy, MCP proxy, defense-in-depth, configuration)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 03:52:59 +03:00
Evgeny Boger
39c472c2e5 Auto-accept dangerous mode prompt inside VM
The VM is already sandboxed, so the interactive confirmation for
--dangerously-skip-permissions is unnecessary. Pass IS_SANDBOX=1
env var when launching claude CLI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 03:24:50 +03:00
Evgeny Boger
698037bd4d Remove github_app_token.sh, improve proxy docs
- Remove unused github_app_token.sh (only github_app_token_demo.py is
  used by claude-vm.sh)
- Document token generation flow: GitHub App device flow with
  repository_id scoping
- Rename "Security layers" to "Defense-in-depth" to clarify these
  are additional layers on top of GitHub's token scoping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 03:11:28 +03:00
Evgeny Boger
180a702916 Add GitHub MCP proxy documentation to README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 02:35:15 +03:00
Evgeny Boger
967bc51256 Add GitHub MCP proxy with security hardening
Defense-in-depth repo scope enforcement for the GitHub MCP proxy:
- Default-deny for unknown tools (allowlist of known tools)
- Search query scoping: auto-inject repo:OWNER/REPO, block org:/user: qualifiers
- Block non-repo-scoped tools (search_users, search_orgs, get_teams, etc.)
- Inject owner/repo when tools omit them
- Server-side tool filtering via X-MCP-Toolsets/Tools/Readonly/Lockdown headers
- Sensible default toolsets: repos,issues,pull_requests,git,labels
- Lockdown mode enabled by default
- VM cannot override X-MCP-* headers
- Skip body re-serialization when unmodified

Also adds GitHub App token generation scripts and comprehensive tests
(unit + end-to-end with mock upstream server).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 02:33:46 +03:00
Evgeny Boger
76f652f831 Add host-side API proxy to keep credentials out of VMs
Instead of storing OAuth tokens inside the VM template, credentials now
stay on the host. A lightweight Python proxy (claude-vm-proxy.py) reads
the host's ~/.claude/.credentials.json, injects the real auth headers
(Bearer + oauth beta for OAuth, x-api-key for API keys), and forwards
requests to api.anthropic.com. The VM gets only ANTHROPIC_BASE_URL
pointing at the proxy and dummy credentials so Claude Code detects
the correct subscription tier.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:01:16 +03:00
Evgeny Boger
ca6c51893d cleanup test 2026-02-10 04:41:30 +03:00
Evgeny Boger
9b9571f25d test scoping 2026-02-10 04:40:41 +03:00
Evgeny Boger
7478e8c7cf Add security hardening for VM sessions
Snapshot security-sensitive files before each VM session and check for
unauthorized modifications afterward. Mount .git/hooks and .git/config
as read-only at the Lima level to prevent the VM from tampering with
host-side git hooks or config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:13:01 +03:00
Sylvain Zimmer
375b784bf6
Add arguments to claude-vm-setup 2026-01-29 10:14:10 +01:00
Sylvain Zimmer
180c575c5d
Merge pull request #1 from sylvinus/claude/forward-vm-arguments-EeIOt
Forward arguments from claude-vm to the underlying claude command
2026-01-29 09:13:01 +01:00
Claude
b181d33245
Forward arguments from claude-vm to the underlying claude command
Allows passing CLI options like -p, --resume, or -c directly to claude-vm,
which are forwarded to the claude command inside the VM.

https://claude.ai/code/session_01ESjq1MiEWwf4zzfa3iChpi
2026-01-29 08:04:57 +00:00
Sylvain Zimmer
10e39f1210
Fix issue with double dashes in VM names 2026-01-28 02:18:43 +01:00
Sylvain Zimmer
827c93403a
Fix login in claude code and add more details to the README on VMs 2026-01-28 01:46:19 +01:00
Sylvain Zimmer
f865122778
first commit 2026-01-28 01:15:09 +01:00