Skip to content

ci(repo): mint the release token from the GitHub App - #58

Merged
arbianst merged 1 commit into
mainfrom
ci/release-token-app
Oct 30, 2026
Merged

arbianst merged 1 commit into
mainfrom
ci/release-token-app

Conversation

@arbianst

Copy link
Copy Markdown
Contributor

Release Please ran on a personal access token that no longer exists (revoked with the other pipeline PATs today), so the merged release PR cut no tag and nothing published: release-please failed: Bad credentials. The token now comes from the sent-dm-sdk-pipeline App, the same way seal-dispatch.yml already mints its token; RELEASE_PLEASE_TOKEN stays as a fallback until the secret is deleted.

Merging this is a push to main, which runs Release Please on the App token; it then cuts the release the merged release PR described, and the publish workflow runs on the release event (an App-created release triggers workflows, a built-in-token one would not).

Part of EPIC-4427.

🤖 Generated with Claude Code

Release Please ran on a personal access token that no longer exists, so
the merged release PR cut no tag and nothing published (Bad credentials).
The token now comes from the sent-dm-sdk-pipeline App, as the seal
dispatch's already does; the old secret stays as a fallback until it is
removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@arbianst
arbianst merged commit ed4a7af into main Oct 30, 2026
7 checks passed
@arbianst
arbianst deleted the ci/release-token-app branch October 30, 2026 16:08

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings marked 🟡 are optional suggestions and need no follow-up push.

Comment on lines +15 to +36
env:
HAS_APP: ${{ secrets.SDK_APP_ID != '' && secrets.SDK_APP_PRIVATE_KEY != '' }}

steps:
- name: Mint the release token from the GitHub App
# A tag or release created with the built-in token starts no
# workflow, so the publish workflow would never run; a personal
# access token expires or dies with its owner's account. The App's
# token does neither.
id: app
if: env.HAS_APP == 'true'
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v3.3.0
with:
app-id: ${{ secrets.SDK_APP_ID }}
private-key: ${{ secrets.SDK_APP_PRIVATE_KEY }}
owner: sentdm
repositories: ${{ github.event.repository.name }}

- uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1
id: release
with:
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
token: ${{ steps.app.outputs.token || secrets.RELEASE_PLEASE_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Maintainers get a conflict on the next regeneration, which blocks every SDK's release. This is the generator-owned release workflow, edited in a hand-written commit with no Stainless-Generated-From trailer. It also rewrites the generator-written token: line at :36. CLAUDE.md says: "Changing lines the generator writes conflicts the next time the API document changes, and a conflict blocks every SDK's release". Fix: make the App-token change in the SDK configuration so the generator emits this workflow. If a stopgap has to land here, add lines only and leave the generated token: line unchanged.

Why this was flagged

CLAUDE.md lists "the publish, release and sync workflows" as generator-owned. REVIEW.md tells reviewers to report any change to them outside a generated commit as Important. Commit a0abe5f has no Stainless-Generated-From trailer, so it is carried forward as a custom-code patch on every regeneration. The patch replaces the generated line token: ${{ secrets.RELEASE_PLEASE_TOKEN }} with token: ${{ steps.app.outputs.token || secrets.RELEASE_PLEASE_TOKEN }} at release-please.yml:36. The next generated commit rewrites that same line, so the patch conflicts. Per CLAUDE.md that conflict blocks every SDK's release, not only this one. On the base branch the file matches generator output and no patch is carried.

Verification: Severity: normal. The trigger is the next generated commit (the next change to the API document) that rewrites this release workflow. Here is what I checked.

  1. The file is generator-owned. CLAUDE.md lists it: "Generator-owned, so don't edit them here: ... the publish, release and sync workflows ... The next generated commit rewrites them, and an edit conflicts."

  2. The line being changed was written by the generator.


steps:
- name: Mint the release token from the GitHub App
# A tag or release created with the built-in token starts no

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 The PR text names a private Sent repository and an internal tracker in a public repo. The description cites the sent-dm-sdk-pipeline App and "EPIC-4427". CLAUDE.md says: "Nothing in it, including PR text, CHANGELOG.md and release notes, links to or names Sent's private repositories, internal systems or providers." Fix: edit the PR description and the merge commit body to drop the App/repo name and the EPIC reference. Describe it only as "a GitHub App installation token".

Why this was flagged

The repository is public (sentdm/sent-dm-csharp). The PR description says the token comes from the sent-dm-sdk-pipeline App, which is also the private config repo that seal-dispatch.yml sets as CONFIG_REPO. It also says "Part of EPIC-4427", an internal tracker ID. Merging leaves both visible on the public PR and, with a merge-commit body, in public history. CLAUDE.md's "This repository is public" rule and REVIEW.md both forbid naming a private repository or internal system. The workflow diff itself avoids these names, so the PR text is the only place they leak.

Verification: CLAUDE.md line 94-97 bars PR text that names Sent's private repositories or internal systems. The PR description says the token "now comes from the sent-dm-sdk-pipeline App" and ends with "Part of EPIC-4427". sent-dm-sdk-pipeline is the private config repo, per .github/workflows/seal-dispatch.yml:37. The EPIC-4427 reference is new. The diff itself is clean.

Comment on lines +22 to +31
# access token expires or dies with its owner's account. The App's
# token does neither.
id: app
if: env.HAS_APP == 'true'
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v3.3.0
with:
app-id: ${{ secrets.SDK_APP_ID }}
private-key: ${{ secrets.SDK_APP_PRIVATE_KEY }}
owner: sentdm
repositories: ${{ github.event.repository.name }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 (optional) The release this PR is meant to unblock may still not publish, because nothing in this repo shows the App can write here. The only proof is seal-dispatch.yml:46, which mints a token for sent-dm-sdk-pipeline and not this repo. The step requests no permission-* inputs, so it gets whatever the installation grants. Fix: before merging, confirm the App is installed on sent-dm-csharp with contents and pull-requests write. Request both through permission-contents: write and permission-pull-requests: write, so a missing grant fails at mint time rather than partway through a release.

Why this was flagged

The trigger is an App installation that covers only selected repos, or that lacks pull_requests: write. That cannot be checked from this checkout. HAS_APP at release-please.yml:16 is true wherever the secrets exist, and seal-dispatch.yml:38 shows they do. So the step at release-please.yml:22-31 always runs, and the || fallback to RELEASE_PLEASE_TOKEN at line 36 is only reached when the secrets are missing, never when minting fails. If the App is not installed on this repo, the token request at line 31 returns Not Found and the job fails. The release that merged PR #56 described then still gets no tag and no NuGet publish, the same outcome as the base's Bad credentials. If the token lacks pull-requests write, release-please can create the release but cannot change the release PR's autorelease: pending label, which leaves later runs stuck. The workflow-level permissions: block at lines 7-9 limits only GITHUB_TOKEN, not the App token, so it gives no protection here.

Verification: nit. Triggering condition: the App behind SDK_APP_ID is not installed on sent-dm-csharp, or its installation lacks contents/pull-requests write. That state cannot be seen from this checkout, but this change is what makes the workflow depend on it.

The mechanism holds in the code:

  • release-please.yml:16 sets HAS_APP: ${{ secrets.SDK_APP_ID != '' && secrets.SDK_APP_PRIVATE_KEY != '' }}. The secrets are shared with seal-dispatch.yml:38/45-46 in this repo, so the mint step at lines 19-31 runs whenever they are set.
  • The mint step has no continue-on-error.

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