Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Git

Claude Code often needs to fetch from or push to a repository. You could put a token into env, but then everything in the VM can read it and use it for anything the token allows.

The git list in the project config is the safer way. It names the repositories git in the VM can fetch from and push to, using the git login on your machine. The login never enters the VM.

git:
  - remote: github.com/owner/repo
    fetch: true
    push:
      - aibox/*
      - feature/login
  - remote: github.com/owner/private-module
    fetch: true
  • remote is the host and path of the repository, without https:// and without .git.
  • fetch: true allows clone and fetch.
  • push lists the branches a push can create or update. * matches any part of a name without a /. So aibox/* allows aibox/fix but not aibox/a/b, and * on its own allows main too.

aibox refuses pushes to other branches, deletes, tags, and pushes from a shallow clone. If one branch of a push is refused, the whole push is. aibox also refuses repositories the list doesn’t name.

Using it

In the VM, use git like you normally would. git clone, git fetch and git push work with the addresses https://HOST/PATH, git@HOST:PATH and ssh://git@HOST/PATH.

aibox sends these requests to a broker on your machine. The broker adds your login and passes on what the list allows. When it refuses something, git in the VM shows you why. The broker writes what it refused, and every push it passed on, into proxy.log.

%%{init: {"sequence": {"mirrorActors": false}}}%%
sequenceDiagram
  participant git as git in the VM
  participant broker as Broker in aibox
  participant server as Git server
  git->>broker: clone, fetch or push
  broker->>broker: check it against the git list
  alt allowed
    broker->>server: the request, with your login
    server-->>broker: answer
    broker-->>git: answer
  else refused
    broker-->>git: why it was refused
  end

The host doesn’t need to be on the allow list for git.

To go get a private module, set GOPRIVATE in env. For hosts other than GitHub, Go first asks the host over HTTPS where the module is, so that host needs to be on the allow list too.

SSH

Before the VM starts, aibox asks git on your machine for the login of each repository, the same way git push over HTTPS would. If git has none, the broker talks to the server over SSH instead, as git@HOST. aibox tells you when it does that.

aibox asks ssh -G how ssh would reach the host. So these settings from your ~/.ssh/config apply: HostName, Port, IdentityFile, IdentitiesOnly, IdentityAgent, UserKnownHostsFile, GlobalKnownHostsFile and HostKeyAlias.

It offers the same keys ssh would, from your SSH agent and from key files without a passphrase. A key with a passphrase works through the agent, which has to keep running while aibox does. aibox refuses a host that your config reaches through ProxyJump or ProxyCommand.

On Windows aibox uses the agent of Windows’ OpenSSH, the service “OpenSSH Authentication Agent”, unless SSH_AUTH_SOCK names another one. Windows turns that service off by default: start it with Start-Service ssh-agent, set it to start by itself, and add your key with ssh-add. The agent of Git Bash sets SSH_AUTH_SOCK to a path only Git Bash can reach, so unset it for aibox. It reads the known hosts of everyone from %ProgramData%\ssh\ssh_known_hosts, as that ssh does. It asks the ssh that comes first on your PATH. The one of Git Bash writes its paths as /c/Users/..., which aibox can’t read, so keep Windows’ own ssh first.

Your known hosts check the server. aibox refuses a server that isn’t in them, so connect to it with ssh once to add it.

The broker logs in once and runs git’s requests from the VM over that connection.

If neither HTTPS nor SSH works, aibox stops. It reads the logins and keys only once, so restart aibox when one expires.

For SSH, aibox keeps a connection to your SSH agent open while it runs, and can connect to the SSH server’s port. To limit what a bug in aibox could do with that, give aibox its own key, or use an agent that asks before it signs, like with ssh-add -c.

Your name and line endings

The VM has a home of its own, without your git config. So aibox gives git in the VM the name and email git uses in your project. aibox run also gives it your core.autocrlf. Git for Windows sets that to true when it installs, and checks out files with CRLF line endings. Without the setting, git in the VM would see every file as changed, and a commit would change the line endings of every file. A task doesn’t need it, since the VM clones the repository itself.

Settings of your own in env win, such as GIT_AUTHOR_NAME, or core.autocrlf in a GIT_CONFIG_KEY_*.

What the broker can’t stop

The broker can’t stop a force push to a branch you allowed. It sees which branches a push updates, but not whether the push drops commits. Protect the branches that matter on the server, for example with branch protection on GitHub.

What the VM pushes is code you haven’t read. A pushed branch can start the repository’s CI, with changes to its workflows and with its secrets.

With push but no fetch, the VM still sees the names of all branches and tags and the commits they point to, because git needs them to push. It doesn’t get the files.

With git, aibox sets GIT_CONFIG_COUNT, GIT_CONFIG_KEY_* and GIT_CONFIG_VALUE_* in the VM, so you can’t set them in env.

How the broker works

aibox asks git on your machine for each repository’s login before the VM starts. It runs git outside any repository and without a terminal. That way the project’s git config, which the VM can write, has no say.

git in the VM gets a config that sends the HTTPS and SSH addresses of each repository to http://127.0.0.1:3130. The init forwards that port to the proxy like the ports on the allow list, and the proxy serves the broker there.

The broker speaks git’s smart HTTP protocol. It only accepts git’s requests, only for the repositories on the list, and only without dot segments or escapes in the path. It sends each request to https://HOST/PATH.git, where the address comes from the config and not from the request. It adds the host’s login and drops the VM’s credentials and cookies. When the server refuses the login or redirects, the VM gets an error. That way git in the VM never asks for a login of its own. The broker also refuses a fetch the config doesn’t allow.

For a push, the broker reads the commands at the start. They name each ref with its old and new commit. The broker only passes the push on when every command updates or creates a branch on the list. Otherwise it refuses all of them, because the pack belongs to the whole push. It also refuses deletes, tags, signed pushes, push options and pushes from a shallow clone. It answers in git’s format, so git in the VM shows why. A push larger than git’s buffer starts with a probe that is just a flush, which the broker passes on.

Over SSH

Before the VM starts, aibox asks ssh -G for the host name, port, key files, agent and known hosts ssh would use. It reads the known hosts and the keys. The server’s port gets added to the ports aibox may connect to.

The broker only asks the server for the key types your known hosts have for it. It logs in once per repository and opens a session on that connection for each request. If the connection breaks, it logs in again. If the server doesn’t open a session in time, the broker logs in again too. It closes the old connection once the requests still on it are done. If the server refuses a session, for example because it has too many open, only that request fails. The other sessions on the connection go on.

HTTP is stateless and SSH isn’t. So for each request from git in the VM, the broker runs the service on the server once:

  • For the advertisement, it passes on what the server advertises, with the line that names the service over HTTP, and then ends the service.
  • For a request, it skips the advertisement, sends the body and passes on the answer. If git compressed the body for HTTP, the broker decompresses it first.

git in the VM sends Git-Protocol, which the broker passes on as GIT_PROTOCOL, so a fetch runs in protocol version 2. The checks of a push are the same as over HTTPS.

Logging in, opening and closing a session, the advertisement and every pause in an answer have a time limit. When git in the VM gives up on a request, the broker ends its session. What the server writes to standard error goes into the error and the log.

A path on the server that starts with - or ~ isn’t allowed in the config, because the server would read it as an option or a home folder.