Skip to main content

Supply chain risk analysis for Dependabot and Renovate PRs, built on Temporal

Project description

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.

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.event_name == 'workflow_dispatch'
    steps:
      - uses: astral-sh/setup-uv@v7
      - run: uvx 'dependency-scout>=0.2.2' 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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dependency_scout-0.7.0.tar.gz (440.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dependency_scout-0.7.0-py3-none-any.whl (196.0 kB view details)

Uploaded Python 3

File details

Details for the file dependency_scout-0.7.0.tar.gz.

File metadata

  • Download URL: dependency_scout-0.7.0.tar.gz
  • Upload date:
  • Size: 440.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dependency_scout-0.7.0.tar.gz
Algorithm Hash digest
SHA256 7c81b82dbf49a14074ae55975790dbc29d7eb11ea311f1486650bfe104db49cf
MD5 c0722951fdc65add34ee855051d990f8
BLAKE2b-256 cfcd8133c4e9f0c9b9367c40f391b95259dd999216c902f373ed36e950a75837

See more details on using hashes here.

Provenance

The following attestation bundles were made for dependency_scout-0.7.0.tar.gz:

Publisher: publish.yml on temporal-community/dependency-scout

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dependency_scout-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for dependency_scout-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0332482da6d4c479cb2bee0e9edfc36753962ce4b42174c608b6bd247fa38efe
MD5 bba2dd9fbaf1c290d06c8b2874db3523
BLAKE2b-256 d5ec8bc9740e0cf233aaae974f807e1835e5635580c7e1f4b6de6c0bf2340504

See more details on using hashes here.

Provenance

The following attestation bundles were made for dependency_scout-0.7.0-py3-none-any.whl:

Publisher: publish.yml on temporal-community/dependency-scout

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page