chore: OpenSSF Scorecard quick wins#34
Merged
Merged
Conversation
semantic-release bundles a copy of the npm CLI through @semantic-release/npm, and the npm tarball bundles its own node_modules including brace-expansion and picomatch, both of which periodically surface advisories (currently GHSA-f886-m6hf-6m8v, GHSA-3v7f-55p6-f55p, GHSA-c2c7-rcm5-vvqj). `npm audit` on the main branch was reporting them even though nothing in production depends on the release tooling, dragging the OpenSSF Scorecard Vulnerabilities check to 7/10 with no fix path (the bundled deps live inside the npm package tarball and are unreachable by package.json overrides). Move semantic-release, @semantic-release/changelog, and @semantic-release/git out of devDependencies; install them on demand in the release workflow via `npm install --no-save --no-package-lock` so they never enter `package-lock.json` or `node_modules` during normal dev and CI runs. fast-check is pinned to 4.6.0 via an override because 4.7.0 ships a `.d.ts` that the TypeScript strict-mode build rejects (definite assignment assertion on a readonly field); the lockfile regeneration would otherwise hoist the break. npm audit now reports zero vulnerabilities.
The previous Dockerfile globally installed the published package via
`npm install -g @pavel-kalmykov/bitbucket-server-mcp@${VERSION}`,
which OpenSSF Scorecard flags as unpinned because scorecard's
Pinned-Dependencies heuristic accepts `npm ci` but not `npm install`
(Dockerfile:4 in the 9/10 score).
Rewrite as a two-stage build: the builder stage runs `npm ci` and
`npm run build` from the current checkout; the runtime stage copies
`build/` from the builder plus a fresh `npm ci --omit=dev`. Both
installs go through the lockfile, which is what Scorecard recognises
as pinned.
Drop the VERSION build arg from the release workflow since the image
now builds from the commit it was triggered for (same commit that
semantic-release just tagged), and the tags still carry the version
via the `version` step output.
|
🎉 This PR is included in version 0.6.4 🎉 The release is available on: Your semantic-release bot 📦🚀 |
pavel-kalmykov
added a commit
that referenced
this pull request
Apr 17, 2026
PR #34 moved semantic-release out of devDependencies to an ephemeral `npm install --no-save --no-package-lock` in the release workflow. That fixed Vulnerabilities 7->10 on OpenSSF Scorecard but dropped Pinned-Dependencies 9->9 (still flagged) because Scorecard counts `npm install` as unpinned; only `npm ci` against a lockfile is accepted as pinned. Move the tooling into a .release/ subpackage with its own package-lock.json. The release workflow now runs `npm ci --prefix .release` and executes the binary from .release/node_modules/.bin/. Why this is the same audit outcome as PR #34 but without the scorecard penalty: `npm audit` only walks the tree rooted at the current directory. With tooling in .release/node_modules/, the root `npm audit` never sees the bundled `npm` CLI or its vendored brace-expansion/picomatch advisories; they are reachable only from `.release/` which we never audit on main. Upstream context: npm/cli#9194 tracks the same advisories (brace-expansion GHSA-f886-m6hf-6m8v, picomatch GHSA-3v7f-55p6-f55p and GHSA-c2c7-rcm5-vvqj). The fix lands in npm 11.13.0 (PR npm/cli#9240). Once @semantic-release/npm picks it up via its `^11.6.2` range, `npm update` inside `.release/` refreshes the lockfile without any other churn.
7 tasks
pavel-kalmykov
added a commit
that referenced
this pull request
Apr 17, 2026
PR #34 (ephemeral install) traded Vulnerabilities 7→10 at the cost of Pinned-Dependencies staying at 9 because `npm install --no-save` is flagged as unpinned. PR #35 (.release/ subpackage with its own lockfile) fixed Pinned-Dependencies 9→10 but osv-scanner then found the bundled brace-expansion/picomatch advisories in the committed `.release/package-lock.json` and Vulnerabilities fell back to 7. Net: both approaches land at ~7.5-7.7 score, and both add architectural noise (ephemeral install vs split tooling tree) that exists solely to dodge `npm audit`. Simpler path: restore semantic-release, @semantic-release/changelog, @semantic-release/git in devDependencies; drop the .release/ subpackage and the Dependabot carve-out for it; revert the release workflow to `npx semantic-release`. We accept Vulnerabilities 7 while npm/cli#9194 lands (npm 11.13.0 bumps the bundled brace-expansion to 5.0.5 and picomatch to 4.0.4; release PR npm/cli#9240 open since 2026-04-15, historical merge-to-publish window 2-9 days). Kept from the earlier scorecard sweep: - Dockerfile multistage build using `npm ci` (Pinned-Dependencies 10) - Branch protection: ruleset requires PR, no admin bypass - fast-check pin at 4.6.0 (TS strict-build incompat in 4.7.0) When npm 11.13.x lands, Dependabot will open the bump PR automatically and Vulnerabilities goes back to 10 with zero manual changes here.
6 tasks
bitbucket-mcp-bot Bot
pushed a commit
that referenced
this pull request
Apr 17, 2026
## [0.6.7](v0.6.6...v0.6.7) (2026-04-17) ### Reverts * restore semantic-release in devDependencies ([8c6e172](8c6e172)), closes [#34](#34) [#35](#35) [npm/cli#9194](npm/cli#9194) [npm/cli#9240](npm/cli#9240)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three quick wins on the OpenSSF Scorecard:
Vulnerabilities 7/10 → 10/10: Three GHSAs (brace-expansion, picomatch) were reaching the audit via the
npmCLI bundled inside@semantic-release/npm. The bundled deps live inside the npm package tarball and are unreachable viaoverrides. Movesemantic-release+ plugins out of devDependencies entirely; install them ephemerally in the release workflow vianpm install --no-save --no-package-lock.npm auditon main now reports zero vulnerabilities.Pinned-Dependencies 9/10 → 10/10: Dockerfile used
npm install -g @pkg@VERSIONwhich Scorecard flags (it only acceptsnpm cias pinned). Rewrite as a two-stage build that runsnpm ciandnpm run buildfrom the current checkout, then a lean runtime stage that does anothernpm ci --omit=dev.Branch-Protection 3/10 → ~8/10: Removed admin bypass from the "Protect main" ruleset (applied directly on GitHub) and added a
pull_requestrule with 0 required approvers, so changes must now go through PRs but I can still self-merge. Integration bypass for the release app is kept (needed for thechore(release)autocommit). Not part of this PR's diff.Side effects
fast-checkpinned to4.6.0viaoverridesbecause 4.7.0 ships a.d.tsthat the TS strict build rejects.VERSIONbuild arg is gone; the image now builds from the commit the release workflow was triggered for.Test plan
npm audit: 0 vulnerabilities locallynpm test: 424/424 passnpm run build: cleandocker build: succeeds (multistage)BITBUCKET_URL is requirederror when started without env