From 9f96ab7198c18ade3facaeac50d561d7563a6eff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 22:38:20 +0000 Subject: [PATCH 1/3] Initial plan From c67a0e4d36e279701d76d0f5ad0c3d7af5853df6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 22:43:37 +0000 Subject: [PATCH 2/3] Use ghastoolkit paginated GraphQL queries and skip unneeded dependency graph calls Co-authored-by: felickz <1760475+felickz@users.noreply.github.com> --- ghascompliance/checks.py | 15 ++-- .../graphql/GetDependencyAlerts.graphql | 34 --------- .../octokit/graphql/GetDependencyInfo.graphql | 40 ----------- tests/test_checks.py | 70 +++++++++++++++++++ 4 files changed, 80 insertions(+), 79 deletions(-) delete mode 100644 ghascompliance/octokit/graphql/GetDependencyAlerts.graphql delete mode 100644 ghascompliance/octokit/graphql/GetDependencyInfo.graphql create mode 100644 tests/test_checks.py diff --git a/ghascompliance/checks.py b/ghascompliance/checks.py index c106346..18b2c2a 100644 --- a/ghascompliance/checks.py +++ b/ghascompliance/checks.py @@ -20,7 +20,6 @@ __HERE__ = os.path.dirname(os.path.realpath(__file__)) LICENSES = [os.path.join(__HERE__, "data", "clearlydefined.json")] -GRAPHQL_QUERIES = [os.path.join(__HERE__, "octokit", "graphql")] class Checks: @@ -193,8 +192,6 @@ def checkDependabot(self): dependabot_violations = [] dependabot = Dependabot() - # Load the GraphQL Queries from the repo - dependabot.graphql.loadQueries(GRAPHQL_QUERIES) depgraph = DependencyGraph() @@ -224,8 +221,16 @@ def checkDependabot(self): "Dependabot REST API returned 400; retrying with GraphQL alerts API" ) alerts = dependabot.getAlertsGraphQL() - # Dependencies - dependencies = depgraph.getDependencies() + + # Dependencies are only needed to resolve the alerts, skip the + # (expensive) Dependency Graph requests if there are no alerts + if alerts: + dependencies = depgraph.getDependencies() + else: + Octokit.debug( + "No Dependabot alerts, skipping Dependency Graph requests" + ) + dependencies = Dependencies() Octokit.info("Total Dependabot Alerts :: " + str(len(alerts))) diff --git a/ghascompliance/octokit/graphql/GetDependencyAlerts.graphql b/ghascompliance/octokit/graphql/GetDependencyAlerts.graphql deleted file mode 100644 index ff601a6..0000000 --- a/ghascompliance/octokit/graphql/GetDependencyAlerts.graphql +++ /dev/null @@ -1,34 +0,0 @@ -{ - repository(owner: "$owner", name: "$repo") { - vulnerabilityAlerts(first: 100, states: [OPEN], $cursor) { - totalCount - pageInfo { - hasNextPage - endCursor - } - edges { - node { - createdAt - dismissReason - securityVulnerability { - package { - ecosystem - name - } - } - securityAdvisory { - ghsaId - severity - cwes(first: 100) { - edges { - node { - cweId - } - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/ghascompliance/octokit/graphql/GetDependencyInfo.graphql b/ghascompliance/octokit/graphql/GetDependencyInfo.graphql deleted file mode 100644 index fa4689d..0000000 --- a/ghascompliance/octokit/graphql/GetDependencyInfo.graphql +++ /dev/null @@ -1,40 +0,0 @@ -{ - repository(owner: "$owner", name: "$repo") { - name - licenseInfo { - name - } - dependencyGraphManifests { - totalCount - pageInfo { - hasNextPage - endCursor - } - edges { - node { - filename - dependencies { - edges { - node { - packageName - packageManager - requirements - repository { - isArchived - isDisabled - isEmpty - isFork - isSecurityPolicyEnabled - isInOrganization - licenseInfo { - name - } - } - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/tests/test_checks.py b/tests/test_checks.py new file mode 100644 index 0000000..9817077 --- /dev/null +++ b/tests/test_checks.py @@ -0,0 +1,70 @@ +import os +import sys +import unittest +from unittest.mock import MagicMock, patch + +sys.path.append(".") + +from ghastoolkit import GitHub +from ghastoolkit.octokit.graphql import QUERIES + +from ghascompliance import checks as checks_module +from ghascompliance.checks import Checks +from ghascompliance.policy import Policy + + +class TestGraphQLQueries(unittest.TestCase): + def testNoLocalQueryOverrides(self): + """Local queries would override the paginated ghastoolkit queries.""" + path = os.path.join( + os.path.dirname(checks_module.__file__), "octokit", "graphql" + ) + self.assertFalse(os.path.exists(path)) + + def testDependencyInfoQueryIsPaginated(self): + """Un-paginated queries time out (502) on large repositories.""" + query = QUERIES.get("GetDependencyInfo", "") + + self.assertIn("dependencyGraphManifests(first:", query) + self.assertIn("$manifests_cursor", query) + self.assertIn("$dependencies_cursor", query) + + +class TestDependabotChecks(unittest.TestCase): + def setUp(self) -> None: + GitHub.init( + "advanced-security/policy-as-code", + reference="refs/heads/main", + retrieve_metadata=False, + ) + self.checks = Checks(Policy("error")) + return super().setUp() + + def testSkipDependencyGraphWithoutAlerts(self): + depgraph = MagicMock() + dependabot = MagicMock() + dependabot.getAlerts.return_value = [] + + with patch.object(checks_module, "Dependabot", return_value=dependabot): + with patch.object(checks_module, "DependencyGraph", return_value=depgraph): + violations = self.checks.checkDependabot() + + self.assertEqual(violations, 0) + depgraph.getDependencies.assert_not_called() + + def testFetchDependencyGraphWithAlerts(self): + alert = MagicMock() + alert.get.return_value = None + alert.purl = "pkg:npm/lodash" + + depgraph = MagicMock() + depgraph.getDependencies.return_value.findPurl.return_value = None + dependabot = MagicMock() + dependabot.getAlerts.return_value = [alert] + + with patch.object(checks_module, "Dependabot", return_value=dependabot): + with patch.object(checks_module, "DependencyGraph", return_value=depgraph): + violations = self.checks.checkDependabot() + + self.assertEqual(violations, 0) + depgraph.getDependencies.assert_called_once() From 00acd919bcef35cc2fe2cc60ad01050d2e6f2be4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:47:51 +0000 Subject: [PATCH 3/3] Fix setUp() to not return super().setUp() Co-authored-by: felickz <1760475+felickz@users.noreply.github.com> --- tests/test_checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_checks.py b/tests/test_checks.py index 9817077..078dd3d 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -38,7 +38,7 @@ def setUp(self) -> None: retrieve_metadata=False, ) self.checks = Checks(Policy("error")) - return super().setUp() + super().setUp() def testSkipDependencyGraphWithoutAlerts(self): depgraph = MagicMock()