# GitHub Integration


Instead of [setting up a GitHub personal access token](faq/github-token),
the GitHub integration connects your GitHub account to exe.dev so that you
can work on private repos without managing tokens, and without having
tokens on the VM itself.

## Linking your GitHub account

Link your GitHub account from the [Integrations page](/integrations).

The exe.dev GitHub App will need to be installed into your account or into
your organization. If someone else has already installed it, you may need
to sign into your account instead of clicking the install button.

## Creating repo integrations

Once connected, create per-repo integrations:

```
exe.dev ▶ integrations add github --name blog --repository ghuser/blog --attach vm:my-vm
Added integration blog

Usage from a VM:
  ssh my-vm 'cd $(mktemp -d) && git clone https://github.int.exe.xyz/ghuser/blog.git'
```

Then, from inside the VM:

```
git clone https://github.int.exe.xyz/ghuser/blog.git
```

## Acting as your user (`--act-as-user`)

By default the integration acts as the exe.dev GitHub App, so pushes
show up as `exe-dev-github-integration[bot]`. Pass `--act-as-user` on
`integrations add github` or `integrations edit` (or use the toggle in
the web UI) to authenticate as your GitHub user instead, attributing
activity to your account. Not available on team integrations.

## Read-only integrations (`--readonly`)

Pass `--readonly` on `integrations add github` or `integrations edit`
(or check "Read-only" in the web UI) to restrict the integration to
read access. `git clone`, `git fetch`, and read API calls work as
usual; `git push`, write API calls, LFS uploads, and GraphQL mutations
are rejected.

Enforcement has two layers. The integration's GitHub tokens are minted
with read-only permissions, which GitHub enforces server-side for
private repositories. Because GitHub still allows some writes on
*public* repositories with any installation token (e.g. opening an
issue), the integration proxy independently enforces read-only access
using allowlists: only known-safe git operations (fetch/clone
negotiation and LFS *download* batches), read HTTP methods on the REST
API, and GraphQL documents that contain only queries are forwarded.
Anything not recognized as read-only is rejected.

Not available with `--act-as-user`: user tokens cannot be restricted
to read access.

Creating read-only integrations is gated by the `github-ro` feature
flag. When it is not enabled for your account, `--readonly` and the
web UI's "Read-only" checkbox are unavailable (you can still turn an
existing read-only integration off). Enforcement of an
already-configured read-only integration is always active regardless of
the flag.

Like other integration edits, toggling read-only can take up to a
minute to reach running VMs (the proxy caches integration
configuration briefly).

## Using the `gh` CLI

The integration also supports the GitHub CLI (`gh`). Set `GH_HOST` to the
aggregate integration hostname:

```
export GH_HOST=github.int.exe.xyz
gh repo view ghuser/blog
gh issue list -R ghuser/blog
gh pr list -R ghuser/blog
```
