Repository navigation
distribution: default-CI parse coverage + archive_reader leak fix (rstudio/package-manager#18746) - #61
Merged
Conversation
Parse only had test coverage behind the distribution_integration build tag, which needs python/twine/cargo/gpg and clones GitHub repos, so default CI (plain `go test ./...`) never exercised it. Builds wheels and sdists in-test with archive/zip, archive/tar and compress/gzip instead of committing sample archives, so every byte is Posit-authored and there is nothing for the pending NOTICE/licensing review on #60 to cover. Refs rstudio/package-manager#18746. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
NewArchiveReader opened f for a .tar.gz, then returned early on a tarReadCheck error without closing it. The gzip.NewReader error branch right above already closes f; this makes the tarReadCheck branch match. Refs rstudio/package-manager#18746. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds default-CI parse coverage for
distribution/with synthetic, in-test fixtures, and fixes a real file descriptor leak inNewArchiveReader.Why
distribution.Parseonly had test coverage behind thedistribution_integrationbuild tag, which needs python/twine/cargo/gpg and clones 12 GitHub repos — plaingo test ./...(what CI runs) never exercised it. Along the way we confirmed a real leak:NewArchiveReaderopened a file for.tar.gz/.tgzinput and didn't close it on thetarReadCheckerror path.Fixture decision
Synthesize wheels and sdists in the test with
archive/zip,archive/tarandcompress/gzip, written tot.TempDir(), instead of committing sample archives. Every byte is Posit-authored fixture data (gppfixture-*names), so there's no third-party content, noNOTICEchange, and nothing here for #60's pending licensing review to cover. The linked issue's original wording ("commit a few small sample wheels and sdists") is not what this does — this keeps the issue's intent (toolchain-free, network-freeParsecoverage in default CI) without the third-party-content risk of committed binaries.Test cases (
distribution/parse_fixture_test.go)License:header with continuation lines.tar.gz, top-level PKG-INFO not the first tar member, deeper egg-info PKG-INFO with differing values.ascfile with dummy bytesAddGPGSignatureonly reads bytes, no gpg needed)One deviation from the brief: the brief asked for a
Description:header with continuation lines. Empirically,BaseDistribution.Parsealways overwritesdescriptionfrom the message body afterward — even to an empty string, sinceio.ReadAllnever returns a nil slice — so aDescriptionheader's value can never survive intoMetadataMap().Licensehits the samecollapseLeadingWScode path and does survive, so it's used instead to pin the same continuation-handling logic. Worth noting separately: this meansDescription:header parsing is dead code in practice — real long descriptions live in the body, not the header.Assertions are literal
assert.Equalcalls against completemap[string][]stringvalues (no cupaloy — a missing snapshot auto-blesses on first run, which is banned per rstudio/package-manager#19392), plusFileType,PythonVersion,SafeName,BaseFilename, and digests computed independently in the test over the written file bytes.md5_digestis never present (NewPackageFilediscardsHexDigest().md5), confirmed by the full-map equality rather than a separate check.Order among multiple wheels is intentionally never asserted by index (
groupWheelFilesFirst'ssort.Sliceisn't stable) — only that every wheel precedes every sdist.The leak fix
NewArchiveReader's.tar.gz/.tgzbranch openedf, then returned early on atarReadCheckerror without closing it (thegzip.NewReadererror branch right above already does close it). Fixed with the same close-and-log pattern. Regression test inarchive_reader_test.gocounts open descriptors via/dev/fdbefore/after 5 failing calls.Not fixed, flagging only:
tarReader.FileNameshas a real double-close (thegzip.NewReadererror branch closesfexplicitly, and the deferred close runs again right after). It's out of scope for this issue; noting it here rather than silently leaving it.Mutation proof
SDist.read'ssort.Slicecomparator (>instead of<) —TestParse_SDistShortestPathSelectionfailed onversion(3.0.0-staleinstead of3.0.0) andsummary. Reverted.f.Close()inarchive_reader.go—TestNewArchiveReader_TarReadCheckFailure_DoesNotLeakFilefailed (expected: 6, actual: 11, exactly +5 for 5 leaking calls). Reverted.Verification
go test ./... -count=1andgo test -race ./... -count=1: all packages pass.go vet ./...: clean.golangci-lint@v2.11.2 run ./...(CI's pinned version, run from module root): 0 issues. Confirmed errcheck is actually active by planting a temporary uncheckedos.Setenv, seeing it flagged, then removing it.gofmt -l .: clean.go list -deps ./.../-test ./...:pgregory.net/rapidabsent from the non-test graph, present in the test graph (module's MPL invariant intact).NOTICEand the first lines of every file it touches are untouched by this PR; no files are shared between the two diffs.Refs rstudio/package-manager#18746.
🤖 Generated with Claude Code