fix(purl): encode opam, swift and conan PURL components - #1350
Merged
Conversation
opam names come from a quoted field, so anything other than a quote reached the PURL verbatim. Splicing them in with `format!` produced strings that either fail to parse or silently change meaning: `ocaml/evil` was reinterpreted as namespace `ocaml` plus name `evil`, `sharp#frag` gained a subpath, `conf gmp` kept a raw space, and an already-encoded `pct%20` decoded to `pct ` instead of the literal name. Build both the package identity and the dependency PURLs through the crate's encoder via a shared `simple_purl` helper for namespace-free types. Every component now survives a round trip and decodes back to the declared text. The helper deliberately excludes the types the crate rewrites — it lowercases names for bitbucket, deb, github, hex, npm and pypi — so those conversions need a decision about case rather than a mechanical swap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
Package and repository names were spliced into `pkg:swift/{namespace}/{name}`
with `format!`, so a name containing a space or any other reserved character
produced a PURL that did not survive a round trip.
Build through the crate's encoder via a `namespaced_purl` helper, which keeps the
namespace's `/` separators — its segments are path parts — while encoding the
name and version.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
A reference carrying a range constraint yields no PURL version, so it took the hand-formatted branch and spliced the name in unencoded — `my pkg/[>=1.0]` produced `pkg:conan/my pkg`, which does not survive a round trip. Route both the versioned and name-only forms through the shared encoder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
Greptile SummaryThis PR replaces hand-formatted opam, Conan, and Swift PURLs with shared packageurl-backed constructors so names, namespaces, and versions are encoded without changing their meaning.
Confidence Score: 5/5The PR appears safe to merge, with no concrete changed-code failure identified. The new constructors preserve the existing parser component choices while applying packageurl validation and encoding, and the investigated omission and identity risks were either pre-existing, invalid-output cases, or lacked a realistic reachable trigger.
|
| Filename | Overview |
|---|---|
| src/parsers/utils.rs | Adds centralized packageurl-backed helpers that trim required components, encode values, and return no PURL when construction fails. |
| src/parsers/opam.rs | Replaces manual package and dependency PURL formatting with encoded construction and adds component round-trip tests. |
| src/parsers/conan.rs | Routes exact, ranged, and name-only Conan references through the shared encoder. |
| src/parsers/conan_test.rs | Adds regression coverage for encoded ranged-reference names and canonical PURL round trips. |
| src/parsers/swift_show_dependencies.rs | Uses the namespaced helper for Swift root and dependency PURLs while preserving existing URL-derived identity behavior. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Parser component values] --> B{PURL shape}
B -->|No namespace| C[simple_purl]
B -->|Namespace required| D[namespaced_purl]
C --> E[packageurl validation and encoding]
D --> E
E --> F[Canonical dependency or package PURL]
Reviews (1): Last reviewed commit: "fix(conan): encode reference PURL compon..." | Re-trigger Greptile
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.
Summary
format!, splicing unvalidated names straight in. The results either fail to parse or silently change meaning.ocaml/evilwas reinterpreted as namespaceocaml+ nameevil;sharp#fraggained a subpath;conf gmpkept a raw space; and an already-encodedpct%20decoded topctrather than the literal name.dependencies[].purlanddependency_uid, which is the output surface nothing downstream re-encodes — assembledpackages[]identities are rebuilt through the crate regardless of type, so package-level sites were already masked. Dependency-level sites are not.Scope and exclusions
simple_purlandnamespaced_purl, so the next conversion is not another hand-rolled string.bitbucket,deb,github,hex,npmandpypi. Converting those (notably.gitmodules, which emitspkg:github/…) is a case-sensitivity decision, not a mechanical swap, so it is deliberately left out.How to verify
Before:
pkg:opam/conf gmp,pkg:opam/ocaml/evil,pkg:opam/sharp#frag. After:pkg:opam/conf%20gmp,pkg:opam/ocaml%2Fevil,pkg:opam/sharp%23frag— each parses, round-trips byte-identically, and decodes back to the declared name.The
pct%20case is the interesting one: already-percent-encoded text is data, so the real name is the six literal characters and the correct PURL ispkg:opam/pct%2520.Intentional differences from Python
packageurl-python, which encodes on construction.Expected-output fixture changes