Add daily OpenAPI PR reviewer agentic workflow#6742
Conversation
Adds a gh-aw (GitHub Agentic Workflow) that runs the openapi-pr-reviewer logic daily: reviews the latest "Update OpenAPI 3.0/3.1 Descriptions" PRs, merges them and closes older superseded PRs when there are no breaking changes, and notifies #api-platform on Slack. Ships in staged (dry-run) mode until secrets and branch-protection bypass are provisioned. Tracked in github/api-platform#3408. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new scheduled gh-aw (GitHub Agentic Workflow) to automatically review and (when safe) merge the latest OpenAPI 3.0/3.1 description update PRs from github-openapi-bot, otherwise alerting #api-platform on Slack when breaking changes are detected.
Changes:
- Introduces a daily
openapi-pr-revieweragentic workflow definition (.md) with two gated safe-output jobs (merge/close + Slack notify; breaking-change Slack alert). - Adds the compiled workflow lockfile (
.lock.yml) generated bygh aw compile(v0.79.6) for Actions execution.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/openapi-pr-reviewer.md | Defines the agentic workflow, including safe-output jobs for merging PRs locally and posting alerts to Slack. |
| .github/workflows/openapi-pr-reviewer.lock.yml | Generated compiled workflow that GitHub Actions will run. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 1/2 changed files
- Comments generated: 3
- Review effort level: Low
| # The #api-platform Slack channel ID. Update this to the real channel ID before enabling. | ||
| env: | ||
| GH_AW_SLACK_CHANNEL_ID: "${{ vars.API_PLATFORM_SLACK_CHANNEL_ID }}" |
There was a problem hiding this comment.
Good catch — fixed in 4edc3aa. gh-aw doesn't inject GH_AW_SAFE_OUTPUTS_STAGED into custom safe-output jobs (only its own built-in jobs), so it was unset. I now set it explicitly in each custom job's env: and, because a step's own step-level env isn't visible to that same step's if:, gate the destructive actions in-script ($GH_AW_SAFE_OUTPUTS_STAGED for run steps, process.env for github-script) rather than via step if:.
| env: | ||
| GH_AW_SLACK_CHANNEL_ID: ${{ vars.API_PLATFORM_SLACK_CHANNEL_ID }} | ||
|
|
There was a problem hiding this comment.
Fixed in 4edc3aa — same root cause as the .md comment. The compiled custom jobs now carry GH_AW_SAFE_OUTPUTS_STAGED: "true" in their step env and gate merge/close/post in-script, so staged (dry-run) mode actually previews instead of executing.
| - name: Checkout default branch | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ env.MERGE_TOKEN }} | ||
| - name: Merge PRs locally and push | ||
| if: ${{ env.GH_AW_SAFE_OUTPUTS_STAGED != 'true' }} | ||
| env: | ||
| PR_30: ${{ steps.req.outputs.pr_30 }} | ||
| PR_31: ${{ steps.req.outputs.pr_31 }} | ||
| run: | | ||
| set -euo pipefail | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| DEFAULT_BRANCH="${GITHUB_REF_NAME}" | ||
| git checkout "$DEFAULT_BRANCH" |
There was a problem hiding this comment.
Addressed in 4edc3aa. The job no longer derives the branch from GITHUB_REF_NAME or pushes directly — it merges each PR via gh pr merge --merge, which targets the PR's base (the default branch) regardless of the ref the workflow was dispatched from. The staged preview now echoes github.event.repository.default_branch.
Replace the direct Slack Web API calls (chat.postMessage + SLACK_BOT_TOKEN /
channel ID) with the repo's existing chatterbox convention, matching
linter-failure-notifier.yml: POST to ${CHATTERBOX_URL}/topics/%23api-platform
with basic auth (CHATTERBOX_TOKEN). Renames the post-to-slack-channel safe
output to post-to-chatterbox and drops the SLACK_BOT_TOKEN /
API_PLATFORM_SLACK_CHANNEL_ID secrets/vars. Recompiled the lock with gh aw.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dcc1f083-b349-4398-ae7e-e2b90b1924b7
Replace the local git merge + direct push to the protected default branch with `gh pr merge` on each of the two latest PRs. Merging a PR is the compliant path through the "require a pull request" branch rule, so the job no longer needs a protected-branch push or any ruleset/branch-protection bypass — OPENAPI_MERGE_TOKEN only needs pull-requests:write + contents:write. The synchronous merge call can gateway-timeout (502/504) on these ~250K-line diffs, so merge_pr retries and polls the PR's merged state after each failure (the merge usually completes server-side despite the timeout). Drops the actions/checkout-with-token step. Recompiled the lock with gh aw. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: dcc1f083-b349-4398-ae7e-e2b90b1924b7
- Staged mode was a no-op: gh-aw does not inject GH_AW_SAFE_OUTPUTS_STAGED into custom safe-output jobs, and a step's own step-level env is not visible to that same step's `if:`. Set the flag explicitly in each custom job's env and gate destructive actions in-script (shell `$GH_AW_SAFE_OUTPUTS_STAGED` for run steps, `process.env` for github-script) instead of via step `if:`. - Merge target: merges now go through `gh pr merge` (targets each PR's base = default branch, not GITHUB_REF_NAME), so workflow_dispatch from a non-default branch can't merge into the wrong branch. Staged preview echoes github.event.repository.default_branch. - Reference secrets.OPENAPI_MERGE_TOKEN directly for GH_TOKEN (the previous `env.MERGE_TOKEN` indirection resolved empty for custom jobs). - Close-older-PRs now also requires success() so a failed merge won't close PRs. Recompiled the lock with gh aw. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: dcc1f083-b349-4398-ae7e-e2b90b1924b7
What
Adds a daily gh-aw (GitHub Agentic Workflow) that automates the API Platform team's
openapi-pr-reviewerprocess, tracked in github/api-platform#3408.Every day the workflow:
github-openapi-bot.changed_files: 0on these ~64-file, 250K-line PRs) to detect breaking changes.main, closes the older superseded PRs, and posts a summary to #api-platform on Slack.Files
.github/workflows/openapi-pr-reviewer.md— the agentic workflow (source of truth)..github/workflows/openapi-pr-reviewer.lock.yml— compiled workflow (gh aw compile, v0.79.6). This is what Actions runs; regenerate it whenever the.mdchanges.Design
The agent runs read-only (
contents: read,pull-requests: read). All privileged writes happen in gated safe-output jobs that hold the write tokens — gh-aw's defense against prompt injection:merge-openapi-prs(contents: write,pull-requests: write): merges the two latest PRs into the default branch via the GitHub merge API (gh pr merge --merge) and closes the older PRs. We can't use the built-inmerge-pull-requestsafe output because it always refuses merges to the default branch, so this is a custom job. Merging a PR is the compliant path through the "require a pull request" branch rule, so no protected-branch push or branch-protection bypass is needed. The synchronous merge call can gateway-timeout (502/504) on these ~250K-line diffs, so the job retries and polls the PR's merged state (the merge usually completes server-side despite the timeout).post-to-chatterbox: posts the breaking-change alert to #api-platform (≤200 chars) via chatterbox.🔒 Security review (required for new secrets)
This workflow introduces the following new secrets / variables. Each has been reviewed:
CHATTERBOX_URL${CHATTERBOX_URL}/topics/%23api-platform. Same secret already used by this repo'slinter-failure-notifier.yml.CHATTERBOX_TOKENchat:writeequivalent)-u "$CHATTERBOX_TOKEN:"). Same secret already used bylinter-failure-notifier.yml.OPENAPI_MERGE_TOKENmerge-openapi-prsjob. Needscontents: write+pull-requests: writeon this repo. Because the job merges PRs (rather than pushing to the default branch), it does not need any protected-branch bypass. Recommend a GitHub App / service-account token, not a personal PAT.No third-party GitHub Actions beyond
actions/checkout@v5andactions/github-script@v9are used. The agent has no network access to write anywhere except through these jobs.The workflow is committed with
safe-outputs.staged: true, so every safe-output job previews its action in the run summary instead of actually merging/closing/posting. This lets us validate the daily run end-to-end before it can change anything.To go live (follow-up, owner action)
CHATTERBOX_URL,CHATTERBOX_TOKEN,OPENAPI_MERGE_TOKEN) and the Copilot engine token (COPILOT_GITHUB_TOKEN/COPILOT_CLI_TOKENper the org's gh-aw setup).CHATTERBOX_URL/CHATTERBOX_TOKENalready exist in this repo forlinter-failure-notifier.yml.OPENAPI_MERGE_TOKENidentity haspull-requests: write+contents: writeon this repo and can merge PRs intomain. No branch-protection bypass is required, since the job merges the PRs rather than pushing to the default branch. (maincurrently has no required status checks, so no CodeQL exemption is needed.)#api-platform, hardcoded in the safe-output jobs) is correct.safe-outputs.stagedtofalse(or remove it) and setGH_AW_SAFE_OUTPUTS_STAGEDto"false"(or remove it) in both custom jobs'env:in the.md, then re-rungh aw compile openapi-pr-reviewer.See github/api-platform#3408 for the full design/tracking notes.