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

Activity

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: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