fix(cli): harden bytelyst-cli env loading, pagination, and HTTP checks
- .env via 'set -a; . ./.env; set +a' (handles quoted values/spaces safely) - printf for the GITHUB_TOKEN message so the newline renders - gh_get_all: paginate all pages (per_page=100) and verify HTTP 200 before jq; rewire list-public/list-private/check-collaborators through it - fix SC2199 whitelist membership (explicit loop, no substring false-matches) - shell-ci: gate shellcheck on bytelyst-cli + run agent-queue self-test
This commit is contained in:
parent
4239648876
commit
76104bda84
@ -37,20 +37,22 @@ jobs:
|
||||
apt-get install -y -qq shellcheck
|
||||
shellcheck --version
|
||||
|
||||
- name: shellcheck agent-queue (errors fail the build)
|
||||
- name: shellcheck (errors fail the build)
|
||||
run: |
|
||||
shellcheck --severity=error --shell=bash agent-queue/agent-queue.sh
|
||||
shellcheck --severity=error --shell=bash \
|
||||
agent-queue/agent-queue.sh \
|
||||
agent-queue/selftest.sh \
|
||||
bytelyst-cli.sh
|
||||
|
||||
- name: shellcheck bytelyst-cli (non-gating — legacy known issues)
|
||||
continue-on-error: true
|
||||
run: |
|
||||
shellcheck --severity=error --shell=bash bytelyst-cli.sh
|
||||
|
||||
- name: bash syntax check (gating, both scripts)
|
||||
- name: bash syntax check (gating, all scripts)
|
||||
run: |
|
||||
bash -n agent-queue/agent-queue.sh
|
||||
bash -n agent-queue/selftest.sh
|
||||
bash -n bytelyst-cli.sh
|
||||
|
||||
- name: agent-queue self-test (no-op engine cycle)
|
||||
run: ./agent-queue/selftest.sh
|
||||
|
||||
- name: node syntax check (dashboard)
|
||||
run: node --check agent-queue/dashboard.mjs
|
||||
|
||||
|
||||
@ -35,17 +35,49 @@ for tool in "${REQUIRED_TOOLS[@]}"; do
|
||||
fi
|
||||
done
|
||||
|
||||
# Load .env if present
|
||||
# Load .env if present. `set -a` exports everything sourced; this safely handles
|
||||
# quoted values and spaces, unlike `export $(grep ... | xargs)`.
|
||||
if [[ -f .env ]]; then
|
||||
export $(grep -v '^#' .env | xargs)
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. ./.env
|
||||
set +a
|
||||
fi
|
||||
|
||||
# Validate GITHUB_TOKEN
|
||||
if [[ -z "$GITHUB_TOKEN" ]]; then
|
||||
echo "${RED}❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g., export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).${RESET}"
|
||||
# Validate GITHUB_TOKEN (printf so the newline renders, unlike echo "...\n...")
|
||||
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
|
||||
printf '%s❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g. export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).%s\n' "$RED" "$RESET" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# gh_get_all <url> -> echo one JSON array combining ALL pages (per_page=100).
|
||||
# Verifies HTTP 200 on every page before parsing; returns non-zero on API error.
|
||||
gh_get_all() {
|
||||
local base="$1" page=1 combined="[]"
|
||||
local joiner='&'; [[ "$base" == *'?'* ]] || joiner='?'
|
||||
while :; do
|
||||
local resp http body n
|
||||
resp=$(curl -sS -w $'\n%{http_code}' \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"${base}${joiner}per_page=100&page=${page}")
|
||||
http="${resp##*$'\n'}"
|
||||
body="${resp%$'\n'*}"
|
||||
if [[ "$http" != "200" ]]; then
|
||||
printf '%s❌ GitHub API error (HTTP %s) for %s%s\n' "$RED" "$http" "$base" "$RESET" >&2
|
||||
printf '%s' "$body" | jq -r '.message? // empty' >&2 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
n=$(printf '%s' "$body" | jq 'length' 2>/dev/null || echo 0)
|
||||
[[ "$n" -eq 0 ]] && break
|
||||
combined=$(jq -s 'add' <(printf '%s' "$combined") <(printf '%s' "$body"))
|
||||
[[ "$n" -lt 100 ]] && break
|
||||
page=$((page+1))
|
||||
[[ "$page" -gt 100 ]] && break
|
||||
done
|
||||
printf '%s' "$combined"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "${BLUE}Bytelyst CLI - Unified GitHub DevOps Tool${RESET}"
|
||||
echo ""
|
||||
@ -75,8 +107,9 @@ list_public_repos() {
|
||||
echo "${RED}❌ Please provide --user <username>.${RESET}"; exit 1
|
||||
fi
|
||||
echo "${BLUE}🔍 Fetching all public repositories for user: $user...${RESET}"
|
||||
local response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/users/$user/repos?per_page=100&type=public")
|
||||
local repos=$(echo "$response" | jq -r '.[].full_name')
|
||||
local json repos
|
||||
json=$(gh_get_all "https://api.github.com/users/$user/repos?type=public") || exit 1
|
||||
repos=$(printf '%s' "$json" | jq -r '.[].full_name')
|
||||
if [[ -z "$repos" ]]; then
|
||||
echo "${YELLOW}🚫 No public repositories found for user.${RESET}"
|
||||
else
|
||||
@ -97,8 +130,9 @@ list_private_repos() {
|
||||
echo "${RED}❌ Please provide --org <orgname>.${RESET}"; exit 1
|
||||
fi
|
||||
echo "${BLUE}🔍 Fetching all private repositories for org: $org...${RESET}"
|
||||
local response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/$org/repos?per_page=100&type=private")
|
||||
local repos=$(echo "$response" | jq -r '.[].full_name')
|
||||
local json repos
|
||||
json=$(gh_get_all "https://api.github.com/orgs/$org/repos?type=private") || exit 1
|
||||
repos=$(printf '%s' "$json" | jq -r '.[].full_name')
|
||||
if [[ -z "$repos" ]]; then
|
||||
echo "${YELLOW}🚫 No private repositories found for org.${RESET}"
|
||||
else
|
||||
@ -127,12 +161,19 @@ check_collaborators() {
|
||||
fi
|
||||
for repo in "${repos[@]}"; do
|
||||
echo "${BLUE}🔍 Checking repo: $repo${RESET}"
|
||||
local collaborators=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators" | jq -r '.[].login')
|
||||
local cjson collaborators
|
||||
cjson=$(gh_get_all "https://api.github.com/repos/$org/$repo/collaborators") \
|
||||
|| { echo "${YELLOW}⚠️ Skipping $repo (API error).${RESET}"; continue; }
|
||||
collaborators=$(printf '%s' "$cjson" | jq -r '.[].login')
|
||||
local non_whitelisted=()
|
||||
for collab in $collaborators; do
|
||||
if [[ ! " ${whitelist[@]} " =~ " ${collab} " ]]; then
|
||||
non_whitelisted+=("$collab")
|
||||
fi
|
||||
# explicit membership test (avoids the array-concatenation pitfall of
|
||||
# [[ " ${whitelist[@]} " =~ " $collab " ]], which false-matches substrings)
|
||||
local is_white=false w
|
||||
for w in "${whitelist[@]}"; do
|
||||
[[ "$w" == "$collab" ]] && { is_white=true; break; }
|
||||
done
|
||||
$is_white || non_whitelisted+=("$collab")
|
||||
done
|
||||
if [[ ${#non_whitelisted[@]} -gt 0 ]]; then
|
||||
echo "${YELLOW}🚨 Repository: $repo${RESET}"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user