# Connecting GitHub

`pipeline.source: github` builds from a GitHub repository, and a private one is
reached through an AWS CodeConnections connection. Setting one up is four steps,
two of which have a wrong answer that produces a working-looking connection and a
failing build.

This is the procedure for both an organization and a personal account. They
differ in one field.

## What has to be true

Three things, and Keel can verify only the first:

1. **A connection exists and is `AVAILABLE`**, recorded at
   `/keel/connections/github/{owner}`.
2. **That connection is bound to a GitHub App installation** which can see the
   repository. Not to a GitHub *user* — see below.
3. **The account has a GitHub source credential** naming that connection. This is
   what CodeBuild reads when it creates a build project.

`keel auth connect github {owner}` does 1 and 3. Step 2 happens in a browser and
is the one that goes wrong.

## The owner comes from `keel.yml`

Keel derives it from `pipeline.repo`:

```yaml
pipeline:
  source: github
  repo: devtide-llc/keel-test    # owner is "devtide-llc"
  branch: main
```

That owner names the connection (`keel-devtide-llc`) and keys the SSM parameter.
**It is a label, not a boundary.** `CreateConnection` takes only a name and a
provider type — AWS is never told which organization you meant, and nothing
constrains where the App is installed. A personal repo works the same way with
`repo: {username}/{repo}`.

## Procedure

### 1. Install the App where the repository is

Do this first. It removes the step where the wrong answer is easiest to give.

- **Organization:** <https://github.com/apps/aws-connector-for-github> → Install →
  choose the organization → *All repositories* or select the ones Keel may clone.
  Verify at `https://github.com/organizations/{org}/settings/installations`.
- **Personal account:** the same page, choosing your own account. Verify at
  <https://github.com/settings/installations>.

**If you have installations you do not want used, remove them now.** The AWS
console lists installations by opaque numeric ID rather than by account name, so
the reliable way to pick the right one is for it to be the only one.

### 2. Create the connection

```bash
keel auth connect github {owner}
```

It creates the connection `PENDING`, records the ARN in SSM, prints a console URL
and waits. An existing connection is reused rather than duplicated.

### 3. Authorize, in the browser

Open the printed URL, choose the connection, and select **Update pending
connection**. Two screens follow and only the second one decides anything:

**`github.com/login/oauth/authorize`** — "AWS Connector for GitHub wants access to
your GitHub account", verifying *your* GitHub identity. There is no organization
option here and that is correct: identities are personal. Click **Authorize**.

**Back in the AWS console — "GitHub connection settings".** This is the decision:

```
App Installation - optional
Install GitHub App to connect as a bot. Alternatively, leave it blank to
connect as a GitHub user, which can be used in AWS CodeBuild projects.
```

**Choose the installation. Do not leave it blank.** The field is marked optional
and the help text says a blank one works with CodeBuild; in practice a
user-bound connection reaches `AVAILABLE` and then fails every `CreateProject`.
If the picker is empty, use **Install a new app** — GitHub then shows an account
picker, and *that* is where you choose the organization rather than your personal
account.

Then **Connect**.

### 4. Apply

```bash
keel up --env {env}
```

`keel auth connect` has already registered the account's GitHub source
credential, so nothing else is needed.

## Verifying, and what Keel cannot tell you

**`AVAILABLE` means an installation is bound. It does not say which one.** No
CodeConnections API returns the install target — not `GetConnection`, and not
`CreateRepositoryLink`, which accepts an owner and repository as plain strings
and does no reachability check at all. So Keel reports the status it can read and
names where you check the rest:

```bash
# the connection Keel will use
aws ssm get-parameter --name /keel/connections/github/{owner} \
  --query Parameter.Value --output text

# the account's source credential — CodeBuild reads this, not the project
aws codebuild list-source-credentials
```

The installation itself is only visible on GitHub, at the organization's or your
own installations page.

## When it goes wrong

### `OAuthProviderException: User is not authorized to access connection {arn}`

Raised by `CreateProject` during `keel up`. **The message names the connection and
is usually not about the connection** — which is what makes it expensive. Check in
this order:

1. **The account's source credential.** `aws codebuild list-source-credentials`
   should return a `GITHUB` entry. Absent, re-run `keel auth connect github
   {owner}`, which registers it, or:
   ```bash
   aws codebuild import-source-credentials --server-type GITHUB \
     --auth-type CODECONNECTIONS --token {connection-arn}
   ```
2. **Whether the connection is bound to a user rather than an installation.** Not
   readable from AWS. If the **App Installation** field was left blank in step 3,
   delete the connection, delete `/keel/connections/github/{owner}`, and redo
   steps 2–3.
3. **Whether the installation can see the repository** — the organization's
   installations page, *Repository access*.

A stale `keel-admin` policy is worth ruling out once, and rarely the answer:

```bash
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::{account}:role/keel-admin \
  --action-names codestar-connections:PassConnection \
  --resource-arns {connection-arn} --query 'EvaluationResults[0].EvalDecision'
```

`implicitDeny` means re-run `keel auth setup`, which rewrites the policies.

### The build creates and then fails to clone

The project exists, so the credential is right; the installation cannot see the
repository. Check *Repository access* on the installation.

### `keel auth connect` says the connection already exists and exits

Reuse rather than repair, by design — but it does re-register the account
credential on every run, so it is the right thing to try first. If the connection
itself is wrong, delete it and the SSM parameter before re-running:

```bash
aws codeconnections delete-connection --connection-arn {arn}
aws ssm delete-parameter --name /keel/connections/github/{owner}
```

## Why CodeBuild works this way

Worth knowing, because the obvious design is the wrong one and reads as correct.

A CodeBuild project can carry a per-source `auth` block naming a connection, and
`CODECONNECTIONS` is a valid type there. It does not work: `CreateProject` fails
with the `OAuthProviderException` above while the connection, the caller's
`PassConnection`, the service role's `UseConnection` and the App installation are
all correct. Established by creating one project twice with the same service role,
differing only in that block — without it the project is created, with it the call
fails.

What CodeBuild reads is `ImportSourceCredentials`: **one credential per account,
per region, per server type.** Keel writes it from `keel auth connect` rather than
from an application's stack, because two applications in one account would
otherwise contend for a single resource and either one's `keel destroy` would take
the other's builds with it — the same reason the account-wide DynamoDB tables are
not in the stack.

The consequence to keep in view: **that credential is account-wide, so connecting
a second owner overwrites it.** One GitHub account or organization per AWS account
and region, for now.

## No connection at all

A public repository clones without one, and `keel up` says so rather than
failing. `pipeline.source: codecommit` avoids GitHub entirely — `keel up` creates
the repository and `keel deploy` pushes to it — which is also the quickest way to
get an environment up while a connection problem is being sorted out.
