Commit Graph

8 Commits

Author SHA1 Message Date
didericis fcbbc4484d refactor(cred_proxy): flat routes, role-driven provisioning (PRD 0010)
test / unit (pull_request) Successful in 14s
test / integration (pull_request) Successful in 22s
Replace bottle.tokens (with Kind enum and hardcoded per-kind
route/auth tables) with bottle.cred_proxy.routes — each route
declares its own path, upstream, auth_scheme, token_ref, and
optional role[]. The manifest is now the source of truth for the
proxy's runtime route table; adding an upstream is a manifest edit,
not a code change.

Agent-side rewrites move from per-kind dispatch to per-role tags
on routes:
  anthropic-base-url -> set ANTHROPIC_BASE_URL=<proxy><path>
  npm-registry       -> write ~/.npmrc registry=
  git-insteadof      -> write ~/.gitconfig [url] insteadOf, keyed
                        off route.upstream (suppressed when
                        bottle.git brokers the same host)
  tea-login          -> add a ~/.config/tea/config.yml login

Roles are a list (string accepted as sugar). A gitea route
typically carries ["git-insteadof", "tea-login"]. Singleton roles
(anthropic-base-url, npm-registry) appear on at most one route.

token_env slots are assigned per distinct TokenRef in declaration
order — two routes sharing a token_ref (e.g. github API + git
endpoints) share a slot.

Drops: TOKEN_KINDS, _KIND_ROUTES, _KIND_AUTH_SCHEME, _TOKEN_DEFAULT_HOST,
cred_proxy_route_path_for_gitea, the kind field on CredProxyUpstream,
and the kind-based hardcoding in pipelock_token_hosts (now derives
from route.UpstreamHost).

Legacy bottle.tokens manifests now die with a hint pointing at
bottle.cred_proxy.routes + this PRD. Tests rewritten end-to-end.
Docs + example.json + the dev ~/claude-bottle.json updated to match.
2026-05-13 21:49:55 -04:00
didericis 431e7481ef docs: README + example.json for cred-proxy (PRD 0010)
test / unit (pull_request) Successful in 15s
test / integration (pull_request) Successful in 29s
- Architecture diagram gains the cred-proxy lane (agent talks plain
  HTTP via bearer-auth-injection; sidecar talks HTTPS to the real
  upstream with the manifest token).
- Adds a cred-proxy entry under the sidecar bullet list, with a
  pointer to PRD 0010.
- Manifest example illustrates the `tokens` array on a bottle.
- Auth section notes that declaring an `anthropic` token routes
  CLAUDE_BOTTLE_OAUTH_TOKEN through the sidecar instead of into
  the agent's environ.
- claude-bottle.example.json gains an `agentic` bottle declaring
  all four token kinds, plus a paired `agentic-helper` agent.
2026-05-13 16:32:46 -04:00
didericis 30d92bef48 docs: drop ssh from README/example, supersede PRD 0007 (PRD 0009)
test / unit (pull_request) Successful in 13s
test / integration (pull_request) Successful in 21s
- README architecture diagram drops the socat/ssh image box and
  the agent's ~/.ssh/config; the prose-bullets section drops the
  ssh image; the manifest example swaps `ssh:` for `git:` so
  someone copy-pasting it picks up the new shape.
- claude-bottle.example.json: `default` bottle's `"ssh": []` is
  gone (now just an empty bottle); the gitea-dev example already
  uses `git:` since the ExtraHosts work.
- PRD 0007 carries a "Superseded by PRD 0009" header at the top
  with a one-paragraph block explaining why; the file stays so
  the rationale of the prior design is still in-tree.
- git_gate.py: drop the now-stale shadow-route mention from a
  docstring (the validator went away in the manifest layer).
2026-05-12 23:57:50 -04:00
didericis 9b7bcc0149 docs(git-gate): document ExtraHosts on bottle.git entries
test / unit (pull_request) Successful in 12s
test / integration (pull_request) Successful in 19s
- example manifest swaps the gitea-dev bottle from ssh: to git:
  and shows ExtraHosts pinning gitea.dideric.is to its Tailscale IP
- README's git-gate paragraph names the field and the case it
  solves (upstream resolvable on the host but not from the gate
  container's default DNS)
- PRD 0008's manifest-field bullet mentions the field for parity
2026-05-12 23:18:46 -04:00
didericis d75cc9325f feat(bottles): implement bottle factory abstraction per PRD 0003
test / run tests/run_tests.py (pull_request) Successful in 16s
Introduce claude_bottle/bottles/ with a Bottle Protocol and a
get_bottle_factory() that dispatches on CLAUDE_BOTTLE_PLATFORM
(default "docker"). Move every Docker-specific subprocess.run call
from cli/start.py, plus the orchestration of build, networks, the
pipelock sidecar, container launch, and per-container provisioning
(prompt, skills, ssh, .git), into create_docker_bottle.

Drop bottles[].runtime from the manifest schema. Auto-detect whether
gVisor is registered with the daemon and pass --runtime=runsc when it
is; the preflight shows the resolved runtime so the choice is visible.
Manifests still carrying 'runtime' get a clear error pointing at the
auto-detect behavior, rather than silent ignore.

Out of scope: cli/cleanup.py and cli/list.py still call docker
directly. They enumerate active bottles across the host, which is a
separate concern from "create a bottle" and is left for a follow-up
that introduces a list_active/cleanup primitive on the factory.
2026-05-10 22:15:05 -04:00
didericis e3f5a5907a feat(bottle): opt-in gVisor runtime per bottle
test / run tests/run_tests.py (push) Successful in 19s
Bottles can now set "runtime": "runsc" to launch the agent container
under gVisor instead of runc, adding a userspace syscall barrier
between the agent and the host kernel. Default is runc (Docker
default). Pipelock stays on the default runtime per the research doc's
minimum-diff prescription.

The launcher verifies runsc is registered with the daemon before
launch, surfaces the runtime in the preflight plan, and dies with an
install pointer (and a macOS-not-supported note) when runsc is
requested but unavailable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 00:48:11 -04:00
didericis 0c1740ca99 chore: remove journal and project-local init-entry skill
test / run tests/run_tests.py (push) Successful in 23s
Drop docs/JOURNAL.md and .claude/skills/init-entry/, and update
CLAUDE.md, docs/INDEX.md, and claude-bottle.example.json so nothing
points at them anymore.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 23:55:39 -04:00
didericis b88fbbaedd docs: add claude-bottle.example.json
test / run tests/run_tests.py (push) Successful in 17s
Worked example covering two bottles (one minimal, one with all three
env-entry modes, an SSH entry, and a wider egress allowlist) and three
agents that share them. Named .example.json so manifest_resolve does
not auto-load it when running cli.py from the repo root.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 23:53:28 -04:00