Skip to content

Commit 3e14459

Browse files
Copilotaegilops
andcommitted
Add TLS certificate bundle support to all Python scripts
- Fix bug in list_secret_scanning_alerts.py (undefined variable) - Add --ca-cert-bundle and --no-verify-tls options to all scripts - Update GitHub class instantiation to pass verify parameter - Update all helper functions to accept and propagate verify parameter - Update test to include new arguments Co-authored-by: aegilops <41705651+aegilops@users.noreply.github.com>
1 parent 9545570 commit 3e14459

7 files changed

+142
-22
lines changed

close_code_scanning_alerts.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,25 @@ def add_args(parser: argparse.ArgumentParser) -> None:
9191
action="store_true",
9292
help="Print the alerts that would be closed, but don't actually close them.",
9393
)
94+
parser.add_argument(
95+
"--hostname",
96+
type=str,
97+
default="github.com",
98+
required=False,
99+
help="GitHub Enterprise hostname (defaults to github.com)",
100+
)
101+
parser.add_argument(
102+
"--ca-cert-bundle",
103+
"-C",
104+
type=str,
105+
required=False,
106+
help="Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)"
107+
)
108+
parser.add_argument(
109+
"--no-verify-tls",
110+
action="store_true",
111+
help="Do not verify TLS connection certificates (warning: insecure)"
112+
)
94113
parser.add_argument(
95114
"-d",
96115
"--debug",
@@ -108,7 +127,18 @@ def main() -> None:
108127

109128
logging.basicConfig(level=logging.INFO if not args.debug else logging.DEBUG)
110129

111-
github = GitHub()
130+
verify = True
131+
if args.ca_cert_bundle:
132+
verify = args.ca_cert_bundle
133+
134+
if args.no_verify_tls:
135+
verify = False
136+
LOG = logging.getLogger(__name__)
137+
LOG.warning("Disabling TLS verification. This is insecure and should not be used in production")
138+
import urllib3
139+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
140+
141+
github = GitHub(hostname=args.hostname, verify=verify)
112142

113143
try:
114144
owner, repo = args.repo_name.split("/")

list_code_scanning_alerts.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ def output_csv(results: list[dict], quote_all: bool) -> None:
124124
writer.writerow(to_list(result))
125125

126126

127-
def list_code_scanning_alerts(name: str, scope: str, hostname: str, state: str|None=None, since: datetime.datetime|None=None, raw: bool=False) -> Generator[dict, None, None]:
128-
g = GitHub(hostname=hostname)
127+
def list_code_scanning_alerts(name: str, scope: str, hostname: str, state: str|None=None, since: datetime.datetime|None=None, raw: bool=False, verify: bool | str = True) -> Generator[dict, None, None]:
128+
g = GitHub(hostname=hostname, verify=verify)
129129
alerts = g.list_code_scanning_alerts(name, state=state, since=since, scope=scope)
130130
if raw:
131131
return alerts
@@ -178,6 +178,18 @@ def add_args(parser: argparse.ArgumentParser) -> None:
178178
required=False,
179179
help="GitHub Enterprise hostname (defaults to github.com)",
180180
)
181+
parser.add_argument(
182+
"--ca-cert-bundle",
183+
"-C",
184+
type=str,
185+
required=False,
186+
help="Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)"
187+
)
188+
parser.add_argument(
189+
"--no-verify-tls",
190+
action="store_true",
191+
help="Do not verify TLS connection certificates (warning: insecure)"
192+
)
181193
parser.add_argument(
182194
"--debug", "-d", action="store_true", help="Enable debug logging"
183195
)
@@ -202,11 +214,21 @@ def main() -> None:
202214
name = args.name
203215
state = args.state
204216
hostname = args.hostname
217+
verify = True
218+
219+
if args.ca_cert_bundle:
220+
verify = args.ca_cert_bundle
221+
222+
if args.no_verify_tls:
223+
verify = False
224+
LOG.warning("Disabling TLS verification. This is insecure and should not be used in production")
225+
import urllib3
226+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
205227

206228
if not GitHub.check_name(name, scope):
207229
raise ValueError("Invalid name: %s for %s", name, scope)
208230

209-
results = list_code_scanning_alerts(name, scope, hostname, state=state, since=since, raw=args.raw)
231+
results = list_code_scanning_alerts(name, scope, hostname, state=state, since=since, raw=args.raw, verify=verify)
210232

211233
if args.json:
212234
print(json.dumps(list(results), indent=2))

list_secret_scanning_alerts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def main() -> None:
375375
verify = True
376376

377377
if args.ca_cert_bundle:
378-
verify = ca_cert_bundle
378+
verify = args.ca_cert_bundle
379379

380380
if args.no_verify_tls:
381381
verify = False

replay_code_scanning_alert_status.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def existing_results_by_location(reader: csv.DictReader) -> dict:
5050
return existing_results
5151

5252

53-
def change_state(hostname, result: dict, res: dict) -> None:
53+
def change_state(hostname, result: dict, res: dict, verify: bool | str = True) -> None:
5454
"""Change the state of the alert to match the existing result using the GitHub API to update the alert."""
55-
g = GitHub(hostname=hostname)
55+
g = GitHub(hostname=hostname, verify=verify)
5656

5757
repo_name = result["repo"]
5858

@@ -77,7 +77,7 @@ def change_state(hostname, result: dict, res: dict) -> None:
7777
return
7878

7979

80-
def update_states(hostname: str, results: Iterable[dict], existing_results: dict) -> None:
80+
def update_states(hostname: str, results: Iterable[dict], existing_results: dict, verify: bool | str = True) -> None:
8181
"""Update the state of matching alerts to match the existing results."""
8282
for result in results:
8383
repo = result["repo"]
@@ -101,7 +101,7 @@ def update_states(hostname: str, results: Iterable[dict], existing_results: dict
101101
if res["state"] != result["state"]:
102102
LOG.warning(f"State mismatch: {res['state']} != {result['state']}")
103103

104-
change_state(hostname, result, res)
104+
change_state(hostname, result, res, verify=verify)
105105

106106

107107
def add_args(parser: argparse.ArgumentParser) -> None:
@@ -145,6 +145,18 @@ def add_args(parser: argparse.ArgumentParser) -> None:
145145
required=False,
146146
help="GitHub Enterprise hostname (defaults to github.com)",
147147
)
148+
parser.add_argument(
149+
"--ca-cert-bundle",
150+
"-C",
151+
type=str,
152+
required=False,
153+
help="Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)"
154+
)
155+
parser.add_argument(
156+
"--no-verify-tls",
157+
action="store_true",
158+
help="Do not verify TLS connection certificates (warning: insecure)"
159+
)
148160
parser.add_argument(
149161
"--debug", "-d", action="store_true", help="Enable debug logging"
150162
)
@@ -166,6 +178,16 @@ def main() -> None:
166178
name = args.name
167179
state = args.state
168180
hostname = args.hostname
181+
verify = True
182+
183+
if args.ca_cert_bundle:
184+
verify = args.ca_cert_bundle
185+
186+
if args.no_verify_tls:
187+
verify = False
188+
LOG.warning("Disabling TLS verification. This is insecure and should not be used in production")
189+
import urllib3
190+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
169191

170192
if not GitHub.check_name(args.name, scope):
171193
raise ValueError("Invalid name: %s for %s", args.name, scope)
@@ -179,9 +201,9 @@ def main() -> None:
179201

180202
LOG.debug(existing_results)
181203

182-
results = list_code_scanning_alerts(name, scope, hostname, state=state, since=since)
204+
results = list_code_scanning_alerts(name, scope, hostname, state=state, since=since, verify=verify)
183205

184-
update_states(hostname, results, existing_results)
206+
update_states(hostname, results, existing_results, verify=verify)
185207

186208

187209
if __name__ == "__main__":

replay_secret_scanning_result_status.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ def existing_results_by_secret(reader: csv.DictReader) -> dict:
4444
return existing_results
4545

4646

47-
def change_state(hostname, result: dict, res: dict) -> None:
47+
def change_state(hostname, result: dict, res: dict, verify: bool | str = True) -> None:
4848
"""Change the state of the alert to match the existing result using the GitHub API to update the alert."""
49-
g = GitHub(hostname=hostname)
49+
g = GitHub(hostname=hostname, verify=verify)
5050

5151
repo_name = result["repo"]
5252

@@ -112,6 +112,18 @@ def add_args(parser: argparse.ArgumentParser) -> None:
112112
required=False,
113113
help="GitHub Enterprise hostname (defaults to github.com)",
114114
)
115+
parser.add_argument(
116+
"--ca-cert-bundle",
117+
"-C",
118+
type=str,
119+
required=False,
120+
help="Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)"
121+
)
122+
parser.add_argument(
123+
"--no-verify-tls",
124+
action="store_true",
125+
help="Do not verify TLS connection certificates (warning: insecure)"
126+
)
115127
parser.add_argument(
116128
"--debug", "-d", action="store_true", help="Enable debug logging"
117129
)
@@ -133,6 +145,16 @@ def main() -> None:
133145
name = args.name
134146
state = args.state
135147
hostname = args.hostname
148+
verify = True
149+
150+
if args.ca_cert_bundle:
151+
verify = args.ca_cert_bundle
152+
153+
if args.no_verify_tls:
154+
verify = False
155+
LOG.warning("Disabling TLS verification. This is insecure and should not be used in production")
156+
import urllib3
157+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
136158

137159
if not GitHub.check_name(args.name, scope):
138160
raise ValueError("Invalid name: %s for %s", args.name, scope)
@@ -146,7 +168,7 @@ def main() -> None:
146168

147169
LOG.debug(existing_results)
148170

149-
results = list_secret_scanning_alerts(name, scope, hostname, state=state, since=since)
171+
results = list_secret_scanning_alerts(name, scope, hostname, state=state, since=since, verify=verify)
150172

151173
for result in results:
152174
repo = result["repo"]
@@ -165,7 +187,7 @@ def main() -> None:
165187
LOG.warning(f"State mismatch: {res['state']} != {result['state']}")
166188

167189
if result["state"] != "pattern_edited":
168-
change_state(hostname, result, res)
190+
change_state(hostname, result, res, verify=verify)
169191

170192

171193
if __name__ == "__main__":

resolve_duplicate_secret_scanning_alerts.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ def index_results_by_secret(results: Iterable[dict]) -> dict:
5151
return indexed_results
5252

5353

54-
def change_state(hostname, old_result: dict, new_result: dict) -> None:
54+
def change_state(hostname, old_result: dict, new_result: dict, verify: bool | str = True) -> None:
5555
"""Change the state of the alert to match the existing result using the GitHub API to update the alert."""
56-
g = GitHub(hostname=hostname)
56+
g = GitHub(hostname=hostname, verify=verify)
5757

5858
repo_name = new_result["repo"]
5959

@@ -83,7 +83,7 @@ def change_state(hostname, old_result: dict, new_result: dict) -> None:
8383

8484

8585
def resolve_duplicates(
86-
indexed_results: dict, matching_secrets_lookup: dict, hostname: str
86+
indexed_results: dict, matching_secrets_lookup: dict, hostname: str, verify: bool | str = True
8787
) -> None:
8888
"""Resolve duplicates by matching on a new secret type and updating the state of the alert to match the existing result."""
8989
for repo, repo_results in indexed_results.items():
@@ -107,7 +107,7 @@ def resolve_duplicates(
107107
LOG.info(f"State mismatch, updating state: {new_result['state']} != {old_result['state']}")
108108

109109
if old_result["state"] != "pattern_edited":
110-
change_state(hostname, old_result, new_result)
110+
change_state(hostname, old_result, new_result, verify=verify)
111111

112112

113113
def add_args(parser: argparse.ArgumentParser) -> None:
@@ -145,6 +145,18 @@ def add_args(parser: argparse.ArgumentParser) -> None:
145145
required=False,
146146
help="GitHub Enterprise hostname (defaults to github.com)",
147147
)
148+
parser.add_argument(
149+
"--ca-cert-bundle",
150+
"-C",
151+
type=str,
152+
required=False,
153+
help="Path to CA certificate bundle in PEM format (e.g. for self-signed server certificates)"
154+
)
155+
parser.add_argument(
156+
"--no-verify-tls",
157+
action="store_true",
158+
help="Do not verify TLS connection certificates (warning: insecure)"
159+
)
148160
parser.add_argument(
149161
"--debug", "-d", action="store_true", help="Enable debug logging"
150162
)
@@ -174,6 +186,16 @@ def main() -> None:
174186
name = args.name
175187
state = args.state
176188
hostname = args.hostname
189+
verify = True
190+
191+
if args.ca_cert_bundle:
192+
verify = args.ca_cert_bundle
193+
194+
if args.no_verify_tls:
195+
verify = False
196+
LOG.warning("Disabling TLS verification. This is insecure and should not be used in production")
197+
import urllib3
198+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
177199

178200
if not GitHub.check_name(args.name, scope):
179201
raise ValueError("Invalid name: %s for %s", args.name, scope)
@@ -187,15 +209,15 @@ def main() -> None:
187209
matching_secrets_lookup = {k: v for k, v in matching_secrets}
188210

189211
# find secret scanning alerts
190-
results = list_secret_scanning_alerts(name, scope, hostname, state=state, since=since, include_secret=True)
212+
results = list_secret_scanning_alerts(name, scope, hostname, state=state, since=since, include_secret=True, verify=verify)
191213
if not results:
192214
LOG.info("No secret scanning alerts found")
193215
return
194216

195217
# index results by secret and type for easy lookup
196218
indexed_results = index_results_by_secret(results)
197219

198-
resolve_duplicates(indexed_results, matching_secrets_lookup, hostname)
220+
resolve_duplicates(indexed_results, matching_secrets_lookup, hostname, verify=verify)
199221

200222

201223
if __name__ == "__main__":

test_resolve_duplicate_secret_scanning_alerts.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ def mock_args():
1919
since="2024-10-08",
2020
hostname="github.com",
2121
debug=True,
22-
add_matching_secret=[("old_type", "new_type")]
22+
add_matching_secret=[("old_type", "new_type")],
23+
ca_cert_bundle=None,
24+
no_verify_tls=False
2325
)
2426
yield mock_parse_args
2527

0 commit comments

Comments
 (0)