> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create your GitHub App

> Register a public, publishable GitHub App for your Pipefort deployment.

If you're running your own Pipefort deployment (self-hosted, or a fork), you need
your own **GitHub App** before users can sign in and connect repositories. This
page is for operators. End users who are just installing the hosted Pipefort App
should read [GitHub setup](/webapp/github-setup) instead.

The App is the credential Pipefort uses to mint per-installation tokens — see
[Architecture](/architecture) for the auth split between Supabase Auth (login)
and the GitHub App (repo access).

## What you need

* A GitHub account or organization that will **own** the App.
* The public URL of your Pipefort deployment (e.g. `https://pipefort.example.com`).
  This is your `APP_BASE_URL` env var.
* 5 minutes.

## 1. Pick where to register the App

| Owner                | Use when                         | URL                                                           |
| -------------------- | -------------------------------- | ------------------------------------------------------------- |
| **Personal account** | Solo, self-host, internal trials | `https://github.com/settings/apps/new`                        |
| **Organization**     | Team or company deployment       | `https://github.com/organizations/YOUR-ORG/settings/apps/new` |

Org-owned Apps survive maintainer departures and can be transferred between
orgs. Prefer org ownership for anything production-bound.

## 2. Register the App

Pipefort ships a manifest at [`deploy/github-app-manifest.json`](https://github.com/pipefort/pipefort/blob/main/deploy/github-app-manifest.json)
that fixes the name, description, and the exact read-only permission set. Use
it as the source of truth — either by pasting the values into the GitHub form,
or by submitting the manifest programmatically.

<Tabs>
  <Tab title="Manual (recommended)">
    Open the URL from step 1 and fill the form:

    | Field                                       | Value                                                                              |
    | ------------------------------------------- | ---------------------------------------------------------------------------------- |
    | **GitHub App name**                         | `Pipefort` (or `Pipefort — Acme` if the name is taken)                             |
    | **Homepage URL**                            | `https://pipefort.example.com`                                                     |
    | **Callback URL**                            | *(leave blank — Pipefort uses Supabase Auth, not GitHub OAuth, for sign-in)*       |
    | **Setup URL (post installation)**           | `https://pipefort.example.com/connect/callback`                                    |
    | **Redirect on update**                      | ✅ enabled                                                                          |
    | **Webhook → Active**                        | ❌ unchecked                                                                        |
    | **Where can this GitHub App be installed?** | **Any account** (required to publish; pick **Only on this account** while testing) |

    Then set the **Repository permissions** below (everything else stays `No access`):

    | Permission                 | Access             | Why                                                                                                                                                                                                                    |
    | -------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Metadata**               | Read-only          | Mandatory for every App.                                                                                                                                                                                               |
    | **Contents**               | Read **and write** | Read `.github/workflows/*.yml`. Write enables the **Open fix PR** button on workflow-rule findings (commits the rewritten YAML to a new branch).                                                                       |
    | **Workflows**              | Read **and write** | Also required by **Open fix PR**: GitHub blocks commits to `.github/workflows/*` unless the App holds this scope on top of `Contents` — without it the commit fails with `403 Resource not accessible by integration`. |
    | **Pull requests**          | Read **and write** | Required by the **Open fix PR** button to open and reuse the pull request.                                                                                                                                             |
    | **Administration**         | Read **and write** | Read branch protection (CICD-SEC-1 BP-\* rules). Write enables the Auto-fix button for branch protection, secret scanning, and Dependabot remediation.                                                                 |
    | **Actions**                | Read **and write** | Workflow permissions, allowed-actions policy (CICD-SEC-4, CICD-SEC-5). Write enables the Auto-fix button for WPERM-\* remediation.                                                                                     |
    | **Dependabot alerts**      | Read-only          | Detect alert state (CICD-SEC-3).                                                                                                                                                                                       |
    | **Secret scanning alerts** | Read-only          | Detect secret scanning + push protection (CICD-SEC-6).                                                                                                                                                                 |

    <Note>
      If you'd rather not grant write on any of these, set the corresponding row
      to Read-only. Scanning still works; the per-finding Auto-fix / Open fix PR
      buttons just stay hidden for any rule whose remediation needs the missing
      scope. See [GitHub App permissions](/concepts/github-app-permissions#opting-out-of-the-write-scopes).
    </Note>

    Click **Create GitHub App**.
  </Tab>

  <Tab title="Manifest flow (programmatic)">
    GitHub can register the App from a manifest in one round-trip. This is
    convenient but requires you to grab the credentials immediately after
    creation (the manifest exchange `code` expires in 1 hour).

    Save this HTML locally, replace `APP_BASE_URL`, and open it in a browser:

    ```html theme={null}
    <form action="https://github.com/settings/apps/new" method="post">
      <input type="hidden" name="manifest" value='{
        "name": "Pipefort",
        "url": "APP_BASE_URL",
        "redirect_url": "APP_BASE_URL/connect/callback",
        "setup_url": "APP_BASE_URL/connect/callback",
        "public": true,
        "default_permissions": {
          "metadata": "read",
          "contents": "write",
          "workflows": "write",
          "pull_requests": "write",
          "administration": "write",
          "actions": "write",
          "vulnerability_alerts": "read",
          "secret_scanning_alerts": "read"
        },
        "default_events": [],
        "hook_attributes": { "active": false }
      }' />
      <button type="submit">Create Pipefort GitHub App</button>
    </form>
    ```

    To register under an organization, change the form action to
    `https://github.com/organizations/YOUR-ORG/settings/apps/new`.

    After you approve in GitHub, the App appears in your settings. Continue
    with step 3 to collect credentials.
  </Tab>
</Tabs>

## 3. Collect credentials

On the new App's settings page, capture five values and stash them in your
deployment's secret manager:

| GitHub field                                                             | Env var                                                     |
| ------------------------------------------------------------------------ | ----------------------------------------------------------- |
| **App ID**                                                               | `GITHUB_APP_ID`                                             |
| **Client ID**                                                            | `GITHUB_APP_CLIENT_ID`                                      |
| **Client secrets → Generate a new client secret**                        | `GITHUB_APP_CLIENT_SECRET`                                  |
| **Private keys → Generate a private key**                                | `GITHUB_APP_PRIVATE_KEY` (the full PEM, newlines preserved) |
| **App's public slug** in the page URL — `https://github.com/apps/<slug>` | `VITE_GITHUB_APP_SLUG` (frontend build env)                 |

<Warning>
  The private key is downloaded once. If you lose it, generate a new one and
  rotate `GITHUB_APP_PRIVATE_KEY` — GitHub keeps both valid until you delete the
  old one.
</Warning>

Apply the env vars and redeploy:

```bash theme={null}
# API (Go)
export GITHUB_APP_ID=123456
export GITHUB_APP_PRIVATE_KEY="$(cat pipefort.YYYY-MM-DD.private-key.pem)"
export GITHUB_APP_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx
export GITHUB_APP_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export APP_BASE_URL=https://pipefort.example.com

# Web (Vite — set at build time)
export VITE_GITHUB_APP_SLUG=pipefort
```

The Go API tolerates these being unset at boot (`HasGitHubApp` is checked per
request), so you can deploy first and add the secrets second.

<Warning>
  The Go API must also have **`SUPABASE_URL`** set to your Supabase project URL
  (e.g. `https://xxxx.supabase.co`). Current Supabase projects sign user tokens
  with an asymmetric ES256 key, which the API verifies via that project's JWKS
  endpoint — without the URL it can't fetch the keys and **every** authenticated
  request fails with `401 invalid token` (the dashboard appears not to detect your
  installation, and `/connect/callback` shows "Connection failed"). The frontend
  `VITE_SUPABASE_URL` is a separate build-time var; if only it is set, the API
  falls back to it, but setting `SUPABASE_URL` explicitly on the API is the
  canonical configuration. (`SUPABASE_PUBLIC_URL`, which the local Supabase CLI
  exports, also works.)
</Warning>

## 4. Publish the App

If you want anyone — not just your account — to install it:

1. Open the App's settings → **Public page** tab.
2. Fill in **Description**, **Avatar**, and **Public link**.
3. Toggle **Make public**. GitHub validates the App is installable on any
   account before allowing this.

The public install URL becomes `https://github.com/apps/<your-slug>`. This is
the link the [`/connect`](/webapp/github-setup) page sends users to.

## 5. Verify

1. Sign in to your Pipefort deployment with GitHub.
2. The dashboard renders with an **Install the Pipefort GitHub App** banner.
3. Click it → install the App on a repo → GitHub redirects to `/connect/callback`.
4. The dashboard reloads with the connected installation and the scan controls
   become available.

If the redirect lands on a 404, the **Setup URL** in step 2 is wrong — fix it
in the App's settings and reinstall.

## Maintenance

When Pipefort adds a new permission (e.g. a new scanner rule requires a new
read scope), update the manifest in your deployment to match
[`deploy/github-app-manifest.json`](https://github.com/pipefort/pipefort/blob/main/deploy/github-app-manifest.json),
then update the App's permissions in GitHub. Existing installations must
re-authorize — see
[GitHub App permissions → Re-authorizing](/concepts/github-app-permissions#re-authorizing-after-pipefort-expands-its-permission-set).
