Skip to content

Add enterprise secret scanning #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ An example of use is below. Note that the custom inputs, such as if you are wan

The API docs are [here](https://docs.github.com/en/enterprise-cloud@latest) and pull requests are welcome! :heart:

## Reporting

| | GitHub Enterprise Cloud | GitHub Enterprise Server (3.4) | 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>:x: Enterprise | :white_check_mark: Repo<br>:x: Org<br>:x: 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.

:information_source: Any item with a :curly_loop: needs some looping logic, since repositories are supported and not higher-level ownership (like orgs or enterprises). How this looks won't differ much between GHAE or GHES. In both cases, you'll need an enterprise admin PAT to access the `all_organizations.csv` or `all_repositories.csv` report from `stafftools/reports`, then looping over it in the appropriate scope. That will tell you about the existence of everything, but not give you permission to access it. To do that, you'll need to use `ghe-org-admin-promote` in GHES ([link](https://docs.github.com/en/enterprise-server@3.4/admin/configuration/configuring-your-enterprise/command-line-utilities#ghe-org-admin-promote))

## Using this with Flat Data

Why? Because look at this beatiful [viewer](https://flatgithub.com). It's so nice to have a working time-series data set without a ton of drama.
Expand Down
7 changes: 5 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@
# Do the things!
if __name__ == "__main__":
if report_scope == "enterprise":
print("enterprise reporting not yet implemented, pull requests welcome!")
pass
# secret scanning
secrets_list = secret_scanning.get_enterprise_secret_scanning_alerts(
api_endpoint, github_pat, scope_name
)
secret_scanning.write_enterprise_secrets_list(secrets_list)
elif report_scope == "organization":
# code scanning
cs_list = code_scanning.list_org_code_scanning_alerts(
Expand Down
124 changes: 124 additions & 0 deletions src/secret_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,127 @@ def write_org_secrets_list(secrets_list):
str(alert["repository"]["private"]),
]
)


def get_enterprise_secret_scanning_alerts(api_endpoint, github_pat, enterprise_slug):
"""
Get all the secret scanning alerts on a given enterprise.

Inputs:
- API endpoint (for GHES/GHAE compatibility)
- PAT of appropriate scope
- Enterprise slug (enterprise name URL, documented below)
- https://docs.github.com/en/rest/reference/enterprise-admin

Outputs:
- List of _all_ secret scanning alerts on the enterprise
"""

# Get secret scanning alerts
url = "{}/enterprises/{}/secret-scanning/alerts?per_page=100&page=1".format(
api_endpoint, enterprise_slug
)
response = requests.get(
url,
headers={
"Authorization": "token {}".format(github_pat),
"Accept": "application/vnd.github.v3+json",
},
)
response_json = response.json()
# The secret scanning API returns a code of 404 if there are no alerts,
# secret scanning is disabled, or the repository is public.
if response.status_code == 404:
return ["not found"]
while "next" in response.links.keys():
response = requests.get(
response.links["next"]["url"],
headers={
"Authorization": "token {}".format(github_pat),
"Accept": "application/vnd.github.v3+json",
},
)
response_json.extend(response.json())

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

# Return secret scanning alerts
return response_json


def write_enterprise_secrets_list(secrets_list):
"""
Write the list of enterprise secret scanning alerts to a csv file.

Inputs:
- List of secret scanning alerts

Outputs:
- CSV file of secret scanning alerts
"""

if secrets_list == ["not found"]:
print("No secret scanning alerts found")
return
# Write secret scanning alerts to csv file
with open("secrets_list.csv", "w") as f:
writer = csv.writer(f)
writer.writerow(
[
"number",
"created_at",
"html_url",
"state",
"resolution",
"resolved_at",
"resolved_by_username",
"resolved_by_type",
"resolved_by_isadmin",
"secret_type",
"secret_type_display_name",
"repo_name",
"repo_owner",
"repo_owner_type",
"repo_owner_isadmin",
"repo_url",
"repo_isfork",
"repo_isprivate",
]
)
for alert in secrets_list:
if alert["state"] == "open":
alert["resolution"] = "none"
alert["resolved_at"] = "none"
alert["resolved_by"] = {
"login": "none",
"type": "none",
"site_admin": "none",
}
writer.writerow(
[
alert["number"],
alert["created_at"],
alert["html_url"],
alert["state"],
alert["resolution"],
alert["resolved_at"],
alert["resolved_by"]["login"],
alert["resolved_by"]["type"],
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"],
alert["repository"]["owner"]["site_admin"],
alert["repository"]["html_url"],
str(alert["repository"]["fork"]),
str(alert["repository"]["private"]),
]
)