fix(ivy,osgi): encode PURL components instead of formatting them - #1351
Conversation
Neither type appears in the central PURL normalizer's rule list, so nothing downstream re-encodes them and a hand-formatted string is exactly what ships. Both take their components from free-form input — ivy from XML attributes, OSGi from manifest headers — and a space truncated the PURL on re-parse, taking the version with it: `pkg:ivy/org with space/mod?x@1.0` re-parses as `pkg:ivy/org%20with%20space/mod`, and `pkg:osgi/my bundle?x@1.0.0` as `pkg:osgi/my%20bundle`. A `#` in an OSGi `Require-Bundle` became a subpath rather than part of the name. Route every site through the shared encoders. An ivy dependency without an organisation keeps its name-only form, now encoded too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
Greptile SummaryThe PR replaces hand-formatted Ivy and OSGi PURLs with shared component encoders and moves field bounding into those helpers.
Confidence Score: 4/5The PR is not yet safe to merge because sufficiently large encoded OSGi components can still produce truncated, malformed, or versionless PURLs. OSGi PURLs are now encoded correctly, but manifest finalization still truncates the serialized identity and dependency strings after encoding, leaving the previously reported corruption path outstanding. Files Needing Attention: src/parsers/maven/manifest.rs
|
| Filename | Overview |
|---|---|
| src/parsers/utils.rs | Bounds decoded components before constructing simple and namespaced PURLs and documents that callers must not truncate serialized results. |
| src/parsers/ivy.rs | Routes Ivy identity and dependency PURLs through shared encoders and removes post-construction truncation. |
| src/parsers/maven/manifest.rs | Routes OSGi identities and dependencies through the encoder, but common finalization still truncates the serialized PURLs afterward. |
| src/parsers/ivy_test.rs | Adds round-trip coverage for encoded Ivy namespace, name, revision, and dependency components. |
| src/parsers/maven/manifest_test.rs | Adds OSGi reserved-character round-trip coverage but does not cover encoded output crossing the field limit. |
| src/parsers/opam.rs | Stops truncating serialized opam dependency PURLs after helper construction. |
Comments Outside Diff (1)
-
src/parsers/maven/manifest.rs, line 256-258 (link)Encoded OSGi PURLs remain truncated
When an OSGi bundle or dependency name contains enough percent-encoded characters for its serialized PURL to exceed the field limit, this finalization truncates the PURL after encoding, splitting an escape or removing the version and emitting a malformed or incorrect package identity.
Reviews (2): Last reviewed commit: "fix(purl): bound PURL components before ..." | Re-trigger Greptile
Greptile review: applying `truncate_field` to an assembled PURL can cut a percent escape in half or drop a trailing component, turning a valid PURL into one that no longer parses — the opposite of what encoding these components achieved. Bound the name, namespace and version inside the shared builders instead, where truncation lands on a decoded component and the structure survives. Callers no longer truncate the result. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
Summary
ivynorosgiappears in the central PURL normalizer's rule list, so nothing downstream re-encodes them — a hand-formatted string is exactly what ships.pkg:ivy/org with space/mod?x@1.0re-parses aspkg:ivy/org%20with%20space/mod, andpkg:osgi/my bundle?x@1.0.0aspkg:osgi/my%20bundle.#in an OSGiRequire-Bundlebecame a subpath rather than part of the name.Scope and exclusions
Import-PackageandRequire-Bundledependencies — all through the shared encoders added in fix(purl): encode opam, swift and conan PURL components #1350.github,npm,hex,deb,bitbucket,pypi); those need a case decision and are handled separately.How to verify
Before:
pkg:osgi/my bundle?x@1.0.0— re-parsing drops?x@1.0.0entirely. After:pkg:osgi/my%20bundle%3Fx@1.0.0, which round-trips and decodes back to namemy bundle?xwith version1.0.0.The ivy equivalent is worth checking too, since it is the one where the namespace also needs encoding while keeping its
/separator.Intentional differences from Python
Expected-output fixture changes