mirror of
https://github.com/Sea-Haven-Industries/shoc-pr-review-runner.git
synced 2026-10-03 20:23:11 +00:00
Manually-dispatched GitHub Actions workflow that reviews SHOC pull requests in a clean environment: exact-head checkout of shoc-frontend-new and shoc-backend, clean build/test gates, a truthful evidence report, a single-shot Fireworks review, deterministic output validation, and published artifacts. The runner never writes to the product repositories or their pull requests. The review checklists move here from the reviewers' local Cursor commands so the instructions live outside both product repos. Phase 1 does not provision a database, start either application, or run live browser flows; the evidence report records those as NOT_RUN so a review cannot claim them. Security architecture: building a PR executes its author's code, so the workflow is split. The gates job runs that code holding no Fireworks key and revokes its App token first; the review job holds the key, executes no product code, and re-checks out this repo fresh. Product checkouts live outside the workspace, the App token is downscoped at mint time, gate results fail closed on any duplicate key, changed files are read from git objects rather than the filesystem, and the validator re-checks every claim against the gate table.
94 lines
3.8 KiB
Bash
Executable file
94 lines
3.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Check out the product repositories at exact SHAs (spec §10).
|
|
#
|
|
# Repos under review are checked out at their PR head SHA. The companion repo of
|
|
# a single-repo review is checked out at its default branch head for contract
|
|
# context (spec §10.2) and recorded as such.
|
|
#
|
|
# Auth: the read-only App installation token is injected ONLY as a host-scoped
|
|
# Basic http.extraHeader via GIT_CONFIG_* environment variables for the fetch
|
|
# commands. It is never placed in a URL, never Bearer, and never written to
|
|
# .git/config, so nothing credential-bearing persists after the run.
|
|
#
|
|
# Usage: checkout-repositories.sh
|
|
# Reads: GH_TOKEN, REVIEW_TYPE, FRONTEND_REPO, BACKEND_REPO,
|
|
# FRONTEND_SHA / BACKEND_SHA (empty when that side has no PR),
|
|
# COMPANION_BRANCH (default: dev)
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=lib.sh
|
|
source "$SCRIPT_DIR/lib.sh"
|
|
|
|
require_env GH_TOKEN REVIEW_TYPE FRONTEND_REPO BACKEND_REPO
|
|
COMPANION_BRANCH="${COMPANION_BRANCH:-dev}"
|
|
|
|
# The Basic-auth header is a derived credential: GitHub masks the raw token it
|
|
# minted, but not this transformation of it. Register the mask explicitly so an
|
|
# accidental trace or debug flag cannot print a working credential to the log.
|
|
AUTH_HEADER_B64="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')"
|
|
if [ -n "${GITHUB_ACTIONS:-}" ]; then
|
|
echo "::add-mask::$AUTH_HEADER_B64"
|
|
fi
|
|
|
|
auth_git() {
|
|
# git with the Basic auth header injected via env for this invocation only.
|
|
GIT_CONFIG_COUNT=1 \
|
|
GIT_CONFIG_KEY_0="http.https://github.com/.extraHeader" \
|
|
GIT_CONFIG_VALUE_0="Authorization: Basic $AUTH_HEADER_B64" \
|
|
GIT_TERMINAL_PROMPT=0 \
|
|
git "$@"
|
|
}
|
|
|
|
# fetch_at <dir> <repo> <ref-or-sha> <label>
|
|
fetch_at() {
|
|
local dir="$1" repo="$2" ref="$3" label="$4"
|
|
# Validate before use: the ref reaches git as an argument, so anything other
|
|
# than a resolved SHA or the configured companion branch is refused.
|
|
if ! [[ "$ref" =~ ^[0-9a-f]{40}$ ]] && [ "$ref" != "$COMPANION_BRANCH" ]; then
|
|
die "refusing to fetch unexpected ref '$ref'"
|
|
fi
|
|
rm -rf "$dir"
|
|
mkdir -p "$dir"
|
|
git -C "$dir" init -q
|
|
git -C "$dir" remote add origin -- "https://github.com/$repo.git"
|
|
auth_git -C "$dir" fetch -q --depth=1 origin -- "$ref" || die "fetch of $repo @ $ref failed"
|
|
git -C "$dir" checkout -q --detach FETCH_HEAD
|
|
local got
|
|
got="$(git -C "$dir" rev-parse HEAD)"
|
|
if [[ "$ref" =~ ^[0-9a-f]{40}$ ]] && [ "$got" != "$ref" ]; then
|
|
die "$repo checkout mismatch: wanted $ref got $got"
|
|
fi
|
|
log "$label: $repo @ $(git -C "$dir" rev-parse --short=7 HEAD) ($ref)"
|
|
}
|
|
|
|
frontend_dir="$WORKSPACE_DIR/frontend"
|
|
backend_dir="$WORKSPACE_DIR/backend"
|
|
|
|
case "$REVIEW_TYPE" in
|
|
frontend)
|
|
require_env FRONTEND_SHA
|
|
fetch_at "$frontend_dir" "$FRONTEND_REPO" "$FRONTEND_SHA" "frontend (PR head)"
|
|
fetch_at "$backend_dir" "$BACKEND_REPO" "$COMPANION_BRANCH" "backend (companion @ $COMPANION_BRANCH)"
|
|
;;
|
|
backend)
|
|
require_env BACKEND_SHA
|
|
fetch_at "$backend_dir" "$BACKEND_REPO" "$BACKEND_SHA" "backend (PR head)"
|
|
fetch_at "$frontend_dir" "$FRONTEND_REPO" "$COMPANION_BRANCH" "frontend (companion @ $COMPANION_BRANCH)"
|
|
;;
|
|
paired)
|
|
require_env FRONTEND_SHA BACKEND_SHA
|
|
fetch_at "$frontend_dir" "$FRONTEND_REPO" "$FRONTEND_SHA" "frontend (PR head)"
|
|
fetch_at "$backend_dir" "$BACKEND_REPO" "$BACKEND_SHA" "backend (PR head)"
|
|
;;
|
|
*) die "invalid REVIEW_TYPE '$REVIEW_TYPE'" ;;
|
|
esac
|
|
|
|
# Record companion context for evidence.
|
|
jq -n \
|
|
--arg review_type "$REVIEW_TYPE" \
|
|
--arg companion_branch "$COMPANION_BRANCH" \
|
|
--arg frontend_head "$(git -C "$frontend_dir" rev-parse HEAD)" \
|
|
--arg backend_head "$(git -C "$backend_dir" rev-parse HEAD)" \
|
|
'{review_type: $review_type, companion_branch: $companion_branch,
|
|
frontend_checkout: $frontend_head, backend_checkout: $backend_head}' \
|
|
>"$ARTIFACTS_DIR/checkout.json"
|