Repository navigation
Match denylist entries the way each ecosystem spells names - #555
Merged
Merged
Conversation
Denylist entries were compared as plain PURL strings, but handlers build PURLs from download URLs that spell packages differently, so some denied versions were still served. Entries and checked PURLs now go through one per-ecosystem comparison form: PyPI names follow PEP 503 (case and runs of -, _ and . are equivalent), NuGet ids and versions ignore case, a gem version also matches its platform builds, and a conda entry matches the package in every channel unless it carries a channel qualifier. Cache keys are unchanged.
Denylist entries now also match Composer versions with Packagist's leading v, OCI repositories written as a path, Swift registry packages in either form (also when streaming), Go versions with escaped uppercase letters, and gems whose names contain a dash followed by a digit. OCI manifests are checked by tag and digest, and denied blobs and Swift archives answer 403 instead of 500 or 502.
andrew
approved these changes
Oct 23, 2026
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.
Denylist entries were compared as plain PURL strings, while handlers build PURLs from download URLs that spell packages differently. Some denied versions were still served:
.vs-/_(wheel filenames always use_)nokogiri-1.16.0-x86_64-linux.gemchannel/namenever matched a plain entry, and qualifiers were rejectedEntries and checked PURLs now go through one comparison form in
internal/denylist. Handlers, cache keys and DB rows are unchanged. A conda entry matches every channel unless it has achannelqualifier. The docs list how each ecosystem is matched and drop the claim that PyPI separators were already handled.A second commit covers more spellings: Composer's leading
v, OCI repositories written as a path (manifests are now checked by tag and digest too), Swift registry packages in either form and when streaming, Go versions with escaped uppercase letters, and gems with a dash followed by a digit in their name. Gems likedevise-2fawere parsed with the wrong name and version, so their cached copies are fetched again once.