Skip to content

fix(ci): add least-privilege permissions and stop the push sync clobbering releases - #405

Open
treff7es wants to merge 3 commits into
masterfrom
fix/linear-release-permissions-and-push-sync
Open

fix(ci): add least-privilege permissions and stop the push sync clobbering releases#405
treff7es wants to merge 3 commits into
masterfrom
fix/linear-release-permissions-and-push-sync

Conversation

@treff7es

Copy link
Copy Markdown
Collaborator

Two independent bugs in the Linear release workflow, both of which fail silently.

1. The jobs had no GitHub permissions they needed

This repo's default_workflow_permissions is read, which grants only contents / metadata / packages. pull-requests is none, so every gh pr view --json comments lookup — the PR-to-ticket resolution in the attach step, and the issue lookup in add-to-cli-next — was failing.

Per-job scopes are now declared explicitly, least privilege:

Job Permissions Why
add-to-cli-next contents: read, pull-requests: read gh pr view --json comments
linear-release contents: read, pull-requests: read actions/checkout, the action's CLI download, and the attach step's PR lookups
delete-linear-release {} talks only to api.linear.app

Note an explicit permissions: block is subtractive — anything not listed becomes none — so contents: read has to be re-declared or actions/checkout breaks. No job needs any write scope on GitHub: the workflow reads GitHub and writes only to Linear.

2. The push sync was overwriting the newest release

linear-release-action's push sync is the pattern for continuous pipelines, where each push becomes its own release. This pipeline is scheduled, so a versionless sync creates nothing — it targets the most recent release, rewrites its commitSha to master HEAD, and attaches commits published after it.

Not hypothetical. On 2026-08-11 a push run did this:

Found 19 matching commits between f579f9c and 5f70929
Synced to release v1.7.0.2 (version: v1.7.0.2): pull requests [17 PRs]

v1.7.0.2's commitSha went from f579f9c4 (its tag) to master HEAD, and 17 PRs that shipped after the release were attached to it. The next ingestion push to master would have done the same to v1.7.0.3.

The behaviour was dormant for three months only because the owner/repo-qualified path filters made every push match zero commits and skip. Fixing those filters in #403 reactivated it — so this is a regression introduced by that fix.

The push trigger and its step are removed. Staging on merge is already add-to-cli-next's job, via pull_request_target, writing to the cli-next release rather than to a versioned one.

Not fixed here

INGESTION_LINEAR_KEY does not exist as a secret in this repo. The workflows that share it (pr-to-linear.yml, linear-assignment-notify.yml) live upstream in datahub-project/datahub, where it is configured, and secrets do not cross the fork boundary. When it is missing GitHub substitutes an empty string, so every direct Linear GraphQL call 401s and the step exits 0 — releases get created with zero issues attached.

That needs a repo (or scoped org) secret containing a Linear personal API key with Read + Write, and access to all teams whose issues can appear in a release — the five tickets resolved for v1.7.0.2 span four (Ingestion Pod, Observability Squad, Open Source, Catalog). A key limited to one team would return null for the rest and skip them silently.

LINEAR_ACCESS_KEY is already present but is not a substitute: it is a release-pipeline access key for the linear-release CLI and cannot authorize issueToReleaseCreate, issueToReleaseDeleteByIssueAndRelease, releaseDelete, or issue lookups.

Once the secret exists, v1.7.0.2 needs its commitSha reset to f579f9c4 and a re-run of sync to attach its issues. Doing that before this PR merges would simply be overwritten by the next push.

Checklist

  • PR conforms to the Contributing Guideline
  • actionlint and githubActionsPrettierCheck pass
  • Tests added/updated — n/a, CI workflow change
  • Breaking changes documented — none

🤖 Generated with Claude Code

This repo's default workflow permission is "read", which grants only
contents/metadata/packages. `gh pr view --json comments` needs pull-requests,
so those lookups were failing silently.

Declare per-job scopes explicitly. An explicit permissions block is
subtractive -- anything not listed becomes none -- so contents: read is
re-declared for actions/checkout and for linear-release-action's github_token,
which it uses only to download the Linear release CLI. delete-linear-release
talks only to api.linear.app and needs no token at all.

Also record why INGESTION_LINEAR_KEY must exist in this repo: the workflows
that share it live upstream in datahub-project/datahub, where it is
configured, and secrets do not cross the fork boundary. When it is missing
GitHub substitutes an empty string, so every Linear call 401s silently and
releases are created with zero issues attached.
linear-release-action's push sync is the pattern for CONTINUOUS pipelines,
where each push becomes its own release. This pipeline is `scheduled`, so a
versionless sync creates nothing -- it targets the most recent release,
rewrites its commitSha to master HEAD and attaches commits published after
it.

That is not hypothetical. On 2026-08-11 a push run rewrote v1.7.0.2's
commitSha from f579f9c (its tag) to master HEAD and attached 17 PRs that
shipped after the release. The next ingestion push would do the same to
v1.7.0.3.

The behaviour was dormant for three months only because the owner/repo-
qualified path filters made every push match zero commits and skip. Fixing
those filters reactivated it.

Drop the push trigger and the step. Staging work on merge is already the
add-to-cli-next job's responsibility, via pull_request_target, which writes
to the cli-next release rather than to a versioned one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant