diff --git a/scripts/compliance-audit.sh b/scripts/compliance-audit.sh index d521e800a..1b7a9b9ca 100755 --- a/scripts/compliance-audit.sh +++ b/scripts/compliance-audit.sh @@ -298,6 +298,12 @@ RULESETS_SRC_DIR="${RULESETS_SRC_DIR:-$SCRIPT_DIR/../standards/rulesets}" # shellcheck source=lib/ring-pins.sh . "$SCRIPT_DIR/lib/ring-pins.sh" +# Repos outside the org standard by the Maintainer's decision — NOT_SERVED_REPOS +# and is_not_served_repo(). Shared with deploy-standard-workflows.sh: the audit +# files no findings or issues where the sweep deploys nothing (#1343, #1352). +# shellcheck source=lib/not-served-repos.sh +. "$SCRIPT_DIR/lib/not-served-repos.sh" + # ADR-0007 agent-ingress identity helpers: a required per-role workflow whose role # an agent-ingress.yml job serves is present, not missing (#1226) — the same rule # deploy-standard-workflows.sh uses to never re-seed a collapsed stub. @@ -3724,6 +3730,18 @@ main() { local repos repos=$(gh repo list "$ORG" --no-archived --json name -q '.[].name' --limit 500) + # Drop repos outside the standard (NOT_SERVED_REPOS) before both the audit loop + # and the issue-management loop, so no finding, issue or label lands there. + local listed served="" + for listed in $repos; do + if is_not_served_repo "$listed"; then + info "Skipping $ORG/$listed (not served — NOT_SERVED_REPOS)" + continue + fi + served+="$listed"$'\n' + done + repos="$served" + if [ -z "$repos" ]; then warn "No repositories found in $ORG — check GH_TOKEN permissions" echo "[]" > "$FINDINGS_FILE" diff --git a/scripts/deploy-standard-workflows.sh b/scripts/deploy-standard-workflows.sh index 3daf65b6e..8c67774e9 100755 --- a/scripts/deploy-standard-workflows.sh +++ b/scripts/deploy-standard-workflows.sh @@ -78,20 +78,12 @@ readonly ENGINE_HOST_REPO=".github-private" # A repo here may still opt into a *specific* workflow via SKIP_OVERRIDES below. SKIP_REPOS=(".github" "$ENGINE_HOST_REPO") -# Repos the standard-workflow sweep does not serve at all. This is a different -# thing from SKIP_REPOS. A SKIP_REPO is inside the standard and self-manages it, -# so every required workflow on it must be reconciled (SKIP_OVERRIDES or -# SKIP_SELF_MANAGED, see reconcile_skip_repo_required_workflows). A repo here is -# outside the standard by a recorded decision of the Maintainer: it receives no -# stub, takes no opt-in, and is not part of that reconciliation. -# software-factory — where the replacement for this fleet is built. Its -# design keeps the two apart (no owner-account token, -# none of the fleet's workflows), and its own workflow -# rules refuse every stub. A sync PR opened there on -# 2026-10-12 was closed unmerged. -# software-factory-canary — throwaway repo for that project's platform trials. -# The audits (compliance, Scorecard, SonarCloud) do not read this list yet. -NOT_SERVED_REPOS=("software-factory" "software-factory-canary") +# Repos the standard-workflow sweep does not serve at all (NOT_SERVED_REPOS, +# is_not_served_repo) — distinct from SKIP_REPOS above, and shared with +# compliance-audit.sh so the audit files nothing where the sweep deploys nothing +# (#1334, #1343). +# shellcheck source=scripts/lib/not-served-repos.sh +source "$SCRIPT_DIR/lib/not-served-repos.sh" # Per-workflow opt-ins for otherwise-skipped repos. Keyed by workflow filename; # value is a space-separated list of SKIP_REPOS that should still receive it. @@ -294,17 +286,6 @@ is_skipped_repo() { return 1 } -# True if is in NOT_SERVED_REPOS (the sweep never touches it). -is_not_served_repo() { - local repo s - # GitHub repo names are case-insensitive; compare lowercased. - repo=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]') - for s in "${NOT_SERVED_REPOS[@]}"; do - [[ "$repo" == "$(printf '%s' "$s" | tr '[:upper:]' '[:lower:]')" ]] && return 0 - done - return 1 -} - # True if a normally-skipped repo has opted into this specific workflow via # SKIP_OVERRIDES — lets a self-managed repo receive one stub while staying # exempt from the rest. diff --git a/scripts/lib/not-served-repos.sh b/scripts/lib/not-served-repos.sh new file mode 100644 index 000000000..ae72969b4 --- /dev/null +++ b/scripts/lib/not-served-repos.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Repos the org standard does not serve at all — shared by +# deploy-standard-workflows.sh (the sweep never touches them, #1334) and +# compliance-audit.sh (the audit files no findings or issues there, #1343, +# #1352), so the two never disagree about which repos are in scope. +# +# This is a different thing from the deploy sweep's SKIP_REPOS. A SKIP_REPO is +# inside the standard and self-manages it, so every required workflow on it must +# be reconciled (SKIP_OVERRIDES or SKIP_SELF_MANAGED, see +# reconcile_skip_repo_required_workflows). A repo here is outside the standard by +# a recorded decision of the Maintainer: it receives no stub, takes no opt-in, is +# not part of that reconciliation, and is not audited. +# software-factory — where the replacement for this fleet is built. Its +# design keeps the two apart (no owner-account token, +# none of the fleet's workflows), and its own workflow +# rules refuse every stub. A sync PR opened there on +# 2026-10-12 was closed unmerged; its departures are +# recorded in its docs/decisions/0014. +# software-factory-canary — throwaway repo for that project's platform trials. +# The Scorecard and SonarCloud audits do not read this list yet. +NOT_SERVED_REPOS=("software-factory" "software-factory-canary") + +# True if is in NOT_SERVED_REPOS. +is_not_served_repo() { + local repo s + # GitHub repo names are case-insensitive; compare lowercased. + repo=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]') + for s in "${NOT_SERVED_REPOS[@]}"; do + [[ "$repo" == "$(printf '%s' "$s" | tr '[:upper:]' '[:lower:]')" ]] && return 0 + done + return 1 +} diff --git a/test/scripts/compliance-audit/not-served-repos.bats b/test/scripts/compliance-audit/not-served-repos.bats new file mode 100644 index 000000000..42272ad98 --- /dev/null +++ b/test/scripts/compliance-audit/not-served-repos.bats @@ -0,0 +1,83 @@ +#!/usr/bin/env bats +# The compliance audit skips NOT_SERVED_REPOS (scripts/lib/not-served-repos.sh). +# +# software-factory and software-factory-canary are outside the org standard by a +# recorded decision of the Maintainer. The deploy sweep already leaves them alone +# (#1334); the audit kept filing findings and issues there (#1343: 43 of 67 +# findings, #1352). main() must drop them from the org listing, so they are not +# audited and the issue-management loop never creates issues or labels there. + +bats_require_minimum_version 1.5.0 + +setup() { + REPO_ROOT="$(cd -- "${BATS_TEST_DIRNAME}/../../.." && pwd)" + SCRIPT="${REPO_ROOT}/scripts/compliance-audit.sh" + REPORT_DIR="$(mktemp -d "$BATS_TEST_TMPDIR/nsr.XXXXXX")" + export REPORT_DIR SCRIPT +} + +# _run_main — source the audit, stub every gh call and every +# per-repo check, feed main() an org listing with served and not-served repos, +# and echo which repos were audited and which reached issue management. +_run_main() { + APPLY_FLAG="$1" run bash -c ' + source "$SCRIPT" >/dev/null 2>&1 + gh() { + case "$1 $2" in + "auth status") return 0 ;; + "repo list") printf "%s\n" markets software-factory Software-Factory-Canary broodly ;; + *) return 0 ;; + esac + } + gh_api() { echo "{\"name\":\"x\"}"; } + for f in $(declare -F | awk "{print \$3}" | grep -E "^(check_|pp_run_all_checks$|detect_ecosystems$)"); do + eval "$f() { :; }" + done + detect_ecosystems() { ECOSYSTEMS=(); } + check_required_workflows() { echo "AUDITED $1"; } + ensure_audit_label() { echo "MANAGED $1"; } + ensure_required_labels() { :; } + create_issue_for_finding() { :; } + close_resolved_issues() { :; } + create_umbrella_issue() { :; } + append_issue_pr_links() { :; } + export GH_TOKEN=dummy + if [ "$APPLY_FLAG" = true ]; then main --apply; else main; fi + ' +} + +@test "main audits served repos and skips not-served ones" { + _run_main false + [[ "$output" == *"AUDITED markets"* ]] + [[ "$output" == *"AUDITED broodly"* ]] + [[ "$output" != *"AUDITED software-factory"* ]] + [[ "$output" != *"AUDITED Software-Factory-Canary"* ]] +} + +@test "the issue-management loop never reaches a not-served repo" { + _run_main true + [[ "$output" == *"MANAGED markets"* ]] + [[ "$output" != *"MANAGED software-factory"* ]] + [[ "$output" != *"MANAGED Software-Factory-Canary"* ]] +} + +@test "not-served repos are not counted in the audited-repos record" { + _run_main false + run cat "$REPORT_DIR/audited-repos.txt" + [[ "$output" == *"markets"* ]] + [[ "$output" != *"software-factory"* ]] + [[ "$output" != *"Software-Factory-Canary"* ]] +} + +# The shared list itself (scripts/lib/not-served-repos.sh). This file runs on any +# scripts/lib/** change (compliance-audit-tests.yml), so the lib is covered here. +@test "is_not_served_repo: software-factory and its canary, case-insensitively" { + run bash -c 'source "$1"; is_not_served_repo software-factory && is_not_served_repo SOFTWARE-FACTORY-CANARY' _ "${REPO_ROOT}/scripts/lib/not-served-repos.sh" + [ "$status" -eq 0 ] +} + +@test "is_not_served_repo: ordinary repos, .github and .github-private are served" { + run bash -c 'source "$1"; for r in markets .github .github-private software-factory-other ""; do is_not_served_repo "$r" && { echo "$r"; exit 1; }; done; exit 0' _ "${REPO_ROOT}/scripts/lib/not-served-repos.sh" + [ "$status" -eq 0 ] + [ -z "$output" ] +}