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. For the workflow catalog see workflows.md.
Repository secrets MUST be set under Settings β Secrets and variables β Actions β Secrets.
Secrets πΒΆ
Secret |
Workflow |
Purpose |
Required when |
|---|---|---|---|
|
GitHub App Client ID (OAuth-style |
|
|
|
PEM-encoded private key of the same GitHub App. Used to sign the JWT that exchanges for the installation token. |
|
|
|
Publishes the |
Never. Unset leaves the route unpublished. |
|
|
Publishes the |
Never. |
|
|
Publishes |
Never. |
|
|
Authenticates the mirror job against Docker Hub, which raises the anonymous pull-rate limit the mirror would otherwise hit. |
Never. Both workflows declare the secret |
|
|
The access token paired with |
Never, and only together with the username. |
API_OPENAI_KEY, API_ANTHROPIC_KEY, API_OPENROUTER_KEY π€ΒΆ
These are optional and fail soft: unset means the providerβs route is never
published, and the deployment falls back to whatever local backend the round
deploys. The workflow reads each as ${{ secrets.X || vars.X }}, so the same
name works as a repository variable; see
configuration.md for why
the secret is the better half of that pair.
Set them the same way as the App credentials: Settings β Secrets and variables β Actions β Secrets β New repository secret, one per provider, the value being the providerβs key verbatim.
The shape each key must have is declared per role rather than here, in
roles/svc-ai-litellm/meta/secrets.yml
with a type: and a regex:. The pattern rejects a truncated or
whitespace-carrying paste and deliberately accepts any vendor prefix, so a
provider changing its issuance format cannot turn a valid key into a failed
inventory run.
BOT_APP_CLIENT_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 cron-update.yml opens an update PR with GITHUB_TOKEN, the pull_request and pull_request_target events that drive entry-pr-change-orchestrate.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 π οΈΒΆ
Create a new GitHub App under Organization settings β Developer settings β GitHub Apps β New GitHub App.
Disable the webhook (uncheck Active under Webhook). The App MUST NOT receive events.
Grant the following repository permissions and nothing else:
Contents: Read and write (the update script force-pushes toupdate/*branches).Pull requests: Read and write (gh pr create/gh pr edit).Metadata: Read (default, cannot be removed).
Restrict installation to the owning account only.
Generate a private key and download the PEM file.
Install the App on the
corerepository only. The App MUST NOT be installed on unrelated repositories.
How to hand the credentials to CI π₯ΒΆ
Open the repository on GitHub.
Go to Settings β Secrets and variables β Actions.
Stay on the Secrets tab.
Click New repository secret and add
BOT_APP_CLIENT_IDwith the Appβs Client ID (shown on the Appβs General page under About, in theIvβ¦format β not the numeric App ID).Click New repository secret and add
BOT_APP_PRIVATE_KEYwith 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 cron-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 πͺͺΒΆ
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 |
|
|
|
Skipped. Its implicit |
|
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.