Skip to content

ci(release-tag): create the tag with the melodic-plugin-release App token - #990

Merged
kyle-sexton merged 1 commit into
mainfrom
ci/release-tag-app-token
Nov 5, 2026
Merged

kyle-sexton merged 1 commit into
mainfrom
ci/release-tag-app-token

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

Refs: melodic-software/claude-code-plugins#11042

Summary

A github-iac tag ruleset will let only the melodic-plugin-release App (App ID 5190206) create, move or delete v* tags in this repository (owner decision: melodic-software/claude-code-plugins#11042 (comment)). GITHUB_TOKEN tag creation gets 422 under a tag ruleset, and the Actions app cannot be a bypass actor, so the release step moves to the App's token.

Fix

  • The release job runs in the plugin-release environment (main only, created by github-iac) and mints a contents: write token with actions/create-github-app-token, scoped to this repository.
  • The workflow token drops to contents: read.

Verification

  • Same pinned create-github-app-token SHA and inputs as claude-code-plugins' release-publish-plugins.yml.
  • GitHub refuses any token without the workflows permission a tag at a commit whose workflow files differ from the default branch's (ci(release): skip a release whose commit can no longer be tagged projectbluefin/server#332). GITHUB_TOKEN has the same limit today, so the App adds no new failure: the tag targets the run's own main commit.
  • The first release after the ruleset lands is watched.

Related

Held with do-not-merge until the App is installed on this repository and PLUGIN_RELEASE_APP_PRIVATE_KEY is set in its plugin-release environment; merging first would break the next release at the token mint. The github-iac ruleset merges and deploys after this.

🤖 Generated with Claude Code

…oken

A github-iac tag ruleset will let only the melodic-plugin-release App create,
move or delete v* tags in ci-workflows (claude-code-plugins#11042), and
GITHUB_TOKEN tag creation gets 422 under a tag ruleset. The tag job now runs in
the main-only plugin-release environment and mints a contents:write App token
for the release step; the workflow token drops to contents:read.

Refs: melodic-software/claude-code-plugins#11042

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton kyle-sexton added the do-not-merge Hard merge gate: do not merge while applied. label Nov 5, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-05T06:27:48.297283Z 69566fb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment thread .github/workflows/release-tag.yml Resolved
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown

claude-security-review reviewed 69566fba879784cf46a5fbf584d5c65f08ef75bc: 0 finding(s), 0 as inline comments.

No security findings in this pull request. I read .github/workflows/release-tag.yml in full at head 69566fb, along with the diff.

critical-findings: 0

What the change does. The job now creates the tag and Release with a melodic-plugin-release GitHub App token instead of GITHUB_TOKEN. It declares environment: plugin-release and drops the job's contents permission from write to read.

What I checked

  • Token scope. The mint step asks for permission-contents: write only. It is limited to one repository through repositories: ${{ github.event.repository.name }}, and create-github-app-token is pinned to a full SHA (v3.3.0). The job holds less ambient authority than before, and the App token is never exposed outside the one step that uses it.
  • Who can trigger it. The only trigger is workflow_dispatch, which needs write access. The bump input is a choice, so it can't carry arbitrary text, and it only reaches the shell through env:, not through inline ${{ }} expansion. NEXT comes from the computed output and is also passed through env:. I found no injection path.
  • Ordering and guards. The App token is minted after the "releases only from main" guard and the "tag does not already exist" guard. Checkout still uses persist-credentials: false, so the token is not written to .git/config. The token goes only into GH_TOKEN for gh release create.
  • Secret exposure. secrets.PLUGIN_RELEASE_APP_PRIVATE_KEY is read only by the mint step. No step prints it or passes it onward.
  • Trust controls. The diff touches none of the listed trust-control paths (trusted-actor list, kill switch, lane token broker, merge holds, .github/actions/*). It narrows the workflow's default token, so it is not a widening.

Not verifiable from the diff. The comment says the plugin-release environment admits only main, and that a github-iac ruleset restricts v* tags to the App. Both are repository or organization settings, not files in this diff, so I took them as stated. If the environment had no branch restriction, anyone who can push a branch could dispatch a modified copy of this workflow from it and read the key. The in-workflow main-only guard would not stop that, because it is part of the workflow file they would be editing. That rests on the environment configuration, which this review could not see. It is a reason to confirm the environment's deployment-branch policy, not a finding against this diff.

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown

claude-review reviewed 69566fba879784cf46a5fbf584d5c65f08ef75bc: 1 finding(s), 1 as inline comments.

Code review: PR #990 (release-tag moves to the App token)

I reviewed the one changed file, .github/workflows/release-tag.yml. I found one advisory finding and posted it inline.

Advisory finding, release-tag.yml:107: the create-github-app-token step reads vars.PLUGIN_RELEASE_APP_CLIENT_ID. The PR's hold condition lists only the App install and PLUGIN_RELEASE_APP_PRIVATE_KEY. Nothing in this repo sets that variable. If it is unset, the mint step fails before gh release create. The PR gives the App ID (5190206), but client-id takes the Client ID, not the numeric App ID. The fix is to add the variable to the hold checklist and say where it is set.

What I checked, with no other findings:

  • Permissions: contents: read at job level is enough for the read-only steps. The "Compute next version" step still uses github.token for read-only gh api. Tag creation uses the App token with permission-contents: write.
  • Checkout credentials: persist-credentials: false is still correct, because tag creation goes through gh and not git push.
  • Main-only guard: the existing GITHUB_REF guard still runs before the token mint.
  • Context: the PR context file has no closing issue with acceptance criteria (the PR uses Refs:). No rule file's paths: matches the change; .claude/rules/pr-body-contract.md is about the PR body, which has the expected sections. README's Versioning section does not describe the token, so it is not stale. No plugin manifests changed.
  • Verification: I ran no tests or workflow runs. The claims about the ruleset, the plugin-release environment, and the first-release watch are author-claimed and unverified by me.
  • Hold classes: no cost or critical-security hold applies. The PR already carries do-not-merge.

@kyle-sexton kyle-sexton removed the do-not-merge Hard merge gate: do not merge while applied. label Nov 5, 2026
@kyle-sexton
kyle-sexton added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 00dec36 Nov 5, 2026
101 of 104 checks passed
@kyle-sexton
kyle-sexton deleted the ci/release-tag-app-token branch November 5, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant