Skip to content

ci: harden GitHub Actions workflows - #1052

Open
EhabY wants to merge 2 commits into
mainfrom
ci/supply-chain-hardening
Open

ci: harden GitHub Actions workflows#1052
EhabY wants to merge 2 commits into
mainfrom
ci/supply-chain-hardening

Conversation

@EhabY

@EhabY EhabY commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Hardens the GitHub Actions release/publish pipeline. No runtime extension code is touched, and no workflow behavior changes on today's happy path (details below).

Least-privilege token permissions

  • ci.yaml: adds a top-level permissions: contents: read block (previously inherited the default, potentially write-all, token).
  • release.yaml / pre-release.yaml: workflow-level permissions downgraded to contents: read; only the publish job gets contents: write + pull-requests: read — the same scopes the whole workflow had before, now confined to the job that creates the release.
  • All actions/checkout steps that do not push now set persist-credentials: false, so the repo-scoped token is not left in .git/config where later steps and node_modules lifecycle scripts can read it.

Publish pipeline

  • publish-extension.yaml: the Marketplace/OpenVSX publish jobs now run in a publish environment, and vsce/ovsx are pinned (@vscode/vsce@3.9.2, ovsx@1.0.2) instead of installing whatever is latest at run time. Both pins are exactly today's latest, and 3.9.2 is also the version the lockfile already uses for vsce package, so packaging and publishing now run the same tool version.
  • Marketplace PATs are passed via VSCE_PAT/OVSX_PAT env vars instead of -p <token> argv, which is world-readable via /proc on the runner. Verified both pinned versions read these env vars natively (vsce 3.9.2 defaults --pat from process.env.VSCE_PAT; ovsx 1.0.2 addEnvOptions reads OVSX_PAT).

Important

Admin follow-up required: the publish environment is auto-created on first run with no protection rules (so it does not block anything by itself). A repo admin should add required reviewers to it and ideally move VSCE_PAT/OVSX_PAT from repo secrets into environment secrets so they are only exposed to approved publish runs.

Why this is behavior-neutral

  • No CI/release job performs writes with GITHUB_TOKEN except the GitHub-release job, which keeps contents: write + pull-requests: read (needed by softprops/action-gh-release + generate_release_notes). Reusable-workflow permission inheritance checked: every called job requests a subset of what its caller grants.
  • No job runs git push/fetch after checkout, so dropping persisted credentials is inert. The github:coder/coder#v2.34.1 catalog dependency is cloned by pnpm in its own store directory, which never saw the checkout's repo-local credential config — it is an anonymous https clone of a public repo before and after.
  • release.yaml's existing tag-on-main verification only needs the refs already fetched by fetch-depth: 0; no network/auth involved.
  • The publish environment adds a Deployments record and nothing else until protection rules are configured.

Not included

  • Pre-release tags intentionally remain buildable off main (used for testing without merging); stable release.yaml keeps its existing tag-on-main check.
  • pnpm audit findings in dev-only transitive dependencies (diff, serialize-javascript, brace-expansion via mocha/@vscode/test-cli) are deliberately not addressed here: they are test-runner-only and unreachable from the shipped extension.
  • Dependency provenance for publish tooling (registry install vs. vendoring) needs a policy decision first. Alternatives: (a) keep registry installs with exact pins + lockfile-enforced integrity (this PR moves in that direction), or (b) vendor/mirror publish tooling.

EhabY added 2 commits July 29, 2026 15:45
- Add least-privilege permissions blocks at workflow and job level so
  jobs only receive the scopes they need (contents: read by default,
  write only where releases are created).
- Set persist-credentials: false on all actions/checkout steps that do
  not push, so the repo-scoped token is not left on disk for later
  steps and node_modules scripts.
- pre-release: verify the release tag commit is an ancestor of
  origin/main before building, preventing releases from tags pointing
  at unreviewed commits.
- publish-extension: gate marketplace publish jobs behind a 'publish'
  environment, pin vsce and ovsx to exact versions instead of
  installing latest at run time, and pass marketplace PATs via env vars
  instead of argv (argv is world-readable via /proc on the runner).
Pre-release tags are intentionally used to test builds without merging
everything to main first, so drop the ancestor check and full fetch;
stable release.yaml keeps its existing tag-on-main verification.
@EhabY
EhabY force-pushed the ci/supply-chain-hardening branch from 75892d1 to f6ec3b7 Compare July 29, 2026 16:02
@EhabY EhabY changed the title ci: harden workflows and override vulnerable transitive dependencies ci: harden GitHub Actions workflows Jul 29, 2026
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