Skip to main content
skill GitHub Copilot official · GitHub

agent-supply-chain — GitHub Copilot skill: install and use

Checks AI agent plugins, tools, and dependencies with SHA-256 manifests. Use it before promoting a plugin or auditing its files.

Install into GitHub Copilot · Skills CLI (Vercel) All methods and platforms ↓
npx skills add github/awesome-copilot --skill agent-supply-chain
Open on GitHub

What agent-supply-chain does

The skill builds an INTEGRITY.json file containing SHA-256 hashes for plugin files, then compares the current directory against that manifest. It reports modified, missing, and untracked files, and creates a combined manifest hash.

Its examples use Python scripts with the standard hashlib, json, and pathlib modules. A separate audit examines version pinning in package.json, requirements.txt, and pyproject.toml, flagging ranges such as ^, ~, *, latest, and versions lacking an upper bound.

Manifest generation excludes .git, node_modules, .venv, __pycache__, .pytest_cache, and INTEGRITY.json. Changes there are outside this check, so review the exclusion rules against your project layout.

What it helps with

  • generate INTEGRITY.json for a plugin directory
  • compare plugin files with a published manifest
  • detect modified, missing, and untracked files
  • audit dependency version pinning
  • check a plugin before promotion between environments

Example prompts for the agent

  • Use agent-supply-chain to generate `INTEGRITY.json` for this plugin directory.
  • Use agent-supply-chain to verify this plugin against its `INTEGRITY.json` and list discrepancies.
  • Audit dependency versions in `package.json` with agent-supply-chain.

How to install agent-supply-chain

1Skills CLI (Vercel)

npx skills add github/awesome-copilot --skill agent-supply-chain

2GitHub CLI

gh skill install github/awesome-copilot agent-supply-chain

3Manually: put the files in place

.github/skills/agent-supply-chain/SKILL.md

From the same set554

The whole set →
git-commit official github This skill reviews Git changes, stages related files, and creates Conventional Commits. Use it when you want an agent to make one commit or split work into separate commits. GitHub Copilot 47,165installs excalidraw-diagram-generator official github Turn a plain-language description into an Excalidraw diagram. Useful for mapping processes, system structure, and relationships between entities. GitHub Copilot 31,639installs multi-stage-dockerfile official github This skill guides GitHub Copilot in writing multi-stage Dockerfiles for different languages and frameworks. Use it when the final runtime image should contain fewer build dependencies. GitHub Copilot 29,688installs documentation-writer official github Skill that turns the agent into a technical writer following the Diátaxis framework: tutorials, how-to guides, reference, and explanation. Proposes structure before writing. GitHub Copilot 27,757installs prd official github Turns a feature idea into a structured PRD with user stories, technical requirements, and risks. Use it when planning a software feature or an AI-powered one. GitHub Copilot 24,035installs refactor official github This skill reshapes existing code without changing its external behavior. Use it for gradual cleanup of large functions, duplication, weak types, and code smells. GitHub Copilot 22,321installs java-springboot official github Gives GitHub Copilot Spring Boot development practices, from project layout to tests and security. Use it when writing or reviewing Java application code. GitHub Copilot 21,272installs create-readme official github This skill reviews a project and creates a structured README.md. Use it when the repository needs clear documentation based on its actual files and code. GitHub Copilot 19,081installs

Similar

pptx-reference-deck-analysis kimtth Reads a PPTX reference deck without changing it, covering structure, theme, typography, layouts, and OOXML. Use it before building a new deck from a reference. Claude Code CX Codex Cursor 2,500installs sign-in-with-google-web official google Guides Google Identity Services setup across web projects. It implements secure token handling and IETF authentication patterns. Claude Code Gemini CLI CX Codex 743installs google-cloud-scc-remediation official google This skill handles Google Cloud Security Command Center findings, from IAM fixes to resource misconfigurations. Use it when an agent must address a specific finding. Claude Code Gemini CLI CX Codex 742installs git-guardrails-claude-code Matt Pocock This skill adds a Claude Code hook that stops risky Git commands before they run. Use it when an agent must not push or discard working-tree changes. Claude Code 499,069installs ponytail-review DietrichGebert ponytail-review reviews a change beyond the diff, checking connected code, bugs, risks, load, tests, speed, and unnecessary code. Use it for PRs and commits. Claude Code CX Codex Cursor +1 56,300installs ponytail-audit DietrichGebert It audits a repository and ranks bugs, risks, and redundant code in a one-shot report. Use it when you need a review without code changes. Claude Code CX Codex Cursor +1 44,800installs security-audit cloudflare Reviews codebases and APIs for vulnerabilities using safe sandboxing. Fits pre-release security reviews, pen-test triage, and architecture checks. Claude Code CX Codex Cursor +1 52,200installs security-and-hardening addyosmani Guides threat modeling and security checks for code that handles user input, authentication, sessions, or external services. Use it when building a feature that accepts untrusted data or reviewing code before release. Claude Code CX Codex Cursor +1 69,400installs

Questions about agent-supply-chain

How do I install agent-supply-chain in GitHub Copilot?

Run npx skills add github/awesome-copilot --skill agent-supply-chain. The skill file is placed at .github/skills/agent-supply-chain/SKILL.md.

What does agent-supply-chain do?

It generates SHA-256 manifests for plugin files and compares them with the current directory. The check identifies modified, missing, and untracked files.

Which dependency files does agent-supply-chain audit?

It examines package.json, requirements.txt, and pyproject.toml. The audit flags ^, ~, *, latest, and >= constraints without an upper bound.

Source text

SKILL.md · MIT
---
name: agent-supply-chain
description: |
  Verify supply chain integrity for AI agent plugins, tools, and dependencies. Use this skill when:
  - Generating SHA-256 integrity manifests for agent plugins or tool packages
  - Verifying that installed plugins match their published manifests
  - Detecting tampered, modified, or untracked files in agent tool directories
  - Auditing dependency pinning and version policies for agent components
  - Building provenance chains for agent plugin promotion (dev → staging → production)
  - Any request like "verify plugin integrity", "generate manifest", "check supply chain", or "sign this plugin"
---

# Agent Supply Chain Integrity

Generate and verify integrity manifests for AI agent plugins and tools. Detect tampering, enforce version pinning, and establish supply chain provenance.

## Overview

Agent plugins and MCP servers have the same supply chain risks as npm packages or container images — except the ecosystem has no equivalent of npm provenance, Sigstore, or SLSA. This skill fills that gap.

```
Plugin Directory → Hash All Files (SHA-256) → Generate INTEGRITY.json
                                                    ↓
Later: Plugin Directory → Re-Hash Files → Compare Against INTEGRITY.json
                                                    ↓
                                          Match? VERIFIED : TAMPERED
```

## When to Use

- Before promoting a plugin from development to production
- During code review of plugin PRs
- As a CI step to verify no files were modified after review
- When auditing third-party agent tools or MCP servers
- Building a plugin marketplace with integrity requirements

---

## Pattern 1: Generate Integrity Manifest

Create a deterministic `INTEGRITY.json` with SHA-256 hashes of all plugin files.

```python
import hashlib
import json
from datetime import datetime, timezone
from pathlib import Path

EXCLUDE_DIRS = {".git", "__pycache__", "node_modules", ".venv", ".pytest_cache"}
EXCLUDE_FILES = {".DS_Store", "Thumbs.db", "INTEGRITY.json"}

def hash_file(path: Path) -> str:
    """Compute SHA-256 hex digest of a file."""
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

def generate_manifest(plugin_dir: str) -> dict:
    """Generate an integrity manifest for a plugin directory."""
    root = Path(plugin_dir)
    files = {}

    for path in sorted(root.rglob("*")):
        if not path.is_file():
            continue
        if path.name in EXCLUDE_FILES:
            continue
        if any(part in EXCLUDE_DIRS for part in path.relative_to(root).parts):
            continue
        rel = path.relative_to(root).as_posix()
        files[rel] = hash_file(path)

    # Chain hash: SHA-256 of all file hashes concatenated in sorted order
    chain = hashlib.sha256()
    for key in sorted(files.keys()):
        chain.update(files[key].encode("ascii"))

    manifest = {
        "plugin_name": root.name,
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "algorithm": "sha256",
        "file_count": len(files),
        "files": files,
        "manifest_hash": chain.hexdigest(),
    }
    return manifest

# Generate and save
manifest = generate_manifest("my-plugin/")
Path("my-plugin/INTEGRITY.json").write_text(
    json.dumps(manifest, indent=2) + "\n"
)
print(f"Generated manifest: {manifest['file_count']} files, "
      f"hash: {manifest['manifest_hash'][:16]}...")
```

**Output (`INTEGRITY.json`):**
```json
{
  "plugin_name": "my-plugin",
  "generated_at": "2026-04-01T03:00:00+00:00",
  "algorithm": "sha256",
  "file_count": 12,
  "files": {
    ".claude-plugin/plugin.json": "a1b2c3d4...",
    "README.md": "e5f6a7b8...",
    "skills/search/SKILL.md": "c9d0e1f2...",
    "agency.json": "3a4b5c6d..."
  },
  "manifest_hash": "7e8f9a0b1c2d3e4f..."
}
```

---

## Pattern 2: Verify Integrity

Check that current files match the manifest.

```python
# Requires: hash_file() and generate_manifest() from Pattern 1 above
import json
from pathlib import Path

def verify_manifest(plugin_dir: str) -> tuple[bool, list[str]]:
    """Verify plugin files against INTEGRITY.json."""
    root = Path(plugin_dir)
    manifest_path = root / "INTEGRITY.json"

    if not manifest_path.exists():
        return False, ["INTEGRITY.json not found"]

    manifest = json.loads(manifest_path.read_text())
    recorded = manifest.get("files", {})
    errors = []

    # Check recorded files
    for rel_path, expected_hash in recorded.items():
        full = root / rel_path
        if not full.exists():
            errors.append(f"MISSING: {rel_path}")
            continue
        actual = hash_file(full)
        if actual != expected_hash:
            errors.append(f"MODIFIED: {rel_path}")

    # Check for new untracked files
    current = generate_manifest(plugin_dir)
    for rel_path in current["files"]:
        if rel_path not in recorded:
            errors.append(f"UNTRACKED: {rel_path}")

    return len(errors) == 0, errors

# Verify
passed, errors = verify_manifest("my-plugin/")
if passed:
    print("VERIFIED: All files match manifest")
else:
    print(f"FAILED: {len(errors)} issue(s)")
    for e in errors:
        print(f"  {e}")
```

**Output on tampered plugin:**
```
FAILED: 3 issue(s)
  MODIFIED: skills/search/SKILL.md
  MISSING: agency.json
  UNTRACKED: backdoor.py
```

---

## Pattern 3: Dependency Version Audit

Check that agent dependencies use pinned versions.

```python
import re

def audit_versions(config_path: str) -> list[dict]:
    """Audit dependency version pinning in a config file."""
    findings = []
    path = Path(config_path)
    content = path.read_text()

    if path.name == "package.json":
        data = json.loads(content)
        for section in ("dependencies", "devDependencies"):
            for pkg, ver in data.get(section, {}).items():
                if ver.startswith("^") or ver.startswith("~") or ver == "*" or ver == "latest":
                    findings.append({
                        "package": pkg,
                        "version": ver,
                        "severity": "HIGH" if ver in ("*", "latest") else "MEDIUM",
                        "fix": f'Pin to exact: "{pkg}": "{ver.lstrip("^~")}"'
                    })

    elif path.name in ("requirements.txt", "pyproject.toml"):
        for line in content.splitlines():
            line = line.strip()
            if ">=" in line and "<" not in line:
                findings.append({
                    "package": line.split(">=")[0].strip(),
                    "version": line,
                    "severity": "MEDIUM",
                    "fix": f"Add upper bound: {line},<next_major"
                })

    return findings
```

---

## Pattern 4: Promotion Gate

Use integrity verification as a gate before promoting plugins.

```python
def promotion_check(plugin_dir: str) -> dict:
    """Check if a plugin is ready for production promotion."""
    checks = {}

    # 1. Integrity manifest exists and verifies
    passed, errors = verify_manifest(plugin_dir)
    checks["integrity"] = {
        "passed": passed,
        "errors": errors
    }

    # 2. Required files exist
    root = Path(plugin_dir)
    required = ["README.md"]
    missing = [f for f in required if not (root / f).exists()]

    # Require at least one plugin manifest (supports both layouts)
    manifest_paths = [
        root / ".github/plugin/plugin.json",
        root / ".claude-plugin/plugin.json",
    ]
    if not any(p.exists() for p in manifest_paths):
        missing.append(".github/plugin/plugin.json (or .claude-plugin/plugin.json)")

    checks["required_files"] = {
        "passed": len(missing) == 0,
        "missing": missing
    }

    # 3. No unpinned dependencies
    mcp_path = root / ".mcp.json"
    if mcp_path.exists():
        config = json.loads(mcp_path.read_text())
        unpinned = []
        for server in config.get("mcpServers", {}).values():
            if isinstance(server, dict):
                for arg in server.get("args", []):
                    if isinstance(arg, str) and "@latest" in arg:
                        unpinned.append(arg)
        checks["pinned_deps"] = {
            "passed": len(unpinned) == 0,
            "unpinned": unpinned
        }

    # Overall
    all_passed = all(c["passed"] for c in checks.values())
    return {"ready": all_passed, "checks": checks}

result = promotion_check("my-plugin/")
if result["ready"]:
    print("Plugin is ready for production promotion")
else:
    print("Plugin NOT ready:")
    for name, check in result["checks"].items():
        if not check["passed"]:
            print(f"  FAILED: {name}")
```

---

## CI Integration

Add to your GitHub Actions workflow:

```yaml
- name: Verify plugin integrity
  run: |
    PLUGIN_DIR="${{ matrix.plugin || '.' }}"
    cd "$PLUGIN_DIR"
    python -c "
    from pathlib import Path
    import json, hashlib, sys

    def hash_file(p):
        h = hashlib.sha256()
        with open(p, 'rb') as f:
            for c in iter(lambda: f.read(8192), b''):
                h.update(c)
        return h.hexdigest()

    manifest = json.loads(Path('INTEGRITY.json').read_text())
    errors = []
    for rel, expected in manifest['files'].items():
        p = Path(rel)
        if not p.exists():
            errors.append(f'MISSING: {rel}')
        elif hash_file(p) != expected:
            errors.append(f'MODIFIED: {rel}')
    if errors:
        for e in errors:
            print(f'::error::{e}')
        sys.exit(1)
    print(f'Verified {len(manifest[\"files\"])} files')
    "
```

---

## Best Practices

| Practice | Rationale |
|----------|-----------|
| **Generate manifest after code review** | Ensures reviewed code matches production code |
| **Include manifest in the PR** | Reviewers can verify what was hashed |
| **Verify in CI before deploy** | Catches post-review modifications |
| **Chain hash for tamper evidence** | Single hash represents entire plugin state |
| **Exclude build artifacts** | Only hash source files — .git, __pycache__, node_modules excluded |
| **Pin all dependency versions** | Unpinned deps = different code on every install |

---

## Related Resources

- [OpenSSF SLSA](https://slsa.dev/) — Supply-chain Levels for Software Artifacts
- [npm Provenance](https://docs.npmjs.com/generating-provenance-statements) — Sigstore-based package provenance
- [Agent Governance Toolkit](https://github.com/microsoft/agent-governance-toolkit) — Includes integrity verification and plugin signing
- [OWASP ASI-09: Supply Chain Integrity](https://owasp.org/www-project-agentic-ai-threats/)

© github · MIT · github/awesome-copilot

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor