Repository avatar
Developer Tools
v0.1.1
active

canari

io.github.lanbass869-cell/canari

Signed, offline-verifiable attestations for agent components; ALLOW/BLOCK/REVIEW per install.

Documentation

Canari

CI tests coverage mutation release

Agent component verification ledger - signed, offline-verifiable, history-preserving attestations for MCP servers, agent skills, and DSH plugins.

Named after the canary in the coal mine: the first to detect that something went wrong.

What it does

  1. Weekly scan of agent component ecosystems (npm, PyPI, MCP Registry, dsh.so)
  2. Each component gets a signed attestation: DSSE/Ed25519 envelope whose payload is an in-toto Statement v1 (subject[] with digest.sha256, predicateType, predicate) binding: artifact hash + host version + scan scenario. Readable by GUAC / cosign / slsa-verifier without Canari-specific code.
  3. Attestations are offline-verifiable by anyone with the public key
  4. History is never deleted - version changes create supersession chains
  5. Public machine-readable feed for any AI agent or host to consume
  6. Trust heuristics: release cadence (L2.4), metadata anomaly (L2.5), typosquatting (L2.6)
  7. Consumer install gate with policies: canari-verify bundle.json --key pub.json --gate --gate-policy paranoid

Install

pip install canari-mcp

Also on PyPI and as a GitHub release (wheel + sdist + SHA256SUMS + Ed25519 signature). Both channels ship byte-identical artifacts; see docs/release-process.md to verify the signed release.

canari-gate --store out --list

Open dataset

dataset/ is the published snapshot of the ledger under CC-BY-4.0: 3251 signed attestations over 883 components, the canonical feed, drift reports, the schema, both public keys and a MANIFEST.json with a sha256 per file. Verify a bundle offline with canari-verify; verify the whole snapshot with the manifest (see dataset/README.md). Refresh it after a scan with python scripts/sync_dataset.py.

Quality gates (enforced in CI)

GateThresholdCurrent
testsgreen on 3.10/3.12/3.13434 passing
line coverage>= 85%90%
mutation kill rate>= 90% (equivalent mutants excluded)100% (50/50)
live-data auditsampled attestations re-derive from npm/PyPI18/18

Run them yourself: python scripts/quality_gate.py

Quick start

# install
pip install canari-mcp

# run a scan
canari-baseline --limit 50

# verify an attestation offline
canari-verify out/attestations/npm_some-package.bundle.json --key out/public_key.json

# verify + policy gate (exit 0 ALLOW / 5 BLOCK / 6 REVIEW)
canari-verify out/attestations/npm_some-package.bundle.json --key out/public_key.json \\
    --gate --gate-policy strict

# custom policy file
canari-verify bundle.json --key out/public_key.json --gate --gate-policy-file my-policy.json

Policy file example

{"name": "my-policy", "block_on_findings": true, "require_native_provenance": false}

Consumer side (the part a host actually uses)

1. Look up a component and gate it

# resolve the newest signed attestation for a component and run the gate
canari-gate --store out --registry npm --name express
canari-gate --store out --registry dsh-registry --name aegis --policy paranoid --json

# exit codes: 0 ALLOW, 5 BLOCK, 6 REVIEW, 3 not found
canari-gate --store out --list

2. Drift report (what changed since last week)

canari-drift --store out --write out/drift
# verdict flips / same-version silent changes / findings added / findings removed

run_weekly.py writes this report automatically after every scan.

3. Use it from any MCP host (dsh, Codex, Claude, ...)

canari-mcp speaks MCP over stdio (zero dependencies) and exposes three tools: gate_check, verify_bundle, store_summary.

{
  "mcpServers": {
    "canari": {
      "command": "canari-mcp"
    }
  }
}

No arguments needed: the wheel ships a snapshot of the newest signed attestation per component (883 components, rebuilt by scripts/build_snapshot.py from dataset/), so gate_check answers out of the box. Point --store (or $CANARI_STORE) at a full ledger checkout when you want the complete supersession history instead of the snapshot.

A host (or agent) can then ask: "is npm:express allowed to install?" and get ALLOW / BLOCK / REVIEW with reasons, backed by a signed, offline-verifiable attestation.

4. Gate the actual install command

canari-guard wraps an install command, checks every component against the ledger, and refuses to execute when the verdict blocks:

canari-guard -- dsh plugin --profile wbpj add dsh-purge
canari-guard -- npm install some-mcp-server
canari-guard -- pip install mcp-server-fetch==0.2.1

# exit 0 allowed+executed | 5 blocked by ledger | 6 review not confirmed
# --dry-run prints what would run; --allow-review accepts pass-with-findings

The host is never patched - the guard sits in front of the install command.

For DeepSeek Harness (dsh), add this to the profile's cordis.patch.yml (verified end-to-end on dsh: the model called mcp__canari__store_summary and received the live component count):

    - id: mcp-canari
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: canari
        transport: stdio
        command: 'E:\Temp\tbdig\_venv_pr_a\Scripts\python.exe'
        args: ['-m', 'canari.mcp_server', '--store', 'E:\Temp\tbdig\canari\out',
               '--key', 'E:\Temp\tbdig\canari\out\public_key.json']
        cwd: 'E:\Temp\tbdig\canari'
        failOnStartupError: true

Multi-registry coverage

RegistrySourceWhat we checkWhat we inherit
npmsearch API + packument + tarball sha256existence, version, artifact hash, maintainers-
PyPISimple API + JSON APIsame-
MCP Registryofficial RESTidentity presence-
dsh.soJSON APIreference existing L1-L5 conclusions (not re-scanned)dsh.so verdicts

Honest limitations

  • This is a risk signal, not a safety guarantee
  • M0/M1 covers meta-level checks (L1-L2); behavioral checks (L3+) are M1+
  • Scan coverage is limited to what registries expose publicly
  • expires_at is 7 days - attestations go stale, re-scan needed

The threat model this addresses

postmark-mcp (MITRE ATLAS AML.CS0053): 15 clean versions, then one poisoned commit, ~300 orgs affected. After takedown, no host was notified. The gap: no longitudinal observation, no cross-host revocation feed, no portable verdict.

Canari fills that gap.

License

Apache-2.0. See LICENSE and SECURITY.md.

PYPI
canari-mcp
Install Command
pip install canari-mcp