Skip to content

feat(ci): add release approval guard action - #79

Open
feliperalmeida wants to merge 5 commits into
mainfrom
felipe/release-approval-guard
Open

feliperalmeida wants to merge 5 commits into
mainfrom
felipe/release-approval-guard

Conversation

@feliperalmeida

@feliperalmeida feliperalmeida commented Oct 1, 2026 •

Copy link
Copy Markdown

Problem

  • SDK releases are gated by a GitHub environment with "Prevent self-review" turned on: NPM Release in posthog-js, and Release SDK for the posthog/posthog CLI release.
  • That setting excludes only the run's triggering actor. When a person merged a PR, the actor was that person, so they couldn't approve the release.
  • With a merge queue (GitHub's in posthog-js, Trunk in posthog/posthog), the push to the default branch comes from a bot, so nobody is excluded and a PR author can approve their own release. Example run.

Changes

  • Add a composite action, .github/actions/release-approval-guard, that restores the old behavior.
    • It finds every PR in the push that triggered the run (before...after). The posthog-js merge queue merges up to 5 PRs per push.
    • It fails the job if an approver of the environment authored or merged one of those PRs. With GitHub's merge queue, merged_by is the person who added the PR to the queue. With Trunk, it's trunk-io[bot], so only the author is checked.
    • On events other than push, it does nothing, because GitHub's own check already excludes whoever triggered the run.
    • It fails closed if the run has no approval for the environment, if a commit in the push isn't part of a merged PR, or if the push range can't be listed in full.
    • It retries GitHub 5xx responses twice.
  • Add unit tests against a fake GitHub API, and a workflow that runs them on Node 24.

Callers add the step to the gated job before it uses its secrets, and give the job actions: read and pull-requests: read. No checkout is needed. See the action's README. Wiring it into posthog-js and posthog/posthog will be separate PRs.

Limitations

  • Like the setting it replaces, it covers only the PRs in the triggering push. If a release also publishes earlier unreleased changes, such as other PRs' changesets or PRs without one, their authors aren't excluded. Covering everything in a release is a possible follow-up.
  • The approvals API doesn't say which run attempt an approval belongs to, so every approval in the run counts. After a block, a different approver must approve a new run. A re-run may fail again.

How did you test this?

  • node --test .github/actions/release-approval-guard/guard.test.mjs: 14 tests pass.
  • Ran checkReleaseApproval against the real GitHub API on past runs, using the head commit's parent as before:
    • posthog-js run 36781673145 (merge queue, #5167 approved by its author): blocked, as author and merger.
    • posthog-js runs 36778517925 and 36153998493: pass.
    • posthog/posthog CLI runs 36435375005 and 36416074414 (Trunk): pass.
  • The repo's semgrep rules report nothing on the new files.
  • Not yet run inside a real workflow with an environment approval.

@feliperalmeida
feliperalmeida requested a review from a team as a code owner October 1, 2026 18:56
Comment thread .github/actions/release-approval-guard/guard.mjs Outdated
Comment thread .github/actions/release-approval-guard/guard.mjs Outdated
@veria-ai

veria-ai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 2 · PR risk: 0/10

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated advisory code review.

Comment thread .github/actions/release-approval-guard/guard.mjs Outdated
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.

2 participants