shoc-backend/scripts/governance-check.sh

131 lines
4.8 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# governance-check.sh — local/CI parity governance gate for the Seahaven backend.
#
# Locally this runs G1–G5, G10, G11, promotion-script tests, and live G13.
# The architecture job in ci.yml sets GOVERNANCE_SKIP_BUILD_TEST=1 so G4/G5
# run only in the Build and test job. Live G13 runs on pull_request and local
# invocations; it skips merge_group and push.
#
# Usage:
# bash scripts/governance-check.sh
# BASE_REF=origin/main bash scripts/governance-check.sh
# BASE_REF=<base-sha> HEAD_REF=<head-sha> bash scripts/governance-check.sh
set -euo pipefail
SOLUTION="SeaHavenIndustries.sln"
ARCH_TEST_PROJECT="Api.SeaHavenIndustries.Tests/Api.SeaHavenIndustries.Tests.csproj"
LIVE_ROOTS=(terraform/live/dev terraform/live/staging)
log() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; }
ok() { printf '\033[32mPASS\033[0m %s\n' "$1"; }
bad() { printf '\033[31mFAIL\033[0m %s\n' "$1"; }
if [[ -n "${DOTNET_BIN:-}" ]]; then
DOTNET="$DOTNET_BIN"
elif command -v dotnet >/dev/null 2>&1; then
DOTNET="$(command -v dotnet)"
elif [[ -x "$HOME/.dotnet/dotnet" ]]; then
DOTNET="$HOME/.dotnet/dotnet"
else
bad "dotnet is unavailable; set DOTNET_BIN or install the repository SDK."
exit 1
fi
# Comparison point for changed-file formatting. Default to main locally; CI
# overrides BASE_REF/HEAD_REF with the PR base/head SHAs.
BASE_REF="${BASE_REF:-origin/main}"
HEAD_REF="${HEAD_REF:-HEAD}"
# Resolve the base ref before using it for a diff.
if ! git rev-parse --verify --quiet "${BASE_REF}^{commit}" >/dev/null; then
bad "G3: BASE_REF '${BASE_REF}' does not resolve to a commit (run: git fetch origin)."
exit 1
fi
# Diff the change set from the merge base, not from the base tip. A two-dot
# diff against a moving base reports everything the base gained after the
# branch point as if this change reverted it, so a branch behind main that
# touches C# would fail G13 whenever main had merged Terraform in the meantime.
# The merge queue no longer requires branches to be current, so this matters.
DIFF_BASE="$(git merge-base "${BASE_REF}" "${HEAD_REF}")" || {
bad "G3: no merge base between '${BASE_REF}' and '${HEAD_REF}'."
exit 1
}
log "G1: restore"
"$DOTNET" restore "$SOLUTION"
ok "G1: restore"
log "G2: architecture boundary tests (dependency direction)"
"$DOTNET" test "$ARCH_TEST_PROJECT" \
--no-restore \
--filter "FullyQualifiedName~ArchitectureTests" \
--nologo
ok "G2: ArchitectureTests"
log "G3: changed-file formatting (${BASE_REF}...${HEAD_REF}, merge base ${DIFF_BASE:0:7})"
changed_cs=()
while IFS= read -r f; do
changed_cs+=("$f")
done < <(
git diff --name-only --diff-filter=ACMR "${DIFF_BASE}" "${HEAD_REF}" -- '*.cs'
)
if (( ${#changed_cs[@]} == 0 )); then
printf '\033[33mSKIP\033[0m G3: no changed C# files between %s...%s\n' "${BASE_REF}" "${HEAD_REF}"
else
printf ' checking %d changed C# file(s)\n' "${#changed_cs[@]}"
"$DOTNET" format "$SOLUTION" \
--no-restore \
--verify-no-changes \
--include "${changed_cs[@]}"
ok "G3: changed-file formatting"
fi
if [[ "${GOVERNANCE_SKIP_BUILD_TEST:-}" == "1" ]]; then
printf '\033[33mSKIP\033[0m G4: Release build (CI Build and test job owns it)\n'
printf '\033[33mSKIP\033[0m G5: full test suite (CI Build and test job owns it)\n'
else
log "G4: Release build"
"$DOTNET" build "$SOLUTION" -c Release --no-restore --nologo
ok "G4: Release build"
log "G5: full test suite"
"$DOTNET" test "$SOLUTION" -c Release --no-build --nologo
ok "G5: full test suite"
fi
log "G10: Terraform import plan safety"
python scripts/test-terraform-import-plan-check.py
ok "G10: Terraform import plan safety"
log "Release promotion scripts"
python3 scripts/test_next_release_tag.py
python3 scripts/test_require_commit_checks.py
python3 scripts/test_check_app_terraform_isolation.py
ok "Release promotion scripts"
log "G11: Terraform formatting and validation"
if ! command -v terraform >/dev/null 2>&1; then
bad "G11: terraform is unavailable; install Terraform or set PATH."
exit 1
fi
terraform fmt -check -recursive terraform
for live_root in "${LIVE_ROOTS[@]}"; do
terraform -chdir="${live_root}" init -backend=false -input=false -lockfile=readonly -no-color
terraform -chdir="${live_root}" validate -no-color
done
ok "G11: Terraform formatting and validation"
if [[ -n "${GITHUB_EVENT_NAME:-}" && "${GITHUB_EVENT_NAME}" != "pull_request" ]]; then
printf '\033[33mSKIP\033[0m G13: live isolation is a pull-request property (event: %s)\n' "${GITHUB_EVENT_NAME}"
else
log "G13: application and Terraform isolation (${BASE_REF}...${HEAD_REF}, merge base ${DIFF_BASE:0:7})"
python3 scripts/check_app_terraform_isolation.py < <(
git diff --name-only --diff-filter=ACMR "${DIFF_BASE}" "${HEAD_REF}"
)
ok "G13: application and Terraform isolation"
fi
log "governance-check: all required repository gates passed"