lmjtfy.git / tools / check-repos
check-repos36 lines · 2.3 KB · raw
1#!/usr/bin/env bash
2# Fail unless the code host serves exactly the private repositories its GitHub token can read.
3#
4#     tools/with-secrets.sh tools/check-repos      (mise run check-repos)
5#
6# The token (LMJTFY_GITHUB_TOKEN) is given repositories one by one on GitHub; the code host serves
7# the ones named in `Repo` (apps/lmjtfy/src/clone.rs). They are two lists kept in two places, so
8# they drift: a repository added to the token and not to `Repo` is not listed and cannot be cloned
9# from the code host; one in `Repo` and not on the token is listed and answers every clone with an
10# error. This asks GitHub for the token's list and compares.
11#
12# Reads only: one GET of the token's own repository list. Needs curl and the token.
13set -euo pipefail
14cd "$(dirname "$0")/.."
15[ -n "${LMJTFY_GITHUB_TOKEN:-}" ] || { echo "check-repos: LMJTFY_GITHUB_TOKEN is not set (see fnox.toml)" >&2; exit 1; }
16
17# A fine-grained token lists every public repository of its owner too; only the private ones are
18# ones it was given. A hundred a page; the owner has far fewer private repositories on it.
19answer="$(curl --silent --show-error --fail --max-time 30 \
20  -H "Authorization: Bearer $LMJTFY_GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" -H "User-Agent: lmjtfy-check-repos" \
21  "https://api.github.com/user/repos?visibility=private&affiliation=owner&per_page=100")"
22token="$(printf '%s' "$answer" | grep -o '"full_name": *"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/' | sort)"
23[ -n "$token" ] || { echo "check-repos: GitHub listed no private repository for the token" >&2; exit 1; }
24[ "$(printf '%s\n' "$token" | wc -l)" -lt 100 ] || { echo "check-repos: a full page of repositories; this script reads one page" >&2; exit 1; }
25
26served="$(grep -o '=> "[A-Za-z0-9_.-]*/[A-Za-z0-9_.-]*",' apps/lmjtfy/src/clone.rs | sed 's/=> "\(.*\)",/\1/' | sort)"
27[ -n "$served" ] || { echo "check-repos: found no repository in apps/lmjtfy/src/clone.rs" >&2; exit 1; }
28
29if [ "$token" = "$served" ]; then
30  echo "check-repos: ok, $(printf '%s\n' "$served" | wc -l) repositories on the token and served"
31  exit 0
32fi
33echo "check-repos: the token's repositories and the code host's differ" >&2
34comm -23 <(printf '%s\n' "$token") <(printf '%s\n' "$served") | sed 's/^/  on the token, not served: /' >&2
35comm -13 <(printf '%s\n' "$token") <(printf '%s\n' "$served") | sed 's/^/  served, not on the token: /' >&2
36exit 1