Scanner releases and verification¶
Scanner binaries use scanner-vX.Y.Z tags so their experimental product version
does not collide with versions of the checklist corpus. A release is built only
from the exact tagged commit. The workflow reruns the source, catalog, schema,
security, benchmark, and pack gates before publishing anything.
Release contents¶
Each scanner release contains:
- Linux, macOS, and Windows archives for AMD64 and ARM64;
- one dependency-free
@marinjursic/prcnpm launcher tarball and six exact native npm platform tarballs for the same systems; - a binary with the scanner version, source revision, source timestamp, and Go
toolchain embedded in
prc version --format json; - the exact compatible
catalog/,packs/, andschemas/trees in every archive, together with the catalog's human-readable objective sources and the packs' benchmark fixtures; - a versioned release manifest binding artifact digests to the catalog and pack validation digests;
- a timestamp-free CycloneDX 1.6 module SBOM;
- a canonical self-scan of the exact tagged source, executed by the packaged binary against its bundled catalog without hiding blocked or manual results;
SHA256SUMS; and- GitHub-hosted Sigstore attestations for SLSA build provenance and the CycloneDX SBOM predicate.
The SBOM describes the scanner's Go module and resolved Go dependencies. It does not claim that the bundled catalog data, schemas, host operating system, or future adapter images are Go components; those files are integrity-bound by the archive checksum and release manifest instead. GitHub documents what its artifact attestations prove and how consumers should verify them.
The builder fixes archive order, ownership, modes, paths, timestamps, binary metadata, and source identity. CI builds the complete release twice and requires a byte-for-byte directory comparison. This is a reproducibility check under the same declared CI toolchain; it is not a claim that provenance or reproducibility proves the artifact is secure.
The npm platform packages use a narrower runtime allowlist than the standalone archives. They retain all catalog files, all 10,042 source controls, schemas, adapter manifests, packs, and benchmark evidence. They exclude website assets, demo video, and contributor-only documentation. The builder caps runtime support at 512 files and 24 MiB, caps each compressed platform package at 24 MiB, and caps the launcher package at 128 KiB. A size-budget failure blocks publication; the builder never drops controls to make a package fit.
The two largest machine-readable control indexes use deterministic gzip only in the npm runtime package. The native scanner expands them in memory with strict compressed and expanded byte limits, then applies the same schemas, source binding, per-control digests, and registry-to-contract checks as the plain JSON files. Standalone archives and repository source keep the plain JSON form.
Verify before running¶
Download the archive, SHA256SUMS, release manifest, and SBOM from the same
GitHub release. Verify the checksum from the directory containing those files:
sha256sum --check SHA256SUMS
On macOS, verify one downloaded archive against the matching line instead:
shasum -a 256 prc_0.1.0_darwin_arm64.tar.gz
grep 'prc_0.1.0_darwin_arm64.tar.gz' SHA256SUMS
Then verify that GitHub's signed provenance binds the archive to this repository and release workflow:
gh attestation verify prc_0.1.0_linux_amd64.tar.gz \
--repo MarinJursic/production-readiness-checklist
Verify the separate CycloneDX SBOM attestation using its recognized predicate:
gh attestation verify prc_0.1.0_linux_amd64.tar.gz \
--repo MarinJursic/production-readiness-checklist \
--predicate-type https://cyclonedx.org/bom
Finally, inspect prc_X.Y.Z_release-manifest.json and compare its
source_commit, catalog digest, pack digests, and artifact digest with the
assessment scope you intend to use. Inspect prc_X.Y.Z_self-scan.json as a
normal prc.run/v0.13 report: a valid signed self-assessment may still be
environment_blocked because organizational, production, or adapter evidence
is deliberately unavailable in the release job. After extraction:
./prc_X.Y.Z_linux_amd64/prc version --format json
The release manifest also binds every npm tarball. Before the packages are published to npm, they can be tested directly from one release directory. On Linux x64, for example:
mkdir npm-smoke && cd npm-smoke
npm install --ignore-scripts --offline --no-audit --no-fund --package-lock=false \
../marinjursic-prc-linux-x64-X.Y.Z.tgz \
../marinjursic-prc-X.Y.Z.tgz
./node_modules/.bin/prc version --format json
./node_modules/.bin/prc scan /path/to/project
The platform package contains the native binary and its exact runtime catalog.
The launcher checks the platform manifest, binary SHA-256, and the size and
SHA-256 of every runtime support file on each start. It fails closed on a
missing, changed, oversized, or unbound file and never downloads a fallback or
starts a binary found on PATH.
The scanner is declared as security-related dual-use software with npm's
contentPolicy metadata and the same plain-text DISCLOSURE in the repository,
launcher, platform packages, and standalone archives. The disclosure describes
the defensive purpose, opt-in analyzers, and prohibited unauthorized use. See
npm's dual-use policy.
Public npm release is deliberately split into two workflows. The tagged release
workflow uses npm trusted publishing from the exact pinned workflow identity,
refuses NPM_TOKEN and NODE_AUTH_TOKEN, creates a draft GitHub release, and
uses npm stage publish for the six native packages before the launcher. A
trusted-publisher relationship is allowed to stage but not directly publish.
The maintainer then reviews and approves each staged package with npm 2FA. The
manual finalizer downloads the draft assets again, checks every SHA-256 and
release-manifest binding, waits for npm's publish-time malware scan, verifies
the public SHA-512 and npm SLSA provenance for all seven exact packages, and
only then makes the GitHub release public. See npm's
staged-publishing guide and
publish-time scanning announcement.
Because npm versions are immutable, any byte mismatch stops the release. The
stager safely skips only an already-public version with exactly matching bytes.
It runs npm in a new empty working directory with user, global, and environment
npm configuration removed, so a saved .npmrc token cannot silently replace
OIDC. It also independently requires the exact repository, workflow file,
release tag, commit, and GitHub OIDC request variables. Running the staging
script locally or from another workflow fails before contacting npm.
Release-time Python validation installs only the seven exact CPython 3.12 Linux
wheels in requirements-release.lock.txt, with required SHA-256 hashes and
source builds disabled. The publication job uses the publisher's standard-
library --verify-only path, so it does not add an unpinned Python dependency
before attesting or publishing the tested bytes.
The release job builds once, uploads those exact bytes, then runs the matching native archive and npm launcher on Linux x64, Linux ARM64, macOS x64, macOS ARM64, Windows x64, and Windows ARM64. Publication starts only after every host has completed a real 10,042-control smoke scan.
One-time npm owner setup¶
npm requires a package to exist before a trusted publisher can be configured. The owner must therefore bootstrap each of the seven package names once from the exact verified release tarballs, with npm's required human authentication. Then configure the same trusted-publisher identity on every package:
- repository owner:
MarinJursic; - repository:
production-readiness-checklist; - workflow filename:
release-scanner.yml; and - no GitHub environment unless the workflow is later changed to use one.
For every package, allow npm stage publish and disable direct npm publish in
the trusted-publisher relationship. At package level, require two-factor
authentication and disallow token publishing. Remove any bypass-capable legacy
publishing token. These settings are state held by npm and must be checked in
the npm package settings; repository files cannot enforce them.
After that one-time setup, scanner-vX.Y.Z tags use OIDC and no long-lived npm
publishing secret. The staging workflow requires Node.js 22.14 or newer and the
exact hash-bound npm 12.0.2 client. npm provenance links a package to its build
source; it does not prove the package has no unsafe code.
For a normal release:
- push one new immutable
scanner-vX.Y.Ztag from a commit already onmain; - wait for all builds, security gates, native scans, and package smoke tests;
- open npm's staged-package list, inspect all seven matching versions, and approve each one with 2FA;
- run Finalize scanner release with that exact tag; and
- require the finalizer to verify checksums, public bytes, and npm provenance before it publishes the draft GitHub release.
Staged publication is per package rather than transactional. If staging stops after only some packages, do not move or recreate the tag. Use an authenticated owner session to list the staged records, compare their names, versions, tags, and downloaded tarball hashes with the draft release, approve only exact matches, and rerun the same tagged workflow. It will verify already-public exact packages and stage only the missing versions. Rejecting a staged package is a separate destructive 2FA action and is not part of automated recovery.
Version 0.1.0 was the one-time human bootstrap. npm registry signatures for
its launcher and selected platform package can be verified, but that bootstrap
version has no npm provenance attestation. Do not describe it as provenance-
verified. All later releases must be published by the trusted workflow with
provenance or fail closed.
Protect the scanner-v* tag pattern with an active GitHub tag ruleset that
restricts creation, update, and deletion to the release maintainer. Require the
main-branch validation, CodeQL, dependency-review, and secret-scan checks before
the tagged commit can enter main. These hosted controls cannot be truthfully
claimed from repository files alone and must be verified in GitHub settings.
Do not substitute a successful signature check for vulnerability review or a production-readiness decision. An attestation proves the signed claim's origin and integrity, not the absence of defects.
Release failure and revocation¶
Publishing is fail closed: an invalid tag, test failure, benchmark regression, schema failure, vulnerability finding, non-reproducible output, checksum error, or attestation failure prevents release publication. A failed workflow is not a release and its temporary artifacts are not supported.
If a signing identity, workflow dependency, tool, release asset, catalog, pack, or scanner version is compromised or materially incorrect, maintainers will:
- publish a private-to-public security advisory as coordination permits;
- mark the affected release and version as revoked, with the exact artifact digests and reason;
- remove or revoke affected attestations where the platform supports it;
- never reuse the affected version or tag and never replace an asset under the same name;
- publish a new patched version from a reviewed commit with new checksums, SBOM, provenance, and compatibility manifest; and
- update bundled trust stores or registry revocations when a pack, adapter, or publisher identity is affected.
Consumers should stop using a revoked artifact even if its historical signature still verifies: verification establishes who produced it, not whether it remains approved.