Skip to content

Commit 4bdfc45

Browse files
authored
Merge pull request #88 from Carreau/priven
Scipt that check which repo has private sec enabled
2 parents c6236c0 + 634a083 commit 4bdfc45

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

private_sec_ignore.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
jupyterlab/scipy2018-jupyterlab-tutorial
2+
ipython/ipython.github.com

tools/private_sec_report.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""GitHub Organization Activity Tracker
2+
3+
This module tracks and reports the last activity of members across GitHub organizations.
4+
It implements disk-based caching to minimize API requests and respect rate limits.
5+
"""
6+
7+
import os
8+
import sys
9+
import asyncio
10+
import aiohttp
11+
from rich import print
12+
from datetime import datetime, timezone, timedelta
13+
import humanize
14+
from itertools import count
15+
import diskcache
16+
import pathlib
17+
from typing import Optional, List, Dict
18+
import argparse
19+
20+
default_orgs = [
21+
"binder-examples",
22+
"binderhub-ci-repos",
23+
"ipython",
24+
"jupyter",
25+
"jupyter-attic",
26+
"jupyter-book",
27+
"jupyter-governance",
28+
"jupyter-incubator",
29+
"jupyter-resources",
30+
"jupyter-server",
31+
"jupyter-standard",
32+
"jupyter-standards",
33+
"jupyter-widgets",
34+
"jupyter-xeus",
35+
"jupytercon",
36+
"jupyterhub",
37+
"jupyterlab",
38+
"voila-dashboards",
39+
"voila-gallery",
40+
"pickleshare",
41+
]
42+
43+
token = os.getenv("GH_TOKEN")
44+
if not token:
45+
print("[red]Error: GH_TOKEN environment variable not set[/red]")
46+
exit(1)
47+
48+
headers = {
49+
"Authorization": f"token {token}",
50+
"Accept": "application/vnd.github.v3+json",
51+
}
52+
53+
54+
async def list_repos(orgs):
55+
async with aiohttp.ClientSession() as session:
56+
tasks = [
57+
session.get(f"https://api.github.com/orgs/{org}/repos", headers=headers)
58+
for org in orgs
59+
]
60+
for org, response in zip(orgs, await asyncio.gather(*tasks)):
61+
repos = await response.json()
62+
for repo in repos:
63+
yield org, repo["name"]
64+
65+
66+
async def get_private_report(session, org, repo):
67+
private_report_url = (
68+
f"https://api.github.com/repos/{org}/{repo}/private-vulnerability-reporting"
69+
)
70+
async with session.get(
71+
f"https://api.github.com/repos/{org}/{repo}", headers=headers
72+
) as repo_response:
73+
repo_info = await repo_response.json()
74+
archived = repo_info.get("archived", False)
75+
async with session.get(private_report_url, headers=headers) as response:
76+
if response.status == 200:
77+
return org, repo, (await response.json()).get("enabled", False), archived
78+
else:
79+
return org, repo, False, archived
80+
81+
82+
async def main():
83+
with pathlib.Path("private_sec_ignore.txt").open("r") as ignore_file:
84+
ignore_repos = [line.strip() for line in ignore_file.readlines()]
85+
86+
async with aiohttp.ClientSession() as session:
87+
tasks = []
88+
async for org, repo in list_repos(default_orgs):
89+
tasks.append(get_private_report(session, org, repo))
90+
91+
results = await asyncio.gather(*tasks)
92+
prev_org = None
93+
for org, repo, enabled, archived in results:
94+
if org != prev_org:
95+
print()
96+
print(f"[bold]{org}[/bold]")
97+
prev_org = org
98+
if enabled:
99+
print(f" [green]{repo}: {enabled}[/green]")
100+
else:
101+
if archived:
102+
print(f" [yellow]{org}/{repo}: {enabled} (archived)[/yellow]")
103+
elif f"{org}/{repo}" in ignore_repos:
104+
print(f" [yellow]{org}/{repo}: {enabled} (ignored)[/yellow]")
105+
else:
106+
print(f" [red]{org}/{repo}: {enabled}[/red]")
107+
108+
109+
asyncio.run(main())

0 commit comments

Comments
 (0)