Supply chain posture
OpenCodeHub ships under Apache-2.0 with a hard rule: every transitive runtime dependency must sit on a permissive-license allowlist. This page documents what we ship, the CI gates that prove it, and the narrow set of tools we invoke as subprocesses rather than link against.
What we ship
Section titled “What we ship”Every release produces a signed bundle of artifacts attached to the
GitHub Release plus a tree of always-on files in main:
| Artifact | Format | Trust anchor |
|---|---|---|
opencodehub-pack.tar.gz | Deterministic 9-item code-pack BOM (100k-token budget). | cosign keyless .sig.bundle |
SBOM.cdx.json | CycloneDX 1.5 SBOM produced by @cyclonedx/cdxgen. | cosign keyless .sig.bundle |
och-scan.sarif | OCH self-scan output at the released SHA. | cosign keyless .sig.bundle |
opencodehub-<tag>.intoto.jsonl | SLSA Level 3 provenance covering all subjects. | slsa-verifier |
In-tree files:
SBOM.cdx.json— CycloneDX v1.5 SBOM, regenerated on every release.THIRD_PARTY_LICENSES.md— human-readable third-party inventory.NOTICE— Apache-2.0 NOTICE file.CHANGELOG.md— generated byrelease-pleasefrom Conventional Commits.
docs/RELEASE.md is the operator-facing runbook for the release
pipeline; it spells out the workflow split (release-please.yml,
pre-release-gate.yml, release.yml), the cosign + SLSA contract,
and the consumer verification commands.
License allowlist
Section titled “License allowlist”Every production dependency must be on this list:
Apache-2.0MITBSD-2-ClauseBSD-3-ClauseISCCC0-1.0BlueOak-1.0.00BSDThe check is enforced by
license-checker-rseidelsohn
on every PR and as part of mise run check:full. See
IP hygiene / License allowlist
for the exact command and the note on the one known acceptance-script
inconsistency.
BSL, BUSL, PolyForm, Commons Clause, GPL, and AGPL are rejected upfront. Source-available engines (e.g. LanceDB’s former license, Elastic) were considered and rejected in ADR 0001 specifically because preserving Apache-2.0 distribution rights is load-bearing.
Vulnerability gates
Section titled “Vulnerability gates”| Gate | Tool | Trigger |
|---|---|---|
| OSV scan | osv-scanner scan source --lockfile pnpm-lock.yaml | Every CI run + mise run check:full |
| CodeQL | .github/workflows/codeql.yml | Every push + weekly schedule |
| OpenSSF Scorecard | .github/workflows/scorecard.yml | Weekly + push to main |
| SARIF schema | mise run sarif:validate + acceptance gate 13 | Every scanner run |
Release gate policy: zero open CVEs on the lockfile at release time. If a bump is blocked (upstream has not shipped a fix, or the fix requires a breaking change), the PR must document the CVE, the reason, and a due date before release-please cuts the version.
All scanner outputs are uploaded as SARIF to the GitHub Security tab, so the org-wide view is one dashboard.
Non-permissive scanners
Section titled “Non-permissive scanners”Some scanners that end users may want to run through codehub scan
— hadolint (GPL-3.0), tflint (MPL-2.0 / BUSL depending on vendor
build) — are not on the permissive allowlist. We still expose them.
The trick is how: we invoke them as subprocesses, we never
import them, never link them in, and never redistribute the
binaries.
Concretely:
packages/scanners/src/is a thin shell-out layer. Each scanner runner spawns the binary, captures stdout as SARIF, and emits findings into the graph.- The scanner binaries are a user-provided runtime dependency.
Users install them separately (via
brew,apt,choco, the vendor-published Docker image, etc.). OpenCodeHub does not ship them, bundle them, or require them at install time. - Scanner license obligations flow to the user running the scanner, not to OpenCodeHub.
This is the same pattern GitHub CodeQL uses with third-party SARIF producers, and it is the reason OBJECTIVES.md can commit to an Apache-2.0-end-to-end posture without crippling the scan surface.
SCIP indexers
Section titled “SCIP indexers”The SCIP indexers OCH uses (scip-typescript, scip-python, scip-go,
rust-analyzer, scip-java, scip-dotnet, scip-clang, scip-kotlin,
scip-ruby) follow the same subprocess-only rule. They are installed
via their language’s native package manager (npm install -g,
go install, rustup component add, coursier install,
dotnet tool install, etc.) and invoked via subprocess. ADR 0006
pins the canonical versions and documents the install channel per
language.
Lockfile policy
Section titled “Lockfile policy”pnpm-lock.yamlis committed.- Every install uses
--frozen-lockfile. - Dependency bumps are Conventional Commits under
build(deps): ...(orchore(deps): ...for devDependencies). - Dependabot or manual bumps go through the same osv + license gates as any other PR.
Verifying a release
Section titled “Verifying a release”To verify a downloaded release end-to-end:
- cosign verify each blob (code-pack, SBOM, SARIF) against its
.sig.bundleand therelease.ymlworkflow identity. - slsa-verifier the
intoto.jsonlprovenance covering the release subjects. - License audit — confirm every component in
SBOM.cdx.jsonis on the allowlist; cross-check againstTHIRD_PARTY_LICENSES.md. - CVE check — run
osv-scanneragainst the tag’s lockfile locally.
The exact commands live in docs/RELEASE.md §3 (Verification
commands). The SBOM is deterministic — two regenerations at the same
commit produce the same bytes. That is an extension of the
determinism contract to the supply-chain layer.
Related
Section titled “Related”- IP hygiene — the rules a contributor has to follow to keep this posture.
- ADR 0001 — Storage backend — why every storage-layer dependency is MIT.
- ADR 0006 — SCIP indexer CI pins — current SCIP indexer version + install channel table.
SBOM.cdx.json,THIRD_PARTY_LICENSES.md,NOTICE,LICENSEat the repo root.