Skip to content

unidoc/unisupply

unisupply

Go supply chain risk assessment — vulnerabilities, maintainer health, typosquatting, AI-generated code risk, CI/CD audit, SBOM, policy enforcement.

What it does

unisupply analyzes a Go project's full module dependency chain and produces a supply chain risk assessment. It runs nine focused scanners — vulnerability lookup, maintenance health, maintainer analysis, typosquatting detection, resilience scoring, AI-generated code heuristics, CI/CD pipeline audit, build file inspection, and Trust Index lookup — combines the in-tree scanner signals into a weighted risk score per dependency, attaches the optional Trust Index data to each report alongside that score, and renders the result as a colored terminal summary, machine-readable JSON, an enterprise PDF report, or a CycloneDX / SPDX SBOM. A built-in policy engine fails CI on configurable thresholds (critical vulns, max age, blocked modules, unpinned actions, ...).

It is intended for engineering teams that need to make merge-time and release-time decisions about third-party Go code.

Install

# Latest release (Go 1.25+ required)
go install github.com/unidoc/unisupply/cmd/unisupply@latest

# Or download a prebuilt binary from the Releases page
#   https://github.com/unidoc/unisupply/releases

Homebrew and other package-manager distribution channels are tracked as post-1.0 follow-ups; for now use go install or the release tarballs.

Quick start

# Scan the current module
unisupply ./

# JSON output for CI ingestion
unisupply ./ --format json --output results.json

# Full PDF report (requires UNIDOC_LICENSE_API_KEY for PDF generation)
unisupply ./ \
    --format pdf \
    --output report.pdf \
    --github-token "$GITHUB_TOKEN"

# Policy-enforced run — exits 2 on violation
unisupply ./ --policy-preset strict

A typical text-format run against a small project looks like this (truncated for the README — your output will list every direct and transitive dependency):

unisupply v0.4.0 — Go Supply Chain Risk Assessment
by UniDoc (unidoc.io)

Project: github.com/example/app
Dependencies: 4 direct, 38 transitive (42 total, 113 graph edges)

═══════════════════════════════════════════════════
OVERALL SUPPLY CHAIN RISK SCORE: 26/100 (MEDIUM)
═══════════════════════════════════════════════════

HIGH RISK (3 dependencies)
────────────────────────────────────────
● golang.org/x/net      Risk: 51/100  (transitive)
  ├─ 4 known vulnerabilities with available fixes
  ├─ Resilience: 70/100 (frequent cadence, 53 releases)
  └─ Score: vuln=100×40% maint=0×25% depth=0×15% maintainer=0×10% maturity=0×10%

MEDIUM RISK (19 dependencies)   [...]
LOW RISK (20 dependencies)      [use --verbose to see details]

PACKAGES ELIGIBLE FOR MAINTENANCE TAKEOVER
────────────────────────────────────────
  ● widely-used/inactive-pkg   Activity: inactive   Bus factor: 1

Pass --verbose for full per-dependency breakdowns including the dependency path that pulled the module in.

Scanners

Scanner What it checks Data source
Vulnerability Known CVEs in dependencies Go vuln DB (vuln.go.dev)
Maintenance Last release, archive status, deprecation Go Module Proxy
Maintainer Contributors, bus factor, activity, org verification GitHub API
Typosquatting Levenshtein-similarity to ~75 well-known modules Built-in list
Resilience Release cadence, governance files, version scheme GitHub API
AI-Generated Fresh modules, few releases, generic names (heuristics) Module metadata
CI/CD Action pinning, permissions, secret exposure .github/workflows/*.yml
Build files Unpinned Docker images, curl | bash patterns Dockerfile, Makefile, *.sh
Trust Index Curated trust scores unitrust API (optional)

The risk score is a weighted composite:

Risk Score (0–100) =
    Vulnerabilities × 0.40
  + Maintenance     × 0.25
  + Depth           × 0.15
  + Maintainer Risk × 0.10
  + Maturity        × 0.10
  + Typosquat Penalty      (0–20)
  + AI-Gen Penalty         (0–15)
  + Low-Resilience Penalty (0–6)  // adds when resilience score < 30

Levels: LOW 0–25 · MEDIUM 26–50 · HIGH 51–75 · CRITICAL 76–100.

Output formats

Format Flag Use
Text (colored) --format text (default) Interactive terminal use
JSON --format json CI ingestion, dashboards, programmatic consumers
PDF --format pdf Enterprise reports (built with UniPDF + UniChart)
CycloneDX SBOM --format sbom-cyclonedx Standard CycloneDX 1.5 software bill of materials
SPDX SBOM --format sbom-spdx SPDX 2.3 software bill of materials

Policy engine

unisupply ships two presets and accepts a custom JSON policy file. Policy violations cause the binary to exit 2, which is the convention CI systems expect for a deliberate fail-fast.

# Built-in presets
unisupply ./ --policy-preset strict
unisupply ./ --policy-preset moderate

# Custom policy
unisupply ./ --policy ./security-policy.json

A minimal custom policy (every field is optional — see pkg/policy/engine.go for the full set):

{
  "max_overall_score": 50,
  "max_risk_score": 75,
  "no_critical_vulns": true,
  "no_archived": true,
  "no_deprecated": true,
  "no_typosquatting": true,
  "no_unmaintained_months": 24,
  "max_depth": 8,
  "max_ci_score": 50,
  "blocked_modules": ["github.com/suspicious/pkg"],
  "allowed_modules": ["golang.org/x/", "github.com/unidoc/"]
}

Notable fields:

  • no_known_vulns / no_critical_vulns — fail on any vuln, or only on high/critical-severity vulns.
  • no_single_maintainer — fail if any direct dependency has bus factor ≤ 1.
  • allowed_modules — when set, acts as a strict whitelist applied to direct dependencies only; transitive modules are not gated by this rule. Each entry matches by exact module path or by path-prefix ("golang.org/x/" matches golang.org/x/net); glob patterns are not supported.
  • blocked_modules — applies to direct and transitive dependencies, with the same exact-or-prefix matching rule.
  • max_ci_score — gate on the CI/CD scanner's overall risk score (requires --scan-ci).

Trust Index integration

unisupply can enrich a scan with curated trust data from a running unitrust instance. The Trust Index is UniDoc's curated database of Go module trustworthiness — it goes beyond what public APIs and heuristics can tell you (vulnerability feeds, GitHub contributor counts, release cadence) and adds vetted, human-reviewed metadata: who actually maintains the package, what country and organization they operate from, whether their identity is verified, the package's stewardship status, and — when a module is known-risky — a recommended safer alternative.

How it works

When --trust-index-url points at a reachable unitrust instance, every discovered module (direct and transitive) is sent in a single batched HTTP request to POST /api/v1/lookup. The returned data is folded into each dependency's report alongside the in-tree scanner output. No per-module calls, no fan-out — one round trip regardless of graph size.

# Hosted unitrust (production CI)
unisupply ./ \
    --trust-index-url https://unitrust.unidoc.io \
    --format json --output results.json

What the Trust Index adds to a report

For every module that unitrust has data on, the report gains:

Field What it tells you
trust_score Composite curated trust score (0–100)
maintainer_trust Curated confidence in the maintainer's identity and track record
resilience_score Project resilience as assessed by UniDoc, not just heuristics
security_score Curated security posture (review history, hardening, response time)
community_score Community health beyond raw star/fork counts
maintainer_name Real maintainer name where known
maintainer_org Sponsoring or employing organization
maintainer_country Maintainer jurisdiction — relevant for compliance / sanctions checks
maintainer_verified Whether UniDoc has verified the maintainer's identity
stewardship_status actively_maintained, community, inactive, abandoned, …
safer_alternative Recommended replacement module, if the entry is flagged as risky
is_unidoc_maintained True for modules under UniDoc's own stewardship

The full schema lives in pkg/scanner/trustindex.go (TrustIndexEntry). Modules unitrust has no entry for are reported with their normal scanner output unchanged.

When to use it

  • CI gating — combine --trust-index-url with --policy-preset strict to fail builds on known-risky modules whose risk isn't yet visible in the CVE feeds.
  • Procurement / vendor review — the maintainer name, country, and verification flag are the fields enterprise reviewers actually need; they are not derivable from go.mod alone.
  • Supply-chain incident response — the safer_alternative field short-circuits "what should we replace this with?" during a live incident.

Privacy and operational notes

  • The lookup payload contains only module paths — the same information that is already in your published go.mod. Versions are not transmitted, and the request includes no source code, scan results, or other project-identifying data.
  • The whole feature is opt-in and additive. Leaving --trust-index-url off produces a fully self-contained scan — unisupply never reaches out to unitrust by default and has no implicit endpoint.
  • Failures of the Trust Index call (network errors, non-200 responses) are surfaced as warnings; they do not abort the scan or alter risk scores derived from the in-tree scanners.

Architecture

CLI (pflag)
  │
  ├── Parse go.mod / go.sum          pkg/parser/
  ├── Resolve dependency graph        pkg/resolver/
  ├── Run 9 security scanners        pkg/scanner/
  │   ├── Vulnerability (govulncheck)
  │   ├── Maintenance health
  │   ├── Maintainer analysis (GitHub API)
  │   ├── Typosquatting detection
  │   ├── Resilience scoring
  │   ├── AI-generated code risk
  │   ├── CI/CD pipeline audit
  │   ├── Trust Index lookup (unitrust, optional)
  │   └── Build file scanning
  ├── Compute risk scores             pkg/scorer/
  ├── Evaluate org policies           pkg/policy/
  └── Generate reports                pkg/report/
      ├── Text (colored terminal)
      ├── JSON (machine-readable)
      ├── PDF (UniPDF)
      └── SBOM (CycloneDX, SPDX)

Configuration reference

The full flag set is always available via:

unisupply --help

The most frequently used flags:

Flag Purpose
-f, --format text, json, pdf, sbom-cyclonedx, sbom-spdx
-o, --output Output file (default: stdout for text/json/sbom)
--github-token GitHub API token (or GITHUB_TOKEN env)
--trust-index-url unitrust endpoint for curated trust scores
--policy-preset strict or moderate
--policy Path to a custom policy JSON file
--scan-workflows Audit .github/workflows/*.yml and *.yaml only
--scan-ci Full CI/CD audit: workflows + Dockerfile / Makefile / scripts
--min-risk Hide dependencies below the given score
--direct-only Skip transitive dependencies
-v, --verbose Per-dependency breakdown

Environment variables:

Variable Purpose
GITHUB_TOKEN Higher GitHub API rate limits and access to private repositories
UNIDOC_LICENSE_API_KEY UniDoc license key (required for PDF report generation)

Documentation

License

Apache License 2.0 — see LICENSE for the full text.

Copyright © UniDoc ehf.

Packages

 
 
 

Contributors