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