mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
feat: make Antigravity a first-class CLI across docs, installer and UI
Antigravity (agy) was wired into the session layer but never propagated to the surfaces around it, while Gemini CLI stayed documented as a consumer product despite being enterprise-only since Google's cutover. Gemini keeps full support; Antigravity now sits beside it everywhere. Functional fixes: - docker/agent.Dockerfile never installed agy, so a docker case with mode 'antigravity' died on command-not-found. agy is not on npm, so it gets its own installer step. --dir /usr/local/bin is load-bearing: the default $HOME/.local/bin resolves to root's home at build time and is unreachable by the `agent` user the container runs as. Verified inside codeman/agent:base (v1.1.10, reachable as `agent`). Note the binary is ~190MB, the largest layer in the image. - Welcome screen gained a Run Antigravity action, gated on agy being present like the other CLI buttons, with a cyan identity matching the toolbar run button and run-mode dot. - install.sh now detects agy (search paths mirroring the resolver), counts it as a satisfying AI CLI, and recommends it over Gemini in the install hints. Detection only, no new auto-install path. Docs corrected where they were factually wrong: - architecture-invariants documented isExternalCliMode() as opencode/codex/gemini when the code has included antigravity for a while, said "all three modes", and omitted ANTIGRAVITY_ from the env prefix allowlist row. - cron-guide's agentType enum, cron-discovery's SessionMode, and remote-sessions' RemoteCommandMode were all stale. Also: README + README.zh-CN (five CLIs, Gemini marked enterprise-only), package.json keyword, and comment drift in 8 places. test/run-mode-ui.test.ts now covers the new welcome button; verified it fails without the settings-ui wiring. Antigravity nests its whole state under ~/.gemini/antigravity-cli/, not ~/.antigravity, so the existing .gemini docker credential seed already covers it. Recorded as a comment so nobody adds dead config later. isAltScreenStripMode() deliberately still excludes antigravity: whether its TUI needs the alt-screen strip is a behavioural question that needs a real agy session, not a guess. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -489,7 +489,7 @@ production layout (`~/.codeman`, `-L codeman`, port 3000).
|
||||
Docker cases (1.4.0) run a session inside a per‑case container instead of on the host. The security posture:
|
||||
|
||||
- **Hardened create flags, always** — `--cap-drop ALL`, `--security-opt no-new-privileges`, `--pids-limit` (fork‑bomb guard), `--memory` == `--memory-swap` (a real OOM cap), `--init`, and non‑root: `--user <hostUid>:0` on Linux (host uid → workspace files stay host‑owned; GID 0 keeps `$HOME` writable), `--userns=keep-id` on rootless Podman. **Never** `--privileged`, and **never** the docker socket — the pure builder in `docker-hosts.ts` cannot emit them and the schema cannot represent them.
|
||||
- **Credentials never enter an image** — the convenient default bind‑mounts host cred dirs (`~/.claude`, `~/.codex`, `~/.gemini`, `~/.config/{gcloud,opencode}`) read‑write. Bind mounts are physically excluded from `docker commit`, so exported images are secret‑free. API‑key CLIs get their key as an exec‑time NAME‑ONLY `--env OPENAI_API_KEY` (no `=value`, no `ps` leak, never committed); a create‑time `-e` for a secret is never used. The **sealed** profile (`mountCredentials:false` + `network:none`) drops the host mounts; full‑image export is then refused (an in‑container login would ride the committed layer) unless a pre‑commit scrub is opted into.
|
||||
- **Credentials never enter an image** — the convenient default bind‑mounts host cred dirs (`~/.claude`, `~/.codex`, `~/.gemini` — which also carries Antigravity's `antigravity-cli/` state — and `~/.config/{gcloud,opencode}`) read‑write. Bind mounts are physically excluded from `docker commit`, so exported images are secret‑free. API‑key CLIs get their key as an exec‑time NAME‑ONLY `--env OPENAI_API_KEY` (no `=value`, no `ps` leak, never committed); a create‑time `-e` for a secret is never used. The **sealed** profile (`mountCredentials:false` + `network:none`) drops the host mounts; full‑image export is then refused (an in‑container login would ride the committed layer) unless a pre‑commit scrub is opted into.
|
||||
- **Blast radius — accept it explicitly** — the convenient profile mounts an arbitrary host workspace RW plus the host credential dirs RW into a network‑enabled container, so container‑run agent code can read/modify those host trees and reach the network at once. Still a net improvement over today's on‑host `--dangerously-skip-permissions` execution; use the sealed profile for genuinely untrusted work.
|
||||
- **Import is untrusted‑bundle‑safe** — `/api/docker-cases/import` validates the manifest + per‑member SHA‑256 before extraction, rejects absolute / `..` tar members (traversal guard), and re‑tags the loaded image into a quarantined namespace so it can never overwrite `codeman/agent:base` or a pre‑existing tag.
|
||||
- **Host guard & the bridge‑hooks listener** — in‑container hook callbacks carry `Host: host.docker.internal` / `host.containers.internal`; both are on the always‑on host‑header allowlist (`DOCKER_HOST_GATEWAY_ALIASES`) and resolve to the host only from inside a container netns, so they are not a browser DNS‑rebinding surface. On a loopback‑only server, in‑container hooks are opt‑in via `CODEMAN_DOCKER_BRIDGE_HOOKS=1`, which binds a SECOND listener on the docker bridge gateway serving **only** the hook endpoints (every other path → `403`) into the same hook‑secret‑gated pipeline. The bridge is host‑internal (containers + host), not the LAN, so it does not widen network exposure; the hook secret is bind‑mounted read‑only and referenced by path.
|
||||
|
||||
Reference in New Issue
Block a user