Fix package-version dropdown hiding fresh versions behind lex-sort + take
Summary
-
Real bug: a user pushed Docker image
1.1.0after a long history of1.0.x-Ntags; the Create-Release dropdown showed 30 versions ending at1.0.3-8and1.1.0was missing. Docker registries return tags in lexicographic order, where1.0.3-8sorts before1.1.0('0' < '1'at the third character). The strategy was truncating totake=30BEFOREPackageVersionFiltersorted by semver — fresh versions past the lex-take were invisible. -
Fix:
IPackageVersionStrategy.ListVersionsAsyncno longer takes atakeparameter. Strategies return ALL upstream versions (with pagination + sanity cap);PackageVersionFilter.Applybecomes the single point of filter + semver sort + take. -
Scaling: Docker + GitHub now follow RFC 5988
Link: rel="next"headers across pages; Helm is single-file (no pagination needed). All three strategies enforce a 5000-default enumeration cap to protect against pathological feeds, withSQUID_PACKAGE_VERSION_MAX_ENUMERATEenv-var override (Rule 8).
Changes
| File | Change |
|---|---|
IPackageVersionStrategy.cs |
Drop take param; doc-comment explains the production bug it fixed |
DockerPackageVersionStrategy.cs |
Pagination loop with sticky bearer-token upgrade on 401 — ?n=100 per page, follow Link header |
GitHubPackageVersionStrategy.cs |
?per_page=100 (was ?per_page={take}) + Link-header pagination loop |
HelmPackageVersionStrategy.cs |
Drop pre-sort take; cap parameter is now a sanity ceiling only |
ExternalFeedPackageVersionService.cs |
Calls strategy without take; passes take only to PackageVersionFilter.Apply
|
LinkHeaderParser.cs (new) |
Pure RFC 5988 parser — GitHub absolute + Docker relative URLs, case-insensitive rel, quoted + bare values |
PackageVersionEnumerationCap.cs (new) |
SQUID_PACKAGE_VERSION_MAX_ENUMERATE env-var-pinnable cap (default 5000) |
Test plan
-
Unit: 5108/5108 pass ( dotnet test tests/Squid.UnitTests/) -
User bug pinned: ListVersionsAsync_ShouldNotHideNewerVersionBehindLexSort(32 lex-ordered Docker tags ending at1.1.0→ result top-of-list is1.1.0) -
Drift pins: MaxTagsPerPage/MaxReleasesPerPage(100),PackageVersionEnumerationCap.Default(5000),MaxItemsEnvVarliteral (Rule 8) -
LinkHeaderParser: 13 cases covering both URL styles + edge formats -
Strategy parsers inverted: each ShouldRespectTakeLimittest nowShouldReturnAllTagsFromPage_NoTruncationso re-introducing pre-sort truncation fails loudly -
Manual: verify the dropdown shows 1.1.0at top of the user's actual web feed in staging post-deploy
Rollout
git revert is clean — no schema or DI surface changed. The contract change is internal-only (IPackageVersionStrategy); the public IExternalFeedPackageVersionService.ListVersionsAsync signature is unchanged so request handlers + callers are untouched.