Skip to content

Commit

Permalink
add enterprise cloud code scanning alerts (#14)
Browse files Browse the repository at this point in the history
* add first draft of enterprise code scanning alerts

* update readme

* update readme

* troubleshoot cs_list type

* split cloud and server cs functions

* fix miscount in secret scanning enterprise
  • Loading branch information
some-natalie authored Jul 27, 2022
1 parent 6f197aa commit b04e287
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 12 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ An example of use is below. Note that the custom inputs, such as if you are wan

```yaml
- name: CSV export
uses: some-natalie/ghas-to-csv@v0.4.0
uses: some-natalie/ghas-to-csv@v0.5.0
env:
GITHUB_PAT: ${{ secrets.PAT }} # you need to set a PAT
- name: Upload CSV
Expand All @@ -49,10 +49,10 @@ An example of use is below. Note that the custom inputs, such as if you are wan
## Reporting
| | GitHub Enterprise Cloud | GitHub Enterprise Server (3.4) | GitHub AE (M2) | Notes |
| | GitHub Enterprise Cloud | GitHub Enterprise Server (3.5) | GitHub AE (M2) | Notes |
| --- | --- | --- | --- | --- |
| Secret scanning | :white_check_mark: Repo<br>:white_check_mark: Org<br>:white_check_mark: Enterprise | :white_check_mark: Repo<br>:white_check_mark: Org<br>:white_check_mark: Enterprise | :white_check_mark: Repo<br>:x: Org<br>:x: Enterprise | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/reference/secret-scanning) |
| Code scanning | :white_check_mark: Repo<br>:white_check_mark: Org<br>:x: Enterprise | :white_check_mark: Repo<br>:x: Org<br>:curly_loop: Enterprise | :white_check_mark: Repo<br>:x: Org<br>:curly_loop: Enterprise | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/reference/code-scanning) |
| Code scanning | :white_check_mark: Repo<br>:white_check_mark: Org<br>:white_check_mark: Enterprise | :white_check_mark: Repo<br>:white_check_mark: Org<br>:curly_loop: Enterprise | :white_check_mark: Repo<br>:x: Org<br>:curly_loop: Enterprise | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/reference/code-scanning) |
| Dependabot | :x: | :x: | :x: | Waiting on [this API](https://github.com/github/roadmap/issues/495) to :ship: |
:information_source: All of this reporting requires either public repositories or a GitHub Advanced Security license.
Expand All @@ -76,10 +76,8 @@ jobs:
data_gathering:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v3
- name: CSV export
uses: some-natalie/ghas-to-csv@v0.4.0
uses: some-natalie/ghas-to-csv@v0.5.0
env:
GITHUB_PAT: ${{ secrets.PAT }} # needed if not running against the current repository
SCOPE_NAME: "OWNER-NAME/REPO-NAME" # repository name, needed only if not running against the current repository
Expand Down
10 changes: 8 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,16 @@
# code scanning
if enterprise.get_enterprise_version(api_endpoint) != "GHEC":
repo_list = enterprise.get_repo_report(url, github_pat)
cs_list = code_scanning.list_enterprise_code_scanning_alerts(
cs_list = code_scanning.list_enterprise_server_code_scanning_alerts(
api_endpoint, github_pat, repo_list
)
code_scanning.write_enterprise_cs_list(cs_list)
code_scanning.write_enterprise_server_cs_list(cs_list)
else:
cs_list = code_scanning.list_enterprise_cloud_code_scanning_alerts(
api_endpoint, github_pat, scope_name
)
code_scanning.write_enterprise_cloud_cs_list(cs_list)

elif report_scope == "organization":
# code scanning
cs_list = code_scanning.list_org_code_scanning_alerts(
Expand Down
123 changes: 121 additions & 2 deletions src/code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def write_org_cs_list(cs_list):
)


def list_enterprise_code_scanning_alerts(api_endpoint, github_pat, repo_list):
def list_enterprise_server_code_scanning_alerts(api_endpoint, github_pat, repo_list):
"""
Get a list of all code scanning alerts on a given enterprise.
Expand Down Expand Up @@ -254,7 +254,7 @@ def list_enterprise_code_scanning_alerts(api_endpoint, github_pat, repo_list):
return alerts


def write_enterprise_cs_list(cs_list):
def write_enterprise_server_cs_list(cs_list):
"""
Write a list of code scanning alerts to a csv file.
Expand All @@ -274,6 +274,8 @@ def write_enterprise_cs_list(cs_list):
writer = csv.writer(f)
writer.writerow(
[
"repository",
"repo_id",
"number",
"created_at",
"html_url",
Expand Down Expand Up @@ -303,6 +305,8 @@ def write_enterprise_cs_list(cs_list):
cs["dismissed_reason"] = "none"
writer.writerow(
[
cs["repository"]["full_name"],
cs["repository"]["id"],
cs["number"],
cs["created_at"],
cs["html_url"],
Expand All @@ -328,3 +332,118 @@ def write_enterprise_cs_list(cs_list):
with open("excluded_repos.csv", "a") as g:
writer = csv.writer(g)
writer.writerow([alert_list])


def list_enterprise_cloud_code_scanning_alerts(
api_endpoint, github_pat, enterprise_slug
):
"""
Get a list of all code scanning alerts on a given enterprise.
Inputs:
- API endpoint (for GHES/GHAE compatibility)
- PAT of appropriate scope
Outputs:
- List of _all_ code scanning alerts in enterprise that PAT user can access
"""

# Get code scanning alerts
url = "{}/enterprises/{}/code-scanning/alerts?per_page=100&page=1".format(
api_endpoint, enterprise_slug
)
headers = {
"Authorization": "token {}".format(github_pat),
"Accept": "application/vnd.github.v3+json",
}
response = requests.get(url, headers=headers)
response_json = response.json()
while "next" in response.links.keys():
response = requests.get(response.links["next"]["url"], headers=headers)
response_json.extend(response.json())

print(
"Found {} code scanning alerts in {}".format(
len(response_json), enterprise_slug
)
)

# Return code scanning alerts
return response_json


def write_enterprise_cloud_cs_list(cs_list):
"""
Write a list of code scanning alerts to a csv file.
Inputs:
- List from list_enterprise_code_scanning_alerts function, which contains
strings and lists of dictionaries for the alerts.
Outputs:
- CSV file of code scanning alerts
- CSV file of repositories not accessible or without code scanning enabled
"""

with open("cs_list.csv", "a") as f:
writer = csv.writer(f)
writer.writerow(
[
"repository",
"repo_id",
"number",
"created_at",
"html_url",
"state",
"fixed_at",
"dismissed_by",
"dismissed_at",
"dismissed_reason",
"rule_id",
"rule_severity",
"rule_tags",
"rule_description",
"rule_name",
"tool_name",
"tool_version",
"most_recent_instance_ref",
"most_recent_instance_state",
"most_recent_instance_sha",
"instances_url",
]
)
for cs in cs_list: # loop through each alert in the list
if cs["state"] == "open":
cs["fixed_at"] = "none"
cs["dismissed_by"] = "none"
cs["dismissed_at"] = "none"
cs["dismissed_reason"] = "none"
writer.writerow(
[
cs["repository"]["full_name"],
cs["repository"]["id"],
cs["number"],
cs["created_at"],
cs["html_url"],
cs["state"],
cs["fixed_at"],
cs["dismissed_by"],
cs["dismissed_at"],
cs["dismissed_reason"],
cs["rule"]["id"],
cs["rule"]["severity"],
cs["rule"]["tags"],
cs["rule"]["description"],
cs["rule"]["name"],
cs["tool"]["name"],
cs["tool"]["version"],
cs["most_recent_instance"]["ref"],
cs["most_recent_instance"]["state"],
cs["most_recent_instance"]["commit_sha"],
cs["instances_url"],
]
)
else:
with open("excluded_repos.csv", "a") as g:
writer = csv.writer(g)
writer.writerow([cs])
2 changes: 0 additions & 2 deletions src/secret_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,6 @@ def write_enterprise_secrets_list(secrets_list):
alert["resolved_by"]["site_admin"],
alert["secret_type"],
alert["secret_type_display_name"],
alert["secret_type"],
alert["secret_type_display_name"],
alert["repository"]["full_name"],
alert["repository"]["owner"]["login"],
alert["repository"]["owner"]["type"],
Expand Down

0 comments on commit b04e287

Please sign in to comment.