# Accessing private repositories

AI agents often need to clone and push to private repositories. This page covers the
main approaches, their trade-offs, and security considerations — particularly important
when the agent is executing code it may have written itself.

## Approaches at a glance

| Approach | Complexity | Scope | Works during provisioning |
|----------|-----------|-------|--------------------------|
| PAT token via `gh` | Low | Configurable | Yes |
| Copy SSH key | Low | All repos your key accesses | Yes |
| Deploy key | Medium | One repo, read or read-write | Yes |
| SSH agent forwarding | Low | All repos your key accesses | No — interactive only |

---

## 1. PAT token with GitHub CLI (recommended)

Use a GitHub [fine-grained personal access token](https://github.com/settings/personal-access-tokens)
with the `gh` CLI. The `gh` mixin authenticates automatically: if `GH_TOKEN` or
`GITHUB_TOKEN` is set in your host environment when you run `agv create`, agv pipes
the value into `gh auth login --with-token` for you. No explicit auth command in
the config.

```toml
# agv.toml
[base]
from    = "ubuntu-24.04"
include = ["devtools", "gh"]
spec    = "large"

[[provision]]
run = [
  "gh auth setup-git",                    # configure git credential helper
  "gh repo clone org/myrepo ~/myrepo",
]
```

```sh
# .env  — add to .gitignore, never commit
GH_TOKEN=ghp_...
```

`GH_TOKEN` takes precedence over `GITHUB_TOKEN` (matches the `gh` CLI's own
ordering). If neither is set, agv leaves `gh` unauthenticated and prints a
manual-setup line telling you to run `gh auth login` inside the VM.

**Token permissions:** Fine-grained tokens let you select exactly which repositories the
token can access and what it can do. For read-only cloning, grant `Contents: Read` on
the target repositories. Add `Pull requests: Read & Write` if the agent needs to open
PRs. Use the minimum permissions needed — especially important when agents are running
code autonomously.

---

## 2. Copy an SSH key into the VM

The simplest option if you already use SSH keys for GitHub. The same key
also works for GitLab, Bitbucket, internal git servers, and
ssh-into-other-hosts.

Use the bundled `ssh-key` mixin: opt-in via `include`, and point
`SSH_KEY` at your private key path on the host.

```toml
# agv.toml
[base]
from    = "ubuntu-24.04"
include = ["devtools", "ssh-key"]
```

```sh
# .env  — add to .gitignore, never commit
SSH_KEY=/Users/you/.ssh/id_ed25519
```

The mixin copies the file in as `~/.ssh/id_ed25519`, fixes ownership and
permissions (700 on `~/.ssh`, 600 on the key), and derives the matching
`.pub` via `ssh-keygen -y` so you only have to provide one path. If
`SSH_KEY` isn't set the mixin becomes a no-op — useful when several VMs
share the same `agv.toml` but only some need a key.

If you want the same shape inline (without `include = ["ssh-key"]`), the
underlying recipe is just `[[files]]` with `optional = true` plus a
permissions-fixup `[[setup]]` step — see the mixin's own TOML for
the full pattern.

**Security:** The key lives on the VM's disk. If the agent runs malicious code or the
VM is compromised, the attacker has your full SSH key and access to everything it unlocks.
Prefer a dedicated key or deploy key (see below) for agent use.

---

## 3. Deploy key (recommended for agents)

A deploy key is a per-repository SSH key. It can be read-only or read-write, and is
scoped to a single repo — ideal for agents that should only access specific repositories.

agv generates a unique SSH key for each VM. Use that key as the deploy key so no
secret needs to be passed in at all.

**Step 1 — create the VM:**

```sh
agv create myvm
agv start myvm
```

**Step 2 — get the VM's public key:**

```sh
agv ssh myvm -- cat ~/.ssh/id_ed25519.pub
```

**Step 3 — add it as a deploy key** in the repo's GitHub Settings → Deploy keys.
Tick "Allow write access" if the agent needs to push.

**Step 4 — use it in provisioning:**

```toml
[[provision]]
run = """
ssh-keyscan github.com >> ~/.ssh/known_hosts
git clone git@github.com:org/myrepo.git ~/myrepo
"""
```

Each VM gets its own key, so revoking one VM's access does not affect others.

---

## 4. SSH agent forwarding (interactive sessions only)

Forward your local SSH agent into the VM with `agv ssh`. The key never touches the
VM's disk — it stays on your machine.

```sh
agv ssh myvm -A
```

Once inside the VM, git operations will authenticate via your forwarded agent as normal.

**Limitation:** Agent forwarding only works for your interactive shell session. It is
not available during `[[provision]]` steps, which run before you connect. Use a
different approach if you need to clone repos during provisioning.

---

## Dotfiles

Dotfiles are a natural fit for VM provisioning — the same config you maintain for your
own machines works equally well inside an agent VM.

**Option A — clone a dotfiles repo:**

```toml
# Assumes the gh mixin is included and GH_TOKEN/GITHUB_TOKEN was set on
# the host so agv could auto-authenticate.
[[provision]]
run = [
  "gh repo clone org/dotfiles ~/dotfiles && ~/dotfiles/install.sh",
]
```

This is the most flexible option: the install script can set up shell config, git
config, editor settings, and anything else the agent needs.

**Option B — copy files directly:**

```toml
[[files]]
source = "{{HOME}}/.gitconfig"
dest   = "/home/{{AGV_USER}}/.gitconfig"

[[files]]
source = "{{HOME}}/.config/gh"
dest   = "/home/{{AGV_USER}}/.config/gh"
```

Simpler, but requires listing each file individually. Works well for a small set of
config files that don't need an install step.

---

## Security summary for agent use

When an agent is executing code — especially AI-generated code — it may inadvertently
run something that reads credentials from the filesystem or environment.

**Prefer:**
- Deploy keys over personal SSH keys (scoped to one repo, separately revocable)
- Fine-grained PATs with minimal repository and permission scope
- Read-only access where possible — agents rarely need to push

**Avoid:**
- Copying your primary SSH key into a VM that runs untrusted code
- Broad PATs when a scoped token would do
- Storing credentials in the config file itself (use `.env` or environment variables)

Destroying a VM with `agv destroy` removes the disk, the generated SSH key, and all
instance state, so credentials do not persist after the VM is gone.
