From a45cff4030f1f5208c32bfbb5d52870481973846 Mon Sep 17 00:00:00 2001 From: "Marcus R. Brown" Date: Sun, 31 May 2026 02:12:20 -0700 Subject: [PATCH 1/2] docs(github-app): add public docs, setup runbook, and app logo Document the Fro Bot Agent GitHub App identity for issue #703: a public-facing page (what it does, contents:read permission, privacy posture, install/uninstall) and an operator runbook (registration, ownership, credential wiring). Add a flat geometric app logo (SVG + 512px PNG) derived from the Fro Bot head mark. Refs #703 --- assets/github-app-logo-512.png | Bin 0 -> 28488 bytes assets/github-app-logo-alt.svg | 37 ++++++++++++++++++++++ assets/github-app-logo.svg | 29 +++++++++++++++++ docs/github-app-setup.md | 47 +++++++++++++++++++++++++++ docs/github-app.md | 56 +++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 assets/github-app-logo-512.png create mode 100644 assets/github-app-logo-alt.svg create mode 100644 assets/github-app-logo.svg create mode 100644 docs/github-app-setup.md create mode 100644 docs/github-app.md diff --git a/assets/github-app-logo-512.png b/assets/github-app-logo-512.png new file mode 100644 index 0000000000000000000000000000000000000000..e54577ed8b2da5092a96b4f6aac143511d4ac1e3 GIT binary patch literal 28488 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 l + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/github-app-logo.svg b/assets/github-app-logo.svg new file mode 100644 index 00000000..d553eac1 --- /dev/null +++ b/assets/github-app-logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/github-app-setup.md b/docs/github-app-setup.md new file mode 100644 index 00000000..45acf568 --- /dev/null +++ b/docs/github-app-setup.md @@ -0,0 +1,47 @@ +# Fro Bot Agent — GitHub App Setup & Ownership Runbook + +This runbook records how the **Fro Bot Agent** GitHub App is registered and owned, and how an operator wires its credentials into their own gateway. For the public, user-facing description of the app, see [github-app.md](./github-app.md). + +> **Note on management:** GitHub does not reconcile App settings from a file in this repository — there is no GitOps for App configuration. This runbook is the source of truth for the App's intended configuration and for recreating it if needed. + +## Canonical app + +| Field | Value | +| ------------------ | ------------------------------------------------------- | +| Name | Fro Bot Agent | +| Owner | the `fro-bot` GitHub account | +| Public page / slug | https://github.com/apps/fro-bot-agent (`fro-bot-agent`) | +| Permission | `contents: read` only | +| Webhook | none | +| Visibility | Public (any account can install) | + +The gateway's default install URL points at this slug (`packages/gateway/src/config.ts`). Operators pointing at a different app override it with `GATEWAY_GITHUB_APP_INSTALL_URL`. + +## Registering the app (one-time, GitHub UI) + +App registration is a manual action in the GitHub UI; it cannot be automated from this repo. The canonical app above is already registered under the `fro-bot` account. These steps are for recreating it or registering a separate app under another account. + +1. Go to **GitHub → Settings → Developer settings → GitHub Apps → New GitHub App** (for the account that should own it). +2. **Name:** `Fro Bot Agent` (or your own name if registering a separate app). +3. **Homepage URL:** the gateway repo or your deployment docs. +4. **Webhook:** uncheck **Active** — the app needs no webhook. +5. **Permissions → Repository → Contents:** **Read-only**. Add nothing else. +6. **Where can this app be installed:** **Any account** (public) for the canonical app, or **Only on this account** for a private operator app. +7. **Create GitHub App.** Note the **App ID** on the settings page. +8. **Private keys → Generate a private key.** Save the downloaded `.pem` — this is the only copy. +9. (Optional) Upload the avatar from `assets/github-app-logo-512.png`. + +## Where credentials live + +Credentials belong to the **operator's own gateway deployment** — never committed to this repository. + +| Credential | Gateway env var | Compose secret file | +| ----------------- | ------------------------ | --------------------------------------- | +| App ID | `GITHUB_APP_ID` | `deploy/secrets/github-app-id` | +| Private key (PEM) | `GITHUB_APP_PRIVATE_KEY` | `deploy/secrets/github-app-private-key` | + +The compose stack reads these via the `*_FILE` convention (`GITHUB_APP_ID_FILE`, `GITHUB_APP_PRIVATE_KEY_FILE`). See the **GitHub App** section of [`deploy/README.md`](../deploy/README.md) for the full secret-wiring walkthrough and upgrade notes. + +## Installing on repositories + +Install the app on only the repositories Fro Bot should read (least privilege), then add them from Discord with `/fro-bot add-project `. See [github-app.md](./github-app.md) for install/uninstall details. diff --git a/docs/github-app.md b/docs/github-app.md new file mode 100644 index 00000000..78c40532 --- /dev/null +++ b/docs/github-app.md @@ -0,0 +1,56 @@ +# Fro Bot Agent — GitHub App + +**Fro Bot Agent** is the GitHub App that lets a self-hosted [Fro Bot](https://github.com/fro-bot/agent) Discord gateway read a repository you choose, so you can drive Fro Bot against it from Discord. + +- **App:** https://github.com/apps/fro-bot-agent +- **Owner:** the `fro-bot` GitHub account +- **Permission:** `contents: read` — read-only access to repository contents. Nothing else. +- **Webhook:** none. The app receives no events from GitHub. + +## What it does + +When you run `/fro-bot add-project ` in a Discord server running a Fro Bot gateway, the gateway uses this app's installation to clone and read the repository you named. The read-only `contents` permission is the entire access surface — the app cannot write to your code, open pull requests, change settings, or read anything beyond repository contents. + +## Permissions + +| Permission | Access | Why | +| ------------------- | -------- | ---------------------------------------------------------------------- | +| Repository contents | **Read** | Clone and read the repo you explicitly add via `/fro-bot add-project`. | + +That is the complete list. The app requests no write scopes, no metadata beyond what `contents: read` implies, and no organization or account permissions. + +## Privacy + +The app is **inert unless you pair it with a Fro Bot gateway in your own Discord server**. Installing it grants read access; nothing happens until a gateway you control uses that access in response to a command you run. + +- This repository collects no data and operates no hosted service. There is no telemetry. +- All credentials and runtime live in **your** gateway deployment, not here. +- The app has no webhook, so GitHub sends it no events and it stores nothing on GitHub's side. + +## Install + +1. Open https://github.com/apps/fro-bot-agent and click **Install** (or **Configure**). +2. Choose the account or organization that owns the repositories you want Fro Bot to read. +3. Select **Only select repositories** and pick the repos you intend to add — least privilege. (You can add more later.) + +You only need to install on repositories you plan to use with `/fro-bot add-project`. + +## Uninstall + +Remove access at any time: + +1. Go to **Settings → Applications → Installed GitHub Apps** (for your account) or your org's **Settings → GitHub Apps**. +2. Find **Fro Bot Agent** and click **Configure**. +3. Remove individual repositories, or scroll to **Uninstall** to revoke all access. + +Uninstalling immediately revokes the gateway's ability to read your repositories. + +## Running your own gateway + +This app is only useful alongside a self-hosted gateway. To register your own app and wire credentials, see the [setup runbook](./github-app-setup.md). + +## Listing copy + +> **Tagline:** Read-only repo access for your self-hosted Fro Bot Discord gateway. +> +> **Description (~150 chars):** Grants a self-hosted Fro Bot Discord gateway read-only access to repositories you choose. Read-only, no webhook, inert until you use it. From db6f2d655e1948a53bc33fc0cb4ae3700cb66618 Mon Sep 17 00:00:00 2001 From: "Marcus R. Brown" Date: Sun, 31 May 2026 02:25:13 -0700 Subject: [PATCH 2/2] docs(github-app): label the App Description field copy explicitly --- docs/github-app.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/github-app.md b/docs/github-app.md index 78c40532..3d86ea7c 100644 --- a/docs/github-app.md +++ b/docs/github-app.md @@ -49,8 +49,30 @@ Uninstalling immediately revokes the gateway's ability to read your repositories This app is only useful alongside a self-hosted gateway. To register your own app and wire credentials, see the [setup runbook](./github-app-setup.md). -## Listing copy +## GitHub App settings copy -> **Tagline:** Read-only repo access for your self-hosted Fro Bot Discord gateway. -> -> **Description (~150 chars):** Grants a self-hosted Fro Bot Discord gateway read-only access to repositories you choose. Read-only, no webhook, inert until you use it. +These values go in the App's **Basic Information** settings page (`fro-bot` account → Settings → Developer settings → GitHub Apps → Fro Bot Agent). + +### Description (paste into "Basic Information → Description") + +This field is displayed to users on the App's public page and renders markdown: + +```markdown +**Fro Bot Agent** gives a self-hosted [Fro Bot](https://github.com/fro-bot/agent) Discord gateway read-only access to repositories you choose, so you can drive Fro Bot against them from Discord. + +**Permission:** `contents: read` only — it can clone and read the repos you add, nothing else. No write access, no webhook. + +**Privacy:** inert until you pair it with a Fro Bot gateway in your own Discord server. No data is collected and no hosted service runs on your behalf; all credentials live in your own deployment. + +Add a repo from Discord with `/fro-bot add-project `. +``` + +### Adjacent fields + +- **Homepage URL:** `https://github.com/fro-bot/agent` +- **Webhook → Active:** unchecked (the app needs no webhook) +- **Badge background color:** `0D0216` (the Void brand color — frames the cyan token on near-black) + +### Short blurb (for any one-line listing) + +> Read-only repo access for your self-hosted Fro Bot Discord gateway — no webhook, inert until you use it.