V1.0.0 Release#76
Conversation
Fixes #59. Multiple installed versions of a declared package were all flagged as direct/first-party because the check matched by name only. Direct now requires the node to appear as an importer child in the dependency tree AND be declared in the (merged) manifest; the manifest gate protects flat/hoisted tree producers (legacy npm lockfile v1, yarn list fallback). Root-cause attribution for transitive duplicates now climbs to the real direct dependents instead of self-reporting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the retired SaaS enrichment with free, local-first registry checks that run on every online scan: - Zero-dep Node 14-safe HTTP client (src/httpClient.ts) fetching abbreviated packuments for every unique package name (capped, time budgeted, keep-alive pooled) - Bounded best-effort repo-archived checks via the public ecosyste.ms API with a circuit breaker - 7-day TTL cache under ~/.cache/dependency-radar (XDG/%LOCALAPPDATA% aware, DEPENDENCY_RADAR_NO_CACHE/CACHE_DIR overrides) - New maintenance block on DependencyRecord; report schema 1.4 -> 1.5 - Registry deprecation now powers package.deprecated, the deprecated upgrade blocker, and findings (previous local-metadata detection was dead on npm 7+, which stopped writing deprecated into installed package.json); latest version backfilled from dist-tags - New findings (maintenance-archived, maintenance-unmaintained) and fail-on rules (deprecated-dependency, unmaintained-dependency, new-deprecated) - Report UI: Maintenance column, per-dependency Maintenance section, "Maintenance concerns" filter; --no-maintenance and --offline opt-outs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The companion SaaS is retired. The CLI is now fully self-contained: - Delete src/cta.ts and every premium CTA (HTML report card, terminal footer, report-ui dev shell); regenerate embedded report assets - Replace the report header CTA with five stat chips: dependencies, vulnerable, maintenance, licence issues, upgrade blockers — counts computed client-side; vulnerable/maintenance chips click-to-filter - Terminal footer now points at the GitHub repo - SARIF helpUri/informationUri point at the GitHub repo (SPDX document namespace and schema $id keep the domain, which remains alive as the CLI landing page) - README premium section replaced by the maintenance-signals docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds maintenance-signal enrichment, caching, CLI/reporting, and policy support; updates schema/versioned fixtures; and refactors aggregator direct-dependency handling for workspace graphs. ChangesMaintenance Signals Feature
Workspace-Aware Direct Dependency Detection
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant cli.ts
participant enrichAggregatedWithMaintenanceSignals
participant MaintenanceCache
participant httpGetJson
cli.ts->>enrichAggregatedWithMaintenanceSignals: enrichAggregatedWithMaintenanceSignals(aggregated, options)
enrichAggregatedWithMaintenanceSignals->>MaintenanceCache: load()
enrichAggregatedWithMaintenanceSignals->>MaintenanceCache: getFresh(name)
enrichAggregatedWithMaintenanceSignals->>httpGetJson: registry packument request
httpGetJson-->>enrichAggregatedWithMaintenanceSignals: { ok, data }
enrichAggregatedWithMaintenanceSignals->>MaintenanceCache: set(name, entry)
enrichAggregatedWithMaintenanceSignals->>MaintenanceCache: setRepoCheck(name, archived)
enrichAggregatedWithMaintenanceSignals->>MaintenanceCache: save()
sequenceDiagram
participant User
participant populateHeaderStats
participant applyFilters
participant dependency list render
User->>populateHeaderStats: click maintenance stat chip
populateHeaderStats->>applyFilters: toggle maintenanceConcerns checkbox
applyFilters->>applyFilters: filter by hasMaintenanceConcern
applyFilters->>dependency list render: re-render filtered dependencies
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cli.ts (1)
1335-1376: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
printHelp()fail-on rule list wasn't updated for the new maintenance rules.
--fail-onnow supportsdeprecated-dependency,unmaintained-dependency, andnew-deprecated(persrc/failOn.ts), but the "Scan rules"/"Compare rules" lists printed byprintHelp()still omit them, sodependency-radar --helpwon't document these new options.📝 Proposed fix
--fail-on <rules> Fail with exit code 1 when selected rules are violated Scan rules: reachable-vuln, production-vuln, high-severity-vuln, licence-mismatch, copyleft-detected, unknown-licence, - supply-chain-source + supply-chain-source, deprecated-dependency, + unmaintained-dependency Compare rules: new-supply-chain-signal, new-install-script, new-native-binding, new-bin, new-direct-dependency, - new-child-process, new-network-access, new-env-access, + new-deprecated, new-child-process, new-network-access, new-env-access, new-home-access, new-ssh-usage, new-obfuscation-signal,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli.ts` around lines 1335 - 1376, The `printHelp()` output in `src/cli.ts` is missing the newly supported `--fail-on` rules, so update the help text to include `deprecated-dependency`, `unmaintained-dependency`, and `new-deprecated` alongside the existing Scan rules / Compare rules list. Make sure the `printHelp` string stays in sync with the rule names defined in `src/failOn.ts` so `dependency-radar --help` documents all supported options.
🧹 Nitpick comments (2)
src/aggregator.test.ts (1)
269-450: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRepeated fixture setup could be extracted into a shared helper.
Each of the four new tests repeats the same
makeTempDir+writeFile(package.json)+aggregateData({...})boilerplate with only the npm-ls tree and pkg deps differing. A small factory (e.g.buildAggregateInput(overrides)) would reduce duplication and make future scenarios easier to add.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/aggregator.test.ts` around lines 269 - 450, The new aggregator tests repeat the same temp project and aggregateData setup, so extract that boilerplate into a shared test helper. Create a small factory or helper around makeTempDir, fs.writeFile, and aggregateData (for example, a buildAggregateInput-style helper) and reuse it in the four cases, keeping only the package deps and npmLsResult tree specific to each test.src/runners/maintenanceSignals.ts (1)
33-33: 🩺 Stability & Availability | 🔵 TrivialNew third-party dependency: repos.ecosyste.ms for archived-repo checks.
This adds a runtime dependency on a third-party API (rather than the GitHub API directly) for maintenance signals. The circuit breaker and bounded concurrency already handle outages/rate-limits gracefully, but worth tracking this external dependency's availability/rate limits operationally (e.g., dashboards or a fallback note in docs) since it's outside GitHub's own SLA.
Also applies to: 421-455
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/runners/maintenanceSignals.ts` at line 33, The maintenance-signal archived-repo check now depends on the third-party repos.ecosyste.ms API through ECOSYSTEMS_REPOS_BASE and the related fetch logic in maintenanceSignals, so add an operational note/documentation entry about this external dependency and its availability/rate-limit assumptions. Update the maintainer-facing docs or runbook to call out that archived-repo checks are backed by repos.ecosyste.ms, and mention any fallback or monitoring guidance alongside the existing circuit-breaker/bounded-concurrency behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/cli.ts`:
- Around line 1335-1376: The `printHelp()` output in `src/cli.ts` is missing the
newly supported `--fail-on` rules, so update the help text to include
`deprecated-dependency`, `unmaintained-dependency`, and `new-deprecated`
alongside the existing Scan rules / Compare rules list. Make sure the
`printHelp` string stays in sync with the rule names defined in `src/failOn.ts`
so `dependency-radar --help` documents all supported options.
---
Nitpick comments:
In `@src/aggregator.test.ts`:
- Around line 269-450: The new aggregator tests repeat the same temp project and
aggregateData setup, so extract that boilerplate into a shared test helper.
Create a small factory or helper around makeTempDir, fs.writeFile, and
aggregateData (for example, a buildAggregateInput-style helper) and reuse it in
the four cases, keeping only the package deps and npmLsResult tree specific to
each test.
In `@src/runners/maintenanceSignals.ts`:
- Line 33: The maintenance-signal archived-repo check now depends on the
third-party repos.ecosyste.ms API through ECOSYSTEMS_REPOS_BASE and the related
fetch logic in maintenanceSignals, so add an operational note/documentation
entry about this external dependency and its availability/rate-limit
assumptions. Update the maintainer-facing docs or runbook to call out that
archived-repo checks are backed by repos.ecosyste.ms, and mention any fallback
or monitoring guidance alongside the existing
circuit-breaker/bounded-concurrency behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 67235d60-27d8-42b3-ba2e-442ee006261b
⛔ Files ignored due to path filters (14)
dist/aggregator.jsis excluded by!**/dist/**dist/cli.jsis excluded by!**/dist/**dist/cta.jsis excluded by!**/dist/**dist/failOn.jsis excluded by!**/dist/**dist/findings.jsis excluded by!**/dist/**dist/httpClient.jsis excluded by!**/dist/**dist/maintenanceCache.jsis excluded by!**/dist/**dist/outputFormats.jsis excluded by!**/dist/**dist/report-assets.jsis excluded by!**/dist/**dist/report.jsis excluded by!**/dist/**dist/runners/maintenanceSignals.jsis excluded by!**/dist/**dist/schema.jsis excluded by!**/dist/**report-ui/dist/report.cssis excluded by!**/dist/**report-ui/dist/report.iife.jsis excluded by!**/dist/**
📒 Files selected for processing (27)
README.mdreport-ui/index.htmlreport-ui/main.tsreport-ui/sample-data.jsonreport-ui/style.cssreport-ui/types.tssrc/aggregator.test.tssrc/aggregator.tssrc/cli.test.tssrc/cli.tssrc/cta.tssrc/failOn.test.tssrc/failOn.tssrc/findings.test.tssrc/findings.tssrc/httpClient.test.tssrc/httpClient.tssrc/maintenanceCache.test.tssrc/maintenanceCache.tssrc/outputFormats.tssrc/report-assets.tssrc/report.tssrc/runners/maintenanceSignals.test.tssrc/runners/maintenanceSignals.tssrc/runners/npmRegistryMetadata.test.tssrc/schema.tssrc/types.ts
💤 Files with no reviewable changes (1)
- src/cta.ts
Restyle the "scan at a glance" chips as proper stat tiles: the count is now the display element (22px sans semibold, proportional figures) with the micro-label beneath; DOM order is unchanged for screen readers via flex column-reverse. State tints (soft bottom wash + keyline + colored value) apply only when a count is non-zero, clickable tiles gain hover lift and "click to filter" tooltips. CSS-only, no new assets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the gradient washes from the header stat tiles: neutral flat surface, status hue on the value, tinted keyline border only when the count is non-zero. Clickable tiles get a flat hover (accent border + card-hover background) instead of lift/shadow. Replace the glossy native WebKit search cancel button with a flat masked ✕ that follows the theme ink color. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Licence issues and upgrade blockers tiles are now clickable, backed by two new filter-panel checkboxes with live counts (licenseRisk != green; blocksNodeMajor or any upgrade blocker). Clicking any stat tile now clears every other filter (including search) before applying its own, and clicking it again toggles it off — tiles act as shortcuts, not additive filters. All four appear as removable active-filter chips and reset with Clear all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- encodePackageName now percent-encodes every name segment (split/encodeURIComponent/join) instead of a first-occurrence string replace; package names come from installed package.json files, so multi-slash or special-character names can no longer alter the registry URL path. Verified the fully-encoded scoped form resolves against registry.npmjs.org, and added a local-server regression test asserting the exact request path. - Test HTTP servers no longer echo request data (req.url, Accept header) back in response bodies; they capture and assert instead, removing the reflected-XSS taint path CodeQL flagged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The maintenance fetcher passed its https.Agent unconditionally, so an http:// registry URL (private mirrors, tests) made Node reject every request, silently degrading all statuses to unknown. Caught by the new URL-encoding regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
compare previously required the baseline's schemaVersion to exactly match the current one, so the 1.4 -> 1.5 bump would have hard-failed every existing committed baseline (exit 1) on upgrade until users regenerated them. Schema changes since 1.2 are purely additive and all baseline consumers optional-chain the newer fields, so compare now accepts 1.2-1.5 via COMPATIBLE_BASELINE_SCHEMA_VERSIONS. This also makes the documented new-deprecated first-compare behavior actually reachable. Verified end-to-end against a hand-built 1.4 baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial pre-release review (confirmed findings only):
- httpClient: a protocol-mismatched agent (https keep-alive agent on an
http request, reachable via https->http redirects) threw synchronously
inside the promise executor, producing an unhandled rejection and a
never-settling promise that hung the scan. The agent is now dropped on
protocol mismatch, transport.get is guarded, and redirect-hop
rejections settle as failure results. Regression tests added.
- Report UI: .stat-chip's explicit display defeated the [hidden]
attribute, so offline/pre-1.5 reports showed a dead Maintenance tile
that wiped filters when clicked; added .stat-chip[hidden]
{ display: none; }.
- Overall card risk stripe and key points now reflect maintenance
status (deprecated/archived -> red, unmaintained -> amber) instead of
showing a green stripe beside a red Deprecated badge.
- The deprecated finding message now distinguishes latest-only registry
deprecations from installed-version deprecations; the legacy
deprecated detail block shows again when a lookup failed for a
locally-deprecated package.
- maintenanceCache: null-prototype entry store (a dependency literally
named __proto__ can no longer corrupt the cache); registry-sourced
strings are length-capped before caching.
- Docs: README trust section and access table now disclose the default
maintenance/ecosyste.ms lookups; JSON contract snippet bumped to 1.5
with the maintenance block documented; scan-pipeline section and
--help now list the maintenance step and the three new fail-on rules;
stale wording fixes; AGENTS.md paths; npm keywords.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/reportDetailRules.ts`:
- Around line 52-68: The maintenance risk logic in buildReportOverallRisk
currently ignores the documented stale status, so it falls through as green.
Update the maintenanceStatus branch in reportDetailRules.ts to handle
dep.maintenance.status === 'stale' consistently, and make sure
buildReportKeyPoints uses the same status handling so it emits the appropriate
maintenance note. If stale is not meant to be surfaced, then update the
DependencyRecord.maintenance.status model/docs to remove it from the supported
statuses.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: abde66c7-1596-4bbd-a467-a5e0e7807cb2
⛔ Files ignored due to path filters (11)
dist/cli.jsis excluded by!**/dist/**dist/findings.jsis excluded by!**/dist/**dist/httpClient.jsis excluded by!**/dist/**dist/maintenanceCache.jsis excluded by!**/dist/**dist/report-assets.jsis excluded by!**/dist/**dist/report.jsis excluded by!**/dist/**dist/reportDetailRules.jsis excluded by!**/dist/**dist/runners/maintenanceSignals.jsis excluded by!**/dist/**dist/schema.jsis excluded by!**/dist/**report-ui/dist/report.cssis excluded by!**/dist/**report-ui/dist/report.iife.jsis excluded by!**/dist/**
📒 Files selected for processing (18)
AGENTS.mdREADME.mdpackage.jsonreport-ui/index.htmlreport-ui/main.tsreport-ui/style.csssrc/cli.test.tssrc/cli.tssrc/findings.tssrc/httpClient.test.tssrc/httpClient.tssrc/maintenanceCache.tssrc/report-assets.tssrc/report.tssrc/reportDetailRules.tssrc/runners/maintenanceSignals.test.tssrc/runners/maintenanceSignals.tssrc/schema.ts
✅ Files skipped from review due to trivial changes (3)
- AGENTS.md
- src/schema.ts
- package.json
🚧 Files skipped from review as they are similar to previous changes (9)
- src/findings.ts
- report-ui/index.html
- src/httpClient.test.ts
- src/report.ts
- src/httpClient.ts
- src/cli.ts
- src/maintenanceCache.ts
- report-ui/main.ts
- src/runners/maintenanceSignals.ts
| const registryRisk = (dep.supplyChain?.registry?.signals?.length || 0) > 0 ? 'amber' : 'green'; | ||
| const maintenanceStatus = dep.maintenance?.status; | ||
| const maintenanceRisk = | ||
| maintenanceStatus === 'deprecated' || maintenanceStatus === 'archived' | ||
| ? 'red' | ||
| : maintenanceStatus === 'unmaintained' | ||
| ? 'amber' | ||
| : 'green'; | ||
|
|
||
| return maxRisk([ | ||
| summary.risk, | ||
| dep.compliance.licenseRisk, | ||
| installRisk, | ||
| supplyChainRisk, | ||
| registryRisk, | ||
| maintenanceRisk | ||
| ]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== src/reportDetailRules.ts (relevant sections) ==\n'
sed -n '1,220p' src/reportDetailRules.ts | cat -n
printf '\n== README maintenance.status documentation ==\n'
rg -n -A6 -B4 "maintenance\.status|stale|unmaintained|deprecated|archived" README.mdRepository: JosephMaynard/dependency-radar
Length of output: 26295
Handle the documented 'stale' maintenance status. DependencyRecord.maintenance.status includes 'stale', but buildReportOverallRisk treats it as green and buildReportKeyPoints emits no maintenance note for it. Add a branch for 'stale' or update the status model/docs if it should stay silent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/reportDetailRules.ts` around lines 52 - 68, The maintenance risk logic in
buildReportOverallRisk currently ignores the documented stale status, so it
falls through as green. Update the maintenanceStatus branch in
reportDetailRules.ts to handle dep.maintenance.status === 'stale' consistently,
and make sure buildReportKeyPoints uses the same status handling so it emits the
appropriate maintenance note. If stale is not meant to be surfaced, then update
the DependencyRecord.maintenance.status model/docs to remove it from the
supported statuses.
Summary by CodeRabbit
--no-maintenance(and clarified--offline) plus new--fail-onrules fordeprecated-dependencyandunmaintained-dependency, including compare-modenew-deprecated.schemaVersion1.5) changes.