advisory-scan: read-only GitHub token from env or file (rate limit only)
Anonymous GitHub API is 60 req/hr — a full weekly sweep across ~20 recipes exhausts it and the scan then reports sources as failed (visible, but degraded coverage). A token lifts it to 5000/hr. _github_token(): GITHUB_TOKEN env wins, else GITHUB_TOKEN_FILE (default /srv/cc-ci/.github-token, 0600, gitignored). Reading PUBLIC advisories needs NO scopes — a classic PAT with nothing ticked, or fine-grained limited to 'Public repositories: read'. The tool only ever GETs advisories; do not grant write scopes. A missing token is not an error: the scan runs anonymously and surfaces failures. Also gitignores .github-token and .hcloud-token.
This commit is contained in:
@@ -28,3 +28,7 @@ master-age.txt
|
||||
# Python bytecode cache
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Local API tokens — never committed (advisory-scan / hetzner recovery)
|
||||
.github-token
|
||||
.hcloud-token
|
||||
|
||||
@@ -59,6 +59,27 @@ OSV_PACKAGES: dict[str, tuple[str, str]] = {
|
||||
}
|
||||
|
||||
|
||||
def _github_token() -> str | None:
|
||||
"""Read-only GitHub token, for the API rate limit ONLY (60/hr anonymous → 5000/hr with a token).
|
||||
|
||||
Env `GITHUB_TOKEN` wins; otherwise the file at `GITHUB_TOKEN_FILE` (default
|
||||
/srv/cc-ci/.github-token, chmod 600, never in git). Reading PUBLIC security advisories needs NO
|
||||
scopes at all — create a classic PAT with every box unticked, or a fine-grained token limited to
|
||||
"Public repositories: read". Do NOT grant repo/write scopes: this tool only ever GETs advisories.
|
||||
A missing token is not an error — the scan simply runs anonymously and will report sources as
|
||||
failed once the 60/hr limit bites, which is visible rather than silent.
|
||||
"""
|
||||
tok = os.environ.get("GITHUB_TOKEN")
|
||||
if tok:
|
||||
return tok.strip()
|
||||
path = os.environ.get("GITHUB_TOKEN_FILE", "/srv/cc-ci/.github-token")
|
||||
try:
|
||||
with open(path) as f:
|
||||
return f.read().strip() or None
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
|
||||
def _fetch(url: str, headers: dict | None = None) -> str:
|
||||
h = {"User-Agent": UA, "Accept-Encoding": "gzip"}
|
||||
h.update(headers or {})
|
||||
@@ -112,7 +133,7 @@ def github_advisories(urls: list[str]) -> list[dict]:
|
||||
seen.add((owner, repo))
|
||||
api = f"https://api.github.com/repos/{owner}/{repo}/security-advisories?per_page=100"
|
||||
hdrs = {"Accept": "application/vnd.github+json"}
|
||||
tok = os.environ.get("GITHUB_TOKEN")
|
||||
tok = _github_token()
|
||||
if tok:
|
||||
hdrs["Authorization"] = f"Bearer {tok}"
|
||||
entry = {"source": f"github-advisories:{owner}/{repo}", "status": "ok", "advisories": []}
|
||||
|
||||
Reference in New Issue
Block a user