Repository navigation
feat(npm)!: Implement final npm provenance contract per ADR 0103-0112 - #151
Conversation
Redefine externalParameters.workflow as the common invocation-interface identity for every SLSA producer profile. Preserve the built-source and SHA-pinned builder identity models, and partially supersede only ADR 0080's omitted-source-ref byte-for-byte compatibility promise. Require migrations to retain equivalent builder-identity verification against runDetails.builder.id and the authenticated signer identity. The former external-parameter builder record's final placement remains a focused follow-up decision. Related #30, #143 Signed-off-by: Yunseo Kim <[email protected]>
Add reciprocal see-also relations from ADRs 0028, 0029, and 0079 to ADR 0103. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Update the ADR sequence, topic tables, and accepted traceability mappings in the agent and bilingual decision indexes. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
End the Context and Problem Statement sections of ADRs 0102 and 0103 with explicit decision questions, matching the established MADR convention. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Accept ADR 0104 to remove the duplicate builder path, SHA, and URI representation while retaining canonical builder identity, authenticated signer identity, and trusted-policy verification. Add the reciprocal see-also relations to the predecessor ADRs. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Update the ADR sequence, topic tables, and accepted traceability mappings in the agent and bilingual decision indexes. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
…dependencies Accept ADR 0105, adding mandatory role-named invocation-source and built-source descriptors with gitCommit digests to the npm profile's closed resolvedDependencies set. The invocation-source descriptor satisfies the npm registry's observed first-entry comparisons and is serialized at index 0 for emission compatibility, while semantic verification remains unordered and name-keyed. Existing externalParameters.source fields are retained under equality invariants until the follow-up consolidation decision. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Add the reverse see-also relations from ADRs 0079, 0080, 0103, and 0104 to ADR 0105, keeping the relations graph symmetric per ADR 0065. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Update the ADR sequence, structure listing, topic tables, and accepted traceability mappings in the agent and bilingual decision indexes. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
…escriptor bindings Accept ADR 0106, removing derived and resolution-output members from externalParameters.source while retaining the caller's explicit full-ref selector as optional source.ref. Release policy bindings move to workflow.repository and the built-source descriptor, and certificate invocation comparisons move to workflow.ref and the invocation-source descriptor with no fallback. The built-source descriptor gains a required annotations.ref_type member under ADR 0105's extension path, and the coexistence invariants that referenced the removed fields are retired. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Add the reverse relations from ADRs 0079, 0080, 0103, 0104, and 0105 to ADR 0106, including the partially-superseded-by entries for ADR 0080's field locations and ADR 0105's retired coexistence invariants with the built-source annotation extension, keeping the relations graph symmetric per ADR 0065. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Update the ADR sequence, structure listing, topic tables, and accepted traceability mappings in the agent and bilingual decision indexes. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
…hub only Accept ADR 0107, making internalParameters.github.event_name the sole statement field for the invocation event and removing source.event_name. The source group is now emitted only when the caller supplied an explicit source-ref selector, so group presence itself distinguishes explicit selection from defaulting. The supported-event admission policy and the certificate Build Trigger comparison are preserved at the new location, with actor fields still excluded. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Add the reverse see-also relations from ADRs 0026, 0079, 0103, and 0106 to ADR 0107, keeping the relations graph symmetric per ADR 0065. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Update the ADR sequence, structure listing, topic tables, and accepted traceability mappings in the agent and bilingual decision indexes. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Signed-off-by: Yunseo Kim <[email protected]>
Revise the common SLSA provenance specification and the identity and
build types specification to the contract decided by ADRs 0103-0112.
The common specification now defines externalParameters.workflow as the
required caller invocation identity {ref, repository, path}, the closed
internalParameters.github triple {event_name, repository_id,
repository_owner_id}, the role-named invocation-source and built-source
descriptors, the package-manifest descriptor with its offline evidence
contract, the deterministic mediaType matrix, the runner-image reported
identity with the on-disk operating_system annotation, the
builder.version {nodejs, npm, corepack?} closed key set, and the npm
windlass_build_script_disposition run metadata. The claim-source and
rejection matrices bind certificate claims to the workflow group and
the descriptors with no source.invocation_* fallback.
The identity specification retains canonical runDetails.builder.id as
the sole builder identity, removes the redundant external-parameter
builder record, and adds the npm profile-path migration guard that
re-proves the exact builder path restriction through canonical builder
validation, same-certificate signer binding, and trusted policy
authorization.
Related #143
Signed-off-by: Yunseo Kim <[email protected]>
Revise the npm profile and composition specifications to the contract decided by ADRs 0103-0112. The package profile contract now exposes exactly seven public inputs and rejects the removed release-tag and provenance-sidecar inputs, with the release target derived from the effective built tag and sidecar publication mandatory in release-asset mode. The provenance and publish specification defines the minimized externalParameters schema, the invocation-source and built-source descriptors with the npm emission order, the package-manifest descriptor, the manifest_evidence offline evidence contract, the deterministic mediaType matrix, the runner-image operating_system annotation, the effective built ref derivation rule, and the re-pointed certificate and policy bindings. The handoff and publisher specifications carry manifest_evidence to the publisher for offline manifest-dependent checks while preserving the internal release-tag contract and the mandatory sidecar distribution. The core profile contract and build/pack specification record the revised shared source model, the original-manifest snapshot captured before caller scripts, and the on-disk runner OS capture. The release manifest specification required no changes: its trusted producer mapping is distinct from the removed external-parameter builder record. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Rebind the verification policy to the ADR 0103-0112 statement contract: certificate source claims bind to the workflow invocation group and the invocation-source descriptor with no source.invocation_* fallback, Build Trigger and Build Config URI bind to internalParameters.github.event_name and workflow.path, release expectations bind to the effective built ref and the built-source descriptor, and manifest-dependent checks run against the offline manifest-evidence contract. The npm package verification policy, the descriptor cardinalities and mediaType matrix, the runner-image annotation set, the builder.version closed key set, and the signed windlass_build_script_disposition metadata are specified together with their rejection families, while the demoted pre-existing package flags move to unsigned diagnostic metadata. Register the seven new diagnostic categories (resolved-dependencies-invocation-source, resolved-dependencies- built-source, resolved-dependencies-package-manifest, package-manifest-evidence, build-script-disposition-mismatch, build-trigger-mismatch, build-config-uri-mismatch) as declarations with their specification tables in lockstep; no runtime emission is added here. Update the architecture index traceability through ADR 0112 in both languages, the repository README input count to one required and six optional inputs, and the workflow interface note to 7 inputs. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Capture the selected package.json bytes exactly once after verified checkout and package selection, before any caller-controlled install, build, or pack script, and thread the snapshot through package-manager selection, build-script detection and disposition, and publish-intent resolution. Workspace discovery reuses the captured manifest for the selected directory instead of re-reading it. This prepares the ADR 0109 manifest-evidence contract: the original selected source-manifest bytes, never a build-mutated or packed manifest, become the single evidence source that the later package-manifest descriptor and manifest_evidence handoff bind to. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Remove the public release-tag and provenance-sidecar inputs from the JS/TS npm reusable workflow per ADR 0108. The workflow now declares exactly seven inputs, the release target derives from the effective built tag, and sidecar publication remains mandatory in release-asset mode. workflow-check rejects the removed names as unknown inputs, and the reserved-mode rejection for release-asset-mode and linked-artifact-metadata is unchanged. The internal handoff release tag and the standalone publisher's release-tag contract are preserved. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The original source-manifest snapshot is the signed evidence, but install, build, and pack ran against the mutable on-disk manifest, so a post-selection rewrite (external edit or a caller-controlled install or build script) could produce an artifact the signed evidence does not cover. The profile now re-reads the selected package.json immediately before install and before pack and fails closed with the new registered windlass.verify.error.source-manifest-drift diagnostic (policy phase, exit 1, no mutation) on any byte drift. The pack window stays outside the byte boundary by design: managers legitimately rewrite fields at pack time (workspace protocol resolution, publishConfig overrides) and caller-declared prepack scripts run inside pack, so the packed manifest is never evidence and the artifact stays bounded by packed identity, consumer-surface validation, and the tarball digests. The build-pack specification records the guard and the boundary. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
ADR 0035 and ADR 0055 carry status "superseded by ADR-0077" but still sat in the accepted traceability table. Move both rows into the superseded/deprecated table so the index agrees with their frontmatter. Signed-off-by: Yunseo Kim <[email protected]>
The new identity and source binding diagnostics inherited the default level 7, so a co-occurring package or handoff error could become primary_id ahead of a higher-priority identity failure. The verification policy's precedence contract places issuer, workflow, source numeric identity, source content, run invocation, and runner identity at level 4; register build-trigger-mismatch, build-config-uri-mismatch, resolved-dependencies-invocation-source, and resolved-dependencies-built-source there, with ordering tests against a level-6 control. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Missing --metadata-* flags are invocation errors at the dispatcher (exit 2), not rejection-report verification failures. Mismatches between caller arguments or tarball handoff digests and the authenticated build metadata now persist a rejection report and exit 1: the argument comparison reports package-manifest-evidence, the metadata/handoff disagreement reports digest-mismatch, and a VerifyPackedArtifact failure keeps its own diagnostic ID through writePublishInputRejection instead of being dropped to a bare exit 2. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
validateStatement's source-repository, subject-cardinality, and Corepack-version rejections were plain errors, so the offline verification command reported them as invocation failures (exit 2) instead of verification failures (exit 1). They now carry source-identity-mismatch, subject-cardinality-error, and builder-version-mismatch respectively, so the command's diagnostic-bearing path classifies them correctly. The remaining ID-less path is the nil-verifier programmer error, which is genuinely an invocation failure. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
DecodeInternalParameters accepted non-numeric, zero, leading-zero, signed, and whitespace-padded repository and owner IDs, so a malformed internalParameters.github record could be signed or accepted. Both identifier fields now require GitHub's positive base-10 form (^[1-9][0-9]*$), and the common provenance contract states the grammar. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
A missing build_script_disposition carried the build-script-disposition-mismatch diagnostic while an explicit null fell through to a plain non-null decode error. Both now use the diagnostic, and the generic non-null loop no longer rechecks the member. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The Included Software URI is signed verbatim, so percent-encoded or otherwise non-canonical forms are no longer interchangeable with the plain path (RawPath must be empty, alongside the existing scheme, host, userinfo, query, and fragment rules). The captured Image Release reference is now validated as the platform's release URL shape with its percent-encoded tag, and its tag must equal the offline image_version projection, matching the consumer-side runner-image rule. The new FuzzParseRunnerMetadata target covers the trust-boundary parser per the fuzz policy and is registered in both the lint smoke matrix and the scheduled deep fuzz matrix. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The unconditional InvocationRef fallback to the built ref made the source-ref completeness check unreachable for the ref component: a source-ref run missing the invocation ref silently recorded the built tag as the invocation identity. Both the command adapter and the metadata finalizer now apply the fallback only when no source-ref is set, so incomplete source-ref invocations fail closed. Production is unchanged: the workflow always passes --invocation-ref from github.ref. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
ResolveStatementSources and validateFinalDependencies each reimplemented the invocation-source/built-source validation, and their omitted-selector messages had already drifted. Both now call one validateSourceDependencies helper so the rule cannot diverge again. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The producer and the evidence consumer each tested scripts.build presence; both agreed on the non-empty rule but nothing kept them from drifting. One manifestDeclaresBuildScript helper now defines declared as a non-empty scripts.build command, and the publish specification states that an explicit empty string counts as not declared. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
A builder ID with a valid immutable reference but the wrong workflow path carried builder-id-not-immutable, which the verification policy reserves for mutable references; the untrusted-identity case is wrong-builder-id. ValidateBuilderIDForWorkflow now returns wrong-builder-id for path mismatches, and the previously uncovered function gains happy-path, wrong-path, mutable-ref, malformed, and untrusted-repository tests. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
BuildPackConfig.RunnerOverride is a cross-package test seam (the command adapter uses it), so it stays exported, but it is now documented as test-only and a supplied capture must satisfy the same identity invariants as a parsed one. The parser's derived-identity checks moved into one validateRunnerCapture shared by both sources, so the override path cannot drift from the on-disk contract. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The common contract's examples showed builder.version nodejs v24.0.0 and npm 11.0.0 while the same documents pin the runtime at Node.js 24.22.1 with bundled npm 11.19.1. Align all four example pairs with the pinned pair so readers copy a consistent shape. Signed-off-by: Yunseo Kim <[email protected]>
The offline verification command derived the Build Config URI expectation from the signed statement unconditionally, silently discarding a consumer-supplied pin; a conflicting non-empty pin now fails with build-config-uri-mismatch before derivation. The same verification path also reported npm validation failures under a generic "npm-evidence" check label; the report now keeps the failing field path from the error's DiagnosticCheck. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
ParseCallerWorkflowPath returned plain errors, so a malformed or non-canonical workflow_ref reached the caller without a diagnostic ID. The npm trusted-publisher contract requires windlass.verify.error.trusted-publisher-mismatch for an unavailable or conflicting caller workflow filename, so the parser now carries it. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Add real negative tests for the publish-side producer evidence contract: manifest digest/identity/privacy/repository/disposition rejections through VerifyProducerPackage, packed-artifact digest and truncation failures through VerifyPackedArtifact, and the binding checks (packed identity, release event, push invocation ref, runtime pin, built and invocation commits) through NewProvenanceSigningInput. Each case mutates one trust-boundary operand and asserts the registered diagnostic. VerifyPackedArtifact is now fully covered and validateProducerBindings rises to 89%. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Exercise the closed external-parameters boundary: wrong member types, an empty source selector, absolute and traversing package directories, the unimplemented release-asset mode flag, and a whitespace dist-tag that is not an omission. Both validateFinalExternalShape and validateFinalExternalParameters are now fully covered. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
Extend the conformance harness evidence binding tests with empty content, traversing package directories, duplicate dependency names, a built-source descriptor without its commit, and malformed bundle documents, each asserting the fail-closed package-manifest-evidence diagnostic. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
There was a problem hiding this comment.
All reported issues were addressed across 64 files (changes from recent commits).
Requires human review: Auto-approval blocked because this review re-detected 2 unresolved issues already reported by Cubic.
View guided diff | Turn on auto-fix | Re-trigger cubic
Restore the missing space in the slsa-provenance-v1 fail-closed
sentence ("registry or release mutation"), add the JS/TS npm package
profile to the ADR 0090 row of the decisions index so the ADR-to-spec
mapping stays bidirectional, and narrow the source-manifest-drift doc
comment to the on-disk bytes the guard actually checks.
Related #143
Signed-off-by: Yunseo Kim <[email protected]>
Tighten the runner image metadata boundary in three ways, matching the descriptor-validation grammar that consumers already enforce. The Included Software URI now rejects any raw query or fragment spelling, including trailing ? or # delimiters that url.Parse would otherwise drop from the reconstructed form. Capture also requires the URI's release-tag component to agree with the full image version's offline projection, the same rule descriptor validation applies. Detail lines with surrounding whitespace, including whitespace-only lines, are rejected as malformed instead of being silently trimmed into the signed record. The build-pack specification pins the canonical spelling and padding rules alongside the capture requirements. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
…k-failed VerifyPackedArtifact returned inspectTarball's errors unwrapped, so a corrupt or truncated tarball fell back to the handoff-schema-mismatch primary ID in the publish report even though the errors already carry the package-pack-failed prefix. Wrap them in the registered diagnostic so the report names the real failure. The publish command tests now cover a truncated tarball end to end, and the former packed-artifact test is renamed to the handoff-versus-metadata disagreement it actually exercises; packed-artifact digest verification itself remains covered directly in the npmprofile unit tests. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
There was a problem hiding this comment.
All reported issues were addressed across 8 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
View guided diff | Turn on auto-fix | Re-trigger cubic
Extend the capture boundary so each Runner Image detail value must equal its trimmed form: an `Image: ubuntu-24.04` style value with interior prefix padding no longer flows into the signed runner_label annotation. The build-pack specification now also states explicitly that capture-time grammar or projection failures exit 2 as malformed local evidence while the same failure in an already-built descriptor exits 1 from descriptor validation. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
The project has never been released, so the [Unreleased] section may not carry Changed or Removed categories, which presuppose previously released behavior. Fold the contract finalization into the Added section as the record the first release ships, revise the runner-image entry in place for the final ADR 0111/0112 annotation set, and drop the release-tag/provenance-sidecar removal entry: those inputs never shipped, so their absence is invisible to every user. Related #143 Signed-off-by: Yunseo Kim <[email protected]>
There was a problem hiding this comment.
2 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- In
CHANGELOG.md, the signedpackage-manifestdescriptor is described as carryingmanifest_evidence, but that evidence is handed off separately in build metadata. Update the description so consumers are not misled about the signed format. - In
CHANGELOG.md,externalParameters.workflowis described as the called workflow, but it records the caller workflow. Replace “called workflow” with “caller workflow.”
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="CHANGELOG.md">
<violation number="1" location="CHANGELOG.md:137">
P3: `externalParameters.workflow` records the caller workflow, not the reusable workflow being called. Replace “called workflow” with “caller workflow” to describe the signed identity accurately.</violation>
<violation number="2" location="CHANGELOG.md:143">
P3: The signed `package-manifest` descriptor does not carry `manifest_evidence`; the build-metadata handoff carries it separately. Update this description so consumers are not misled about the signed format.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| signing certificate's platform-fixed claims. `resolvedDependencies` records the ordered chain of | ||
| `invocation-source`, `built-source`, `package-manifest`, `lockfile`, `node-runtime`, a | ||
| `package-manager-distribution` for non-npm managers, and `runner-image`; the signed | ||
| package-manifest descriptor carries offline `manifest_evidence` (`path` plus base64 content) so |
There was a problem hiding this comment.
P3: The signed package-manifest descriptor does not carry manifest_evidence; the build-metadata handoff carries it separately. Update this description so consumers are not misled about the signed format.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At CHANGELOG.md, line 143:
<comment>The signed `package-manifest` descriptor does not carry `manifest_evidence`; the build-metadata handoff carries it separately. Update this description so consumers are not misled about the signed format.</comment>
<file context>
@@ -123,12 +123,27 @@ Era five-digit years (e.g., `## [0.1.0] - 12026-06-13`).
+ signing certificate's platform-fixed claims. `resolvedDependencies` records the ordered chain of
+ `invocation-source`, `built-source`, `package-manifest`, `lockfile`, `node-runtime`, a
+ `package-manager-distribution` for non-npm managers, and `runner-image`; the signed
+ package-manifest descriptor carries offline `manifest_evidence` (`path` plus base64 content) so
+ verifiers can recompute it without repository access. `builder.version` records the observed
+ `nodejs`, `npm`, and conditionally `corepack` versions, and build script invocations are recorded
</file context>
| rollout windows do not fail honest builds. The ambient `ImageOS` variable is diagnostic-only and | ||
| never feeds the signed record. | ||
| - Added the finalized JS/TS npm SLSA provenance contract (ADR 0103-0112). | ||
| `externalParameters.workflow` records exactly the called workflow's `ref`, `repository`, and |
There was a problem hiding this comment.
P3: externalParameters.workflow records the caller workflow, not the reusable workflow being called. Replace “called workflow” with “caller workflow” to describe the signed identity accurately.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At CHANGELOG.md, line 137:
<comment>`externalParameters.workflow` records the caller workflow, not the reusable workflow being called. Replace “called workflow” with “caller workflow” to describe the signed identity accurately.</comment>
<file context>
@@ -123,12 +123,27 @@ Era five-digit years (e.g., `## [0.1.0] - 12026-06-13`).
+ rollout windows do not fail honest builds. The ambient `ImageOS` variable is diagnostic-only and
+ never feeds the signed record.
+- Added the finalized JS/TS npm SLSA provenance contract (ADR 0103-0112).
+ `externalParameters.workflow` records exactly the called workflow's `ref`, `repository`, and
+ `path`, and `internalParameters.github` is a closed triple of `event_name`, `repository_id`, and
+ `repository_owner_id`, bound to the OIDC Build Trigger and Build Config URI claims and to the
</file context>
| `externalParameters.workflow` records exactly the called workflow's `ref`, `repository`, and | |
| + `externalParameters.workflow` records exactly the caller workflow's `ref`, `repository`, and |
Summary
Implements the final npm SLSA provenance contract decided in ADR 0103-0112 (the issue #143 provenance-compatibility follow-up). The branch carries the accepted ADR set, the spec revisions (
docs/architecture/), and the trusted-core implementation in SDD order: specification commits land before the implementation commits that realize them.What changed:
externalParameters.workflowrecords exactly the called workflow's{ref, repository, path}; the legacy environment snapshots leave the signed record.internalParameters.githubis a closed triple ofevent_name,repository_id,repository_owner_id, bound to the OIDC Build Trigger and Build Config URI claims (certificate OIDs .16/.18) and to the signing certificate's platform-fixed source claims. A builder identity migration guard rejects bundles that mix old and new identity shapes.resolvedDependenciesrecords the ordered chaininvocation-source,built-source,package-manifest,lockfile,node-runtime, pluspackage-manager-distributionfor non-npm managers andrunner-image, with the governed mediaType matrix. The signedpackage-manifestdescriptor carries offlinemanifest_evidence(path+ base64 content, 16 MiB bound) so verifiers can recompute it without repository access; the selected manifest is snapshotted before any build script runs.builder.versionrecords the observed{nodejs, npm, corepack?}triple, and build script invocations are recorded asrunDetails.metadata.windlass_build_script_disposition.runner-imagedescriptor's annotation set is exactlydeployment_version,operating_system,image_version,runner_label;operating_systemcomes from the same bounded on-disk metadata snapshot asimage_version, and ambientImageOSis diagnostic-only.release-tagandprovenance-sidecaroptional inputs are removed, shrinking the npm reusable workflow contract to one required input (package-directory) and six optional inputs.resolved-dependencies-invocation-source,resolved-dependencies-built-source,resolved-dependencies-package-manifest,package-manifest-evidence,build-script-disposition-mismatch,build-trigger-mismatch,build-config-uri-mismatch); the conformance corpus is regenerated with 47 registrations across 17 requirement IDs, and new fuzz targets (FuzzDecodeInternalParameters,FuzzParseCallerWorkflowPath,FuzzManifestEvidence,FuzzFixtureManifestEvidence,FuzzBindOIDCSignerIdentity) are registered in both the lint and scheduled fuzz workflows.Why: the issue #143 investigation fixed npm's registry-side provenance handling (npm/cli#9882, shipped in npm 11.20.0/12.1.0); this migration lands the slsa-builder-side contract that pairs with it, completing the ADR 0103-0112 decision set.
How to test:
go test ./...(full suite and race),go run ./cmd/slsa-builder-internal fixture-check --index testdata/fixtures/index.json,go run ./cmd/slsa-builder-internal workflow-check --workflow .github/workflows/js-ts-npm-package-slsa3.yml --profile npm-only, plus the eight scenario contracts (happy tag push, dispatch retry, offline manifest evidence, closed-schema regression, runner evidence, builder migration guard, seven-input contract, historical P02 cryptographic verification).Related Issues
Change Type
Changelog
release-tag/provenance-sidecarworkflow inputs are removed.Changelog update:
CHANGELOG.md[Unreleased]updatedChecklist
General
type(scope): SummaryCI/Workflow Changes (if applicable)
If this PR modifies GitHub Actions workflows or CI/CD configuration, it must comply with our
Supply Chain Integrity requirements:
uses:references are pinned to full 40-character commit SHAs (with# vX.Y.Zcomment)step-security/harden-runneris included as the first step in every jobpermissionsare used instead of top-levelpermissionsProtocol / Compatibility Impact
Compatibility impact: this is a breaking change to the signed npm provenance shape and the public workflow input contract, delivered while the project is pre-release (no stable version exists). The specification revisions in
docs/architecture/define the new observable behavior, the ADR set 0103-0112 records the decisions, andCHANGELOG.md[Unreleased]carries the Breaking: entries. Callers pinned by workflow SHA are unaffected until they deliberately re-pin; the builder identity migration guard rejects mixed-shape bundles rather than misclassifying them.Testing
Test evidence:
go test ./...andgo test -race ./...fully green;golangci-lint run ./...reports 0 issues andgolangci-lint fmt --diffis clean;fixture-checkandworkflow-check --profile npm-onlypass;actionlintpasses; Prettier and markdownlint pass. All five new fuzz targets pass 30-second smokes. The eight migration scenario contracts pass individually (including the historical P02 production signer fixture and the dispatch-retry signed invocation context).cubic reviewwas run per commit and over the full branch diff againstorigin/main; final result: no issues (seven findings were fixed during the review loop, two were rejected with documented grounds).Documentation
docs/architecture/specifications plus the ADR index)Rollout / Risk
git revertof the implementation commits (spec and ADR commits are decision records and stay). The M1 live dogfood (issue [P06] Live M1 dogfood #30, attempt 5) verifies the migrated contract against the real npm registry before any release.Reviewer Checklist
Summary by cubic
Lands the final npm SLSA provenance contract from ADRs 0103-0112 as the first-release record of the signed provenance shape and public workflow inputs, pairing with the registry-side handling fixed in issue #143.
externalParameters.workflow{ref, repository, path}plus a closedinternalParameters.githubtriple, both bound to OIDC certificate claims with a migration guard rejecting mixed-shape bundles.resolvedDependenciescarries the orderedinvocation-source,built-source,package-manifest,lockfile,node-runtimechain, with offlinemanifest_evidenceon the signed package-manifest so verifiers recompute it without repository access.release-tagandprovenance-sidecarwere never shipped.ImageOSis diagnostic-only.source-manifest-drift.package-pack-failed, plus fuzz fixes including the.gitrepository rejection and module-proxy storage allowlist.Verification impact
Written for commit cfda119. Summary will update on new commits.