managing-dependencies

📁 andrew/managing-dependencies 📅 9 days ago
1
总安装量
1
周安装量
#52156
全站排名
安装命令
npx skills add https://github.com/andrew/managing-dependencies --skill managing-dependencies

Agent 安装分布

claude-code 1

Skill 文档

Package Management

Before suggesting any package, verify it exists on the registry. Check that the name, maintainer, and purpose match expectations. Do not hallucinate package names.

Decline to:

  • Suggest a package that cannot be verified to exist
  • Add a dependency when stdlib provides equivalent functionality
  • Run install scripts without explicit user approval
  • Auto-merge updates that violate the safety criteria below

If verification fails (registry unreachable, metadata incomplete, provenance missing), default to refusal and explain why.

Before Adding a Dependency

Check in order:

  1. Standard library – Does the language already provide this? (e.g., date parsing, HTTP, JSON)
  2. Transitive cost – How many dependencies does it bring? Check with npm ls, pip show, bundle info, cargo tree
  3. Smaller alternative – Is there a focused package that does just what’s needed?
  4. Inline it – Can you write 20-50 lines instead of adding a dependency?

When in doubt, don’t add. PRs that only remove dependencies are usually good PRs.

Always clarify if a dependency is for development only (--save-dev, group :development, [tool.poetry.group.dev.dependencies]) to minimize the production attack surface.

Evaluating a Package

For quick checks, visit the package’s registry page and repo. When you need depth:

# Any ecosystem via ecosyste.ms
curl -s "https://packages.ecosyste.ms/api/v1/registries/<registry>/packages/<package>" | jq '{
  dependent_repos: .dependent_repos_count,
  dependent_packages: .dependent_packages_count,
  latest: .latest_release_number,
  latest_release: .latest_release_published_at,
  created: .first_release_published_at,
  maintainers: (.maintainers | length),
  repo: .repository_url,
  license: .normalized_licenses,
  advisories: (.advisories | length),
  archived: .repo_metadata.archived
}'
# See API Reference below for full registry list

Good signals:

  • High dependent count (other packages trust it)
  • Few direct dependencies
  • Responsive issue tracker
  • Multiple maintainers
  • OSI-approved license
  • Provenance attestation (see below)

Less reliable signals:

  • GitHub stars (gameable)
  • Download counts (gameable)
  • Commit frequency (stable packages don’t need commits)
  • Contributor count

Red flags:

  • Package less than 90 days old
  • Maintainer account created recently
  • Name similar to popular package (typosquatting)
  • No license or non-OSI license
  • Vendors copies of common dependencies
  • Very few downloads for claimed purpose
  • Runs code on install (postinstall scripts, setup.py)

OpenSSF Scorecard – check project security practices:

scorecard --repo=github.com/owner/repo
# Or visit: https://securityscorecards.dev

Score below 5 warrants a closer look, though small or mature projects often score lower without being risky. If Maintained or Dangerous-Workflow scores are below 3, flag as higher risk.

Typosquatting Patterns

Watch for these when verifying package names:

  • Character substitution: djang0 vs django, requets vs requests
  • Character omission: loadsh vs lodash, electon vs electron
  • Homoglyphs: pyp1 (one) vs pypi (letter i), Cyrillic а vs Latin a
  • Delimiter variation: cross-env vs crossenv vs cross_env
  • Scope confusion: @angular-devkit/core vs @angulardevkit/core
  • Combosquatting: lodash-js, axios-api, express-utils
  • Namespace confusion (Maven): org.fasterxml vs com.fasterxml

Always copy package names from official docs rather than typing from memory.

AI-Suggested Packages (Slopsquatting)

AI coding assistants hallucinate package names regularly. Attackers register these names with malicious code.

Before installing any AI-suggested package:

  1. Verify it exists: npm view <package> or pip index versions <package>
  2. Check age and downloads: Very new + few downloads = suspect
  3. Cross-reference docs: Does the framework’s official docs mention it?
  4. Check for typosquatting: See patterns above

Hallucinated names are often repeatable across sessions, making them predictable targets for attackers.

Dependency Confusion

When using both public and private registries, attackers can publish public packages matching your internal package names with high version numbers.

Defenses:

Use scoped/namespaced packages for internal code:

# npm - attackers can't register under your scope
@yourcompany/internal-utils

# Configure scope to route to private registry
# .npmrc
@yourcompany:registry=https://your-internal-registry.com

For pip, use --index-url for private registry, --extra-index-url for PyPI:

# Correct - private registry checked first
pip install --index-url https://private.example.com/simple \
            --extra-index-url https://pypi.org/simple \
            mypackage

Defensively register your internal package names on public registries with placeholder packages.

Provenance and Attestation

Check if a package has verified build provenance:

# npm - check for attestation
npm audit signatures

# PyPI - check for Sigstore attestation
curl -s "https://pypi.org/pypi/<package>/json" | jq '.urls[0].digests'
# Look for attestation bundle in release assets

# GitHub Actions - verify with gh
gh attestation verify <artifact> --owner <org>

Trusted publishing means the package was published directly from CI (GitHub Actions, GitLab CI) without maintainer credentials. The registry verifies the source via OIDC. npm, PyPI, and RubyGems support this.

If a package has provenance, you can verify the published artifact matches the source repo and commit. Support varies by ecosystem; absence of attestation doesn’t mean insecure.

Version Constraints

Applications: Use ranges in manifest, pin via lockfile.

Libraries: Use wide ranges. Don’t force consumers to upgrade.

Ecosystem Exact Flexible Patch only
npm/Cargo 1.0.0 ^1.0.0 ~1.0.0
Bundler = 1.0.0 ~> 1.0 ~> 1.0.0
pip ==1.0.0 ~=1.0
Go v1.2.3 MVS MVS

Bundler’s ~> is commonly misread: ~> 1.0 allows 1.x (minor updates), ~> 1.0.0 allows 1.0.x (patch only).

Go uses minimal version selection – it picks the minimum version satisfying all requirements. Don’t vendor specific versions or use replace directives to simulate ranges.

Lockfiles

Always commit lockfiles.

Detect ecosystem:

  • package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lock → npm
  • Gemfile.lock → Bundler
  • Cargo.lock → Cargo
  • poetry.lock / uv.lock / requirements.txt with hashes → Python
  • go.sum → Go

In CI, install from lockfile (don’t regenerate):

npm ci                    # not npm install
pip install --require-hashes -r requirements.txt
bundle install --frozen
cargo build --locked
uv sync --frozen
go mod verify

Review lockfile changes in PRs:

  • Watch for changes to resolved URLs (lockfile injection attack)
  • Large diffs can hide malicious additions
  • Unexpected registry URL changes are red flags

Regenerate on conflict rather than manually merging:

# npm
rm package-lock.json && npm install

# Bundler
rm Gemfile.lock && bundle install

# Cargo
rm Cargo.lock && cargo generate-lockfile

# Poetry
rm poetry.lock && poetry lock

# uv
rm uv.lock && uv lock

Security Audits

Run in CI and before adding dependencies:

# npm
npm audit

# Bundler (install bundler-audit gem first)
bundle audit check --update

# pip (install pip-audit first)
pip-audit

# Cargo (install cargo-audit first)
cargo audit

# Go
govulncheck ./...

When Vulnerability Has No Patch

First check reachability: is the vulnerable code path actually called by your usage? Many CVEs affect features you don’t use.

Options in order of preference:

  1. Override transitive – Force newer version of vulnerable transitive dependency
  2. Fork and patch – Apply security fix to fork, reference fork in manifest
  3. Remove dependency – Find alternative or inline the functionality
  4. Accept risk – Document why it’s not exploitable in your context

Vendoring

Copy dependencies into your repo for airgapped environments, auditing, or when you need to patch upstream:

# Go - built-in
go mod vendor
go build -mod=vendor

# Ruby
bundle package --all
bundle install --local

# Python (pip download, then install offline)
pip download -r requirements.txt -d ./vendor
pip install --no-index --find-links=./vendor -r requirements.txt

# npm (less common, use npm-pack-all or similar)

Vendoring trades registry availability risk for increased repo size and manual update burden. Justified for airgapped builds, audited security-critical code, or long-term forks you maintain.

Check Licenses

# npm
npx license-checker --summary

# pip
pip-licenses

# Bundler
bundle licenses

# Cargo
cargo license

Safe: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense

Review needed: LGPL, MPL-2.0

Copyleft (affects distribution): GPL, AGPL

No license = not open source – do not use.

Install Scripts

Package managers execute code during install – a common attack vector:

  • npm: preinstall, postinstall in package.json
  • pip: setup.py runs during install
  • Ruby: extconf.rb for native extensions

Audit before allowing scripts:

# npm - install without running scripts, then review
npm install --ignore-scripts
# After reviewing, run scripts explicitly
npm rebuild

For high-security environments, consider disabling install scripts globally and allowlisting specific packages.

GitHub Actions

Actions are dependencies too. Pin to commit SHA, not tags:

# Bad - tag can be moved
- uses: actions/checkout@v4

# Good - immutable reference
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

Use Dependabot or Renovate to keep pinned SHAs updated.

Automated Updates

Tool Platform Best for
Dependabot GitHub only Simple needs, free
Renovate Multi-platform Complex configs, monorepos
Snyk Multi-platform Security-first, vulnerability focus

Safe auto-merge criteria (all must apply):

  • Patch updates only (not minor/major)
  • Dev dependencies only
  • Established, trusted packages
  • All CI checks pass
  • Package available 3+ days (catches quick reverts of bad releases)

Never auto-merge:

  • Major version updates
  • Production dependencies
  • New packages not yet in your codebase
  • Security-sensitive packages (crypto, auth)

Example Renovate config for conservative auto-merge:

{
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"],
      "matchDepTypes": ["devDependencies"],
      "automerge": true,
      "minimumReleaseAge": "3 days"
    }
  ]
}

API Reference

ecosyste.ms

curl -s "https://packages.ecosyste.ms/api/v1/registries/<registry>/packages/<package>" | jq

Registries: npmjs.org, pypi.org, rubygems.org, crates.io, proxy.golang.org, nuget.org, repo1.maven.org, cocoapods.org, hub.docker.com

Risk Thresholds

Field Threshold Risk
latest_release_published_at >2 years ago Possibly abandoned
dependent_repos_count <500 Low adoption
first_release_published_at <90 days ago Too new
maintainers (length) <2 Bus factor risk
versions_count =1 Immature
repo_metadata.archived true Abandoned
advisories non-empty Known vulnerabilities

Development Distribution Score

Found at .repo_metadata.metadata.development_distribution_score. Measures commit distribution across contributors (0-1).

  • <0.15 – Single contributor dominance (high bus factor)
  • 0.15-0.5 – Moderate distribution
  • >0.5 – Well distributed

OpenSSF Scorecard API

curl -s "https://api.scorecard.dev/projects/github.com/<owner>/<repo>" | jq '{
  score: .score,
  maintained: (.checks[] | select(.name == "Maintained") | .score),
  dangerous_workflow: (.checks[] | select(.name == "Dangerous-Workflow") | .score),
  code_review: (.checks[] | select(.name == "Code-Review") | .score)
}'

Human-readable: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/<owner>/<repo>

deps.dev API

Alternative for dependency graph analysis:

curl -s "https://api.deps.dev/v3/systems/<ecosystem>/packages/<package>" | jq

Ecosystems: npm, pypi, cargo, go, maven, nuget


About This Skill