test(npm): streampub fixtures, fuzz, and coherence suite (part 8/8)
📦 What this MR does
Part 8/8 — the final part of the stack splitting the streampub streaming publish-envelope library (S11 Step 13). See Part 1/8 (!432) for the stack overview.
- Targets
10io/npm-local-step-13-part7of8(Part 7/8). GitLab retargets tomainas the parent merges. - Depends on Part 7/8 (set as a merge-request dependency).
Lands the checked-in tarball corpus, the fixture-driven tests, and the fuzz target — completing Step 13.
testdata/— the generated tarball corpus (8.tgz) +generate.go(one-shot generator,//go:build ignore) + README..gitattributesmarks the.tgzas generated so GitLab collapses them.streampub_test.go—fixture()reader,TestProcess_FixtureDigestsDistinct(guards against content-addressed fixture collapse),FuzzProcess(untrusted-input parsing must never panic — only succeed or return a typed*streampub.ProcessError).coherence_test.go—TestProcess_CoherenceFailures: malformed gzip/tar, missing manifest, path traversal (dotdot + escape), oversizedpackage.json, each driven by a corpus fixture.lifecycle_test.go—TestProcess_DrainOnError_BoundedTimeandTestProcess_BackpressureBufferWired..gitlab-ci.yml— thefuzz:npmjob (mirrorsfuzz:oci), the first fuzz target underinternal/format/npm.
🧪 Tests
golangci-lint(repo-pinned v2.12) → 0 issuesGOEXPERIMENT=jsonv2 go test -race -count=1 ./internal/format/npm/streampub/...→ pass (23 tests +FuzzProcessseed corpus)
✅ Stack byte-identity verification
This is the merge point of the stack. git diff <this branch> <reference> over internal/format/npm/ + the wired config shows only the reviewed deltas accumulated across Parts 1–8, and nothing else:
error.go/streampub.go—ProcessErrorAPI (renamed type, unexportedcode/wrapped) + six-capLimits.validate(Parts 1–2, from Duo/AppSec review).sink.go—sizeLimitWriterreports bytes written on the cap-exceeded path (io.Writercontract, Part 5).pipeline.go— deferred pipe-close panic backstop (S11 coherence-sink contract, Part 6).inspector.go— non-regular tar entry skip at the manifest path (go-secure-coding.md, Part 6).- Test files — the
*ProcessErrorrename, the "forbidden rune" case label, the corrected test-author-phase comments, and the Part 8 review fixes below.
Part 8 review fixes (Duo/AppSec, in this MR):
lifecycle_test.go—BackpressureBufferWireddropst.Parallel()(runs serially, matching its//nolint:paralleltesttiming rationale);DrainOnError_BoundedTimewidens the context deadline to 10s so a broken drain trips thetime.Afterdiagnostic rather than a misleading context-deadline error.streampub_test.go—FuzzProcessdrops the deadcontext.Canceledcarve-out (the fuzz uses a non-cancelable context), enforcing the full typed-*ProcessError-or-success contract like the OCI fuzz target.
The testdata corpus, .mise.toml GOEXPERIMENT, and .gitattributes are byte-identical to the reference.
One forced .gitlab-ci.yml deviation: the fuzz:npm job runs go test -fuzz=FuzzProcess ./internal/format/npm/streampub/, not the reference's ./internal/format/npm/.... On this stack's (newer) base, that glob matches two packages (the npm handler + streampub) and go test -fuzz rejects multiple packages; scoping to the package that contains FuzzProcess fixes it. (The reference's glob worked only on its older base, before the handler package existed alongside streampub.)
🚩 Deviations from the reference (!420 (closed))
The deltas listed under Stack byte-identity verification above — each a Duo/AppSec review fix or a propagated rename, documented in the part where it landed. No others.
🔗 References
- Reference MR (read-only): !420 (closed)
- Related work item: #131 (closed) (not closed by this MR)