AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Dependency Pinning

skill-carlkibler-agent-skills-dependency-pinning · by carlkibler

Audit Docker, CI, and language dependencies for SHA/digest pinning and cooldowns.

— No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-carlkibler-agent-skills-dependency-pinning

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-carlkibler-agent-skills-dependency-pinning)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dependency Pinning? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Dependency Pinning

A dependency safety scan — not a CVE scan. It checks two things across every ecosystem in scope:

  1. Pinning — dependencies pinned to an immutable content SHA / digest, not a

movable tag. Tags can be silently re-pointed to altered or malicious artifacts (the tj-actions class of supply-chain attacks). A digest can't.

  1. Cooldown — a project never adopts an artifact newer than N days (default

7). A fresh release is where a compromise lands first; the cooldown buys time for it to be caught before it reaches the build.

Report first. Mutate only on explicit approval. Bumping a pin is itself risky, so every proposed change names the new SHA and flags it for a supply-chain check.

Scope

Ask what to scan if unclear: a single project, a list of repos, or "everything under ~/dev/work". Then discover dependency manifests:

ROOT="${1:-.}"
/usr/bin/find "$ROOT" -type d \( -name node_modules -o -name .git -o -name .terraform \
    -o -name vendor -o -name packages -o -name bin -o -name obj -o -path '*/assets/libs' \) -prune -o \
  -type f \( \
    -iname 'Dockerfile*' -o -name 'docker-compose*.y*ml' -o -name 'compose*.y*ml' \
    -o -path '*/.github/workflows/*.y*ml' \
    -o -name 'package.json' -o -name 'deno.json*' \
    -o -name 'pyproject.toml' -o -name 'requirements*.txt' \
    -o -name '*.csproj' -o -name 'packages.config' -o -name 'Directory.Packages.props' \
    -o -name 'Cargo.toml' -o -name 'go.mod' \
    -o -name 'pom.xml' -o -name 'build.gradle' -o -name 'build.gradle.kts' \
    -o -name 'Gemfile' -o -name '*.gemspec' \
    -o -name '*.tf' \
  \) -print 2>/dev/null
# Also catch images pulled from scripts/CI, not just Dockerfiles/compose:
grep -rEn 'docker (run|pull|build)[^|]*[a-z0-9./-]+:[a-z0-9._-]+' "$ROOT" \
  --include='*.sh' --include='*.y*ml' --include='Makefile' 2>/dev/null

Ignore vendored/minified asset trees (*/assets/**, *.min.*) — those package.json files are bundled libraries, not your declared dependencies.

What "good" looks like, how to detect violations, how to fix

Docker / Compose (pinning: required · cooldown: manual)

  • Good: FROM repo/img@sha256: · image: repo/img@sha256:
  • Bad: :latest, floating tags, no digest.
  • Detect: grep -rEn '^\s*FROM |image:\s' → flag any ref without @sha256:.

Also scan scripts/CI/Makefiles for docker run|pull|build ... img:tag — images pulled outside Dockerfiles/compose are easy to miss and just as swappable.

  • Fix: resolve the digest of a tag that is ≥ N days old:

docker buildx imagetools inspect repo/img: --format '{{.Manifest.Digest}}' then write repo/img@sha256: # .

  • Cooldown: no native support — enforce by choosing a digest for an old-enough tag.

GitHub Actions (pinning: required · cooldown: via tooling)

  • Good: uses: owner/repo@ # vX.Y.Z
  • Bad: @v4, @main, @.
  • Detect: grep -rEn 'uses:\s' .github/workflows → flag any ref not matching a 40-char hex SHA.
  • Fix: git ls-remote https://github.com// refs/tags/ → SHA; pin with the version in a trailing comment.
  • Cooldown / automation: ratchet (sethvargo/ratchet) or pinact pin+update actions by SHA;

Renovate/Dependabot minimumReleaseAge / cooldown gates the version that gets pinned.

JavaScript — npm / yarn / pnpm / bun / deno (pinning: lockfile · cooldown: tooling)

  • Good: lockfile committed (package-lock.json / yarn.lock / pnpm-lock.yaml /

bun.lock / deno.lock) with integrity hashes, and CI installs frozen (npm ci, pnpm i --frozen-lockfile, yarn --immutable, deno install --frozen).

  • Bad: no lockfile committed; relying on ^/~/latest without a lock; npm install in CI.
  • Detect: manifest present but lockfile missing/gitignored; CI using non-frozen installs.
  • Fix: generate + commit the lockfile; switch CI to the frozen install command.
  • Cooldown: pnpm has native minimumReleaseAge (config/.npmrc). For npm/yarn/bun,

add Renovate minimumReleaseAge: "7 days" (or Dependabot cooldown). Deno: pin exact versions in import map / deno.json; deno.lock carries integrity.

Python — uv / pdm / poetry / pip (pinning: lockfile+hashes · cooldown: uv native / tooling)

  • Good: lockfile committed with hashes (uv.lock, pdm.lock, poetry.lock) and

installed locked (uv sync --locked, pdm sync, poetry install); for bare pip, hashed pins via pip-compile --generate-hashes + pip install --require-hashes.

  • Bad: unpinned/>=/* requirements, no lockfile, no hashes.
  • Detect: pyproject.toml/requirements.txt present but no lockfile/hashes; ranges without a lock.
  • Fix: adopt a lock workflow or generate hashed requirements; commit the lock.
  • Cooldown: uv has native exclude-newer / UV_EXCLUDE_NEWER (resolve as of a date —

a true cooldown). Otherwise Renovate minimumReleaseAge.

.NET — NuGet (pinning: exact versions + lockfile · cooldown: tooling)

  • Good: exact versions (packages.config version="x.y.z", or ` with no range/) **plus a committed packages.lock.json`*

(enable true, restore with dotnet restore --locked-mode). The lockfile carries contentHash per package.

  • Bad: floating versions (Version="*", Version="[1.0,)"), no lockfile, packages

restored from a non-pinned feed.

  • Detect: grep -rEn 'Version="\*"|Version="\[' **/*.csproj; .csproj/packages.config

present but no packages.lock.json beside it; check Directory.Packages.props for central versions if used.

  • Fix: pin exact versions; enable + commit packages.lock.json; pin the feed in

nuget.config.

  • Cooldown: no native NuGet cooldown — use Renovate minimumReleaseAge (NuGet supported).

Rust — Cargo · Go · Java (Maven/Gradle) · Ruby (Bundler)

Terser, but the same two questions apply (immutable pin? cooldown?):

  • Rust/Cargo: commit Cargo.lock (carries crates.io sha256 checksums); cargo --locked.

No native cooldown → Renovate minimumReleaseAge (cargo datasource). cargo audit/cargo vet adjacent.

  • Go modules: go.mod + go.sum (cryptographic hashes, verified vs the checksum DB);

go mod verify, build with -mod=readonly. No native cooldown → Renovate (gomod).

  • Java/Maven: pin exact versions in pom.xml — ban LATEST/RELEASE/version ranges

(enforce with maven-enforcer requireReleaseDeps / ban-dynamic-versions). No lockfile natively.

  • Java/Gradle: enable dependency locking (gradle.lockfile) + verification metadata

(gradle --write-verification-metadata sha256 → verification-metadata.xml with checksums/signatures).

  • Ruby/Bundler: commit Gemfile.lock; bundle config set frozen true; add checksums with

bundle lock --add-checksums (Bundler 2.5+). No native cooldown → Renovate (bundler).

  • Cooldown across all of the above is best delivered by Renovate minimumReleaseAge /

Dependabot cooldown, which support these datasources.

Any other ecosystem you encounter (general rule)

Don't stop at the languages listed here. For any package manager in the target:

  1. Identify the manifest + its lockfile; confirm the lockfile carries **integrity

hashes and is committed, and that CI installs frozen/locked**.

  1. Flag floating/range/latest version specifiers in the manifest.
  2. Research whether that manager supports a cooldown — native settings first

(names vary: minimumReleaseAge, exclude-newer, --as-of, min-age, quarantine), then a meta-tool (Renovate minimumReleaseAge / Dependabot cooldown) for that datasource. If unsure, check the tool's current docs rather than guessing.

  1. Report findings the same way and propose the concrete setting to add.

Terraform (pinning: lock + version constraints)

  • Good: .terraform.lock.hcl committed with multi-platform hashes

(terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 ...); providers pinned in required_providers; modules pinned by version or git commit SHA; AMIs/data sources pinned by ID (no most_recent = true).

  • Bad: lock gitignored, missing platforms, most_recent = true, modules on main.
  • Detect: lock in .gitignore; grep -rn 'most_recent\s*=\s*true' *.tf; module sources on a branch.
  • Fix: un-ignore + commit the lock (multi-platform); pin module/AMI refs.

Adding cooldowns where supported (offer these)

  • Renovate (cross-ecosystem): "minimumReleaseAge": "7 days" in renovate.json — the

single best lever; gates npm/pip/docker/actions/etc. behind the cooldown.

  • Dependabot: cooldown: block in .github/dependabot.yml.
  • pnpm: minimumReleaseAge · uv: exclude-newer · GH Actions: ratchet/pinact.

Report format

DEPENDENCY SAFETY REPORT  (cooldown target: 7 days)
===================================================

  Docker        : 2 images unpinned (FROM node:20, postgres:16) — PIN MISSING
  GH Actions    : 3 actions on tags (@v4) — PIN MISSING
  JS (pnpm)     : lockfile committed ✓ · no cooldown — COOLDOWN MISSING
  Python (uv)   : uv.lock ✓ · exclude-newer not set — COOLDOWN MISSING
  Terraform     : .terraform.lock.hcl gitignored — LOCK NOT COMMITTED
  ...
SUMMARY: 4 pin gaps, 3 cooldown gaps, 1 uncommitted lock across N repos.

Classify each as: OK · PIN MISSING · COOLDOWN MISSING · LOCK NOT COMMITTED. Then list exact fixes (the resolved SHA/digest, the config snippet) per item.

Action rules

  • Default to read-only. Do not edit files, run installers, or commit until the user approves.
  • When approved, change one ecosystem at a time; show the diff.
  • Every pin bump names the new SHA/digest and reminds the user to do a supply-chain

check and respect the cooldown (no artifact newer than N days).

  • Never weaken an existing pin. Never add a :latest/floating ref as a "fix".
  • Keep the human-readable version in a trailing comment beside every SHA pin.
  • Commit lockfiles — never gitignore them.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.