Files
computer-playbook/docs/contributing/tools/github/actions/secrets.md
T
kevinveenbirkenbachandClaude Opus 4.7 f9147e4486 refactor(scripts/github): split helpers into responsibility subfolders
Group the shell helpers under scripts/github/ into five subfolders
that match how the workflow files consume them:

  runner/   host-runner hygiene (disk, swap, Docker daemon, diagnostics)
  cancel/   run cancellation on PR-close and branch-delete events
  resolve/  derivation of workflow inputs and outputs from repo state
  update/   scheduled Update: Versions pipeline
  release/  release-time gates

Drop the now-redundant subfolder prefix from each filename, e.g.
dump_runner_state.sh becomes dump_state.sh and cancel_pull_request_runs.sh
becomes pull_request_runs.sh. Each subfolder carries a README that
describes its scope per documentation.md rules; the top-level README
points at the subfolders without inventorying files.

Propagate the new paths through ten workflow files, three docs
(workflow.md, pipeline.md, secrets.md), and two tests. Fix a real
runtime bug in enlarge_swap.sh, which still referenced the
pre-rename dump_runner_state.sh path. Extend the inline-block-size
lint hint to describe the new subfolder convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:50:26 +02:00

79 lines
5.8 KiB
Markdown

# CI Secrets 🔐
This page lists every repository secret that GitHub Actions workflows in this repository consume, and documents the failure mode when a secret is missing. For repository **variables** see [configuration.md](configuration.md). For the workflow catalog see [workflows.md](workflows.md).
Repository secrets MUST be set under **Settings → Secrets and variables → Actions → Secrets**.
## Secrets 📋
| Secret | Workflow | Purpose | Required when |
|---|---|---|---|
| `BOT_APP_ID` | [update.yml](../../../../../.github/workflows/update.yml) | GitHub App ID used to mint a short-lived installation token for the update PR. | `CI_ENABLE_AUTO_UPDATES == 'true'` |
| `BOT_APP_PRIVATE_KEY` | [update.yml](../../../../../.github/workflows/update.yml) | PEM-encoded private key of the same GitHub App. Used to sign the JWT that exchanges for the installation token. | `CI_ENABLE_AUTO_UPDATES == 'true'` |
## `BOT_APP_ID` and `BOT_APP_PRIVATE_KEY` 🤖
### Why these secrets exist 🎯
Actions performed with the workflow-provided `GITHUB_TOKEN` do not start further workflow runs. When [update.yml](../../../../../.github/workflows/update.yml) opens an update PR with `GITHUB_TOKEN`, the `pull_request` and `pull_request_target` events that drive [entry-pull-request-change.yml](../../../../../.github/workflows/entry-pull-request-change.yml) do not fire on that PR, so the CI orchestrator never runs against it.
Opening the PR through a GitHub App installation token bypasses this restriction. The App counts as a distinct actor, so PR-lifecycle events fire normally and the full CI pipeline runs against every update PR.
### Why a GitHub App and not a PAT 🏷️
A GitHub App installation token SHOULD be used because:
- The token lifetime is bounded to one hour, and a new token is minted on every workflow run.
- Permissions are scoped at the App installation level, independent of any user account.
- No personal account footprint appears in audit logs.
A classic personal access token MAY be used as a fallback for unrelated automation, but it MUST NOT be used here because user-bound credentials expand the blast radius and require manual rotation.
### How to generate the App 🛠️
1. Create a new GitHub App under **Organization settings → Developer settings → GitHub Apps → New GitHub App**.
2. Disable the webhook (uncheck **Active** under **Webhook**). The App MUST NOT receive events.
3. Grant the following repository permissions and nothing else:
- `Contents`: **Read and write** (the update script force-pushes to `update/*` branches).
- `Pull requests`: **Read and write** (`gh pr create` / `gh pr edit`).
- `Metadata`: **Read** (default, cannot be removed).
4. Restrict installation to the owning account only.
5. Generate a private key and download the PEM file.
6. Install the App on the `core` repository only. The App MUST NOT be installed on unrelated repositories.
### How to hand the credentials to CI 📥
1. Open the repository on GitHub.
2. Go to **Settings → Secrets and variables → Actions**.
3. Stay on the **Secrets** tab.
4. Click **New repository secret** and add `BOT_APP_ID` with the numeric App ID.
5. Click **New repository secret** and add `BOT_APP_PRIVATE_KEY` with the complete PEM content, including the `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` lines.
### How the workflow consumes the secrets ⚙️
Each PR-opening job in [update.yml](../../../../../.github/workflows/update.yml) runs an `actions/create-github-app-token@v2` step gated on `steps.diff.outputs.changed == 'true'`, then forwards the minted token as `GH_TOKEN` and the resolved `APP_SLUG` to the subsequent PR step. The job's `permissions:` block keeps the workflow-provided `GITHUB_TOKEN` read-only; write access is provided exclusively by the App token, scoped to the App's repository permissions.
### Commit identity propagation 🪪
[open_pr.sh](../../../../../scripts/github/update/open_pr.sh) reads `APP_SLUG` from the environment and resolves the App's bot user via `gh api /users/<slug>[bot]`. The resolved login and numeric user ID are written into `git config user.name` and `git config user.email` in the `<id>+<slug>[bot]@users.noreply.github.com` form that GitHub accepts for verified commits. When `APP_SLUG` is unset, the script falls back to the `github-actions[bot]` identity. That branch is reached only when the script is invoked outside the workflow, for example a local smoke test where the caller has set `GH_TOKEN` to something other than an App token.
### Failure mode when secrets are missing 💥
A missing secret resolves to an empty string in workflow expressions. The workflow run starts and proceeds normally until the token-minting step:
| Stage | Behaviour when both secrets are missing |
|---|---|
| Workflow parse | Run starts. GitHub emits the warning `The following secrets are referenced but not defined: BOT_APP_ID, BOT_APP_PRIVATE_KEY`. |
| `Generate app token` step | `actions/create-github-app-token` declares both inputs as required and fails with `Error: Input required and not supplied: app-id`. |
| `Open PR if … changed` step | Skipped. Its implicit `if:` condition is `success() && (steps.diff.outputs.changed == 'true')`, and `success()` is false after the token step failed. |
| `open_pr.sh` | Not executed. No commit, no push, no PR. |
| Outcome | The run is marked failed. GitHub notifies repository admins. No PR is created with a wrong identity. |
The behaviour is fail-loud by design. Missing or mistyped secret names MUST surface as a failed workflow run rather than as a PR with an unintended author.
## Related 🔗
- [configuration.md](configuration.md): repository variables that gate the same workflows.
- [workflows.md](workflows.md): full workflow catalog.
- [pipeline.md](../../../artefact/git/pipeline.md): how the orchestrator routes PR runs.