Skip to content

getjerry/npm-cooldown

Repository files navigation

npm-cooldown

npm version License: ISC

A security tool to prevent supply chain attacks by enforcing package age requirements for new and updated npm dependencies.

Overview

npm-cooldown protects your projects from potential supply chain attacks by ensuring that newly added or updated packages have been available for a minimum period before installation. This "cooling-off" period helps avoid packages that might contain malicious code that hasn't been discovered yet.

Key Features

  • 🔒 Supply Chain Protection: Blocks installation of packages that are too new
  • 📊 Multiple Lockfile Support: Works with npm, yarn, and pnpm lockfiles
  • 🎯 Flexible Comparisons: Compare local files, git HEAD, or specific commits
  • ⚙️ Configurable Age Requirements: Set custom minimum package age in days
  • 🔍 Dependency Graph Analysis: Uses Snyk's dependency graph parser for accurate analysis
  • 📝 Comprehensive Logging: Clear feedback on what packages are blocked and why
  • 🧪 Effect.js Integration: Built with Effect.js for robust error handling and composition

Installation

npm install -g npm-cooldown

Or use with npx:

npx npm-cooldown

Usage

Basic Usage

# Compare local package.json/lockfile with git HEAD
npm-cooldown

# Set minimum age requirement to 7 days
npm-cooldown --min-age 7

# Compare specific git revisions
npm-cooldown --source head --target local
npm-cooldown --source abc123 --target def456

Command Line Options

Option Description Default
--min-age <days> Minimum package age in days 3
--source <revision> Source revision: 'local', 'head', or commit hash 'local'
--target <revision> Target revision: 'local', 'head', or commit hash 'head'
--lockfile <path> Path to lockfile (auto-detected if not specified) Auto-detected
--manifest <path> Path to package.json './package.json'
--registry <url> NPM registry URL 'https://registry.npmjs.org'
--help Show help message

Examples

CI/CD Integration

# In your CI pipeline, compare what's in the repository with local changes
npm-cooldown --source head --target local --min-age 7

Pre-commit Hook

# Check if any new dependencies are too fresh
npm-cooldown --min-age 3

Yarn/PNPM Projects

# Works automatically with yarn.lock
npm-cooldown --min-age 5

# Works automatically with pnpm-lock.yaml
npm-cooldown --min-age 5

How It Works

  1. Detects Lockfile Type: Automatically identifies whether you're using npm, yarn, or pnpm
  2. Reads Source & Target Files: Retrieves lockfiles and manifests from filesystem or git
  3. Parses Dependency Graphs: Uses Snyk's lockfile parser to build dependency graphs
  4. Compares Dependencies: Identifies added or updated packages between revisions
  5. Checks Package Ages: Queries the npm registry for package publish dates
  6. Validates Age Requirements: Blocks packages that don't meet the minimum age requirement

Integration with Package Managers

npm

Add to your package.json scripts:

{
  "scripts": {
    "preinstall": "npm-cooldown",
    "security-check": "npm-cooldown --min-age 7"
  }
}

Husky Git Hooks

# Install husky
npm install --save-dev husky

# Add pre-commit hook
npx husky add .husky/pre-commit "npm-cooldown"

GitHub Actions

name: Security Check
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0 # Full git history needed for comparisons

      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install npm-cooldown
        run: npm install -g npm-cooldown

      - name: Check dependency ages
        run: npm-cooldown --source origin/main --target HEAD --min-age 7

Configuration

Environment Variables

  • NPM_REGISTRY_URL: Default registry URL
  • TMPDIR: Temporary directory for file operations

Whitelisting Packages

Currently, package whitelisting is not implemented via CLI but can be configured programmatically:

import { validatePackages } from 'npm-cooldown';

const config = {
  minAgeHours: 72, // 3 days
  whitelistedPackages: ['trusted-package', '@company/internal-package'],
  registryUrl: 'https://registry.npmjs.org',
};

Error Handling

The tool exits with different codes based on the outcome:

  • 0: All dependencies pass age requirements
  • 1: One or more dependencies are too new or other errors occurred

Common error scenarios:

  • Lockfile not found: Ensure your project has a lockfile (package-lock.json, yarn.lock, or pnpm-lock.yaml)
  • Git revision not found: Verify the specified commit hash or branch exists
  • Registry errors: Check network connectivity and registry URL
  • Package not found: Some packages might not exist in the registry

API Usage

You can also use npm-cooldown programmatically:

import { Effect } from 'effect';
import { getFiles } from 'npm-cooldown/get-file';
import { parseLockfile } from 'npm-cooldown/parse-lockfile';
import { compareDepGraphs } from 'npm-cooldown/compare-dep-graphs';

const program = Effect.gen(function* () {
  // Get lockfiles from local and HEAD
  const [sourceFiles, targetFiles] = yield* Effect.all([
    getFiles('package-lock.json', 'package.json', 'local'),
    getFiles('package-lock.json', 'package.json', 'head'),
  ]);

  // Parse dependency graphs
  const [sourceGraph, targetGraph] = yield* Effect.all([
    parseLockfile(sourceFiles[0], sourceFiles[1], 'package-lock.json'),
    parseLockfile(targetFiles[0], targetFiles[1], 'package-lock.json'),
  ]);

  // Compare graphs
  const differences = yield* compareDepGraphs(sourceGraph, targetGraph);

  return differences;
});

Effect.runPromise(program).then(console.log);

Security Considerations

What npm-cooldown Protects Against

  • Typosquatting attacks: Malicious packages with names similar to popular packages
  • Account takeovers: Compromised maintainer accounts publishing malicious updates
  • Dependency confusion: Internal packages being overshadowed by public packages
  • Zero-day supply chain attacks: Newly published malicious packages

Limitations

  • Does not scan existing packages: Only checks new/updated dependencies
  • Age-based protection only: Does not perform static analysis or vulnerability scanning
  • Registry dependency: Requires access to npm registry for age verification
  • Bypass potential: Developers can override with direct package installation

Best Practices

  1. Use in CI/CD: Integrate into your continuous integration pipeline
  2. Combine with other tools: Use alongside vulnerability scanners and license checkers
  3. Regular updates: Keep npm-cooldown updated for the latest security improvements
  4. Team education: Ensure team understands why package age matters
  5. Emergency procedures: Have a process for urgent package updates when needed

Troubleshooting

Common Issues

Error: "No lockfile found"

# Ensure you have a lockfile in your project
npm install  # Creates package-lock.json
# or
yarn install  # Creates yarn.lock
# or
pnpm install  # Creates pnpm-lock.yaml

Error: "Git revision not found"

# Make sure you're in a git repository and the revision exists
git status
git log --oneline -n 5

Error: "Failed to fetch metadata"

# Check your network connection and registry access
npm ping
# or use a different registry
npm-cooldown --registry https://your-private-registry.com

Debug Mode

For verbose output, you can examine the source code or add logging. The tool uses Effect.js for structured error handling.

Performance

  • Large projects: Processing time scales with the number of dependencies
  • Network dependency: Registry queries can be slow; results are cached
  • Git operations: Large repositories may have slower git operations

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/getjerry/npm-cooldown.git
cd npm-cooldown
npm install
npm run build
npm test

Running Tests

# Unit tests
npm test

# E2E tests with Verdaccio
npm run test:e2e

# Type checking
npm run typecheck

# Linting
npm run lint

License

ISC License - see LICENSE file for details.

Changelog

See CHANGELOG.md for version history and updates.

Security

If you discover a security vulnerability, please send an email to security@getjerry.com. All security vulnerabilities will be promptly addressed.

Credits


Made with ❤️ by the Jerry Security Team

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published