Skip to content

temporal-community/dependency-scout

Repository files navigation

Dependency Scout

You have 47 unreviewed Dependabot PRs. It’s midnight, CI is green, and you’ve merged dozens of these before. And yet...

Maintainers aren’t careless — they’re exhausted. And modern supply-chain attacks are specifically designed to slip past smart, well-intentioned humans doing their best under impossible workloads.

This tool gives every dependency PR a data-backed second opinion before it merges.

What it checks:

  • Known vulnerabilitiesOSV database (includes OpenSSF malicious-packages) and the NIST NVD (catches freshly-disclosed CVEs before OSV ingests them)
  • Supply chain scoreSocket.dev for obfuscated code, install-time scripts, typosquatting
  • What code actually changed — diffs the package archives; flags new binaries, new install hooks, network calls, obfuscated code, git-URL dependencies
  • Release freshness — flags releases under 24h ("very fresh") or 7 days ("recent"); won't auto-merge anything under 7 days by default
  • Maintainer changes — a new account publishing a popular package is a classic attack vector
  • Build provenanceSLSA attestations; flags dropped tag signing and re-release patterns
  • Repo healthOpenSSF Scorecard for dangerous CI workflows, overprivileged tokens, maintenance status
  • Zombie packages — deprecated packages and patches to abandoned major version lines
  • Suspicious PR files — CI scripts or Dockerfiles in a "routine dep bump" are a red flag

Classifies 🟢 GREEN / 🟡 YELLOW / 🔴 RED, posts a comment explaining its reasoning, and takes action based on your config (or nothing if you haven't configured anything).

Ecosystems covered (15): pip/uv (Python), npm (JavaScript/TypeScript), RubyGems (Ruby), Maven/Gradle (Java/Kotlin), NuGet (.NET), Cargo (Rust), Go modules, Composer (PHP), Mix (Elixir/Hex), Pub (Dart), Elm, Swift, GitHub Actions, Docker, and Terraform.

Status: Experimental — self-hosted, bring your own keys. No shared infrastructure, no accounts, no sign-up.

See it in action

Single dependency run:

Running against requests 2.32.0 [pip] returns RED result due to pulled release

Running across PR queue:

Testing 24 PRs at once, with LLM-based classifier determining both security checks and merge-ability

Temporal UI running checks:

The Temporal UI shows each check as a discrete activity, and even if one call fails (such as Socket.dev in this case), the result returns anyway with the information it has

Posting comment to GitHub:

Sample comment showing checks

Install

Just want to check packages? No clone needed — install from PyPI:

# One-off: no install required
uvx dependency-scout check requests 2.32.0 --from 2.31.0 --ecosystem pip

# Persistent install
uv tool install dependency-scout
dependency-scout check requests 2.32.0 --from 2.31.0 --ecosystem pip

Want PR triage, auto-merge, or webhook mode? Those require a running Temporal worker — continue with the full setup below.


Quick start

You need Python 3.10+, uv, and the Temporal CLI.

git clone https://github.com/temporal-community/dependency-scout
cd dependency-scout
uv run python setup.py

The setup script checks prerequisites, explains the tradeoffs between a PAT and a GitHub App, lets you choose your LLM (Claude, OpenAI, Ollama, or skip), and writes .env.

The Temporal dev server runs entirely on your machine — no account, no payment, no sign-up:

# Terminal 1 — Temporal dev server
temporal server start-dev

# Terminal 2 — Scout worker
uv run python -m worker

# Terminal 3 — triage a single PR
uv run dependency-scout triage https://github.com/your-org/your-repo/pull/123

Open http://localhost:8233 to watch the workflow run. With GITHUB_TOKEN set, the Scout posts a comment directly on the PR — here's a real example.

No API keys needed to start — the rule-based classifier runs entirely locally. Without GITHUB_TOKEN it prints what it would have posted instead of actually posting it.

Batch-triage your open PRs

Once the worker is running, point it at a whole repo to clear the backlog:

# Triage every open Dependabot/Renovate PR in a repo
uv run dependency-scout triage --repo your-org/your-repo

# Or limit to a subset while you're getting a feel for it
uv run dependency-scout triage --repo your-org/your-repo --limit 5

Check a package before installing it

The Scout can also vet a dependency before you install or upgrade it — useful when you're adding something new or when an agent is about to run pip install / npm install:

# Fresh install check (no old version)
uv run dependency-scout check requests 2.32.0

# Upgrade check
uv run dependency-scout check requests 2.32.0 --from 2.31.0 --ecosystem pip

# Different ecosystems
uv run dependency-scout check @angular/core 18.0.0 --ecosystem npm
uv run dependency-scout check serde 1.0.219 --ecosystem cargo

Exit codes are scriptable: 0 = green, 1 = yellow, 2 = red.

Results are automatically shared across callers — if another project already checked the same version bump today, you get the cached verdict instantly.

Use as a Claude Code tool (MCP)

Add the Scout as an MCP server so Claude Code can call it automatically when it's about to install a new dependency. From the dependency-scout directory:

claude mcp add dependency-scout -- uv run python -m mcp_server

Once configured, Claude Code will have a check_dependency tool available and can call it before pip install, npm install, etc.

Test by asking Claude a question like:

Check if requests 2.32.0 is safe to install 

You should get back a response somewhat like:

⏺ Let me use the dependency-scout MCP tool to check that package.
                                                                                
  Called dependency-scout (ctrl+o to expand)

⏺ RED — Do not install requests 2.32.0.

  Here's the summary of why:

  - Version is yanked on PyPI — officially pulled due to a conflict with the CVE-2024-35195
  mitigation. It broke applications using custom schemes (e.g. docker-py).
  - Open CVEs not fixed — CVE-2024-47081 and CVE-2026-25645 remain unresolved at this version.
  - Install script regression — setup.py was substantially rewritten, reverting from modern
  pyproject.toml packaging to a legacy build script with older Python/dependency constraints.
  - Maintainer change with unknown account age adds further supply chain concern.

  Recommendation: upgrade to requests 2.32.2 or newer — that's the version that properly resolved
  the CVE regression without the breakage that caused 2.32.0 to be yanked.

Remediate a vulnerable dependency

When a (often transitive) dependency is stuck on a vulnerable version that Dependabot won't bump — e.g. a CVE fix that's newer than your cooldown window, or an indirect dep Dependabot's security updates don't cover — the Scout can open the fix PR itself by regenerating the lockfile:

# Bump a vulnerable package to a safe version and open a PR
uvx 'dependency-scout>=0.9.1' remediate \
  --repo your-org/your-repo --package starlette --to 1.3.1

# Limit to one project, or preview without pushing
uvx 'dependency-scout>=0.9.1' remediate \
  --repo your-org/your-repo --package starlette --to 1.3.1 \
  --project-dir services/api --dry-run

It clones the repo, regenerates the lockfile script-safely (uv lock — resolution only, no install scripts), verifies the package actually reached the safe version (and reports the blocker — e.g. a parent constraint — if it can't), then opens a PR @-mentioning CODEOWNERS. A security remediation deliberately bypasses the repo's exclude-newer freshness cooldown — a known-CVE fix is exactly the case a cooldown should make an exception for, and the reviewer still approves the PR.

Auth (needs write access to push a branch):

  • GITHUB_TOKEN with repo/Contents+PR write — on a SAML-SSO org, authorize the token for the org first, or
  • a GitHub App (GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY or …_PATH) — Scout mints an installation token itself, which sidesteps the per-user SAML-SSO wall. See GitHub App setup.

Currently supports uv/pip projects; more ecosystems are planned.

Configure your stack

The Scout works with zero configuration — rule-based classifier, no PR comments, no auto-actions. Each addition makes it smarter or more capable:

.env setting What it enables
(none) Rule-based classifier, log-only output
ANTHROPIC_API_KEY Claude classifies (set ANTHROPIC_MODEL to pin a version)
OPENAI_API_KEY + OPENAI_MODEL OpenAI classifies instead
OLLAMA_HOST + OLLAMA_MODEL Local Ollama classifies — free, no data leaves your machine
CLASSIFIER=rule_based Force rule-based even when an LLM key is present
GITHUB_TOKEN or GitHub App Posts real PR comments on GitHub
GITLAB_TOKEN Posts real MR comments on GitLab
ENABLE_PR_ACTIONS=true Can automatically merge GREEN PRs and/or close RED ones
SOCKET_API_KEY Adds Socket.dev supply-chain score check (create token — scope: packages:list)
NVD_API_KEY Raises the NIST NVD rate limit from 5 to 50 requests / 30s (request a key). Strongly recommended on shared CI (GitHub-hosted runners share IPs, so the keyless public limit is exhausted fast). The key is per-requestor — keep it in a secret, never commit or share it.

Copy .env.example to .env and fill in what you have, or run uv run python setup.py to be walked through it interactively.

What's next: continuous triage on every new PR

Zero-infra (recommended): GitHub Actions. Triage every Dependabot/Renovate PR with no server to host — the --local flag boots an ephemeral in-process Temporal server + worker for the single run, so the whole thing is one uvx step. Drop a workflow in the repo you want to watch:

# .github/workflows/dependency-scout.yml
name: Dependency Scout
on:
  pull_request_target:
    types: [opened, reopened, synchronize]
  workflow_dispatch:
permissions:
  contents: write          # only if you enable auto-merge
  pull-requests: write
jobs:
  triage:
    runs-on: ubuntu-latest
    if: github.actor == 'dependabot[bot]' || github.actor == 'renovate[bot]' || github.event_name == 'workflow_dispatch'
    steps:
      - uses: astral-sh/setup-uv@v7
      - run: uvx 'dependency-scout>=0.8.0' triage "${{ github.event.pull_request.html_url }}" --local
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}   # optional — LLM verdicts
          NVD_API_KEY: ${{ secrets.NVD_API_KEY }}               # optional — raises NVD rate limit
          SOCKET_API_KEY: ${{ secrets.SOCKET_API_KEY }}         # optional — Socket.dev signal

What it does to each PR. Alongside the verdict comment, Scout applies one at-a-glance label so you can clear the queue by color:

Verdict Label Action
🟢 safe scout: merge recommended auto-merged if you opt in, otherwise left open for you to merge
🟡 needs a look scout: needs review requests review
🔴 unsafe scout: blocked @-mentions CODEOWNERS, then closes

For repos where a human must merge to a protected branch (no bot auto-merge), keep auto_merge_enabled: false (the default): safe bumps are labelled scout: merge recommended and left open for you — no failed merge attempts. Flip it to true only where bot auto-merge is allowed, and GREENs queue via GitHub's native auto-merge once required checks/reviews pass.

Add .github/dependency-scout.yml (below) to let it merge/close/request review; until then it just comments. Add --dry-run to the step to watch verdicts before it acts. Full workflow (manual single-PR + sweep-all triggers) is in docs/deployment.md; a live example runs in temporalio/ai-cookbook.

Higher volume / lower latency: webhook server. For instant triage the moment a PR opens, run the Scout as a persistent webhook listener (auto-merge GREEN, close RED). This needs a server that stays up — see docs/deployment.md.


Configuring your repo

Add .github/dependency-scout.yml to any repo where you want the Scout to do more than comment. All fields are optional — omitting the file entirely is safe (comment-only mode). A ready-to-copy template is at .github/dependency-scout.yml.example.

See docs/configuration.md for the full field reference.


What data leaves your machine

Data Where it goes Notes
Package name, version numbers OSV, Socket.dev, deps.dev, pypistats Public registry APIs — this data is already public
Package archive (the actual .whl/.tgz/.gem) Downloaded to local temp dir, deleted after diff Never forwarded to any external service
Diff summary (changed file names + added/removed lines) Your configured LLM (Claude/OpenAI/Ollama) Up to 100 KB of actual code changes
Package description, release notes, Socket alert strings Your configured LLM Labeled as untrusted in the prompt
Source repo URL (from registry metadata) GitHub API Used to look up release tags and CI workflow changes

The diff summary does include real code lines from the package archive. For private packages on a self-hosted registry, use Ollama to keep analysis fully local. The rule-based classifier (the default when no LLM key is configured) runs entirely locally.


Ecosystem coverage

pip/uv, npm, RubyGems, Cargo, Composer, Maven/Gradle, NuGet, Go modules, GitHub Actions, Mix (Hex), Pub (Dart/Flutter), Elm, Docker, Terraform, Swift. Signal availability varies by registry — see docs/architecture.md for the full coverage table.


Learn more


A Temporal Community project. Credit to Daniel Hensby for inspiration.

This product uses data from the OSV and deps.dev APIs, Socket.dev, and OpenSSF Scorecard. This product uses the NVD API but is not endorsed or certified by the NVD.

About

A durable, supply-chain-aware agent that automatically triages Dependabot + Renovate PRs. (Powered by Temporal)

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages