Skip to content

chore(release): Harden agent npm and desktop release pipelines#3153

Open
charlesvien wants to merge 6 commits into
mainfrom
chore/harden-release-pipelines
Open

chore(release): Harden agent npm and desktop release pipelines#3153
charlesvien wants to merge 6 commits into
mainfrom
chore/harden-release-pipelines

Conversation

@charlesvien

@charlesvien charlesvien commented Jul 5, 2026

Copy link
Copy Markdown
Member

Problem

@posthog/agent auto-publishes to npm on every merge touching packages/agent/**, 3 to 8 times a day, with no human review. It runs in PostHog cloud sandboxes, so one bad merge to main is live in production within minutes. This adopts the SDK release handbook process (example: posthog-php), as asked for supply chain risk.

Changes

One commit each, desktop isolated in the last:

  • inject agent version only in release builds: changesets needs a real version committed in package.json, so the 0.0.0-dev "latest source" sentinel that dev and desktop builds rely on is now injected by tsup instead. Only release builds (AGENT_RELEASE_BUILD=1) bake the real version.
  • add changesets for agent releases: releases happen when a PR adds a changeset (pnpm changeset), not on every merge. Config locks versioning to @posthog/agent only.
  • gate agent npm publish behind human approval: deletes the auto-tagger and rewrites agent-release.yml as prepare -> verify (build + test) -> Slack ping -> approval on the protected Release environment -> version-bump commit, tag, npm publish with OIDC provenance, GitHub release. Integrity-checked (sha256 patch, main-moved check), idempotent on re-run. Adds CODEOWNERS on release-critical files and stops agent tags from posting to the desktop Discord.
  • harden desktop release publish workflow: finalize-release (the step that makes a release public) now runs in a Desktop Release environment, inert until reviewers are configured on it, and two checkouts stop persisting write tokens they never use.

Full process doc: packages/agent/RELEASING.md.

What I need from a human

Before merging:

  1. Create the Release environment: required reviewers, prevent self-review, no admin bypass, deployments restricted to main. Skip this and the first changeset still publishes ungated.
  2. Create the releaser GitHub App (Contents R/W, this repo only); store GH_APP_POSTHOG_AGENT_RELEASER_APP_ID / _PRIVATE_KEY as Release environment secrets.
  3. Add the App to the main ruleset bypass list (it commits the version bump straight to main) and CodeQL ruleset bypass. Check classic branch protection separately.
  4. Check the seeded version 2.3.1250 still matches the latest agent-v* tag at merge time.

After merging: merge a trivial test changeset, let it pause at the gate, then set the npm trusted publisher for @posthog/agent to environment Release (org PostHog, case-sensitive), then approve.

Recommended, not blocking: tag rulesets for agent-v* and v* (bypass only the App), reviewers on Desktop Release, Slack secrets (SLACK_CLIENT_LIBRARIES_BOT_TOKEN, POSTHOG_PROJECT_API_KEY) and vars (SLACK_APPROVALS_CODE_CHANNEL_ID, GROUP_CODE_SLACK_GROUP_ID). Slack failures never block a release; the environment is the gate.

How did you test this?

  • Built the agent with and without AGENT_RELEASE_BUILD=1; dist bakes the real version with the flag, the sentinel without.
  • 919 agent tests pass, full-repo typecheck passes, biome clean; re-verified after rebasing onto latest main.
  • changeset version dry run changes exactly the three allowlisted files and nothing else.
  • actionlint clean on touched workflows; all new action SHAs verified against upstream refs.
  • Not tested: a live pipeline run. That is deliberately the first test changeset once the environment exists.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?
  • Added a changeset? (required to ship packages/agent, shared, git or enricher changes to npm; run pnpm changeset)

No changeset on purpose: it would trigger the pipeline on merge before the environment exists.

@trunk-io

trunk-io Bot commented Jul 5, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit 9362a78.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. .github/workflows/agent-release.yml, line 536-546 (link)

    P2 Heredoc injection risk with rejection comment

    $COMMENT is embedded directly inside a message<<EOF heredoc written to $GITHUB_OUTPUT. If a reviewer writes a rejection comment that contains the literal string EOF on its own line, the heredoc delimiter fires early, truncating the message output variable. The Slack notification would then send only the partial text before EOF appeared. This is a cosmetic issue (no security impact), but multiline rejection comments are plausible and would silently produce a wrong Slack thread reply.

    A safe alternative is to use a random delimiter that cannot appear in user-controlled content, e.g. message<<DELIMITER_$(uuidgen) or to strip newlines from $COMMENT.

Reviews (1): Last reviewed commit: "harden desktop release publish workflow" | Re-trigger Greptile

Comment thread .github/CODEOWNERS Outdated
@charlesvien

Copy link
Copy Markdown
Member Author

Re the outside-diff heredoc finding on notify-release-failed: addressed in 9362a78. The truncation could not actually fire before (head -1 forced the comment to a single prefixed line), but that also silently dropped multiline rejection comments. The step now takes the first rejection comment in full and writes it with a random heredoc delimiter, so reviewer-controlled text can neither terminate the heredoc nor get truncated.

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