Skip to content

Add a dependency_graph check: verify the Dependency graph feature is enabled (not just the dependency-review workflow) #110

Description

@pofallon

Summary

Hangar has no check that verifies the GitHub Dependency graph feature is enabled on a repo. The two adjacent Supply-chain checks each cover something else:

  • dep_review ("Dependency review enabled") passes purely on the presence of the dependency-review-action in .github/workflows/* (see _workflows_group in providers/github/detection.py). It never checks whether the graph the action depends on is actually on.
  • dependabot_alerts reads the vulnerability-alerts endpoint (204/404) — a different feature, and (see below) not a reliable proxy for the graph being enabled.

The result is a blind spot: a repo can show dep_review ✅ and dependabot_alerts ✅ while the dependency-review workflow fails at runtime with "Dependency review is not supported on this repository. Please ensure that Dependency graph is enabled."

Evidence this is real

  • get2knowio/remo: had the dependency-review-action wired up (so dep_review would pass) and vulnerability-alerts returned 204 (so dependabot_alerts would pass), yet every PR's dependency-review check failed because the Dependency graph feature was disabled. Enabling Settings → Advanced Security → Dependency graph was the only fix.

  • Hangar's own Manual policy remediation: settings & org-level checks not fixable by PR #62 already documents the same symptom on the hangar repo:

    Enable Dependency graph … The workflow currently fails with "Dependency review is not supported on this repository." … Hangar's dep_review check passes on the workflow's presence regardless, but the workflow itself only goes green once this is on.

    Manual policy remediation: settings & org-level checks not fixable by PR #62 tracks manually remediating hangar's own repo; this issue is the product gap — teaching Hangar to detect the state across every managed repo.

Proposed change — add a dependency_graph check

1. Check definition — domain/checks/supply_chain.py, group Supply chain:

Check(
    id="dependency_graph", label="Dependency graph enabled", group=_G,
    tier=RemediationTier.link, required_capabilities=caps_for_tier(RemediationTier.link),
    evidence_fail="Dependency graph feature disabled (dependency-review cannot run)",
    doc_url="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph",
),

It complements dep_review: dep_review = the action is wired up; dependency_graph = the feature the action needs is actually on.

2. Detection — providers/github/detection.py, a new group gathered alongside _dependabot_alerts_group. The graph's enablement is not cleanly exposed as a per-repo security_and_analysis field, so probe an endpoint that only works when it's on. Two options (implementer's call, matching Hangar's "honest unknown, never fabricate a pass" rule):

  • SBOM GET /repos/{owner}/{repo}/dependency-graph/sbom — 200 → pass; 403/undeterminable → unknown. Caveat: a fresh-enabled repo can 404 briefly before the first scan, so treat bare 404 cautiously.
  • Compare GET /repos/{owner}/{repo}/dependency-graph/compare/{base}...{head} — this is what the dependency-review action itself calls; it returns a distinct "not supported" error when the graph is off, which is the most faithful signal. Needs two refs (e.g. default_branch~1...default_branch).

⚠️ Do not piggyback on the dependabot_alerts (vulnerability-alerts) signal: on remo that endpoint returned 204 (alerts "enabled") while the graph was genuinely off, so it is not a reliable proxy.

3. Remediation tier = link, not settings_patch. There is no reliable REST API to auto-enable the graph per repo:

  • PATCH /repos/{o}/{r} with security_and_analysis.dependency_graph is silently ignored (verified — no effect).
  • POST /orgs/{org}/dependency_graph/enable_all returns 204 but is org-scoped and effectively a no-op on free-plan orgs (verified on get2knowio).

So it must deep-link the operator, consistent with how secret_scanning/code_scanning are handled. Add to adapter.py's deep_link:

"dependency_graph": "/settings/security_analysis",

(Per _apply_settings' own contract, a settings_patch that can't converge "would be a silent no-op that falsely reports success" — this check must stay link.)

4. Gitea — providers/gitea/detection.py: no dependency-graph feature, so mark dependency_graph as unknown/unsupported alongside dependabot_alerts.

5. Tests / seed — extend the GitHub detection tests (enabled → pass, disabled → fail, 403/no-capability → unknown) and add the id to any seed fixtures.

Acceptance criteria

  • dependency_graph check appears in the Supply-chain group.
  • Detects enabled (pass) / disabled (fail) / undeterminable (unknown) on GitHub, capability-gated.
  • Gitea reports it unknown (unsupported).
  • Remediation deep-links to …/settings/security_analysis (link tier; no false-success settings_patch).
  • Running Hangar against get2knowio/remo (graph now enabled) passes, and would have failed before it was enabled — i.e. it catches the exact state dep_review misses.

Related: #62 (manual remediation checklist that first surfaced this on the hangar repo).

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

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions