Skip to content

Commit 14c7226

Browse files
Copilotfelickz
andcommitted
Redesign secret scanning to use two API calls by default
Co-authored-by: felickz <1760475+felickz@users.noreply.github.com>
1 parent b5aa829 commit 14c7226

File tree

3 files changed

+108
-32
lines changed

3 files changed

+108
-32
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ The list of all available options that can be set as environmental variables is
7777
- `GITHUB_REPORT_SCOPE`: The scope of the report to generate. Valid values are `repository` (default), `organization` or `enterprise`.
7878
- `SCOPE_NAME` or `GITHUB_REPOSITORY`: The name of the repository, organization or enterprise to generate the report for. If `SCOPE_NAME` is not set, the value of `GITHUB_REPOSITORY` is used if it is set. If neither is set, an error occurs.
7979
- `FEATURES`: A comma-separated list of features to include in the report. Valid values are `codescanning`, `secretscanning`, `dependabot` or simply `all`. Default value: `all`.
80-
- `SECRET_TYPE_FILTER`: A comma-separated list of secret types to filter secret scanning alerts. For example: `password,api_key,oauth_token`. If not set, all secret types are included.
8180

8281
The first two are only needed if you're running this in a GitHub Enterprise Server or GitHub AE environment. The last one is useful if you only want to get data on a specific feature. For example, if you only want to get data on secret scanning, you can set `FEATURES` to `secretscanning`. Here's just another example how you would configure this on a GitHub Enterprise Server:
8382

main.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
report_scope = os.getenv("GITHUB_REPORT_SCOPE", "repository")
3535
scope_name = os.getenv("SCOPE_NAME", os.getenv("GITHUB_REPOSITORY"))
3636
requested_features = os.getenv("FEATURES")
37-
secret_type_filter = os.getenv("SECRET_TYPE_FILTER")
3837
if (requested_features is None) or (requested_features == "all"):
3938
features = FEATURES
4039
else:
@@ -53,7 +52,7 @@
5352
# secret scanning
5453
if "secretscanning" in features:
5554
try:
56-
secrets_list = secret_scanning.get_enterprise_ss_alerts(api_endpoint, github_pat, scope_name, secret_type_filter)
55+
secrets_list = secret_scanning.get_enterprise_ss_alerts(api_endpoint, github_pat, scope_name)
5756
secret_scanning.write_enterprise_ss_list(secrets_list)
5857
except Exception as e:
5958
if any(x in str(e).lower() for x in secret_scanning_disabled_strings):
@@ -105,7 +104,7 @@
105104
# secret scanning
106105
if "secretscanning" in features:
107106
try:
108-
secrets_list = secret_scanning.get_org_ss_alerts(api_endpoint, github_pat, scope_name, secret_type_filter)
107+
secrets_list = secret_scanning.get_org_ss_alerts(api_endpoint, github_pat, scope_name)
109108
secret_scanning.write_org_ss_list(secrets_list)
110109
except Exception as e:
111110
if any(x in str(e).lower() for x in secret_scanning_disabled_strings):
@@ -133,7 +132,7 @@
133132
# secret scanning
134133
if "secretscanning" in features:
135134
try:
136-
secrets_list = secret_scanning.get_repo_ss_alerts(api_endpoint, github_pat, scope_name, secret_type_filter)
135+
secrets_list = secret_scanning.get_repo_ss_alerts(api_endpoint, github_pat, scope_name)
137136
secret_scanning.write_repo_ss_list(secrets_list)
138137
except Exception as e:
139138
if any(x in str(e).lower() for x in secret_scanning_disabled_strings):

src/secret_scanning.py

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,51 @@
55
from . import api_helpers
66

77

8-
def get_repo_ss_alerts(api_endpoint, github_pat, repo_name, secret_type_filter=None):
8+
def get_repo_ss_alerts(api_endpoint, github_pat, repo_name):
99
"""
1010
Get all the secret scanning alerts on a given repository.
1111
1212
Inputs:
1313
- API endpoint (for GHES/GHAE compatibility)
1414
- PAT of appropriate scope
1515
- Repository name
16-
- Secret type filter (optional comma-separated list of secret types)
1716
1817
Outputs:
19-
- List of _all_ secret scanning alerts on the repository
18+
- List of _all_ secret scanning alerts on the repository (both default and generic secret types)
2019
"""
21-
url = f"{api_endpoint}/repos/{repo_name}/secret-scanning/alerts?per_page=100&page=1"
22-
if secret_type_filter:
23-
url += f"&secret_type={secret_type_filter}"
24-
ss_alerts = api_helpers.make_api_call(url, github_pat)
25-
print(f"Found {len(ss_alerts)} secret scanning alerts in {repo_name}")
26-
return ss_alerts
20+
# First call: get default secret types (without any filters)
21+
url_default = f"{api_endpoint}/repos/{repo_name}/secret-scanning/alerts?per_page=100&page=1"
22+
ss_alerts_default = api_helpers.make_api_call(url_default, github_pat)
23+
24+
# Second call: get generic secret types with hardcoded list
25+
generic_secret_types = "password,http_basic_authentication_header,http_bearer_authentication_header,mongodb_connection_string,mysql_connection_string,openssh_private_key,pgp_private_key,postgres_connection_string,rsa_private_key"
26+
url_generic = f"{api_endpoint}/repos/{repo_name}/secret-scanning/alerts?per_page=100&page=1&secret_type={generic_secret_types}"
27+
ss_alerts_generic = api_helpers.make_api_call(url_generic, github_pat)
28+
29+
# Combine results and deduplicate
30+
combined_alerts = []
31+
alert_numbers_seen = set()
32+
duplicates_found = False
33+
34+
# Add default alerts
35+
for alert in ss_alerts_default:
36+
alert_numbers_seen.add(alert["number"])
37+
combined_alerts.append(alert)
38+
39+
# Add generic alerts, checking for duplicates
40+
for alert in ss_alerts_generic:
41+
if alert["number"] in alert_numbers_seen:
42+
duplicates_found = True
43+
else:
44+
alert_numbers_seen.add(alert["number"])
45+
combined_alerts.append(alert)
46+
47+
# Warn if duplicates were found
48+
if duplicates_found:
49+
print(f"::warning::Duplicate secret scanning alerts detected in {repo_name}. Please report this behavior via an issue to the repository owners as the API behavior may have changed.")
50+
51+
print(f"Found {len(combined_alerts)} secret scanning alerts in {repo_name} ({len(ss_alerts_default)} default, {len(ss_alerts_generic)} generic)")
52+
return combined_alerts
2753

2854

2955
def write_repo_ss_list(secrets_list):
@@ -72,25 +98,51 @@ def write_repo_ss_list(secrets_list):
7298
)
7399

74100

75-
def get_org_ss_alerts(api_endpoint, github_pat, org_name, secret_type_filter=None):
101+
def get_org_ss_alerts(api_endpoint, github_pat, org_name):
76102
"""
77103
Get all the secret scanning alerts on a given organization.
78104
79105
Inputs:
80106
- API endpoint (for GHES/GHAE compatibility)
81107
- PAT of appropriate scope
82108
- Organization name
83-
- Secret type filter (optional comma-separated list of secret types)
84109
85110
Outputs:
86-
- List of _all_ secret scanning alerts on the organization
111+
- List of _all_ secret scanning alerts on the organization (both default and generic secret types)
87112
"""
88-
url = f"{api_endpoint}/orgs/{org_name}/secret-scanning/alerts?per_page=100&page=1"
89-
if secret_type_filter:
90-
url += f"&secret_type={secret_type_filter}"
91-
ss_alerts = api_helpers.make_api_call(url, github_pat)
92-
print(f"Found {len(ss_alerts)} secret scanning alerts in {org_name}")
93-
return ss_alerts
113+
# First call: get default secret types (without any filters)
114+
url_default = f"{api_endpoint}/orgs/{org_name}/secret-scanning/alerts?per_page=100&page=1"
115+
ss_alerts_default = api_helpers.make_api_call(url_default, github_pat)
116+
117+
# Second call: get generic secret types with hardcoded list
118+
generic_secret_types = "password,http_basic_authentication_header,http_bearer_authentication_header,mongodb_connection_string,mysql_connection_string,openssh_private_key,pgp_private_key,postgres_connection_string,rsa_private_key"
119+
url_generic = f"{api_endpoint}/orgs/{org_name}/secret-scanning/alerts?per_page=100&page=1&secret_type={generic_secret_types}"
120+
ss_alerts_generic = api_helpers.make_api_call(url_generic, github_pat)
121+
122+
# Combine results and deduplicate
123+
combined_alerts = []
124+
alert_numbers_seen = set()
125+
duplicates_found = False
126+
127+
# Add default alerts
128+
for alert in ss_alerts_default:
129+
alert_numbers_seen.add(alert["number"])
130+
combined_alerts.append(alert)
131+
132+
# Add generic alerts, checking for duplicates
133+
for alert in ss_alerts_generic:
134+
if alert["number"] in alert_numbers_seen:
135+
duplicates_found = True
136+
else:
137+
alert_numbers_seen.add(alert["number"])
138+
combined_alerts.append(alert)
139+
140+
# Warn if duplicates were found
141+
if duplicates_found:
142+
print(f"::warning::Duplicate secret scanning alerts detected in {org_name}. Please report this behavior via an issue to the repository owners as the API behavior may have changed.")
143+
144+
print(f"Found {len(combined_alerts)} secret scanning alerts in {org_name} ({len(ss_alerts_default)} default, {len(ss_alerts_generic)} generic)")
145+
return combined_alerts
94146

95147

96148
def write_org_ss_list(secrets_list):
@@ -153,7 +205,7 @@ def write_org_ss_list(secrets_list):
153205
)
154206

155207

156-
def get_enterprise_ss_alerts(api_endpoint, github_pat, enterprise_slug, secret_type_filter=None):
208+
def get_enterprise_ss_alerts(api_endpoint, github_pat, enterprise_slug):
157209
"""
158210
Get all the secret scanning alerts on a given enterprise.
159211
@@ -162,17 +214,43 @@ def get_enterprise_ss_alerts(api_endpoint, github_pat, enterprise_slug, secret_t
162214
- PAT of appropriate scope
163215
- Enterprise slug (enterprise name URL, documented below)
164216
- https://docs.github.com/en/rest/reference/enterprise-admin
165-
- Secret type filter (optional comma-separated list of secret types)
166217
167218
Outputs:
168-
- List of _all_ secret scanning alerts on the enterprise
219+
- List of _all_ secret scanning alerts on the enterprise (both default and generic secret types)
169220
"""
170-
url = f"{api_endpoint}/enterprises/{enterprise_slug}/secret-scanning/alerts?per_page=100&page=1"
171-
if secret_type_filter:
172-
url += f"&secret_type={secret_type_filter}"
173-
ss_alerts = api_helpers.make_api_call(url, github_pat)
174-
print(f"Found {len(ss_alerts)} secret scanning alerts in {enterprise_slug}")
175-
return ss_alerts
221+
# First call: get default secret types (without any filters)
222+
url_default = f"{api_endpoint}/enterprises/{enterprise_slug}/secret-scanning/alerts?per_page=100&page=1"
223+
ss_alerts_default = api_helpers.make_api_call(url_default, github_pat)
224+
225+
# Second call: get generic secret types with hardcoded list
226+
generic_secret_types = "password,http_basic_authentication_header,http_bearer_authentication_header,mongodb_connection_string,mysql_connection_string,openssh_private_key,pgp_private_key,postgres_connection_string,rsa_private_key"
227+
url_generic = f"{api_endpoint}/enterprises/{enterprise_slug}/secret-scanning/alerts?per_page=100&page=1&secret_type={generic_secret_types}"
228+
ss_alerts_generic = api_helpers.make_api_call(url_generic, github_pat)
229+
230+
# Combine results and deduplicate
231+
combined_alerts = []
232+
alert_numbers_seen = set()
233+
duplicates_found = False
234+
235+
# Add default alerts
236+
for alert in ss_alerts_default:
237+
alert_numbers_seen.add(alert["number"])
238+
combined_alerts.append(alert)
239+
240+
# Add generic alerts, checking for duplicates
241+
for alert in ss_alerts_generic:
242+
if alert["number"] in alert_numbers_seen:
243+
duplicates_found = True
244+
else:
245+
alert_numbers_seen.add(alert["number"])
246+
combined_alerts.append(alert)
247+
248+
# Warn if duplicates were found
249+
if duplicates_found:
250+
print(f"::warning::Duplicate secret scanning alerts detected in {enterprise_slug}. Please report this behavior via an issue to the repository owners as the API behavior may have changed.")
251+
252+
print(f"Found {len(combined_alerts)} secret scanning alerts in {enterprise_slug} ({len(ss_alerts_default)} default, {len(ss_alerts_generic)} generic)")
253+
return combined_alerts
176254

177255

178256
def write_enterprise_ss_list(secrets_list):

0 commit comments

Comments
 (0)