Repository navigation
Conversation
Adds a new `dependabot` subcommand alongside `code-scanning`, auditing whether the dependency graph, Dependabot alerts, version updates, pull request health and dependency review enforcement are actually working, not just enabled. Key features: - Dependency graph coverage detection for Maven/Gradle/NuGet manifests that need build-time or lockfile resolution to show transitive dependencies, with auto-submission mitigation detection (workflow-file scan across 14+ known marketplace actions, plus an SBOM-based fallback for GitHub's native no-workflow-file toggle). - Dependabot alert counts by severity (critical/high/medium/low) plus a separate malware-classification count. - Authoritative pause-for-inactivity detection via the automated-security-fixes endpoint (works even with zero open PRs), falling back to the dependabot-paused label when unavailable. - Security-update vs. version-update pull request classification via the RepositoryVulnerabilityAlert.dependabotUpdate GraphQL linkage, with a package-name fallback for stale/missing links. - Dependency review enforcement checked via required-status-check patterns at diagnostics depth, correctly skipped (not reported as an error) for GitHub's temporary private security-advisory forks, identified by their documented -GHSA-xxxx-xxxx-xxxx name suffix. - Shared concurrency/--verbose progress reporting improvements applied to both commands. - GraphQL client retry coverage extended to secondary rate limits, 5xx responses, GraphQL-level execution timeouts, and truncated response bodies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Incomplete evidence and health-detection errors can produce misleading healthy verdicts and inaccurate audit results.
15 open findings
Collection failures do not mark evidence incomplete · New Dependency inspection cap misclassifies transitive coverage · New Unparseable and oversized manifests do not affect completeness · New Submission actions incorrectly mitigate unrelated manifest gaps · New Substring matching accepts disabled or non-submitting workflow actions · New Alert pagination cap reports truncated results as complete · New PR linkage pagination cap produces incomplete mappings · New Commit status inspection omits failing check runs · New PR check failures and skipped checks are silently ignored · New Backlog limits are evaluated across ecosystems instead of blocks · New Branch rules inspection omits classic required checks · New Security configuration filter is accepted but ignored · New Config-depth path leaves Dependabot alerts state undefined · New Pause state is lost on zero-PR and failed collection paths · New Gradle is missing from supported Dependabot ecosystems · New
What changed in this PR
Adds Dependabot health auditing alongside CodeQL auditing, reusing shared scope, cache, concurrency, and output infrastructure.
Changes:
- Adds dependency graph, alert, update PR, and dependency review assessment.
- Introduces report models, output writers, documentation, and tests.
- Adds verbose progress reporting and broader GraphQL retries.
| File | Description |
|---|---|
| README.md | Documents Dependabot auditing and verbose output. |
| internal/output/dependabot.go | Adds table, JSON, NDJSON, and CSV writers. |
| internal/output/dependabot_test.go | Tests report rendering and serialization. |
| internal/model/dependabot.go | Defines report contracts and health classification. |
| internal/model/dependabot_test.go | Tests classification and aggregation. |
| internal/ghapi/client.go | Expands GraphQL retry handling. |
| internal/ghapi/client_test.go | Tests transient GraphQL failures. |
| internal/collector/dependabot.go | Collects and evaluates Dependabot evidence. |
| internal/collector/dependabot_test.go | Tests collection and detection scenarios. |
| internal/collector/dependabot_apitypes.go | Defines API and configuration response types. |
| internal/collector/collector.go | Adds verbose CodeQL scan progress. |
| internal/collector/collector_test.go | Tests verbose progress reporting. |
| go.mod | Makes YAML parsing a direct dependency. |
| cmd/root.go | Registers the Dependabot command. |
| cmd/dependabot.go | Implements command options and report delivery. |
| cmd/dependabot_test.go | Tests validation, filtering, and output. |
| cmd/code_scanning.go | Exposes the verbose flag. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Set Status.Incomplete whenever repo.Errors is non-empty (the single most impactful fix: this was never set, so collection failures could still silently roll up to a healthy verdict). - Config-depth now explicitly sets DependabotAlerts=not-evaluated instead of leaving it a zero-value empty string. - Move the authoritative paused-for-inactivity assignment to the start of collectPullRequests so it survives every early return, including zero open pull requests or a failed pull request list fetch. - Detect failing checks via both the legacy Combined Status endpoint and the separate Checks API (what GitHub Actions actually posts); track pull requests whose check status could not be established at all as "unchecked" rather than implicitly healthy. - Sum open-pull-requests-limit per ecosystem across all configured update blocks (VersionUpdates.EcosystemLimits), instead of multiplying a single default limit by the count of distinct ecosystems, so two blocks for the same ecosystem no longer collapse into one block's worth of headroom. - Add gradle to the dependency-graph/alert ecosystem coverage map (Gradle dependencies are tracked under the GraphQL MAVEN enum value). - Reject --security-configuration for the dependabot command instead of silently ignoring it (no filtering mechanism exists for it today). - Record alert-list and vulnerability-alert-linkage pagination-cap truncation as collection errors instead of silently reporting a truncated result as complete. - Record unparseable/oversized manifests as collection errors so they correctly feed Status.Incomplete. - Treat a manifest whose dependency sample was capped by the GraphQL query's own per-manifest limit, with no transitive dependency found in the inspected subset, as inconclusive rather than a confirmed gap. - Scope auto-submission mitigation to the ecosystem(s) a detected action can actually resolve, so a Maven-only submission action no longer mitigates an unrelated NuGet manifest gap. - Strip commented-out workflow lines before substring-matching auto-submission markers, and remove gradle/actions/setup-gradle and gradle/gradle-build-action (both default dependency-graph submission to disabled) from the known-detector list. - Also check classic branch protection (required_status_checks) for a dependency-review-matching check, not just rulesets, which are two independent systems. Adds 17 new unit tests covering every fix above.
…gging inconclusive The dependencyGraphManifests nested dependencies connection caps each manifest at the first 100 dependencies in the bulk query, but GitHub's schema (DependencyGraphDependencyConnection) actually supports full cursor pagination via the Node interface. Rather than leaving a manifest with >100 dependencies and no transitive dependency in that first-100 sample as permanently inconclusive, page through its remaining dependencies (bounded by a 10-page safety cap) looking for a transitive one, with an early exit as soon as one is found. Only confirmed-gap or confirmed-coverage results in a settled classification now; "inconclusive" is reserved for the rare case where the safety cap is hit before the manifest's dependency list is exhausted. This replaces the earlier scope-limited fix (always inconclusive, never confirmed) with a more complete one, after confirming via the public GraphQL schema reference and live API testing that pagination is actually available here, and that it successfully returns a confident transitive- relationship signal beyond the first page for a real Maven repository.
The 10-page cap was an arbitrary round number, not derived from any real worst case. This cap is fundamentally different from the per-repo alert (3 page) and vulnerability-alert-linkage (5 page) caps elsewhere in this collector: those apply to every repository that has any alerts, so their cost multiplies across an entire org scan. This one only ever applies to an ambiguous Maven/Gradle/NuGet manifest with zero transitive dependencies in its first 100 (npm, pip, etc. never reach this code path at all, since their relationships are already known from a static lockfile parse) -- a live scan of 100 real repositories never hit this even once. Raised to 50 pages (5,100 total dependencies inspected) as a generous safety net against a pathological manifest or a non-terminating cursor, not as a practically-expected limit.
There was a problem hiding this comment.
Note
Copilot was unable to run its full agentic suite in this review.
Copilot review overview
7 open findings
This logic can accidentally treat non-tool SPDX creator entries (e.g.,Person: .../… · New These limitations don’t match the implementation in this PR: (1) the collector does parse… · New The append loop iterates over a map, so the order of added org-error entries is non-deterministic.… · NewisNotFoundErroris currently based on substring matches againsterr.Error(), which is brittle… · NewbuildTimeResolutionManifesttreats.vbprojas NuGet build-time-resolution manifests, but… · NewResolveDependabotPropertyColumnsreturns property column names in map-iteration order, which is… · New This comment saysStateis used to exclude FIXED/DISMISSED alerts from the package-name fallback,… · New
15 resolved since last review
Branch rules inspection omits classic required checks Backlog limits are evaluated across ecosystems instead of blocks PR check failures and skipped checks are silently ignored Commit status inspection omits failing check runs PR linkage pagination cap produces incomplete mappings Alert pagination cap reports truncated results as complete Substring matching accepts disabled or non-submitting workflow actions Submission actions incorrectly mitigate unrelated manifest gaps Unparseable and oversized manifests do not affect completeness Dependency inspection cap misclassifies transitive coverage Collection failures do not mark evidence incomplete Gradle is missing from supported Dependabot ecosystems Pause state is lost on zero-PR and failed collection paths Config-depth path leaves Dependabot alerts state undefined Security configuration filter is accepted but ignored
🧠 Review effort: Lite
…, brittle error matching - SBOM creator parsing: require creator entries to actually start with "Tool:" before treating them as a tool name; strings.TrimPrefix silently passes through non-tool entries (Person:/Organization:) unchanged, which were being misread as unrecognized auto-submission tools. - README: corrected two stale "Limitations" bullets describing behavior this PR had already superseded (re-parsing open-pull-requests-limit per block, and the temp_clone_token-based temporary-fork signal), updating them to describe the actual current collector logic. - mergeDependabotOrgErrors: sort the rebuilt organization list by login (mirroring code scanning's mergeOrgErrors), since appending previously- errored orgs back in map-iteration order made this user-facing output non-deterministic across runs. - Replace the collector's brittle, substring-based isNotFoundError (which misclassified any error whose text happened to mention "404" or "not found") with the existing, type-safe ghapi.IsNotFound helper already used throughout the code-scanning collector. - manifestEcosystem: classify .vbproj as "nuget", matching buildTimeResolutionManifest, which already treats it as a NuGet build-time-resolution manifest; the mismatch left .vbproj-only repositories showing no ecosystem at all. - ResolveDependabotPropertyColumns: sort the discovered property columns and pick the lexicographically-smallest spelling per folded name (mirroring code scanning's PropertyColumns), fixing non-deterministic CSV/table column ordering and casing. - Corrected a stale comment describing vulnerabilityAlertPullRequestNode's State field as used to filter the package-name fallback; filtering already happens at the GraphQL query level (states:[OPEN,AUTO_DISMISSED]), so the field is not read anywhere in the collector today. Adds 6 new tests covering the behavioral fixes above.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Adds a new
dependabotsubcommand alongsidecode-scanning, auditing whether the dependency graph, Dependabot alerts, version updates, pull request health, and dependency review enforcement are actually working, not just enabled. Sharescode-scanning's scope flags, cache, concurrency, and output formats (table/json/ndjson/csv).Key features
malware.automated-security-fixesendpoint (works even with zero open PRs), falling back to thedependabot-pausedlabel only when that endpoint is unavailable.RepositoryVulnerabilityAlert.dependabotUpdateGraphQL linkage (the only authoritative signal), with a package-name fallback for alerts whose link is stale or missing, and a body-text heuristic as a last resort.--scan-depth diagnostics. Correctly skipped (not reported as a collection error) for GitHub's temporary private security-advisory forks, identified by their documented-ghsa-xxxx-xxxx-xxxxname suffix — their rules/rulesets endpoints always 404 regardless of the real repository's configuration.--verboseprogress reporting (per-repository name, status, elapsed time) and explicit concurrency reporting, applied to bothdependabotandcode-scanning."timedout"), and truncated/empty response bodies, all previously unretried and causing permanent first-attempt failures.Testing
go build ./...,go vet ./...,go test ./...all pass (all packages, including a Windows-native run)gofmt -lclean on every changed filego mod tidyproduces no diffdependabotcommand covering dependency-graph coverage, auto-submission detection (workflow + SBOM), alert severity/malware counting, PR security/version classification, pause detection, dependency-review skip logic, and GraphQL retry behaviorNotes for reviewers
code-scanningcommand's behavior beyond the shared--verbose/concurrency-reporting addition.temp_clone_tokenfield, which turns out to be populated for every private/internal repository, not just these forks. It was replaced with GitHub's documented name-suffix convention for these forks, which is far more specific.