Skip to content

Tracking: build and classify purls through one validated utils::purl API #748

Description

[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: discussion #560 register.

Kind: tracking. Source: review 6.4, 7.3; register C20.

Problem (verified on 045d7ec)

utils/purl.rs has two builder families:

On top of these, 42 production format!("pkg:…") sites outside utils/purl.rs build purls by hand. The review counted 48; corrected here. The largest groups:

  • vex/product.rs: 13 sites, including versionless purls
  • vendor/path.rs::leaf_to_purl: 10
  • vendor/lock_inventory/recover.rs: 6
  • vex/discover/mod.rs: 5, with their own PyPI/composer/nuget canonicalization in discover/mod.rs L1455-L1468
  • hosted/engine.rs:622

There are also 24 inline starts_with("pkg:<type>/") checks beside Ecosystem::from_purl.

Drift already present. The families disagree on canonicalization:

  • composer_purl lowercases, while build_composer_purl, leaf_to_purl and recover.rs don't.
  • pypi_purl canonicalizes the name, while leaf_to_purl, recover.rs and the hosted skip purl (hosted/engine.rs:622) don't. vex::discover re-canonicalizes afterwards.
  • vlt.rs:290 alone percent-encodes the npm scope @.

Every consumer that compares purls therefore needs purl_eq/normalize_purl to paper over the differences.

Target design

  • utils::purl exposes one validated constructor per ecosystem (or Purl::new(Ecosystem, ns, name, version) -> Option<String>) that owns name canonicalization (PyPI PEP 503, composer and nuget lowercase), plus one versionless base_purl. build_* becomes private or is deleted.
  • Type checks go through Ecosystem::from_purl.

Checklist (one PR each, in order)

  • Route purl ecosystem checks through Ecosystem::from_purl instead of 24 inline starts_with("pkg:<type>/") tests #747: purl type checks through Ecosystem::from_purl (mechanical; can start now).
  • Vendored ledger keys (vendor/{gem,maven_repo,nuget_feed,composer_lock}.rs) and redirect/golang_local.rs move to the validated builders. An unsafe coordinate becomes a refusal instead of a ledger key. Owner: ecosystems area.
  • vendor/path.rs::leaf_to_purl and lock_inventory/recover.rs build through the validated builders, canonicalizing PyPI and composer once. Delete the re-canonicalization in vex::discover.
  • vex/product.rs versionless/product purls through one base_purl builder.
  • Delete the build_* family and purl_name_version, which only has a test caller.

Dependencies


Consolidated work — backlog review, 2026-10-08

The following standalone issues are now tracked here. Their closure consolidates scheduling; it does not mean their implementation is complete. Original reports and discussion remain linked below.

#630: Move the crawler coordinate guards and composer's leading-v rule into utils and delete the copies

Preserved scope and acceptance criteria from #630

Proposed change

  • Add path_safety::is_safe_name_version(name, version) and move is_safe_maven_coordinate into utils::path_safety.
  • Call them from the three crawlers, simple_purl, maven_purl and vendor/maven_repo.rs.
  • Make utils::composer_version::strip_leading_v pub(crate) and point every normalize_version caller at it: the composer crawler and its oracle, formats::composer, lock_inventory::composer and upstream::composer.

Delete: is_safe_{cargo,gem,nuget}_coordinate and their three test copies (keep one table test on the shared function), plus composer_crawler::normalize_version.

Size and scope

About 40 production lines deleted and about 10 added, in crawlers/{cargo,ruby,nuget,maven,composer}_crawler.rs, utils/{path_safety,purl,composer_version}.rs, formats/composer/mod.rs, patch/redirect/upstream/composer.rs and vendor/maven_repo.rs. There is no behavior change. Out of scope: the go and deno guards, which use multi-segment and JSR-component rules, and the purl builder families (C20).

Acceptance criteria

  • One single-segment name/version guard and one Maven guard, both in utils::path_safety.
  • formats/, utils/ and patch/redirect/ no longer import crawlers::composer_crawler::normalize_version or crawlers::maven_crawler::is_safe_maven_coordinate.
  • One table test covers the traversal, colon, NUL, backslash and empty cases now spread over the three crawler tests. purl_builders_validate_coordinates and the composer test_normalize_version cases, moved to strip_leading_v, stay green.
  • cargo test -p socket-patch-core --lib crawlers and cargo clippy --workspace --all-features -- -D warnings stay green.

Activity

  1. added
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code
    on Oct 4, 2026
  2. mikolalysenko commented on Oct 4, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged: priority:p3 (tracking/refactor). Child work starts with #747. Related: #630.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 8, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue for the architecture refactor routine (highest leverage: the #630 item's three byte-identical crawler coordinate guards and simple_purl's inline copy are the best item in files no open PR touches). Branch: arch-refactor/748-name-version-guard. Claim-ID: 2026-10-08T17:56:10Z-d68635

    Slice: one path_safety::is_safe_name_version for the cargo, gem and NuGet crawlers and purl::simple_purl, deleting is_safe_{cargo,gem,nuget}_coordinate and their three test copies. The composer leading-v half waits for #1108 (it touches upstream/composer.rs); the Maven guard already lives in formats::maven.


    Generated by Claude Code

  4. mikolalysenko commented on Oct 8, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR for the #630 item (coordinate guards slice): #1153.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)priority:p3refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions