Skip to content

chore: generate and publish npm-shrinkwrap.json to lock full dependency tree#563

Open
jonathannorris wants to merge 2 commits intomainfrom
chore-npm-shrinkwrap
Open

chore: generate and publish npm-shrinkwrap.json to lock full dependency tree#563
jonathannorris wants to merge 2 commits intomainfrom
chore-npm-shrinkwrap

Conversation

@jonathannorris
Copy link
Copy Markdown
Member

@jonathannorris jonathannorris commented Apr 3, 2026

Summary

  • Adds npm-shrinkwrap.json generation to the publish pipeline via a new prepack step, locking the full transitive dependency tree to the exact versions resolved at build time
  • Pins all 27 production dependencies to exact versions (removing ^ and ~ ranges) as defense-in-depth
  • scripts/generate-shrinkwrap.js handles the full flow: generates the lockfile via npm install --package-lock-only, converts it to shrinkwrap, strips workspace entries (mcp-worker), and protects yarn.lock from npm's Berry-incompatible rewrite via a save/restore in a finally block

Motivation

package.json already listed /npm-shrinkwrap.json in the files array but the file was never generated, so consumers running npm install -g @devcycle/cli resolved all caret-ranged transitive deps to whatever was latest at install time. This is the same class of exposure that let the malicious axios@1.14.1 reach users on March 31. Pinning axios directly in 6.3.0 only covers one package; the shrinkwrap covers the full tree.

@jonathannorris jonathannorris requested a review from a team as a code owner April 3, 2026 21:09
Copilot AI review requested due to automatic review settings April 3, 2026 21:09
@jonathannorris jonathannorris requested a review from JamieSinn April 3, 2026 21:11
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
devcycle-mcp-server 8b3a95f Apr 03 2026, 09:11 PM

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automated npm-shrinkwrap.json generation during publish to fully lock the transitive dependency tree shipped to npm consumers, and pins direct production dependencies to exact versions.

Changes:

  • Add a prepack step to generate npm-shrinkwrap.json (and adjust postpack cleanup).
  • Pin production dependencies in package.json (and update yarn.lock accordingly).
  • Add helper scripts for shrinkwrap generation and (future) verification; ignore generated artifacts in .gitignore.

Reviewed changes

Copilot reviewed 3 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
yarn.lock Updates lock entries to reflect newly pinned dependency versions/ranges.
scripts/verify-shrinkwrap.js New verifier/cleaner for shrinkwrap contents vs installed node_modules (not wired yet).
scripts/generate-shrinkwrap.js New generator invoked from prepack to create shrinkwrap while protecting yarn.lock.
package.json Adds shrinkwrap generation to prepack, expands postpack cleanup, pins dependencies, adds shrinkwrap script.
.gitignore Ignores generated shrinkwrap/lock artifacts and yarn.lock backup file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +67
} catch (err) {
console.error('Error during shrinkwrap generation:', err.message)
process.exit(1)
} finally {
// Always restore yarn.lock. npm operations rewrite it to Yarn v1 format,
// which corrupts the Yarn Berry lockfile used for development.
restoreYarnLock()
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

process.exit(1) inside the catch prevents the finally block from running, so yarn.lock may remain in the corrupted Yarn v1 format if npm install/npm shrinkwrap fails. Instead, capture the error, restore yarn.lock in finally, then exit (e.g., set process.exitCode = 1 and return, or rethrow after finally).

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +57
execSync('npm install --package-lock-only --ignore-scripts', {
cwd: ROOT,
stdio: 'inherit',
})

console.log('Converting package-lock.json to npm-shrinkwrap.json...')
execSync('npm shrinkwrap', {
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This script claims to generate shrinkwrap for production deps only (and verify-shrinkwrap.js assumes --omit=dev), but the npm commands here don't omit dev dependencies. That will include dev packages in package-lock.json/npm-shrinkwrap.json and can publish a larger-than-intended dependency tree. Add --omit=dev (and ensure it applies to both the lock generation and shrinkwrap conversion).

Suggested change
execSync('npm install --package-lock-only --ignore-scripts', {
cwd: ROOT,
stdio: 'inherit',
})
console.log('Converting package-lock.json to npm-shrinkwrap.json...')
execSync('npm shrinkwrap', {
execSync('npm install --package-lock-only --ignore-scripts --omit=dev', {
cwd: ROOT,
stdio: 'inherit',
})
console.log('Converting package-lock.json to npm-shrinkwrap.json...')
execSync('npm shrinkwrap --omit=dev', {

Copilot uses AI. Check for mistakes.
Comment on lines +131 to +135
// Skip @types/* packages: pure TypeScript type definitions, stripped at
// compile time and absent from the distributed dist/ output. Version
// differences have no runtime or security impact.
if (pkgName.startsWith('@types/')) continue

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

The script skips @types/* packages while asserting they have “no runtime or security impact”. Even though they’re type-only at runtime, they are still installed by consumers and could theoretically contain install scripts or malicious payloads. Consider including @types/* in verification, or at minimum adjust the comment/output so it doesn’t claim there is no security impact.

Copilot uses AI. Check for mistakes.
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.

3 participants