Skip to content
8 changes: 8 additions & 0 deletions ghascompliance/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
github_arguments.add_argument("--github-repository", default=GITHUB_REPOSITORY)
# github_arguments.add_argument("--github-event", default=GITHUB_EVENT_PATH)
github_arguments.add_argument("--github-ref", default=GITHUB_REF)
github_arguments.add_argument("--github-base-ref", default=None)
github_arguments.add_argument("--github-head-ref", default=None)
# github_arguments.add_argument("--workflow-event", default=GITHUB_EVENT_NAME)
github_arguments.add_argument("--github-policy")
github_arguments.add_argument("--github-policy-branch", default="main")
Expand Down Expand Up @@ -101,6 +103,10 @@
)
Octokit.info(f"GitHub Instance :: {GitHub.instance}")
Octokit.info(f"GitHub Reference (branch/pr) :: {GitHub.repository.reference}")
if arguments.github_base_ref:
Octokit.info(f"GitHub Base Reference :: {arguments.github_base_ref}")
if arguments.github_head_ref:
Octokit.info(f"GitHub Head Reference :: {arguments.github_head_ref}")

if arguments.list_severities:
for severity in SEVERITIES:
Expand Down Expand Up @@ -186,6 +192,8 @@
display=arguments.display,
results_path=results,
caching=arguments.disable_caching,
base_ref=arguments.github_base_ref,
head_ref=arguments.github_head_ref,
)

errors = 0
Expand Down
95 changes: 75 additions & 20 deletions ghascompliance/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def __init__(
debugging: bool = False,
results_path: str = ".compliance",
caching: bool = True,
base_ref: str = None,
head_ref: str = None,
):
self.policy = policy

Expand All @@ -40,6 +42,9 @@ def __init__(

self.caching = caching

self.base_ref = base_ref
self.head_ref = head_ref

os.makedirs(self.results, exist_ok=True)

def getResults(self, name: str, callback: Callable, file_type: str = "json"):
Expand Down Expand Up @@ -83,7 +88,11 @@ def checkCodeScanning(self):
Octokit.info("Code Scanning is not active in the policy")
return 0

if GitHub.repository.isInPullRequest():
if self.base_ref:
Octokit.info("Code Scanning Alerts from Base Ref (alert diff)")
alerts = codescanning.getAlertsInPR(self.base_ref)

elif GitHub.repository.isInPullRequest():
Octokit.info("Code Scanning Alerts from Pull Request (alert diff)")
pr_base = (
GitHub.repository.getPullRequestInfo().get("base", {}).get("ref", "")
Expand Down Expand Up @@ -187,7 +196,25 @@ def checkDependabot(self):

depgraph = DependencyGraph()

if GitHub.repository.isInPullRequest():
if self.base_ref and self.head_ref:
Octokit.info("Dependabot Alerts from Base Ref (alert diff)")
dependencies = depgraph.getDependenciesInPR(self.base_ref, self.head_ref)
alerts = []
try:
open_alerts = dependabot.getAlerts("open")
for pending_alert in open_alerts:
for alert in dependencies:
if pending_alert.manifest == alert.path:
# Compare the Purl
if alert.getPurl(version=False) == pending_alert.purl:
# check if the security_advisory ghsa_id matches the alert vulnerabilitity advisory_ghsa_id
for vuln in alert.alerts:
if vuln.advisory.ghsa_id == pending_alert.advisory.ghsa_id:
alerts.append(pending_alert)
break
except Exception as err:
Octokit.warning(f"Unable to get Dependabot alerts :: {err}")
elif GitHub.repository.isInPullRequest():
Octokit.info("Dependabot Alerts from Pull Request")
pr_info = GitHub.repository.getPullRequestInfo()
pr_base = pr_info.get("base", {}).get("ref", "")
Expand All @@ -196,8 +223,20 @@ def checkDependabot(self):
# note, need to use dep review API
dependencies = depgraph.getDependenciesInPR(pr_base, pr_head)
alerts = []
for dep in dependencies:
alerts.extend(dep.alerts)
try:
open_alerts = dependabot.getAlerts("open")
for pending_alert in open_alerts:
for alert in dependencies:
if pending_alert.manifest == alert.path:
# Compare the Purl
if alert.getPurl(version=False) == pending_alert.purl:
# check if the security_advisory ghsa_id matches the alert vulnerabilitity advisory_ghsa_id
for vuln in alert.alerts:
if vuln.advisory.ghsa_id == pending_alert.advisory.ghsa_id:
alerts.append(pending_alert)
break
except Exception as err:
Octokit.warning(f"Unable to get Dependabot alerts :: {err}")

else:
# Alerts
Expand All @@ -212,7 +251,6 @@ def checkDependabot(self):
dependencies = depgraph.getDependencies()

Octokit.info("Total Dependabot Alerts :: " + str(len(alerts)))

for alert in alerts:
if alert.get("dismissReason") is not None:
Octokit.debug(
Expand Down Expand Up @@ -312,12 +350,20 @@ def checkDependencyLicensing(self):
return 0

# TODO: Check if enabled

if GitHub.repository.isInPullRequest():
if self.base_ref and self.head_ref:
Octokit.info("Dependencies from Base Ref")
dependencies = depgraph.getDependenciesInPR(self.base_ref, self.head_ref)
elif GitHub.repository.isInPullRequest():
Octokit.info("Dependencies from Pull Request")
pr_info = GitHub.repository.getPullRequestInfo()
pr_base = pr_info.get("base", {}).get("ref", "")
pr_head = pr_info.get("head", {}).get("ref", "")
if self.base_ref:
pr_base = self.base_ref
else:
pr_base = pr_info.get("base", {}).get("ref", "")
if self.head_ref:
pr_head = self.head_ref
else:
pr_head = pr_info.get("head", {}).get("ref", "")
dependencies = depgraph.getDependenciesInPR(pr_base, pr_head)
else:
dependencies = depgraph.getDependencies()
Expand Down Expand Up @@ -392,7 +438,7 @@ def checkDependencyLicensing(self):
continue

licensing_violations.append(
[violation.fullname, violation.license if warning.license else "None"]
[violation.fullname, violation.license if violation.license else "None"]
)
if self.display:
Octokit.error(
Expand Down Expand Up @@ -456,12 +502,20 @@ def checkDependencies(self):
return 0

# TODO: Check if DependencyGraph is enabled in GitHub

if GitHub.repository.isInPullRequest():
if self.base_ref and self.head_ref:
Octokit.info("Dependencies from Base Ref")
dependencies = depgraph.getDependenciesInPR(self.base_ref, self.head_ref)
elif GitHub.repository.isInPullRequest():
Octokit.info("Dependencies from Pull Request")
pr_info = GitHub.repository.getPullRequestInfo()
pr_base = pr_info.get("base", {}).get("ref", "")
pr_head = pr_info.get("head", {}).get("ref", "")
if self.base_ref:
pr_base = self.base_ref
else:
pr_base = pr_info.get("base", {}).get("ref", "")
if self.head_ref:
pr_head = self.head_ref
else:
pr_head = pr_info.get("head", {}).get("ref", "")
dependencies = depgraph.getDependenciesInPR(pr_base, pr_head)

else:
Expand All @@ -480,12 +534,13 @@ def checkDependencies(self):
names.append(dependency.getPurl())

#  none is set to just check if the name or pattern is discovered
if self.policy.checkViolation("none", "dependencies", names=names, ids=ids):
dependency_violations.append([dependency.fullname])
if self.display:
Octokit.error(
"Dependency Graph Alert :: {}".format(dependency.fullname)
)
for alert in dependency.alerts:
if self.policy.checkViolation(alert.severity, "dependencies", names=names, ids=ids):
dependency_violations.append([dependency.fullname])
if self.display:
Octokit.error(
"Dependency Graph Alert :: {}".format(dependency.fullname)
)

violation_count = len(dependency_violations)
Octokit.info(f"Dependency Graph violations :: {violation_count}")
Expand Down
2 changes: 1 addition & 1 deletion vendor/ghastoolkit/supplychain/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def getPurl(self, version: bool = True) -> str:
if self.manager:
result += f"{self.manager.lower()}/"
if self.namespace:
result += f"{self.namespace}/"
result += f"{self.namespace}:"
result += f"{self.name}"
if version and self.version:
result += f"@{self.version}"
Expand Down