Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 66 additions & 6 deletions .github/workflows/generate-index.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Generate Protocol Index

on:
# Tracking the generator at @main means the next run uses it — but a generator change upstream
# raises no event here, so nothing regenerates until a local change does. Run this by hand after a
# generator change that alters the output.
workflow_dispatch:
push:
branches: [main]
# The index is a function of the protocols *and* of the generator version pinned below, so a
Expand All @@ -9,16 +13,72 @@ on:
- 'protocols/**'
- '.github/workflows/generate-index.yml'

# The push uses the App installation token, not GITHUB_TOKEN, so GITHUB_TOKEN needs no write
# access. Granting it would hand every step a second write-capable credential for nothing.
permissions:
contents: write
contents: read

# Two merges in quick succession would otherwise run concurrently, and the second push would be
# rejected as non-fast-forward: its checkout predates the first run's index commit. Queue instead of
# cancelling — a cancelled run leaves the index describing the previous commit.
concurrency:
group: generate-index
cancel-in-progress: false

jobs:
generate-index:
runs-on: ubuntu-latest
# The App credentials live in this environment, whose deployment branch policy allows only
# `main`. A pull request from a branch in this repository could otherwise read them — same-repo
# PRs do receive secrets — and they mint a token that bypasses branch protection.
environment: index-generation
steps:
# The require-pr-review ruleset blocks github-actions[bot], and GitHub Actions itself cannot be
# granted a bypass: bypass actors of type Integration must be GitHub Apps installed on the
# organisation, and Actions is not one. A purpose-built App is — this one holds `contents:
# write` and nothing else, and its token expires after an hour.
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.INDEX_APP_ID }}
private-key: ${{ secrets.INDEX_APP_PRIVATE_KEY }}
# Request the scope explicitly rather than inheriting whatever the installation holds, so
# granting the App another permission later cannot silently widen this token.
permission-contents: write

- uses: actions/checkout@v4
# @v0 is a moving tag, so this repository tracks the standard without a PR per release —
# which is the point: an index generated by a stale generator is an index that disagrees with
# the standard it claims to follow. Pin @v0.3.0 or a commit SHA instead if you need the action
# to be immutable, and accept updating it by hand.
- uses: waldronlab/agent-protocol-standard/actions/generate-index@v0
with:
token: ${{ steps.app-token.outputs.token }}
Comment thread
Copilot marked this conversation as resolved.
# The branch tip, not the event SHA. Serialising runs is not enough on its own: a queued
# run would still check out the commit that triggered it and push a non-fast-forward once
# `main` had moved. It also means the index describes `main` as it is, not as it was.
ref: main
Comment on lines +52 to +55
# The email prefix below is the bot's user id, which is NOT the App registration id held in
# INDEX_APP_ID. Getting it wrong still pushes, but GitHub does not link the commit to the bot.
- name: Resolve the App's bot user id
id: bot
env:
GH_TOKEN: ${{ github.token }}
SLUG: ${{ steps.app-token.outputs.app-slug }}
run: |
# Assigned separately, not interpolated into echo: `echo "id=$(gh api ...)"` exits 0 even
# when the lookup fails, writing an empty id, and attribution is then silently wrong.
set -euo pipefail
id="$(gh api "/users/${SLUG}[bot]" --jq .id)"
[ -n "$id" ] || { echo "::error::could not resolve the bot user id for ${SLUG}[bot]"; exit 1; }
echo "id=$id" >> "$GITHUB_OUTPUT"

# @main, not a release tag. @v0 resolved to a commit from before the Python rewrite, so this
# workflow was silently running the old R generator while CI stayed green. A generator that
# has fallen behind produces an index that disagrees with the standard it claims to follow.
- uses: waldronlab/agent-protocol-standard/actions/generate-index@main
with:
# The checkout above is pinned to `main`, so the generator must build `protocol_url`
# values from `main` too, or a workflow_dispatch from another branch would index main's
# content under that ref's URLs. Passed as an input because GITHUB_REF_NAME is
# runner-provided and a workflow cannot reliably override it.
ref: main
# Attribute the commit to the App that pushes it, rather than to github-actions[bot],
# which no longer has anything to do with this push.
committer-name: ${{ steps.app-token.outputs.app-slug }}[bot]
committer-email: ${{ steps.bot.outputs.id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com
4 changes: 3 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: waldronlab/agent-protocol-standard/actions/validate-protocols@v0
# @main, not a release tag. @v0 predated the Python rewrite, so every pull request here was
# being checked by the old R validator — the Pydantic rules were enforcing nothing, silently.
- uses: waldronlab/agent-protocol-standard/actions/validate-protocols@main
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ End the file with a `## History & Reviews` section as demonstrated in the templa
## Step 4: Validate and Submit
Open a pull request. **You can rely on CI for validation.** The repository's automated testing infrastructure will check your syntax and tell you precisely what is wrong. Focus on getting the scientific correctness right.

*(To run the validator locally before pushing, clone `waldronlab/agent-protocol-standard` beside this repository and, from here, run `Rscript ../agent-protocol-standard/scripts/validate-protocol.R protocols`. It takes the protocols directory, not a single file, and validates every protocol in it.)*
*(To run the validator locally before pushing, clone `waldronlab/agent-protocol-standard` beside this repository, install its dependencies with `pip install 'pydantic>=2.0.0' pyyaml`, and from here run `python3 ../agent-protocol-standard/scripts/validate_protocol.py protocols`. It takes the protocols directory, not a single file, and validates every protocol in it.)*

---

Expand Down
Loading