← All docs

Signet — Ecosystem & Distro Support Matrix

What Signet discovers, how it resolves each to source, and what that means for the read path (coverage) and the audit queue. Generated as part of the 24-hour breadth plan (breadth-24h-plan.md).

Discovery watchers

Each watcher is off by default; the discovery Spring profile (application-discovery.properties) turns them all on at once. Cursors persist in feed_cursors; releases land in package_releases.

EcosystemFeed / mechanismCursorResolver path
npmregistry _changes + latest fetchseqdeps.dev → version-doc gitHead (VERIFIED) → tag peel fallback
PyPIRSS recent updates— (dedup)deps.dev → tag peel
crates.io/summary just_updated— (dedup)deps.dev → crate .cargo_vcs_info.json (VERIFIED) → tag peel fallback
Goindex.golang.org/indextimestampdeps.dev → tag peel
RubyGemsactivity/just_updated.json— (dedup)deps.dev → tag peel
Maven Centralsolr /select, oldest-first from cursor (head-seeded)epoch-msdeps.dev → tag peel
NuGetcatalog change-log walkISO commitdeps.dev → tag peel
Debian/Ubuntu (deb)Sources index (RFC822, gz)skip-offset (wraps at end)metadata upstream inference
CentOS/RHEL/Rocky/Fedora (rpm)repomd.xmlprimary.xmlskip-offset (wraps at end)metadata upstream inference

Resolution confidence ladder

(ecosystem, name, version) → (repo, commit) grades, from package_source_resolutions.confidence:

ConfidenceMeaningSubject-eligible?Produced by
VERIFIEDpublisher asserts the exact commityescargo.cargo_vcs_info.json git.sha1 inside the immutable published crate; npm — the per-version registry doc's gitHead (recorded by npm CLI at publish). No tag inference; refresh re-reads the registry, and a changed sha on an immutable version is flagged as registry tampering
ATTESTED_TAGwe peeled a host tag on the declared repoyespypi/go/rubygems/maven/nuget; npm/cargo when the publish carried no commit record
HEURISTICinferred upstream repo + a tag we peeledyesdistro upstream inference (deb/rpm)
NONEno commit mappingnoartifact-only / unresolved

Subject-eligible = can become an audit_targets row and carry attestations. Only a real commit qualifies — see the guardrail below.

The distro guardrail (deb/rpm)

Distro packages wrap patched upstream tarballs and frequently have no clean commit. The decisive rules (DistroUpstreamResolver), never relaxed:

  1. Infer upstream when possible. From the discovered metadata (Homepage,

Vcs-Git, rpm <url>), if a github.com/gitlab.com project is identifiable, strip the distro version (epoch:, -revision, +dfsg/+ds) and peel the upstream tag. A hit → a **real upstream commit graded HEURISTIC** (the shipped source may differ from the tagged tree, so never ATTESTED/VERIFIED).

  1. Otherwise, advisory artifact. Record the tarball/package sha256 as a

resolved-artifact row. It is never a subject, never enters the lease queue, carries no coverage or attestations. Surfaced on the portal Discovery page as an advisory count.

  1. Otherwise, unresolved (UPSTREAM_UNKNOWN).

We do not synthesize a commit, do not loosen StatementValidator, and do not touch the conformance vectors — artifact-only-as-subject would be a spec-wide, Rust↔Java-conformance-breaking schema change (product decision, still "no").

Source hosts for tag peeling

GitTagResolver is host-aware:

  • GitHubgit/ref/tags peel (annotated → tag object → commit).
  • GitLabrepository/tags (nested-group paths; self-hosted via configurable API

base + PRIVATE-TOKEN).

  • Other hosts (Bitbucket, salsa.debian.org packaging repos, …) → TAG_NOT_FOUND; the

distro path then falls back to advisory artifact.

A host 403/429 raises HostRateLimitedException so the jobs runtime retries with backoff — it is never cached as a false "unresolved".

Read-path / coverage semantics

  • Coverage and attestations attach only to subject-eligible (repo, commit) pairs.
  • ATTESTED_TAG and HEURISTIC mappings are surfaced but should be down-weighted

relative to VERIFIED by consumers — the released artifact may diverge from the tagged tree, and tags mutate (the TTL-refresh producer re-peels and flags mutation).

  • Mutation incidents bind (v1.205–v1.224): every refresh-caught mapping change

is persisted (resolution_mutations) and reaches all consumer surfaces — the /v1/disputes incident feed, the package dossier, signet ops triggers (machine-checked PD-2/PD-3 revisit condition, windowed to recent evidence), both CI gates (signet gate and signet deps fail on verified-grade tampering, warn on repoints, both with SARIF), the README badge (tampering detected outranks every state), the catalog chip (tampered), and mutation.recorded webhooks push incidents to package subscribers. AI verdicts computed pre-tampering are marked stale on every surface, the release rejoins the sweep at the head of the queue for a re-read, tampered releases dominate the human audit-target queue (the priority model's incident term outranks advisories + reach + posture combined), and mutations.jsonl in the signed dumps keeps incidents portable (kind-aware mirror verify). One deliberate asymmetry: mirror sync federates signed records only — a sync-built replica verifies the incidents partition but does not import it (a registry records what its own refresh witnesses), so it reports fewer trust incidents than its upstream until then; the CLI prints this, and a dump restore keeps them.

  • Artifact-only distro rows never contribute to coverage.

Monorepo #subpath sources (PD-9)

A package's coverage scope is its subtree within the repo when a subpath is known; NULL = whole repo. Per-ecosystem population state:

EcosystemSubpath sourceStatus
npmrepository.directory from the registry package docpopulated (normalized at resolve; guardrail: PackageReleaseSubpathTest)
Cargo.cargo_vcs_info.json path_in_vcs inside the published .crate (written by cargo publish — authoritative)populated (bounded tarball scan at resolve; live-verified against crates.io)
Mavenunique repo-tree directory whose leaf equals the artifactId and holds a pom.xml (GitHub trees API; ambiguous/truncated → whole repo)populated (heuristic; rate limits defer per PD-4)
Gomodule path suffix vs the repo slug (…/repo/service/s3service/s3; a trailing /vN is version, not directory)populated (derived at resolve, no network; explicit metadata wins)
PyPI…/tree/<ref>/<path> link in the version's project_urls (e.g. langchain-core → libs/core) — GitHub + GitLab URL formspopulated where publishers link it (widespread in monorepos); else whole repo
RubyGemssame tree-URL convention on source_code_uri (e.g. actionpack → actionpack)populated where published; live-verified against rubygems.org
NuGetunique repo-tree directory whose leaf equals the package id and holds <id>.csprojpopulated (heuristic; the <id>.csproj marker keeps prefixed siblings distinct)
deb / rpmn/a — distro rows are advisory-only

Packages without a subpath keep the pre-PD-9 whole-repo semantics, which errs toward showing repo-level coverage — honest for single-package repos (the vast majority), and the dossier labels monorepo scoping explicitly where it applies.