# Build and supply-chain gate ## Local blocking controls - `pnpm install --frozen-lockfile` and a real manifest/lock mismatch fixture - all direct and transitive lockfile rows with package SHA-512 integrity - production/development, direct/transitive and platform-optional classification - package-manifest license allow/deny policy - approved inventory baseline digest and actual add/remove/change/upgrade diff - independent review for new direct production dependencies - CycloneDX 1.6 SBOM and inventory component/edge coherence - source/lock/SBOM/dist-linked local provenance statement - source, opt-in recipes, scripts, tests, tracked config/schema, public, built asset and generated release metadata secret scan - two-build `SOURCE_DATE_EPOCH` reproducibility check The canonical commands are: ```bash corepack pnpm verify:lockfile corepack pnpm verify:reproducible-build corepack pnpm build:release-candidate corepack pnpm verify:local-evidence corepack pnpm check:supply-chain:fixtures ``` `config/security/dependency-baseline.json` is the approved local baseline. Changing it requires `DEPENDENCY_BASELINE_OWNER` and `DEPENDENCY_BASELINE_REASON`; editing the digest or hardcoding an empty diff is rejected. ## External promotion controls Promotion reads the provider files named by `VULNERABILITY_REPORT_PATH` and `PROVENANCE_ATTESTATION_PATH`. The vulnerability report must bind both the exact lockfile digest and candidate `distSha256`; the provenance attestation must name `dist` with that same digest. Both documents use strict schemas and Ed25519 signatures verified with separately configured trusted public keys and key IDs. If either provider input is absent, local verification remains meaningful but `artifacts/security/supply-chain-verification.json` records `promotionStatus: FAIL_UNVERIFIED`. `verify:provider-evidence` and `verify:promotion` then exit non-zero. Promotion recomputes the candidate file set and digests and never rebuilds it. Scanner or signing outages are not converted to an empty PASS. Approved vulnerability exceptions require vulnerability/package identity, owner, a different reviewer, reason and expiry. Expired or self-approved exceptions are blocking.