This document is the source of truth for every CI credential and branch- protection setting the submission pipeline depends on. It is written so that, on a fresh clone or a brand-new repo, you can reconstruct the entire CI auth posture from this file alone — no UI screenshots, no tribal knowledge.
The benchmark repository leanprover/lean-eval has its own
docs/ci-secrets.md covering its lean-eval-regenerator App; that one
is unrelated to this pipeline.
| Item | Type | Stored as | Used by |
|---|---|---|---|
lean-eval-bot |
GitHub App | LEAN_EVAL_BOT_APP_ID, LEAN_EVAL_BOT_PRIVATE_KEY |
submission.yml (fetch) |
lean-eval-recorder |
GitHub App | LEAN_EVAL_RECORDER_APP_ID, LEAN_EVAL_RECORDER_PRIVATE_KEY |
submission.yml (record) |
lean-eval-archiver |
GitHub App | LEAN_EVAL_ARCHIVER_APP_ID, LEAN_EVAL_ARCHIVER_PRIVATE_KEY |
submission.yml (archive) |
LEADERBOARD_WRITE_TOKEN |
Fine-grained PAT | LEADERBOARD_WRITE_TOKEN |
submission.yml (leaderboard redeploy dispatch) |
Ruleset main protection |
Repository Ruleset | (config in this file, applied via API) | branch protection on main |
To check the live state at any time:
gh secret list -R leanprover/lean-eval-submissions
gh api /repos/leanprover/lean-eval-submissions/rules/branches/main --jq '[.[].type]'Used by .github/workflows/submission.yml
to mint installation tokens that fetch submission source from contributor
repositories (which may be private).
- Owner account:
kim-em(User account). - Webhook: deactivated.
- Repository permissions:
Contents: Read
- Where can this GitHub App be installed: Any account. Contributors install it on their own submission repos so the workflow can clone them.
LEAN_EVAL_BOT_APP_ID— the App ID number.LEAN_EVAL_BOT_PRIVATE_KEY— the full PEM contents of a private key generated for the app.
.github/workflows/submission.yml,
in the Mint lean-eval-bot installation token step, via
actions/create-github-app-token. The minted token is scoped to the
single Fetch submission step and is used to clone the contributor's
submission source.
The issue template
.github/ISSUE_TEMPLATE/submit.yml
instructs contributors to install this app on their submission repo.
This is the same App that previously served leanprover/lean-eval's
submission workflow. The migration step is to install it on
leanprover/lean-eval-submissions and copy its secrets here. A
from-scratch rebuild:
- As the desired app owner, visit https://github.com/settings/apps/new.
- Fill in:
- Name:
lean-eval-bot - Homepage URL:
https://github.com/leanprover/lean-eval-submissions - Webhook → Active: unchecked
- Repository permissions → Contents: Read
- Where can this GitHub App be installed: Any account
- Name:
- Save → record the App ID.
- Generate a private key, download the
.pem. - Install the app on
leanprover/lean-eval-submissions(so the workflow has an installation to mint tokens against). - Set the secrets:
gh secret set LEAN_EVAL_BOT_APP_ID -R leanprover/lean-eval-submissions --body <APP_ID> gh secret set LEAN_EVAL_BOT_PRIVATE_KEY -R leanprover/lean-eval-submissions < path/to/key.pem
Used by .github/workflows/submission.yml
to push the record: commit (a results-store update) directly to this
repo's main, bypassing branch protection.
- Owner account:
kim-em(User account). - Webhook: deactivated.
- Repository permissions:
Contents: Read and write
- Where can this GitHub App be installed: Any account. (Required so
the org can install it; the only intended installation is on
leanprover/lean-eval-submissionsitself.) - Installed on:
leanprover/lean-eval-submissionsonly (single-repo installation).
This is a distinct App from lean-eval-bot, on purpose:
lean-eval-bot is installed on arbitrary contributor repositories, so it
must stay Contents: Read only. A write-capable App must never be
installable on third-party repos.
LEAN_EVAL_RECORDER_APP_ID— the App ID number.LEAN_EVAL_RECORDER_PRIVATE_KEY— the full PEM contents of a private key generated for the app.
.github/workflows/submission.yml,
in the Mint lean-eval-recorder installation token step. The token
authenticates the results-store/ checkout so the push-retry loop's
git push origin HEAD:main lands on protected main.
GITHUB_TOKEN-authored pushes cannot bypass branch protection (no actor
can put github-actions[bot] itself in the bypass list at workflow
granularity). A dedicated app's principal can be in the bypass list (see
the Ruleset section below); the bypass is then narrow because only this
workflow has the app's secrets.
- As the desired app owner, visit https://github.com/settings/apps/new.
- Fill in:
- Name:
lean-eval-recorder - Homepage URL:
https://github.com/leanprover/lean-eval-submissions - Webhook → Active: unchecked
- Repository permissions → Contents: Read and write (everything else stays "No access")
- Where can this GitHub App be installed: Any account
- Name:
- Save → record the App ID.
- Generate a private key, download the
.pem. - Install the app on
leanprover/lean-eval-submissionsonly. - Set the secrets:
gh secret set LEAN_EVAL_RECORDER_APP_ID -R leanprover/lean-eval-submissions --body <APP_ID> gh secret set LEAN_EVAL_RECORDER_PRIVATE_KEY -R leanprover/lean-eval-submissions < path/to/key.pem
- Add the App ID to the
mainruleset's bypass list (see Ruleset section below).
Used by .github/workflows/submission.yml
to push age-encrypted submission tarballs and unencrypted metadata
sidecars to leanprover/lean-eval-audit.
See docs/audit-archive.md for the design.
- Owner account:
kim-em(User account). - Webhook: deactivated.
- Repository permissions:
Contents: Read and write
- Where can this GitHub App be installed: Only on this account.
- Installed on:
leanprover/lean-eval-auditonly (single-repo installation, scoped viarepositories: lean-eval-auditin the workflow'sactions/create-github-app-tokenstep).
This is a distinct App from lean-eval-bot and lean-eval-recorder,
on purpose:
lean-eval-botis installed on arbitrary contributor repositories so it must stayContents: Readonly — bumping it to write would silently expand the trust boundary for every submitter who installed it.lean-eval-recorderwrites the leaderboard results store, a public repo; the audit archive is a private repo with a different access policy. Keeping the apps separate means an audit-archive compromise cannot also rewrite the leaderboard, and vice versa.
LEAN_EVAL_ARCHIVER_APP_ID— the App ID number.LEAN_EVAL_ARCHIVER_PRIVATE_KEY— the full PEM contents of a private key generated for the app.
.github/workflows/submission.yml,
in the Mint lean-eval-archiver installation token step of the
archive job. The minted token authenticates the
scripts/archive_submission.py push invocation, which writes one
ciphertext file and one sidecar JSON to lean-eval-audit via the
GitHub Contents API.
The archive job runs on a separate runner from the one that elaborates
untrusted Lean (the evaluate job), so the write-capable installation
token is never co-resident with an attacker-influenced process. See
docs/audit-archive.md > "Threat model".
- As the desired app owner, visit https://github.com/settings/apps/new.
- Fill in:
- Name:
lean-eval-archiver - Homepage URL:
https://github.com/leanprover/lean-eval-audit - Webhook → Active: unchecked
- Repository permissions → Contents: Read and write (everything else stays "No access")
- Where can this GitHub App be installed: Only on this account
- Name:
- Save → record the App ID.
- Generate a private key, download the
.pem. - Install the app on
leanprover/lean-eval-auditonly. - Set the secrets:
gh secret set LEAN_EVAL_ARCHIVER_APP_ID -R leanprover/lean-eval-submissions < <(printf '%s' "<APP_ID>") gh secret set LEAN_EVAL_ARCHIVER_PRIVATE_KEY -R leanprover/lean-eval-submissions < path/to/key.pem
Fine-grained Personal Access Token used by
.github/workflows/submission.yml
to fire a repository_dispatch (event_type: results-advanced) at
https://github.com/leanprover/lean-eval-leaderboard after a result is
recorded, so the leaderboard site redeploys with the new result.
This is the same PAT leanprover/lean-eval and leanprover/lean-eval-leaderboard
already use for their leaderboard interactions; the submission pipeline
just needs its own copy of the secret.
LEADERBOARD_WRITE_TOKENinleanprover/lean-eval-submissions.
The token must be a fine-grained PAT with
leanprover/lean-eval-leaderboard selected and Contents: Read and write — that permission is what the repository_dispatch REST endpoint
authorizes on (per
https://docs.github.com/en/rest/repos/repos#create-a-repository-dispatch-event).
- Open https://github.com/settings/personal-access-tokens/new.
- Resource owner: leanprover (requires org-owner approval).
- Repository access: Only select repositories →
leanprover/lean-eval-leaderboard. - Repository permissions: Contents: Read and write.
- Save the token, then write it to this repo:
gh secret set LEADERBOARD_WRITE_TOKEN -R leanprover/lean-eval-submissions --body <TOKEN>
When rotating the PAT, update the copies in leanprover/lean-eval and
leanprover/lean-eval-leaderboard together (see those repos' own docs).
main is protected by a Repository Ruleset. The lean-eval-recorder app
is on the bypass list so the record job can push results directly;
everyone and everything else goes through a PR with a passing verify
check.
gh api /repos/leanprover/lean-eval-submissions/rulesets \
--jq '.[] | {id, name, target, enforcement}'
gh api "/repos/leanprover/lean-eval-submissions/rulesets/<ID>" \
--jq '{name, bypass_actors}'The <RECORDER_APP_ID> placeholder is the lean-eval-recorder App ID.
integration_id: 15368 pins the verify status check to the GitHub
Actions app, so a hostile third-party app can't satisfy it with a bogus
check of the same name.
{
"name": "main protection",
"target": "branch",
"enforcement": "active",
"conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } },
"rules": [
{ "type": "deletion" },
{ "type": "non_fast_forward" },
{ "type": "pull_request",
"parameters": {
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": false,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": false } },
{ "type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": false,
"required_status_checks": [ { "context": "verify", "integration_id": 15368 } ] } }
],
"bypass_actors": [
{ "actor_id": <RECORDER_APP_ID>, "actor_type": "Integration", "bypass_mode": "always" }
]
}- Make sure the
lean-eval-recorderapp exists, is installed on the repo, and you know its App ID. - Save the payload above to
/tmp/main-ruleset.json, substituting the App ID. - Apply:
gh api -X POST /repos/leanprover/lean-eval-submissions/rulesets \ --input /tmp/main-ruleset.json
- The
recordjob's results push tomaindoes not need to re-trigger any workflow: the leaderboard redeploy is driven by an explicitresults-advancedrepository_dispatch, andci.ymlrunning (or not) on a machine-authored results commit changes nothing —results/*.jsonis not exercised byci.yml. - Anyone who can land a PR that modifies
submission.ymlto push arbitrary content tomaincould, after merge, exfiltrate that capability. This is the same trust boundary as merging any PR.