npm hosted: decide how a provenance publish's .sigstore attachment is handled (npm and yarn --provenance send a second _attachments entry)
Closed Beta blocker: Broken main path (pending product decision)
npm publish --provenance, the default in hardened CI setups, fails hard with a 400. For the user: your publish fails with no explanation of what to change. We must decide the beta behavior (accept and discard the attestation, or document provenance as unsupported) before users hit it.
Context
npm publish --provenance and yarn npm publish --provenance send a second _attachments entry: libnpmpublish 11.2 (lib/publish.js) and yarn 4.18's makePublishBody (packages/plugin-npm/sources/npmPublishUtils.ts) both add {name}-{version}.sigstore, whose data is the JSON sigstore bundle rather than a base64 tarball. npm supports the flow on GitLab CI through SIGSTORE_ID_TOKEN.
S11 has required _attachments to hold exactly one entry, {name}-{version}.tgz, since before fix(npm): accept yarn's _attachments-first publ... (!2228 - merged) • Hayley Swimelar • 19.4. Before that MR the tokenizer never read a second entry, so a provenance publish was admitted and its bundle silently discarded. Once it merges, a provenance publish answers 400 (code: publish_envelope_invalid) at the second key. e2e.npm.publish.reject-two-attachments in docs/testing/e2e/npm.md pins the refusal and names the flow.
Decision to make
- Admit a second entry named
{name}-{version}.sigstoreand skip its value under the token bounds, restoring the admit-and-discard behavior with the spec text saying so; or - store the attestation and serve it the way the npm registry does (
dist.attestationson the packument); or - keep the
400and document that provenance publishing is unsupported.
The first is small: readAttachments already skips unknown attachment-object fields under the token bounds, and the key check would run where validateShape runs, because yarn's order delivers name and the version after _attachments.
Done when
S11 says which of the three the registry does, the code and the e2e row match it, and a yarn npm publish --provenance run against a local instance is recorded.