Skip to content

Commit

Permalink
Merge pull request #13 from GeekMasher/depgraph-updates
Browse files Browse the repository at this point in the history
feat: Update to Dependencies and the Graph
  • Loading branch information
GeekMasher authored May 2, 2023
2 parents f524daa + 1c70d0d commit 86f6ddb
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "ghastoolkit"
version = "0.1.11"
version = "0.1.12"
authors = [
{ name="GeekMasher" },
]
Expand Down
2 changes: 1 addition & 1 deletion src/ghastoolkit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__name__ = "ghastoolkit"
__title__ = "GHAS Toolkit"

__version__ = "0.1.11"
__version__ = "0.1.12"

__description__ = "GitHub Advanced Security Python Toolkit"
__summary__ = """\
Expand Down
5 changes: 2 additions & 3 deletions src/ghastoolkit/octokit/dependabot.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import logging
from typing import Optional

from requests import options

from ghastoolkit import GitHub, Repository
from ghastoolkit.octokit.octokit import GraphQLRequest

Expand Down Expand Up @@ -30,7 +28,8 @@ def getAlerts(self) -> list[dict]:
.get("vulnerabilityAlerts", {})
)

results.extend(alerts.get("edges", []))
for alert in alerts.get("edges", []):
results.append(alert.get("node", {}))

if not alerts.get("pageInfo", {}).get("hasNextPage"):
logger.debug(f"GraphQL cursor hit end page")
Expand Down
54 changes: 46 additions & 8 deletions src/ghastoolkit/octokit/dependencygraph.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fnmatch
import logging
from dataclasses import dataclass, field
from datetime import datetime
Expand All @@ -21,7 +20,7 @@ class Dependency:

licence: Optional[str] = None

def getPurl(self) -> str:
def getPurl(self, version: bool = True) -> str:
"""Get PURL
https://github.com/package-url/purl-spec
"""
Expand All @@ -31,29 +30,50 @@ def getPurl(self) -> str:
if self.namespace:
result += f"{self.namespace}/"
result += f"{self.name}"
if self.version:
if version and self.version:
result += f"@{self.version}"

return result

@staticmethod
def fromPurl(purl: str) -> "Dependency":
dep = Dependency("")
pkg, dep.version = purl.split("@", 1)
# version (at end)
if "@" in purl:
pkg, dep.version = purl.split("@", 1)
else:
pkg = purl

if pkg.count("/") == 2:
slashes = pkg.count("/")
if slashes == 0 and pkg.count(":", 1):
# basic purl `npm:name`
manager, dep.name = pkg.split(":", 1)
elif slashes == 2:
manager, dep.namespace, dep.name = pkg.split("/", 3)
elif pkg.count("/") == 1:
elif slashes == 1:
manager, dep.name = pkg.split("/", 2)
elif pkg.count("/") > 2:
elif slashes > 2:
manager, dep.namespace, dep.name = pkg.split("/", 2)
else:
raise Exception(f"Unable to parse PURL :: {purl}")

_, dep.manager = manager.split(":", 1)
if manager.startswith("pkg:"):
_, dep.manager = manager.split(":", 1)
else:
dep.manager = manager

return dep

@property
def fullname(self) -> str:
"""Full Name of the Dependency"""
if self.namespace:
sep = "/"
if self.manager == "maven":
sep = ":"
return f"{self.namespace}{sep}{self.name}"
return self.name

def __str__(self) -> str:
return self.getPurl()

Expand Down Expand Up @@ -108,6 +128,24 @@ def findLicenses(self, licenses: list[str]) -> "Dependencies":
]
)

def findUnknownLicenses(
self, licenses: Optional[list[str]] = None
) -> "Dependencies":
licenses = licenses or ["NA", "NOASSERTION"]
return self.findLicenses(licenses)

def contains(self, dependency: Dependency) -> bool:
purl = dependency.getPurl(version=False)
for dep in self:
if dep.name == dependency.name or dep.getPurl(version=False) == purl:
return True
return False

def find(self, name: str) -> Optional[Dependency]:
for dep in self:
if dep.name == name or dep.fullname == name:
return dep

def findNames(self, names: list[str]) -> "Dependencies":
"""Find by Name using wildcards"""
regex_list = [re.compile(name_filter) for name_filter in names]
Expand Down
8 changes: 7 additions & 1 deletion src/ghastoolkit/octokit/octokit.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,11 @@ def __init__(self, repository: Optional[Repository] = None) -> None:
self.loadQueries(DEFAULT_GRAPHQL_PATHS)

def query(self, name: str, options: dict[str, Any] = {}) -> dict:
logger.debug(f"Loading Query by Name :: {name}")
query_content = self.queries.get(name)

if not query_content:
return {}
raise Exception(f"Failed to load GraphQL query :: {name}")

cursor = f'after: "{self.cursor}"' if self.cursor != "" else ""

Expand All @@ -235,7 +237,11 @@ def query(self, name: str, options: dict[str, Any] = {}) -> dict:

def loadQueries(self, paths: list[str]):
for path in paths:
if not os.path.exists(path):
logger.debug(f"Query load path does not exist :: {path}")
continue
if not os.path.isdir(path):
logger.debug(f"Query path is not a dir :: {path}")
continue
for file in os.listdir(path):
root = os.path.join(path, file)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_depgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ def test_dependency(self):
self.assertEqual(dep.manager, "pypi")
self.assertEqual(dep.version, "1.11.1")

def test_fullname_maven(self):
dep = Dependency("express", manager="npm")
self.assertEqual(dep.fullname, "express")

dep = Dependency("spring-boot-starter-web", "org.springframework.boot", manager="maven")
self.assertEqual(dep.fullname, "org.springframework.boot:spring-boot-starter-web")

def test_purl(self):
# python
Expand Down Expand Up @@ -41,6 +47,12 @@ def test_purl_from(self):
self.assertEqual(dep.manager, "pypi")
self.assertEqual(dep.version, "2.28.2")

def test_purl_from_basic(self):
dep = Dependency.fromPurl("npm/ini")
self.assertEqual(dep.name, "ini")
self.assertEqual(dep.manager, "npm")


class TestDependencies(unittest.TestCase):
def setUp(self) -> None:
self.deps = Dependencies()
Expand Down Expand Up @@ -73,4 +85,9 @@ def test_findName(self):
self.assertEqual(pys[0].name, "pyyaml")
self.assertEqual(pys[1].name, "pyproject-hooks")

def test_find(self):
dep = self.deps.find("pyyaml")
self.assertIsNotNone(dep)
assert dep is not None
self.assertEqual(dep.name, "pyyaml")

0 comments on commit 86f6ddb

Please sign in to comment.