From 9b7bcc01494ea52b0836deaa1401724146725c3b Mon Sep 17 00:00:00 2001 From: didericis Date: Tue, 12 May 2026 23:07:32 -0400 Subject: [PATCH] docs(git-gate): document ExtraHosts on bottle.git entries - 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 --- README.md | 10 ++++++++-- claude-bottle.example.json | 11 +++++------ docs/prds/0008-git-gate.md | 7 ++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e877274..56b8876 100644 --- a/README.md +++ b/README.md @@ -118,8 +118,14 @@ that enforces the manifest before it leaves the host. upstream has *now* (fail-closed if unreachable). The agent's `~/.gitconfig` rewrites the real URL to the gate via `insteadOf`, so push, fetch, clone, and pull all route through. The agent - never sees the upstream credential. Brought up only when - `bottle.git` has entries. Design in `docs/prds/0008-git-gate.md`. + never sees the upstream credential. If the upstream's hostname + isn't resolvable from the gate container (e.g. a Tailscale-only + host whose public DNS points elsewhere), pin its IP via + `ExtraHosts: { "": "" }` on the `bottle.git` entry — + the gate's `/etc/hosts` gets the override while the agent's + `insteadOf` rewrite still keys off the original hostname. Brought + up only when `bottle.git` has entries. Design in + `docs/prds/0008-git-gate.md`. When the agent exits, `cli.py` tears down every sidecar that was brought up and the two networks; nothing about a bottle persists diff --git a/claude-bottle.example.json b/claude-bottle.example.json index dbfd93c..d288613 100644 --- a/claude-bottle.example.json +++ b/claude-bottle.example.json @@ -19,14 +19,13 @@ "GIT_AUTHOR_NAME": "Eric Diderich", "NODE_ENV": "development" }, - "ssh": [ + "git": [ { - "Host": "gitea", - "Hostname": "gitea.dideric.is", - "User": "git", - "Port": 30009, + "Name": "claude-bottle", + "Upstream": "ssh://git@gitea.dideric.is:30009/didericis/claude-bottle.git", "IdentityFile": "/Users/didericis/.ssh/id_ed25519_gitea", - "KnownHostKey": "gitea.dideric.is ssh-ed25519 AAAA..." + "KnownHostKey": "ssh-ed25519 AAAA...", + "ExtraHosts": { "gitea.dideric.is": "100.78.141.42" } } ], "egress": { diff --git a/docs/prds/0008-git-gate.md b/docs/prds/0008-git-gate.md index 47033b5..d24e316 100644 --- a/docs/prds/0008-git-gate.md +++ b/docs/prds/0008-git-gate.md @@ -83,7 +83,12 @@ for a declared upstream: - **Manifest field.** `bottle.git` — a list of git remotes the bottle is allowed to talk to, each with the credential the gate uses to push upstream. The agent gets no parallel `bottle.ssh` - entry for those upstreams. + entry for those upstreams. Each entry may also carry an + `ExtraHosts: { hostname: ip }` map, surfaced to the gate as + `--add-host` so the gate can resolve upstreams whose public DNS + doesn't point at the reachable IP (e.g. Tailscale-only hosts). + The agent-side `insteadOf` rewrite keys off the original hostname, + so the manifest's `Upstream` URL stays human-readable. - **Agent-side URL rewrite.** Provisioner emits `~/.gitconfig` with `[url ""] insteadOf = ` so every git operation against the declared upstream (push, fetch, clone,