Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions scripts/propagate-hypatia-caller-id.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# propagate-hypatia-caller-id.sh — deliberate, audit-first standardisation of the
# Hypatia wrapper's caller job id across consumer repositories.
#
# WHY THIS EXISTS
# ---------------
# The check a reusable-caller job publishes is `<caller job id or name> / <inner
# job display name>`. The estate's canonical required context is
# `hypatia / Hypatia Neurosymbolic Analysis` (docs/audits/audit-hypatia-pin-orphan-2026-05-27.adoc),
# which requires the caller job to be named `hypatia`. In practice the caller is
# named `scan` in the large majority of consumer repositories, so they publish
# `scan / Hypatia Neurosymbolic Analysis` instead. Two names for one gate: any
# required context written against one of them is unsatisfiable in a repository
# that publishes the other — the defect class of hyperpolymath/tropical-types#17.
#
# This is the standards-side action that settles it: rename the caller job id to
# the canonical one, per repository, deliberately.
#
# Mode: READ-ONLY (audit) by default. Pass --fix to stage the rewrite in the
# consumer checkout. The script NEVER commits, NEVER pushes, and NEVER edits a
# required-status-check — that is the human's / bot's job (estate guardrail: no
# unattended mutations; mirrors scripts/propagate-workflow-pins.sh).
#
# Principles (do not violate):
# * Non-destructive: rewrites one job key, nothing else. The body of the job,
# its pin, its inputs and its secrets are untouched byte-for-byte.
# * Idempotent: a caller already at the canonical id is left untouched.
# * Requirement-aware: a rename silently breaks any repository whose rules name
# the old prefixed string. Those are reported BLOCKED and refused under --fix
# until the requirement is updated in the same change.
# * Honest about blindness: legacy branch protection cannot be read with an
# ordinary token. If requirements cannot be read, the verdict is UNVERIFIED
# and --fix refuses. Never rename on an unread requirement set.
# * Shell-only: no Python, no Ruby.
#
# Usage:
# bash scripts/propagate-hypatia-caller-id.sh [PATH]
# bash scripts/propagate-hypatia-caller-id.sh --fix [PATH]
# bash scripts/propagate-hypatia-caller-id.sh --caller-id <id> [PATH]
# bash scripts/propagate-hypatia-caller-id.sh --no-network [PATH]
#
# PATH may be a single consumer repo (has .github/workflows) or a parent
# directory of many repos. Defaults to the current directory.
#
# --caller-id <id> canonical caller job id (default: hypatia)
# --no-network never probe the API; requirements count as UNVERIFIED
# --fix rewrite the caller job id in place (no commit, no push)
#
# Environment seams (testing / CI):
# HYPATIA_REQUIRED_JSON file containing a JSON array of required context
# strings for the repositories under PATH. When set, it
# replaces the API probe entirely (hermetic).
# GITHUB_REPOSITORY used to probe one repository's rulesets when the path
# argument is a single repo and the API is reachable.
#
# Output: tab-separated audit lines
# <repo>\t<workflow-file>\t<caller-id>\t<verdict>
# verdict ∈ canonical | stage | BLOCKED | UNVERIFIED | unchanged-shape | absent
set -uo pipefail

CANONICAL="hypatia"
MODE_FIX=0
OFFLINE=0
TARGET="."

while [ $# -gt 0 ]; do

Check failure on line 69 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jV&open=AaDBATeCZDGRIvaeo1jV&pullRequest=877
case "$1" in
--fix) MODE_FIX=1; shift ;;
--no-network) OFFLINE=1; shift ;;
--caller-id) CANONICAL="${2:-}"; shift 2 ;;
-h|--help) sed -n '2,60p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
-*) printf 'unknown option: %s\n' "$1" >&2; exit 2 ;;
*) TARGET="$1"; shift ;;
esac
done

[ -n "$CANONICAL" ] || { echo "canonical caller id must not be empty" >&2; exit 2; }

Check failure on line 80 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jW&open=AaDBATeCZDGRIvaeo1jW&pullRequest=877

say() { printf '%s\n' "$*"; }

Check warning on line 82 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jX&open=AaDBATeCZDGRIvaeo1jX&pullRequest=877
note() { printf '::notice::%s\n' "$*" >&2; }

Check warning on line 83 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jY&open=AaDBATeCZDGRIvaeo1jY&pullRequest=877

# ---- requirement discovery -------------------------------------------------
# The rename is only safe when nothing requires the old prefixed string.
# Returns "read" / "unreadable" and prints one required context per line.
requirements() {
if [ -n "${HYPATIA_REQUIRED_JSON:-}" ]; then

Check failure on line 89 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jZ&open=AaDBATeCZDGRIvaeo1jZ&pullRequest=877
[ -f "$HYPATIA_REQUIRED_JSON" ] || { note "HYPATIA_REQUIRED_JSON not found"; echo unreadable; return 0; }

Check failure on line 90 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1ja&open=AaDBATeCZDGRIvaeo1ja&pullRequest=877
if ! command -v jq >/dev/null 2>&1; then echo unreadable; return 0; fi
jq -r '.[]' "$HYPATIA_REQUIRED_JSON" 2>/dev/null || { echo unreadable; return 0; }
echo "__read__"
return 0
fi
[ "$OFFLINE" = 1 ] && { echo unreadable; return 0; }

Check failure on line 96 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jb&open=AaDBATeCZDGRIvaeo1jb&pullRequest=877
command -v gh >/dev/null 2>&1 || { echo unreadable; return 0; }
command -v jq >/dev/null 2>&1 || { echo unreadable; return 0; }
[ -n "${GITHUB_REPOSITORY:-}" ] || { echo unreadable; return 0; }

Check failure on line 99 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jc&open=AaDBATeCZDGRIvaeo1jc&pullRequest=877
local list body
list="$(gh api "repos/$GITHUB_REPOSITORY/rulesets" 2>/dev/null || true)"
printf '%s' "$list" | jq -e 'type == "array"' >/dev/null 2>&1 || { echo unreadable; return 0; }
for id in $(printf '%s' "$list" | jq -r '.[]? | select(.target=="branch") | .id'); do
body="$(gh api "repos/$GITHUB_REPOSITORY/rulesets/$id" 2>/dev/null || true)"
printf '%s' "$body" | jq -r '
if type == "object" and .enforcement != "disabled" then
.rules[]? | select(.type=="required_status_checks") | .parameters.required_status_checks[]?
| (.context|tostring)
else empty end' 2>/dev/null
done
echo "__read__"
}

# Read the requirement set once for the whole run: a parent directory of repos
# cannot be probed per-repo with a single GITHUB_REPOSITORY, so the seam is
# per-run by design and the API path is documented as single-repo only.
REQ_RAW="$(requirements)"
REQ_READABLE=0
REQ_LIST=""
if printf '%s\n' "$REQ_RAW" | grep -qx '__read__'; then
REQ_READABLE=1
REQ_LIST="$(printf '%s\n' "$REQ_RAW" | grep -vx '__read__')"

Check warning on line 122 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal '__read__' 4 times.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jq&open=AaDBATeCZDGRIvaeo1jq&pullRequest=877
fi

requires_old_name() { # $1 = old caller id
[ "$REQ_READABLE" = 1 ] || return 2 # 2 = unknown

Check failure on line 126 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jd&open=AaDBATeCZDGRIvaeo1jd&pullRequest=877
printf '%s\n' "$REQ_LIST" | grep -Fxq "$1 / Hypatia Neurosymbolic Analysis"

Check warning on line 127 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1je&open=AaDBATeCZDGRIvaeo1je&pullRequest=877
}

process_repo() { # $1 = repository directory
local repo="$1" wf caller verdict
repo="$(cd "$repo" && pwd)"
wf="$repo/.github/workflows/hypatia-scan.yml"
if [ ! -f "$wf" ]; then

Check failure on line 134 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jf&open=AaDBATeCZDGRIvaeo1jf&pullRequest=877
printf '%s\t%s\t-\tabsent\n' "$(basename "$repo")" ".github/workflows/hypatia-scan.yml"
return 0
fi

# The caller job is the one whose `uses:` names the estate's scan reusable.
caller="$(awk '
/^[[:space:]]*[A-Za-z0-9_.-]+:[[:space:]]*$/ { key=$1; sub(/:$/, "", key) }
/^[[:space:]]+uses:.*hypatia-scan-reusable\.ya?ml@/ { print key; exit }
' "$wf")"

if [ -z "$caller" ]; then

Check failure on line 145 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jg&open=AaDBATeCZDGRIvaeo1jg&pullRequest=877
printf '%s\t%s\t-\tunchanged-shape\n' "$(basename "$repo")" ".github/workflows/hypatia-scan.yml"
return 0
fi
if [ "$caller" = "$CANONICAL" ]; then

Check failure on line 149 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jh&open=AaDBATeCZDGRIvaeo1jh&pullRequest=877
printf '%s\t%s\t%s\tcanonical\n' "$(basename "$repo")" ".github/workflows/hypatia-scan.yml" "$caller"
return 0
fi

# A rename changes the published check name. Refuse when a rule names the old one.
if requires_old_name "$caller"; then
verdict="BLOCKED"
elif [ "$REQ_READABLE" = 1 ]; then

Check failure on line 157 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1ji&open=AaDBATeCZDGRIvaeo1ji&pullRequest=877
verdict="stage"
else
verdict="UNVERIFIED"
fi

if [ "$verdict" = "stage" ] && [ "$MODE_FIX" = 1 ]; then

Check failure on line 163 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jk&open=AaDBATeCZDGRIvaeo1jk&pullRequest=877

Check failure on line 163 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jj&open=AaDBATeCZDGRIvaeo1jj&pullRequest=877
# Rewrite only the job key line: same indentation, same position.
local tmp; tmp="$(mktemp)"
awk -v from="$caller" -v to="$CANONICAL" '
BEGIN { done = 0 }
!done && $0 ~ "^[[:space:]]*" from ":[[:space:]]*$" { sub(from ":", to ":"); done = 1 }
{ print }
' "$wf" > "$tmp" && mv "$tmp" "$wf"
verdict="staged"
fi

printf '%s\t%s\t%s\t%s\n' "$(basename "$repo")" ".github/workflows/hypatia-scan.yml" "$caller" "$verdict"

Check warning on line 174 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal '.github/workflows/hypatia-scan.yml' 4 times.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jr&open=AaDBATeCZDGRIvaeo1jr&pullRequest=877
return 0
}

if [ -f "$TARGET/.github/workflows/hypatia-scan.yml" ]; then

Check failure on line 178 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jl&open=AaDBATeCZDGRIvaeo1jl&pullRequest=877
process_repo "$TARGET"
else
found=0
for d in "$TARGET"/*/; do
[ -d "$d/.github/workflows" ] || continue

Check failure on line 183 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jm&open=AaDBATeCZDGRIvaeo1jm&pullRequest=877
process_repo "$d"
found=1
done
[ "$found" = 1 ] || { note "no consumer repositories found under $TARGET"; exit 1; }

Check failure on line 187 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jn&open=AaDBATeCZDGRIvaeo1jn&pullRequest=877
fi

if [ "$REQ_READABLE" != 1 ]; then

Check failure on line 190 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jo&open=AaDBATeCZDGRIvaeo1jo&pullRequest=877
note "requirements unreadable (no API access, offline, or a multi-repo path): every differing caller id is UNVERIFIED, and --fix refuses. Read the requirements first — a rename is only safe when nothing requires the old name."
fi
if [ "$MODE_FIX" = 1 ]; then

Check failure on line 193 in scripts/propagate-hypatia-caller-id.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATeCZDGRIvaeo1jp&open=AaDBATeCZDGRIvaeo1jp&pullRequest=877
note "--fix only stages edits. Commit, push and open the PR yourself or via the fleet bot (estate guardrail: no unattended mutations)."
fi
exit 0
115 changes: 115 additions & 0 deletions scripts/tests/propagate-hypatia-caller-id-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# propagate-hypatia-caller-id-test.sh — fixture suite for
# scripts/propagate-hypatia-caller-id.sh.
#
# Builds synthetic consumer repositories in a temp directory and drives the
# audit / --fix / refused paths. No network, no gh, no token: the requirement
# probe is supplied through the HYPATIA_REQUIRED_JSON seam.
#
# Branches driven:
# * caller already canonical -> canonical, --fix is a no-op
# * caller `scan`, nothing requires the old name -> stage, --fix rewrites the
# job key and NOTHING else in the file
# * caller `scan`, a rule requires `scan / …` -> BLOCKED, --fix refuses and the
# file is byte-identical afterwards
# * workflow with no reusable call -> unchanged-shape
# * repository without the wrapper -> absent
# * requirements unreadable (offline) -> UNVERIFIED, --fix refuses
#
# Run: bash scripts/tests/propagate-hypatia-caller-id-test.sh
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$SCRIPT_DIR/../propagate-hypatia-caller-id.sh"
[ -f "$SCRIPT" ] || { echo "FAIL: script not found at $SCRIPT"; exit 1; }

Check failure on line 26 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jL&open=AaDBATb_ZDGRIvaeo1jL&pullRequest=877

fail=0
check() { # name expected actual

Check warning on line 29 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jP&open=AaDBATb_ZDGRIvaeo1jP&pullRequest=877
if [ "$2" = "$3" ]; then printf 'PASS %s\n' "$1"; else printf 'FAIL %s\n expected: %s\n actual: %s\n' "$1" "$2" "$3"; fail=$((fail+1)); fi

Check failure on line 30 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jM&open=AaDBATb_ZDGRIvaeo1jM&pullRequest=877

Check warning on line 30 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jO&open=AaDBATb_ZDGRIvaeo1jO&pullRequest=877

Check warning on line 30 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jN&open=AaDBATb_ZDGRIvaeo1jN&pullRequest=877
}

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
mkdir -p "$work/fleet"

wrapper() { # $1 dir, $2 caller id

Check warning on line 37 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jS&open=AaDBATb_ZDGRIvaeo1jS&pullRequest=877
mkdir -p "$1/.github/workflows"

Check warning on line 38 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jQ&open=AaDBATb_ZDGRIvaeo1jQ&pullRequest=877
cat > "$1/.github/workflows/hypatia-scan.yml" <<EOF

Check warning on line 39 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jR&open=AaDBATb_ZDGRIvaeo1jR&pullRequest=877
# fixture wrapper
name: Hypatia Scan
on:
push:
pull_request:

jobs:
$2:
name: Hypatia Neurosymbolic Analysis
uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@84355587cb2a1f86e6882de83514a32db2646e7a
secrets: inherit
EOF
}

wrapper "$work/fleet/aaa-canonical" hypatia
wrapper "$work/fleet/bbb-needs-rename" scan
wrapper "$work/fleet/ccc-blocked" scan
wrapper "$work/fleet/ddd-absent" scan && rm "$work/fleet/ddd-absent/.github/workflows/hypatia-scan.yml"

mkdir -p "$work/fleet/eee-inline/.github/workflows"
cat > "$work/fleet/eee-inline/.github/workflows/hypatia-scan.yml" <<'EOF'
name: Hypatia Scan
on: [push]
jobs:
scan:
name: Hypatia Neurosymbolic Analysis
runs-on: ubuntu-latest
steps:
- run: echo inline
EOF

# Nothing requires the old prefixed name anywhere in the safe fixture.
printf '["hypatia / Hypatia Neurosymbolic Analysis","CodeRabbit"]' > "$work/safe.json"
# One rule requires it -> the rename must be refused for that repository.
printf '["scan / Hypatia Neurosymbolic Analysis"]' > "$work/blocking.json"

out="$(HYPATIA_REQUIRED_JSON="$work/safe.json" bash "$SCRIPT" "$work/fleet" 2>/dev/null)"
check "canonical-caller-is-reported-canonical" "canonical" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="aaa-canonical"{print $4}')"
check "differing-caller-is-stage" "stage" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="bbb-needs-rename"{print $4}')"
check "no-wrapper-is-absent" "absent" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="ddd-absent"{print $4}')"
check "non-reusable-is-unchanged-shape" "unchanged-shape" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="eee-inline"{print $4}')"

out="$(HYPATIA_REQUIRED_JSON="$work/blocking.json" bash "$SCRIPT" "$work/fleet" 2>/dev/null)"
check "required-old-name-blocks-the-rename" "BLOCKED" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="ccc-blocked"{print $4}')"

# --fix must refuse the blocked repo and stage the safe one.
before_blocked="$(cat "$work/fleet/ccc-blocked/.github/workflows/hypatia-scan.yml")"
HYPATIA_REQUIRED_JSON="$work/blocking.json" bash "$SCRIPT" --fix "$work/fleet" >/dev/null 2>&1
after_blocked="$(cat "$work/fleet/ccc-blocked/.github/workflows/hypatia-scan.yml")"
check "fix-leaves-blocked-file-untouched" "$before_blocked" "$after_blocked"
check "fix-refuses-blocked-repo" "scan" "$(awk '/^[[:space:]]*[A-Za-z0-9_.-]+:[[:space:]]*$/{k=$1; sub(/:$/,"",k)} /uses:.*hypatia-scan-reusable/{print k; exit}' "$work/fleet/ccc-blocked/.github/workflows/hypatia-scan.yml")"

before_safe="$(cat "$work/fleet/bbb-needs-rename/.github/workflows/hypatia-scan.yml")"
out="$(HYPATIA_REQUIRED_JSON="$work/safe.json" bash "$SCRIPT" --fix "$work/fleet" 2>/dev/null)"
check "fix-reports-staged" "staged" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="bbb-needs-rename"{print $4}')"
after_safe="$(cat "$work/fleet/bbb-needs-rename/.github/workflows/hypatia-scan.yml")"
check "fix-renames-the-caller-key" "hypatia" "$(awk '/^[[:space:]]*[A-Za-z0-9_.-]+:[[:space:]]*$/{k=$1; sub(/:$/,"",k)} /uses:.*hypatia-scan-reusable/{print k; exit}' "$work/fleet/bbb-needs-rename/.github/workflows/hypatia-scan.yml")"
# Only the key line may differ: the pin, the secrets line and the comments stay.
check "fix-touches-only-the-job-key" "2" "$(diff <(printf '%s\n' "$before_safe") <(printf '%s\n' "$after_safe") | grep -c '^[<>]')"
check "fix-keeps-the-pin" "1" "$(printf '%s\n' "$after_safe" | grep -c '84355587cb2a1f86e6882de83514a32db2646e7a')"
check "fix-keeps-secrets-inherit" "1" "$(printf '%s\n' "$after_safe" | grep -c '^[[:space:]]*secrets: inherit$')"
check "fix-is-idempotent" "canonical" "$(HYPATIA_REQUIRED_JSON="$work/safe.json" bash "$SCRIPT" "$work/fleet" 2>/dev/null | awk -F'\t' '$1=="bbb-needs-rename"{print $4}')"

# Unreadable requirements: never rename on an unknown requirement set.
wrapper "$work/fleet/fff-unverified" scan
out="$(bash "$SCRIPT" --no-network "$work/fleet" 2>/dev/null)"
check "unreadable-requirements-are-unverified" "UNVERIFIED" "$(printf '%s\n' "$out" | awk -F'\t' '$1=="fff-unverified"{print $4}')"
before="$(cat "$work/fleet/fff-unverified/.github/workflows/hypatia-scan.yml")"
bash "$SCRIPT" --no-network --fix "$work/fleet" >/dev/null 2>&1
check "fix-refuses-when-requirements-unreadable" "$before" "$(cat "$work/fleet/fff-unverified/.github/workflows/hypatia-scan.yml")"

if [ "$fail" -gt 0 ]; then

Check failure on line 111 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jT&open=AaDBATb_ZDGRIvaeo1jT&pullRequest=877
echo "::error file=$SCRIPT::$fail fixture(s) failed"

Check warning on line 112 in scripts/tests/propagate-hypatia-caller-id-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaDBATb_ZDGRIvaeo1jU&open=AaDBATb_ZDGRIvaeo1jU&pullRequest=877
exit 1
fi
echo "PASS $0"
Loading