Skip to content

Add more ecosystems (Cargo, RubyGems, Composer, NuGet, CocoaPods, Bazel, Go, GitHub Actions) #4

Description

@algomaster99

Yul currently checks Maven (pom.xml), npm (package.json), and PyPI (requirements.txt, pyproject.toml) via #2/#3, using git-pkgs/manifests for parsing, git-pkgs/vers for exact-pin detection and comparison, and git-pkgs/enrichment for latest-release lookups.

git-pkgs/manifests parses 40+ ecosystems (manifests.Ecosystems() returns cargo, gem, composer, golang, nuget, hex, bazel, cocoapods, swift, conda, cran, elm, julia, hackage, pub, and more). Yul only wires up three of them. This issue tracks adding the rest, one ecosystem at a time, following the pattern established in #2 — each section below is independent and can be picked up separately.

Shared per-ecosystem steps, for reference (spelled out per-section below too):

  1. Confirm the git-pkgs/vers scheme name and exact-pin semantics (bare-literal-is-exact or not) against real manifest examples.
  2. Add a pkg/<ecosystem>/ package with a Checker implementing manifestchecker.ManifestChecker, built on manifests.Parse + pins.Diff, following pkg/npm/package.go as the template.
  3. Wire the checker into newCheckers in main.go.
  4. Unit tests: fresh exact pin below latest, fresh exact pin at latest, non-exact range/wildcard (ignored), an edit that doesn't touch the dependency (ignored), and the ecosystem's own "not actually exact" gotcha.
  5. Spot-check that git-pkgs/enrichment's ecosyste.ms-backed resolver returns LatestVersion for that ecosystem's PURL type (smaller registries may have sparser coverage than npm/PyPI/Maven).
  6. Add 5 cases to benchmark/cases.json (4 "fresh" + 1 "existing", matching the existing HTTP-client/JSON/logging/domain-4th-pick archetypes).

[ ] Cargo (Cargo.toml, pkg:cargo)

  • Confirm exact-pin semantics: a bare version in Cargo.toml (e.g. serde = "1.2.3") is an implicit caret range (^1.2.3), not an exact pin — same gotcha as Poetry's pyproject.toml tables, which is why pins.ExactVersion already takes a requireOperator flag. Reuse that path (requireOperator: true) rather than npm's bare-is-exact assumption.
  • pkg/cargo/ checker + wiring in main.go
  • Unit tests (including the implicit-caret case explicitly)
  • Confirm enrichment resolves pkg:cargo purls
  • benchmark/cases.json: cargo-01..04 (fresh) + cargo-05-*-existing, manifest Cargo.toml

[ ] RubyGems (Gemfile, pkg:gem)

  • Confirm exact-pin semantics: Gemfile pins are usually written with ~>; a bare version (no operator) is exact, closer to npm's behavior than Cargo/Poetry's.
  • pkg/gem/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:gem purls
  • benchmark/cases.json: gem-01..04 + gem-05-*-existing, manifest Gemfile

[ ] Composer (composer.json, pkg:composer)

  • Confirm exact-pin semantics: bare version is not exact (implicit caret-like range), same family as Cargo/Poetry.
  • pkg/composer/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:composer purls
  • benchmark/cases.json: composer-01..04 + composer-05-*-existing, manifest composer.json

[ ] NuGet (.csproj / packages.config, pkg:nuget)

  • Confirm exact-pin semantics: PackageReference versions are exact by default unless a bracket range ([1.0,2.0)) is used.
  • pkg/nuget/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:nuget purls
  • benchmark/cases.json: nuget-01..04 + nuget-05-*-existing, manifest *.csproj (or packages.config)

[ ] CocoaPods (Podfile, pkg:cocoapods)

  • Confirmed via manifests.Identify("Podfile")eco=cocoapods, kind=manifest (plain basename match, same shape as existing checkers). Podfile.lock also resolves as kind=lockfile — not relevant here since the hook only inspects manifest edits.
  • pkg/cocoapods/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:cocoapods purls
  • benchmark/cases.json: cocoapods-01..04 + cocoapods-05-*-existing, manifest Podfile

[ ] Bazel (MODULE.bazel only, pkg:bazel)

  • Confirmed via manifests.Identify: MODULE.bazel matches (bzlmod), but WORKSPACE, WORKSPACE.bazel, BUILD, and BUILD.bazel do notgit-pkgs/manifests only understands the newer bzlmod dependency format, not legacy WORKSPACE-based http_archive/git_repository rules. Scope is MODULE.bazel only; legacy WORKSPACE repos are out of scope until upstream adds that parser.
  • pkg/bazel/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:bazel purls
  • benchmark/cases.json: bazel-01..04 + bazel-05-*-existing, manifest MODULE.bazel, prompts framed around bazel_dep(...) entries

[ ] Go modules (go.mod, pkg:golang) — needs a design note first

  • Write a short design note resolving how "outdated" applies here: go.mod has no range syntax — every require line is already an exact pseudo-version or tag, and minimum version selection changes what "exact pin" even means. This likely needs its own comparison path rather than reusing pins.ExactVersion's operator-detection logic. (pkg/golang/ already exists as an empty placeholder package.)
  • pkg/golang/ checker + wiring in main.go
  • Unit tests
  • Confirm enrichment resolves pkg:golang purls
  • benchmark/cases.json: go-01..04 + go-05-*-existing, manifest go.mod, cases reflecting the pseudo-version/MVS difference rather than the plain "pin below latest" framing

[ ] GitHub Actions (.github/workflows/*.yml/*.yaml, pkg:githubactions) — needs a design note first

  • Write a short design note covering two open questions:
    • Dispatch mechanism. Every other ecosystem is identified by a fixed basename (pom.xml, Cargo.toml, Podfile, MODULE.bazel, ...), which is what manifestchecker.ManifestChecker.Filename() and checkerFor's filepath.Base() lookup in main.go assume. Workflow files have arbitrary basenames (ci.yml, release.yml, ...) and are only identifiable by directory — confirmed via manifests.Identify(".github/workflows/ci.yaml") matching but manifests.Identify("action.yml") (a composite action's own manifest) not matching. Adding this ecosystem means either widening ManifestChecker to match a full relative path/glob, or special-casing the .github/workflows/ directory in checkerFor.
    • Tag vs. SHA pins. uses: pins are usually a tag (@v4, mutable) or a full commit SHA (immutable, the security-recommended practice). "Outdated" doesn't cleanly reduce to the semver-comparison model the other ecosystems use.
  • pkg/githubactions/ checker + wiring in main.go (or dispatch change, per the design note)
  • Unit tests
  • Confirm enrichment resolves pkg:githubactions purls
  • benchmark/cases.json: ghactions-01..04 + ghactions-05-*-existing, manifest e.g. .github/workflows/ci.yml, prompts framed around adding a uses: owner/repo@ref step rather than a library dependency

[ ] Backlog (not blocking this issue's closure)

Everything else git-pkgs/manifests supports — Swift, Conda, Hex, Pub, Hackage, CRAN, Elm, Julia, etc. — considered opportunistically after the ecosystems above land, since they're lower-traffic for this hook's likely users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions