{"slug": "git-push-is-hard", "title": "Git Push is Hard", "summary": "A new approach to safely allow AI coding agents to run `git push` from sandboxed VMs uses a short-lived GitHub token injected by a proxy outside the sandbox, avoiding exposure of real credentials. The method, detailed in a technical guide, configures an nginx proxy on the host to attach a temporary GitHub App installation token to outgoing requests, enforcing rules like allowing push only to specific branches and denying force pushes. This pattern gives agents minimal, task-scoped permissions without granting full identity access.", "body_md": "# Git Push is Hard\n\nIf you run a coding agent inside a sandbox VM, the usual advice is simple: isolate the filesystem, restrict network access, don’t mount your home directory, don’t expose SSH keys or cloud credentials.\n\nBut that leads to one question: without an SSH key, how would the agent run `git push`\n\nsafely?\n\nYou could give the VM an SSH key or a GitHub token. That basically diminishes the purpose of the VM, and gives the agent more access than it needs. So, **don’t do this.** AI agents had [bad reputation](https://openai.com/index/hugging-face-incident-and-the-road-ahead/).\n\n### Use a short-lived token instead\n\nBasically, configure a proxy outside the sandbox.\n\nInside the VM, let `git push`\n\ntalk to the remote with a scoped, synthetic credential. A custom proxy running outside the sandbox attaches the real GitHub OAuth token before forwarding the request — so the real token is invisible to the model.\n\nA GitHub App works well for this. The host keeps the app’s private key and creates a short-lived installation token for the repo. The VM uses that token to push its branch.\n\nThe broker can enforce rules such as:\n\n- allow fetch\n- allow push\n`agent/run-123`\n\n- deny push\n`main`\n\n- deny force push\n- deny other repos\n\nThe agent does not need to hold the real GitHub credential at all.\n\n### A practical guide\n\nIn practice, the proxy can be as simple as an nginx docker process listening on `127.0.0.1:8082->80/tcp`\n\n. It injects `gh auth token`\n\ninto outgoing requests as the auth header.\n\nInside the VM, the push command looks like `git push https://github.com/name/repo.git main`\n\n.\n\nGetting an agent to use it doesn’t take much: just hint it. Something like “push via GitHub broker on host port 8082 instead of origin” works well — the agent figures out the rest on its own.\n\nHere’s [a script that keeps that nginx conf fresh](https://gist.github.com/soasme/0f93509db16e6a5a950cff26769ae11c): pull a short-lived token with `gh auth token`\n\n, write it into `$XDG_CONFIG_HOME/ghe-proxy/nginx.conf`\n\nas a `Basic`\n\nauth header, lock the file down to `0600`\n\n, then tear down and recreate the container — a plain restart would keep serving the old, stale token — and check `docker inspect`\n\nto confirm it actually came back up.\n\n### The general pattern\n\nThis is a useful way to think about agent permissions in general. A runtime does not need your identity. It needs a small set of capabilities for the current task. For `git push`\n\n, that capability is usually: this repo, this branch, for a short time.", "url": "https://wpnews.pro/news/git-push-is-hard", "canonical_source": "https://julin.ai/2026/08/28/let-ai-agent-push-code-safely/", "published_at": "2026-08-27 12:00:00+00:00", "updated_at": "2026-08-28 09:49:20.422504+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-safety"], "entities": ["GitHub", "nginx", "OpenAI"], "alternates": {"html": "https://wpnews.pro/news/git-push-is-hard", "markdown": "https://wpnews.pro/news/git-push-is-hard.md", "text": "https://wpnews.pro/news/git-push-is-hard.txt", "jsonld": "https://wpnews.pro/news/git-push-is-hard.jsonld"}}