Skip to content

Commit ac8dc50

Browse files
committed
cleanup
1 parent 15d24f2 commit ac8dc50

File tree

1 file changed

+85
-37
lines changed

1 file changed

+85
-37
lines changed

tools/private-sec-reporting.py

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,46 @@
11
import os
2-
import json
32
import asyncio
43
import aiohttp
54
from rich import print
65
from datetime import datetime
6+
from pathlib import Path
77
import humanize
88
from itertools import count
99

10-
orgs = ["jupyter", 'ipython', 'jupyterhub', 'jupyterlab']
10+
orgs = [
11+
"binder-examples",
12+
"binderhub-ci-repos",
13+
"ipython",
14+
"jupyter",
15+
"jupyter-book",
16+
"jupyter-governance",
17+
"jupyter-incubator",
18+
"jupyter-server",
19+
"jupyter-standards",
20+
"jupyter-widgets",
21+
"jupyterhub",
22+
"jupyterlab",
23+
"jupyter-xeus",
24+
"jupytercon",
25+
"voila-dashboards",
26+
"voila-gallery",
27+
]
1128
token = os.getenv("GH_TOKEN")
1229
if not token:
1330
print("[red]Error: GH_TOKEN environment variable not set[/red]")
1431
exit(1)
1532

1633
headers = {
17-
'Authorization': f'token {token}',
18-
'Accept': 'application/vnd.github.v3+json'
34+
"Authorization": f"token {token}",
35+
"Accept": "application/vnd.github.v3+json",
1936
}
2037

21-
async def check_private_vulnerability_reporting(session: aiohttp.ClientSession, org: str, repo_name: str) -> bool:
38+
39+
async def check_private_vulnerability_reporting(
40+
session: aiohttp.ClientSession, org: str, repo_name: str
41+
) -> bool:
2242
"""Check if private vulnerability reporting is enabled for a repository
23-
43+
2444
Parameters
2545
----------
2646
session: aiohttp.ClientSession
@@ -34,17 +54,18 @@ async def check_private_vulnerability_reporting(session: aiohttp.ClientSession,
3454
-------
3555
bool: True if enabled, False otherwise
3656
"""
37-
url = f'https://api.github.com/repos/{org}/{repo_name}/private-vulnerability-reporting'
38-
57+
url = f"https://api.github.com/repos/{org}/{repo_name}/private-vulnerability-reporting"
58+
3959
async with session.get(url, headers=headers) as response:
4060
if response.status == 200:
4161
data = await response.json()
42-
return data.get('enabled', False)
62+
return data.get("enabled", False)
4363
return False
4464

65+
4566
async def get_org_repos(session: aiohttp.ClientSession, org: str) -> list[dict]:
4667
"""Get all repositories for an organization
47-
68+
4869
Parameters
4970
----------
5071
session: aiohttp.ClientSession
@@ -57,33 +78,41 @@ async def get_org_repos(session: aiohttp.ClientSession, org: str) -> list[dict]:
5778
list[dict]: The list of repositories
5879
"""
5980
repos = []
60-
81+
6182
for page in count(1): # starts at 1 and counts up infinitely
62-
url = f'https://api.github.com/orgs/{org}/repos?page={page}&per_page=100'
83+
url = f"https://api.github.com/orgs/{org}/repos?page={page}&per_page=100"
6384
async with session.get(url, headers=headers) as response:
6485
if response.status != 200:
6586
print(f"[red]Error fetching repos: {response.status}[/red]")
6687
break
67-
88+
6889
page_repos = await response.json()
6990
if not page_repos: # empty page means we've reached the end
7091
break
71-
92+
7293
repos.extend(page_repos)
73-
94+
7495
return repos
7596

97+
7698
async def main():
99+
ignores = Path("psc_ignore.txt").read_text().splitlines()
77100
async with aiohttp.ClientSession() as session:
78101
# Check rate limit before making requests
79-
async with session.get('https://api.github.com/rate_limit', headers=headers) as response:
102+
async with session.get(
103+
"https://api.github.com/rate_limit", headers=headers
104+
) as response:
80105
if response.status == 200:
81106
rate_data = await response.json()
82-
remaining = rate_data['resources']['core']['remaining']
83-
reset_time = datetime.fromtimestamp(rate_data['resources']['core']['reset'])
107+
remaining = rate_data["resources"]["core"]["remaining"]
108+
reset_time = datetime.fromtimestamp(
109+
rate_data["resources"]["core"]["reset"]
110+
)
84111
reset_in = humanize.naturaltime(reset_time)
85112
if remaining < 100:
86-
print(f"[yellow]Warning: Rate limit is low! ({remaining} remaining, full in {reset_in})[/yellow]")
113+
print(
114+
f"[yellow]Warning: Rate limit is low! ({remaining} remaining, full in {reset_in})[/yellow]"
115+
)
87116
if remaining < 10:
88117
print("[red]Aborting due to very low rate limit[/red]")
89118
return
@@ -99,27 +128,46 @@ async def main():
99128
for (org, _), org_repos in zip(org_tasks, org_results):
100129
for repo in org_repos:
101130
repos.append((org, repo))
102-
103-
for org, repo in sorted(repos, key=lambda x: x[1]['name']):
104-
repo_name = repo['name']
105-
131+
132+
for org, repo in sorted(repos, key=lambda x: x[1]["name"]):
133+
if f"{org}/{repo['name']}" in ignores:
134+
print(
135+
f"[yellow]Ignoring {org}/{repo['name']} from ignore file[/yellow]"
136+
)
137+
continue
138+
repo_name = repo["name"]
139+
106140
task = check_private_vulnerability_reporting(session, org, repo_name)
107141
tasks.append((repo, org, repo_name, task))
108-
109-
results = await asyncio.gather(*[task for _,_,_, task in tasks])
110-
111-
for (repo, org, repo_name, _), has_vuln_reporting in sorted(zip(tasks, results), key=lambda x: x[0][0]['pushed_at'], reverse=True):
112-
last_activity = repo['pushed_at']
113-
last_activity_date = datetime.fromisoformat(last_activity).strftime("%Y-%m-%d")
114-
last_activity_ago_human = humanize.naturaltime(datetime.now(datetime.fromisoformat(last_activity).tzinfo) - datetime.fromisoformat(last_activity))
115-
116-
if repo['archived']:
117-
print(f"{org+'/'+repo_name:<55}: [yellow]Archived {'Enabled' if has_vuln_reporting else 'Disabled[/yellow]'}")
118-
elif repo['private']:
119-
print(f"{org+'/'+repo_name:<55}: [yellow]Private {'Enabled' if has_vuln_reporting else 'Disabled[/yellow]'} –– last activity: {last_activity_date} ({last_activity_ago_human})")
142+
143+
results = await asyncio.gather(*[task for _, _, _, task in tasks])
144+
145+
for (repo, org, repo_name, _), has_vuln_reporting in sorted(
146+
zip(tasks, results), key=lambda x: x[0][0]["pushed_at"], reverse=True
147+
):
148+
last_activity = repo["pushed_at"]
149+
last_activity_date = datetime.fromisoformat(last_activity).strftime(
150+
"%Y-%m-%d"
151+
)
152+
last_activity_ago_human = humanize.naturaltime(
153+
datetime.now(datetime.fromisoformat(last_activity).tzinfo)
154+
- datetime.fromisoformat(last_activity)
155+
)
156+
157+
if repo["archived"]:
158+
print(
159+
f"{org+'/'+repo_name:<55}: [yellow]Archived {'Enabled' if has_vuln_reporting else 'Disabled[/yellow]'}"
160+
)
161+
elif repo["private"]:
162+
print(
163+
f"{org+'/'+repo_name:<55}: [yellow]Private {'Enabled' if has_vuln_reporting else 'Disabled[/yellow]'} –– last activity: {last_activity_date} ({last_activity_ago_human})"
164+
)
120165

121166
else:
122-
print(f"{org+'/'+repo_name:<55}: {'[green]Enabled[/green]' if has_vuln_reporting else '[red]Disabled[/red]'} –– last activity: {last_activity_date} ({last_activity_ago_human})")
167+
print(
168+
f"{org+'/'+repo_name:<55}: {'[green]Enabled[/green]' if has_vuln_reporting else '[red]Disabled[/red]'} –– last activity: {last_activity_date} ({last_activity_ago_human})"
169+
)
170+
123171

124172
if __name__ == "__main__":
125-
asyncio.run(main())
173+
asyncio.run(main())

0 commit comments

Comments
 (0)