Skip to content

Commit 8b60420

Browse files
authored
Merge pull request #12 from advanced-security/fix-quality
Merge changes to secret types
2 parents a955cfb + 770e310 commit 8b60420

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ A note on common arguments: generally, the date in `--since` can be specified as
2929
This script retrieves secret scanning alerts from GitHub repositories, organizations, or Enterprises and outputs them in CSV or JSON format. It supports filtering by state, date, and push protection bypass status. Use this to audit, analyze, or export secret scanning data for compliance or security purposes.
3030

3131
```text
32-
usage: list_secret_scanning_alerts.py [-h] [--scope {ent,org,repo}] [--generic] [--bypassed] [--state {open,resolved}]
33-
[--no-include-secret] [--include-locations] [--include-commit] [--since SINCE]
34-
[--json] [--raw] [--quote-all] [--hostname HOSTNAME]
32+
usage: list_secret_scanning_alerts.py [-h] [--scope {ent,org,repo}] [--no-generic] [--no-default] [--include-types INCLUDE_TYPES [INCLUDE_TYPES ...]] [--bypassed] [--state {open,resolved}]
33+
[--no-include-secret] [--include-locations] [--include-commit] [--since SINCE] [--json] [--raw] [--quote-all] [--hostname HOSTNAME]
3534
[--ca-cert-bundle CA_CERT_BUNDLE] [--no-verify-tls] [--quiet] [--debug]
3635
name
3736
@@ -44,24 +43,24 @@ options:
4443
-h, --help show this help message and exit
4544
--scope {ent,org,repo}
4645
Scope of the query
47-
--generic, -g Include generic secret types (not just vendor secret types/custom patterns, which is the
48-
default)
46+
--no-generic Exclude generic secret types from the output
47+
--no-default Exclude default secret types from the output
48+
--include-types INCLUDE_TYPES [INCLUDE_TYPES ...]
49+
Include specific secret types in the output (adds to any generic/default secrets that are output, so use --no-generic and --no-default to exclude those if required)
4950
--bypassed, -b Only show alerts where push protection was bypassed
50-
--state {open,resolved}, -s {open,resolved}
51+
--state, -s {open,resolved}
5152
State of the alerts to query
5253
--no-include-secret, -n
5354
Do not include the secret in the output
5455
--include-locations, -l
5556
Include locations in the output
5657
--include-commit, -c Include commit date and committer in the output
57-
--since SINCE, -S SINCE
58-
Only show alerts created after this date/time - ISO 8601 format, e.g. 2024-10-08 or
59-
2024-10-08T12:00; or Nd format, e.g. 7d for 7 days ago
58+
--since, -S SINCE Only show alerts created after this date/time - ISO 8601 format, e.g. 2024-10-08 or 2024-10-08T12:00; or Nd format, e.g. 7d for 7 days ago
6059
--json Output in JSON format (otherwise CSV)
6160
--raw, -r Output the raw data from the GitHub API
6261
--quote-all, -Q Quote all fields in CSV output
6362
--hostname HOSTNAME GitHub Enterprise hostname (defaults to github.com)
64-
--ca-cert-bundle CA_CERT_BUNDLE, -C CA_CERT_BUNDLE
63+
--ca-cert-bundle, -C CA_CERT_BUNDLE
6564
Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)
6665
--no-verify-tls Do not verify TLS connection certificates (warning: insecure)
6766
--quiet, -q Suppress non-error log messages

githubapi.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ def list_secret_scanning_alerts(
430430
scope: str = "org",
431431
bypassed: bool = False,
432432
generic: bool = False,
433+
secret_types: list[str] | None = None,
433434
progress: bool = True,
434435
) -> Generator[dict, None, None]:
435436
"""List secret scanning alerts for a GitHub repository, organization or Enterprise."""
@@ -438,6 +439,9 @@ def list_secret_scanning_alerts(
438439
if generic:
439440
query["secret_type"] = GENERIC_SECRET_TYPES
440441

442+
if secret_types:
443+
query["secret_type"] = ",".join(secret_types)
444+
441445
alerts = self.query(
442446
scope,
443447
name,

list_secret_scanning_alerts.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
"""List secret scanning alerts for a GitHub repository, organization or Enterprise."""
44

5+
import itertools
56
import sys
67
import argparse
78
import logging
89
import datetime
910
import json
10-
from typing import Generator, Any
11+
from typing import Generator, Any, Iterable
1112
from defusedcsv import csv # type: ignore
1213
from githubapi import GitHub, parse_date
1314
from requests.exceptions import HTTPError
@@ -142,7 +143,7 @@ def output_csv(results: list[dict], quote_all: bool) -> None:
142143
LOG.info("Stopped by user")
143144
return
144145

145-
def decorate_alerts(g: GitHub, alerts: Generator[dict[str, Any], None, None], include_locations: bool = False, include_commit: bool = False) -> Generator[dict[str, Any], None, None]:
146+
def decorate_alerts(g: GitHub, alerts: Iterable[dict[str, Any]], include_locations: bool = False, include_commit: bool = False) -> Generator[dict[str, Any], None, None]:
146147
"""Decorate alerts with additional information, for both the raw and make_result outputs.
147148
148149
Resolve locations and commit information, if that was asked for.
@@ -225,6 +226,8 @@ def list_secret_scanning_alerts(
225226
bypassed: bool = False,
226227
raw: bool = False,
227228
generic: bool = False,
229+
default: bool = False,
230+
specific: list[str] | None = None,
228231
verify: bool | str = True,
229232
progress: bool = True,
230233
) -> Generator[dict[str, Any], None, None] | None:
@@ -235,18 +238,37 @@ def list_secret_scanning_alerts(
235238
Output either the raw alert data, or flattened results.
236239
"""
237240
g = GitHub(hostname=hostname, verify=verify)
238-
alerts = g.list_secret_scanning_alerts(
239-
name, state=state, since=since, scope=scope, bypassed=bypassed, generic=generic, progress=progress
240-
)
241241

242-
alerts = decorate_alerts(g, alerts, include_locations=include_locations, include_commit=include_commit)
242+
alerts = []
243+
244+
if default:
245+
default_alerts = g.list_secret_scanning_alerts(
246+
name, state=state, since=since, scope=scope, bypassed=bypassed, generic=False, progress=progress
247+
)
248+
249+
alerts.append(default_alerts)
250+
251+
if generic:
252+
generic_alerts = g.list_secret_scanning_alerts(
253+
name, state=state, since=since, scope=scope, bypassed=bypassed, generic=True, progress=progress
254+
)
255+
256+
alerts.append(generic_alerts)
257+
258+
if specific:
259+
specific_alerts = g.list_secret_scanning_alerts(
260+
name, state=state, since=since, scope=scope, bypassed=bypassed, secret_types=specific, progress=progress
261+
)
262+
alerts.append(specific_alerts)
263+
264+
decorated_alerts = decorate_alerts(g, itertools.chain.from_iterable(alerts), include_locations=include_locations, include_commit=include_commit)
243265

244266
if raw:
245-
for alert in alerts:
267+
for alert in decorated_alerts:
246268
yield alert
247269
return None
248270
else:
249-
for alert in alerts:
271+
for alert in decorated_alerts:
250272
result = make_result(g, alert, scope, name, include_secret=include_secret, include_locations=include_locations, include_commit=include_commit)
251273
if result is not None:
252274
yield result
@@ -268,10 +290,20 @@ def add_args(parser: argparse.ArgumentParser) -> None:
268290
help="Scope of the query",
269291
)
270292
parser.add_argument(
271-
"--generic",
272-
"-g",
293+
"--no-generic",
294+
action="store_true",
295+
help="Exclude generic secret types from the output",
296+
)
297+
parser.add_argument(
298+
"--no-default",
273299
action="store_true",
274-
help="Include generic secret types (not just vendor secret types/custom patterns, which is the default)",
300+
help="Exclude default secret types from the output",
301+
)
302+
parser.add_argument(
303+
"--include-types",
304+
type=str,
305+
nargs="+",
306+
help="Include specific secret types in the output (adds to any generic/default secrets that are output, so use --no-generic and --no-default to exclude those if required)",
275307
)
276308
parser.add_argument(
277309
"--bypassed",
@@ -374,7 +406,9 @@ def main() -> None:
374406
include_locations = args.include_locations
375407
include_commit = args.include_commit
376408
bypassed = args.bypassed
377-
generic = args.generic
409+
generic = not args.no_generic
410+
default = not args.no_default
411+
specific = args.include_types
378412
verify = True
379413

380414
if args.ca_cert_bundle:
@@ -402,6 +436,8 @@ def main() -> None:
402436
bypassed=bypassed,
403437
raw=args.raw,
404438
generic=generic,
439+
default=default,
440+
specific=specific,
405441
verify=verify
406442
)
407443

0 commit comments

Comments
 (0)