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
This commit is contained in:
2026-05-12 23:07:32 -04:00
parent 102e29ee77
commit 9b7bcc0149
3 changed files with 19 additions and 9 deletions
+8 -2
View File
@@ -118,8 +118,14 @@ that enforces the manifest before it leaves the host.
upstream has *now* (fail-closed if unreachable). The agent's upstream has *now* (fail-closed if unreachable). The agent's
`~/.gitconfig` rewrites the real URL to the gate via `insteadOf`, `~/.gitconfig` rewrites the real URL to the gate via `insteadOf`,
so push, fetch, clone, and pull all route through. The agent so push, fetch, clone, and pull all route through. The agent
never sees the upstream credential. Brought up only when never sees the upstream credential. If the upstream's hostname
`bottle.git` has entries. Design in `docs/prds/0008-git-gate.md`. isn't resolvable from the gate container (e.g. a Tailscale-only
host whose public DNS points elsewhere), pin its IP via
`ExtraHosts: { "<hostname>": "<ip>" }` 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 When the agent exits, `cli.py` tears down every sidecar that was
brought up and the two networks; nothing about a bottle persists brought up and the two networks; nothing about a bottle persists
+5 -6
View File
@@ -19,14 +19,13 @@
"GIT_AUTHOR_NAME": "Eric Diderich", "GIT_AUTHOR_NAME": "Eric Diderich",
"NODE_ENV": "development" "NODE_ENV": "development"
}, },
"ssh": [ "git": [
{ {
"Host": "gitea", "Name": "claude-bottle",
"Hostname": "gitea.dideric.is", "Upstream": "ssh://git@gitea.dideric.is:30009/didericis/claude-bottle.git",
"User": "git",
"Port": 30009,
"IdentityFile": "/Users/didericis/.ssh/id_ed25519_gitea", "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": { "egress": {
+6 -1
View File
@@ -83,7 +83,12 @@ for a declared upstream:
- **Manifest field.** `bottle.git` — a list of git remotes the - **Manifest field.** `bottle.git` — a list of git remotes the
bottle is allowed to talk to, each with the credential the gate bottle is allowed to talk to, each with the credential the gate
uses to push upstream. The agent gets no parallel `bottle.ssh` 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` - **Agent-side URL rewrite.** Provisioner emits `~/.gitconfig`
with `[url "<gate-url>"] insteadOf = <real-url>` so every git with `[url "<gate-url>"] insteadOf = <real-url>` so every git
operation against the declared upstream (push, fetch, clone, operation against the declared upstream (push, fetch, clone,