Skip to content

fix(ci): thank first contributors on push, not on the fork's PR event - #25

Merged
GabrielBBaldez merged 1 commit into
mainfrom
fix/first-contribution-fork-token
Aug 3, 2026
Merged

fix(ci): thank first contributors on push, not on the fork's PR event#25
GabrielBBaldez merged 1 commit into
mainfrom
fix/first-contribution-fork-token

Conversation

@GabrielBBaldez

Copy link
Copy Markdown
Member

The workflow has never once posted a comment. Every run was green — a 403 on the POST only raises a ::warning::, and nobody reads a warning on a green run.

Caught it live merging #16, @ashudhanda's first contribution here:

ashudhanda has 1 merged PR(s) here.
gh: Resource not accessible by integration (HTTP 403)
::warning::could not comment — the workflow token is read-only for this org

The count was right. The POST was not allowed.

Why the setting change didn't reach it

pull_request_target: closed is the obvious trigger and cannot work. A run triggered by a fork's pull request gets a read-only GITHUB_TOKEN whatever the repository's Workflow permissions say. Setting those to write — done yesterday, and verified write on all three repos — does not apply to this event.

Granting it means enabling "send write tokens to workflows from fork pull requests", which hands a write token to every fork-triggered run in the repository. Not a trade worth making for a thank-you note.

A push to main is not fork-triggered, so its token honours the permissions: block.

Detail worth keeping

The PR behind the pushed commit comes from repos/:repo/commits/:sha/pulls, not from parsing the commit subject — squash writes (#12), a merge commit writes Merge pull request #12, and a rebase merge writes neither.

workflow_dispatch with a pr input stays so the path can be exercised without waiting on someone's first contribution. I'll use it to verify against #16 once this lands, and post the result here.

The workflow has never once posted a comment. Every run was green, because a
403 on the POST only raises a ::warning::, and nobody reads a warning on a
green run.

pull_request_target: closed is the obvious trigger and cannot work here. A run
triggered by a fork's pull request gets a read-only GITHUB_TOKEN whatever the
repository's Workflow permissions say — setting that to write, which was done
yesterday, does not reach it. Granting it means enabling "send write tokens to
workflows from fork pull requests", which hands a write token to every
fork-triggered run in the repository. That is not a trade worth making for a
thank-you note.

A push to main is not fork-triggered, so its token honours the permissions
block. The PR behind the pushed commit comes from repos/:repo/commits/:sha/pulls
rather than the commit subject, because squash writes "(#12)", a merge commit
writes "Merge pull request #12", and a rebase merge writes neither.

Confirmed on the real failure: ashudhanda's first merged PR (#16) counted
correctly as 1 and then 403'd on the comment.

workflow_dispatch with a pr input is kept so the path can be exercised without
waiting for someone's first contribution.
@GabrielBBaldez
GabrielBBaldez merged commit 35b855c into main Aug 3, 2026
2 checks passed
@GabrielBBaldez
GabrielBBaldez deleted the fix/first-contribution-fork-token branch August 3, 2026 13:45
@GabrielBBaldez

Copy link
Copy Markdown
Member Author

Dispatched against #16 as promised. Still 403 — and that rules out the reason given in this PR.

MANUAL_PR: 16
ashudhanda has 1 merged PR(s) here.
gh: Resource not accessible by integration (HTTP 403)

A workflow_dispatch run is not fork-triggered, so the fork-token restriction cannot be what is denying it. The evidence now says the cap is above the repository:

repos/stacktale/stacktale-intellij/actions/permissions/workflow default_workflow_permissions: write
workflow's own permissions: block issues: write
effective token on a non-fork run read-only

The organisation's Workflow permissions setting is still "Read repository contents and packages permissions", and a repository cannot exceed it. Setting the repository value succeeds and simply has no effect — which is why yesterday's change looked like it had worked.

The change here is still right and stays: pull_request_target gets a read-only token for fork PRs regardless, so triggering on push removes one variable that would otherwise bite the moment the org setting is fixed. But it is not sufficient on its own.

Unblocking needs one click, at the org rather than the repo:
github.com/organizations/stacktale/settings/actions → General → Workflow permissions → Read and write permissions.

Leave "Allow GitHub Actions to create and approve pull requests" unchecked — nothing here needs it.

Re-run this workflow with pr: 16 afterwards to confirm, without waiting on someone's first contribution.

@GabrielBBaldez

Copy link
Copy Markdown
Member Author

Found it, and it was not the org setting — that page is already on "Read and write permissions", and so is every repository. Two wrong diagnoses from me before this one.

It was this workflow's own permissions block:

permissions:
  pull-requests: read     # ← the denial
  issues: write           # ← granted, never consulted

The comment goes through POST /repos/:owner/:repo/issues/:number/comments, so issues: write is the obvious reading of what it needs. GitHub scopes that endpoint by what the number points at, and for a pull request the permission checked is pull-requests. An explicit permissions: block replaces the default rather than adding to it, so pull-requests: read capped the exact thing being asked for, and the repository being on "Read and write" could not compensate.

Verified by dispatching against #16 with pull-requests: write:

ashudhanda has 1 merged PR(s) here.

— and the bot's comment is on the PR. Same fix pushed to stacktale and stacktale-vscode, which carried the identical block.

One correction to this PR's own description, since it is now on record wrongly. The fork-token claim was never tested. The original pull_request_target run carried the same pull-requests: read, so its 403 is fully explained without any fork restriction, and that trigger may well work now too. The push trigger stays because a push to main is plainly not fork-triggered, which takes the question off the table — a preference, not a fix for something demonstrated. The header comment says so now.

The thing that let this sit through several merges is worth naming: a 403 here only raises a ::warning::, and nobody reads a warning on a green run. The tolerance is still right — a red X on main over a thank-you note would be worse — but "degrades quietly" and "degrades invisibly" turned out to be the same thing in practice.

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