Skip to content

feat(tools): Packagist enrichment in get_dependency_blast_radius - #107

Open
manus-use wants to merge 1 commit into
mainfrom
feat/enrich-packagist
Open

feat(tools): Packagist enrichment in get_dependency_blast_radius#107
manus-use wants to merge 1 commit into
mainfrom
feat/enrich-packagist

Conversation

@manus-use

Copy link
Copy Markdown
Owner

Summary

Adds _enrich_packagist to get_dependency_blast_radius.py, bringing PHP/Packagist package coverage to the blast-radius tool.

What changed

src/manus_agent/tools/get_dependency_blast_radius.py

  • New constant _PACKAGIST_PKG_URLhttps://packagist.org/packages/{name}.json
  • New helper _extract_packagist_latest_stable(versions) — filters out dev/branch aliases (names containing dev) and returns the highest stable version using version_normalized for correct sort ordering
  • New helper _extract_packagist_first_release(pkg) — prefers the top-level time field (package first-indexed date); falls back to the oldest time value across all version entries
  • New _enrich_packagist(name) — single API call pattern:
    • downloads.total, downloads.monthly, downloads.daily — download stats
    • weekly_downloads = monthly // 4 — weekly proxy so _blast_score works correctly (PHP packages have no weekly endpoint)
    • dependent_packages_count from pkg.dependents — Packagist tracks this natively
    • favers — Packagist star-equivalent
    • latest_version — latest stable (dev excluded)
    • total_versions — total version count
    • first_release_date + age_years — derived from package time field
    • home_page from pkg.repository
    • description truncated to 120 chars
    • ISO-8601 normalisation handles Z suffix, +HH:MM offset, naive TZ, sub-second fractions (any precision)
    • datetime.now(timezone.utc) used instead of deprecated utcnow()
  • _enrich_package dispatch: new elif eco_lower in ("packagist", "php", "composer") branch
  • Packagist output block in main tool output loop:
    • Latest version, Total versions, Total downloads, PHP dependents, Packagist favers, First released + age, Description, Repository
  • Doc string update: Packagist listed as data source Feat: Virtualized Environment Exploit Automation  #7; blast-radius metric list updated
  • Summary footer: "npm dependent packages" → "dependent packages" (generic, covers all ecosystems)

tests/test_dependency_blast_radius.py

25 new tests across 4 new classes:

Class Tests
TestExtractPackagistLatestStable 5
TestExtractPackagistFirstRelease 5
TestEnrichPackagist 12
TestEnrichPackageDispatch (additions) 3

Highlights:

  • test_weekly_downloads_is_monthly_divided_by_four — verifies the proxy formula
  • test_weekly_downloads_none_when_monthly_absent — graceful degradation
  • test_blast_score_critical_for_large_monthly_downloads — 20M monthly → weekly proxy 5M → CRITICAL
  • test_blast_score_uses_dependent_packages_count — 60K dependents → CRITICAL
  • test_full_output_contains_packagist_fields — end-to-end integration test for CLI output lines
  • All HTTP calls mocked; no real network I/O

Design decisions

  • Single API call — unlike npm (2 calls) and NuGet (2 calls), Packagist returns all needed data in one /packages/{name}.json response. The downloads block includes total, monthly, and daily. dependents and favers are top-level fields.
  • Weekly proxy — Packagist has no weekly download endpoint. monthly // 4 is a conservative approximation. This ensures _blast_score produces meaningful labels (symfony/http-foundation has 16M monthly → 4M weekly → CRITICAL).
  • Dev version filter — Packagist versions dict contains branch aliases like 2.0.x-dev and dev-main. These are filtered by the presence of dev (case-insensitive) before sorting by version_normalized.
  • time field — the top-level package.time is Packagist's "when this package was first indexed" and reliably gives the earliest release date without scanning all version timestamps.
  • No auth required — Packagist API is fully public and unauthenticated.

Existing open PRs checked — confirmed no overlap

#51 (silent-patches), #53 (cve-timeline), #54 (version-range), #58 (vendor-response), #60 (poc-freshness), #64 (sbom-scan), #65 (temporal-priority), #67 (variant-cluster), #74 (epss-decay), #75 (exploit-maturity), #76 (vulnerability-triage-card), #77 (cve-report-generator), #78 (diff-report), #79 (reachability-scorer), #80 (epss-watchlist), #82 (attack-surface-scorer), #83 (watch-alert), #85 (cli-integration-tests), #86 (patch-lag-rating), #87 (kev-context-dimension), #88 (readme-scoring-workflow), #89 (core-tools-test-suite), #90 (exploit-search-tools-tests), #96 (maven-first-release-date), #97 (osv), #98 (pypi-first-release-date), #100 (npm-first-release-date), #103 (enrich-crates), #104 (enrich-rubygems), #105 (enrich-nuget), #106 (enrich-go) — none overlap with Packagist enrichment.

Test count delta

Suite Before After
test_dependency_blast_radius.py 99 99 + 25 = 124
Full suite 1158 1183

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant