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
18 changes: 18 additions & 0 deletions docs/audits/audit-ci-context-producibility-2026-09-20.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,21 @@ Hypatia verdict grid / Hypatia Neurosymbolic Analysis # published on every pul

The deep scan keeps running weekly on `main`; it simply stops being *required*,
which it was never able to be.

That edit is scripted, because it is not a command anyone should type by hand
against live branch protection:

[source,bash]
----
scripts/fix-required-context-name.sh # report the one-line diff; writes nothing
scripts/fix-required-context-name.sh --apply # needs administration:write
----

It refuses when the ruleset is not `active`, when both names are present, when
neither is, when the name occurs more than once, and when the payload would
change the rule or context count — and after writing it verifies the read-back
rather than trusting what it sent. `scripts/apply-branch-gates.sh` deliberately
does not do this: it derives contexts from checks that run and then has to pick
a ruleset, and with six additive branch rulesets it cannot justify a choice, so
it reports `AMBIGUOUS` and declines. A scripted single-field edit is the safe
instrument; a general-purpose rewriter is not.
177 changes: 177 additions & 0 deletions scripts/fix-required-context-name.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
#
# fix-required-context-name.sh — repoint ONE required status check at the call
# site that actually publishes it on a pull request.
#
# WHY THIS EXISTS
# ---------------
# A required status check is matched by NAME. For a job that calls a reusable
# workflow, that name is `<caller job name> / <callee job name>`. Two workflows
# that run the same reusable therefore publish two different contexts, and a
# ruleset can require the one that only runs after merge.
#
# That is this repository's position today:
#
# scan / Hypatia Neurosymbolic Analysis hypatia-scan.yml
# ↑ named by ruleset 23787415 push/schedule only
# Hypatia verdict grid / Hypatia Neurosymbolic Analysis fork-governance.yml
# ↑ published on every pull_request same scanner
#
# The result is not a red pull request, it is an UNDECIDABLE one: #1336 reached
# 65 passing checks, a cleared reviewDecision and mergeable=MERGEABLE while
# mergeStateStatus stayed BLOCKED, because the required check can never appear.
# No rebase, re-run, or code change can satisfy it — the only route to `main`
# is the ruleset's `always` bypass, which discards the other nineteen required
# checks in the same action.
#
# `scripts/apply-branch-gates.sh` cannot fix this: it derives contexts from
# checks that actually run and then has to choose a ruleset, and it refuses
# because six active branch rulesets are additive and none is uniquely
# checks-only (correct — guessing which one to rewrite is how protection gets
# silently dropped). This script instead touches exactly one named context in
# exactly one named ruleset, and refuses if the before-state is not what it
# expects.
#
# NOT a rename to make a gate pass. The two names are the same scanner; the
# required one simply names a call site that cannot run while the pull request
# is open. The deep scan keeps its weekly `main` run.
#
# Requires `administration: write`. Installation tokens report repo admin=true
# and still get 403 here; run it with an admin-scoped user token.
#
# Usage:
# scripts/fix-required-context-name.sh # report what would change
# scripts/fix-required-context-name.sh --apply # write it
# REPO=owner/name RULESET=123 scripts/fix-required-context-name.sh

set -uo pipefail

REPO="${REPO:-hyperpolymath/standards}"
RULESET="${RULESET:-23787415}"
OLD_CONTEXT="${OLD_CONTEXT:-scan / Hypatia Neurosymbolic Analysis}"
NEW_CONTEXT="${NEW_CONTEXT:-Hypatia verdict grid / Hypatia Neurosymbolic Analysis}"

# The binary is injectable so scripts/tests/fix-required-context-name-test.sh
# can drive every refusal branch offline. Nothing else about the call changes.
GH="${GH:-gh}"

APPLY=0
case "${1:-}" in
--apply) APPLY=1 ;;
-h|--help) sed -n '2,45p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
"") ;;
*) echo "unknown argument: $1 (try --help)" >&2; exit 2 ;;
esac

command -v "$GH" >/dev/null || { echo "'$GH' is required" >&2; exit 2; }
command -v jq >/dev/null || { echo "jq is required" >&2; exit 2; }

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

echo "== $REPO ruleset $RULESET"

if ! "$GH" api "repos/$REPO/rulesets/$RULESET" >"$tmp/before.json" 2>"$tmp/err"; then
echo "FATAL: cannot read the ruleset: $(head -1 "$tmp/err")" >&2
echo " (needs read access to the repository rules; a 403 here means the" >&2
echo " token cannot see protection at all, not that nothing is required)" >&2
exit 1
fi

enforcement="$(jq -r '.enforcement' "$tmp/before.json")"
n_rules="$(jq -r '.rules | length' "$tmp/before.json")"
n_ctx="$(jq -r '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]?] | length' "$tmp/before.json")"
has_old="$(jq -r --arg c "$OLD_CONTEXT" '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]? | select(.context==$c)] | length' "$tmp/before.json")"
has_new="$(jq -r --arg c "$NEW_CONTEXT" '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]? | select(.context==$c)] | length' "$tmp/before.json")"

printf ' name %s\n' "$(jq -r '.name' "$tmp/before.json")"
printf ' enforcement %s\n' "$enforcement"
printf ' rules %s (%s required context(s))\n' "$n_rules" "$n_ctx"

if [ "$enforcement" != "active" ]; then

Check failure on line 93 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW2&open=AaFvz9kFMR3EMC2WMvW2&pullRequest=1337
echo "FATAL: ruleset is '$enforcement', not 'active' — editing it would change" >&2
echo " nothing while looking like it did." >&2
exit 1
fi

# Refuse rather than guess. Each of these means the world moved and a scripted
# single-field edit is no longer the right instrument.
if [ "$has_new" -gt 0 ] && [ "$has_old" -eq 0 ]; then

Check failure on line 101 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW4&open=AaFvz9kFMR3EMC2WMvW4&pullRequest=1337

Check failure on line 101 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW3&open=AaFvz9kFMR3EMC2WMvW3&pullRequest=1337
echo "OK: already repaired — '$NEW_CONTEXT' is required, '$OLD_CONTEXT' is not."
exit 0
fi
if [ "$has_old" -eq 0 ]; then

Check failure on line 105 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW5&open=AaFvz9kFMR3EMC2WMvW5&pullRequest=1337
echo "FATAL: '$OLD_CONTEXT' is not a required context in this ruleset." >&2
echo " Nothing to repoint; refusing to invent a change." >&2
exit 1
fi
if [ "$has_new" -gt 0 ]; then

Check failure on line 110 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW6&open=AaFvz9kFMR3EMC2WMvW6&pullRequest=1337
echo "FATAL: both names are required. Remove '$OLD_CONTEXT' by hand:" >&2
echo " one of them can never be produced on a pull request." >&2
exit 1
fi
if [ "$has_old" -gt 1 ]; then

Check failure on line 115 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW7&open=AaFvz9kFMR3EMC2WMvW7&pullRequest=1337
echo "FATAL: '$OLD_CONTEXT' appears $has_old times; this script replaces one." >&2
exit 1
fi

jq --arg old "$OLD_CONTEXT" --arg new "$NEW_CONTEXT" '{
name, target, enforcement, bypass_actors, conditions,
rules: [.rules[] | if .type=="required_status_checks" then
{type, parameters: (.parameters | .required_status_checks |=
map(if .context==$old then .context=$new else . end))}
else {type, parameters} end]
}' "$tmp/before.json" >"$tmp/after.json"

# The whole safety property: exactly one string changed, the rule count and the
# context count are identical, and nothing else in the ruleset moved.
n_after="$(jq -r '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]?] | length' "$tmp/after.json")"
n_rules_after="$(jq -r '.rules | length' "$tmp/after.json")"
if [ "$n_after" != "$n_ctx" ] || [ "$n_rules_after" != "$n_rules" ]; then

Check failure on line 132 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW9&open=AaFvz9kFMR3EMC2WMvW9&pullRequest=1337

Check failure on line 132 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW8&open=AaFvz9kFMR3EMC2WMvW8&pullRequest=1337
echo "FATAL: payload changed the shape of the ruleset ($n_rules→$n_rules_after rules," >&2
echo " $n_ctx→$n_after contexts). Refusing to send." >&2
exit 1
fi

echo
echo "== context diff (whole ruleset; anything else changing is a bug)"
diff <(jq -r '.rules[]|select(.type=="required_status_checks")|.parameters.required_status_checks[].context' "$tmp/before.json") \
<(jq -r '.rules[]|select(.type=="required_status_checks")|.parameters.required_status_checks[].context' "$tmp/after.json") \
|| true

if [ "$APPLY" -eq 0 ]; then

Check failure on line 144 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW-&open=AaFvz9kFMR3EMC2WMvW-&pullRequest=1337
echo
echo "REPORT-ONLY. Re-run with --apply to write this to $REPO."
exit 0
fi

echo
echo "== applying"
if ! "$GH" api -X PUT "repos/$REPO/rulesets/$RULESET" --input "$tmp/after.json" >"$tmp/resp.json" 2>"$tmp/err"; then
echo "FATAL: the API refused the write:" >&2
sed 's/^/ /' "$tmp/err" >&2
echo " 'Resource not accessible by integration' means the token is an" >&2
echo " installation token: it may report admin=true and still lack" >&2
echo " administration:write. Use an admin user token." >&2
exit 1
fi

# Verify against the server, not against the payload we sent.
"$GH" api "repos/$REPO/rulesets/$RULESET" >"$tmp/verify.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail closed when the verification request fails

If the read-back request fails after a successful PUT, such as during a network interruption, the script still reports success and exits zero without verifying the protection settings. With set -uo pipefail but no explicit status check here, an empty response leaves all three verification variables empty; the subsequent numeric comparisons produce integer expression expected errors and fall through to the OK message. This is reproducible with the injectable $GH returning exit 1 and no stdout on the final GET. Explicitly reject a failed request and an invalid or empty verification response before comparing the counts.

Useful? React with 👍 / 👎.

v_new="$(jq -r --arg c "$NEW_CONTEXT" '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]? | select(.context==$c)] | length' "$tmp/verify.json")"
v_old="$(jq -r --arg c "$OLD_CONTEXT" '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]? | select(.context==$c)] | length' "$tmp/verify.json")"

Check warning on line 164 in scripts/fix-required-context-name.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal '[.rules[] | select(.type==\"required_status_checks\") | .parameters.required_sta…' 4 times.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFvz9kFMR3EMC2WMvXC&open=AaFvz9kFMR3EMC2WMvXC&pullRequest=1337
v_cnt="$(jq -r '[.rules[] | select(.type=="required_status_checks") | .parameters.required_status_checks[]?] | length' "$tmp/verify.json")"

if [ "$v_new" -ne 1 ] || [ "$v_old" -ne 0 ] || [ "$v_cnt" -ne "$n_ctx" ]; then

Check failure on line 167 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvW_&open=AaFvz9kFMR3EMC2WMvW_&pullRequest=1337

Check failure on line 167 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvXA&open=AaFvz9kFMR3EMC2WMvXA&pullRequest=1337

Check failure on line 167 in scripts/fix-required-context-name.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=AaFvz9kFMR3EMC2WMvXB&open=AaFvz9kFMR3EMC2WMvXB&pullRequest=1337
echo "FATAL: read-back does not match what was intended." >&2
echo " new=$v_new old=$v_old contexts=$v_cnt (expected 1/0/$n_ctx)" >&2
exit 1
fi

echo "OK: $NEW_CONTEXT is now required ($v_cnt contexts, unchanged);"
echo " $OLD_CONTEXT is no longer required."
echo
echo "Next: the blocked pull request should become decidable on the next rule"
echo "evaluation. Re-check with: gh pr view <n> --json mergeStateStatus"
158 changes: 158 additions & 0 deletions scripts/tests/fix-required-context-name-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
#
# Offline tests for scripts/fix-required-context-name.sh.
#
# The script edits branch protection, so the branches that matter are the
# refusals: every one of them exists to stop a well-meaning run from dropping
# nineteen required checks while appearing to fix one. A fake `gh` on PATH
# (via $GH) serves fixtures and records whether a write was attempted, so no
# test touches a real ruleset.

set -uo pipefail

here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
script="$here/../fix-required-context-name.sh"
pass=0; fail=0

work="$(mktemp -d)"; trap 'rm -rf "$work"' EXIT

ctx() { jq -c '.' ; }

Check warning on line 21 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWm&open=AaFvz9asMR3EMC2WMvWm&pullRequest=1337

# A faithful slice of ruleset 23787415: one checks rule, 20 contexts, five rules.
base() {

Check warning on line 24 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWq&open=AaFvz9asMR3EMC2WMvWq&pullRequest=1337
jq -n --arg old "$1" --arg new "$2" --argjson both "$3" '$ctxs |

Check warning on line 25 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWn&open=AaFvz9asMR3EMC2WMvWn&pullRequest=1337

Check warning on line 25 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWp&open=AaFvz9asMR3EMC2WMvWp&pullRequest=1337

Check warning on line 25 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWo&open=AaFvz9asMR3EMC2WMvWo&pullRequest=1337
[$ctxs[] | {context: ., integration_id: 15368}] as $list' 2>/dev/null
}

mk_ruleset() { # $1=old context present (1/0) $2=new context present (1/0)

Check warning on line 29 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWt&open=AaFvz9asMR3EMC2WMvWt&pullRequest=1337
# Pure jq: inline Python is banned in this repository
# (scripts/tests/check-inline-python-test.sh), and a fixture generator is not
# a good enough reason to open the door.
jq -n --argjson o "$1" --argjson n "$2" '

Check warning on line 33 in scripts/tests/fix-required-context-name-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=AaFv09INZptvl_vNRvDq&open=AaFv09INZptvl_vNRvDq&pullRequest=1337

Check warning on line 33 in scripts/tests/fix-required-context-name-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=AaFv09INZptvl_vNRvDr&open=AaFv09INZptvl_vNRvDr&pullRequest=1337
(["CodeQL", "SPARK Theatre Gate"]
+ [range(0;17) | "governance / filler \(.)"]
+ (if $o == 1 then ["scan / Hypatia Neurosymbolic Analysis"] else [] end)
+ (if $n == 1 then ["Hypatia verdict grid / Hypatia Neurosymbolic Analysis"] else [] end)) as $ctx
| {name: "main gate: append-only + required checks + signatures + scanning",
target: "branch", enforcement: "active",
bypass_actors: [{actor_id: 5, actor_type: "RepositoryRole", bypass_mode: "always"}],
conditions: {ref_name: {exclude: [], include: ["~DEFAULT_BRANCH"]}},
rules: [
{type: "deletion"},
{type: "non_fast_forward"},
{type: "required_status_checks", parameters: {
strict_required_status_checks_policy: false,
do_not_enforce_on_create: false,
required_status_checks: [$ctx[] | {context: ., integration_id: 15368}]}},
{type: "pull_request", parameters: {required_approving_review_count: 0}},
{type: "required_signatures"}
]}'
}

# Fake `gh`: `api repos/R/rulesets/N` serves $FIXTURE, unless a write has
# happened, in which case it serves $WRITTEN. `api -X PUT ... --input FILE`
# records the payload and flips the switch. $REFUSE=1 makes the write 403.
install_gh() {

Check warning on line 57 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWu&open=AaFvz9asMR3EMC2WMvWu&pullRequest=1337
cat >"$work/gh" <<'SH'
#!/usr/bin/env bash
set -uo pipefail
method=GET
args=()
while [ $# -gt 0 ]; do
case "$1" in
-X) method="$2"; shift 2 ;;
--input) payload="$2"; shift 2 ;;
*) args+=("$1"); shift ;;
esac
done
if [ "$method" = PUT ]; then
cp "${payload:?}" "$PUT_CAPTURE"
if [ "${REFUSE:-0}" = 1 ]; then
echo '{"message":"Resource not accessible by integration","status":"403"}' >&2
exit 1
fi
cp "$PUT_CAPTURE" "$WRITTEN"
fi
if [ -s "${WRITTEN:-/dev/null}" ]; then cat "$WRITTEN"; else cat "$FIXTURE"; fi
SH
chmod +x "$work/gh"
}

# Sets $out and $rc in the CALLER. Deliberately not `out="$(run ...)"`: a
# command substitution runs in a subshell, so the exit status captured inside
# would never reach the assertion.
out=""; rc=0
run() { # fixture-file [arg]

Check warning on line 87 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWv&open=AaFvz9asMR3EMC2WMvWv&pullRequest=1337
: >"$work/written"
FIXTURE="$1" WRITTEN="$work/written" PUT_CAPTURE="$work/payload.json" \
REFUSE="${REFUSE:-0}" GH="$work/gh" \
bash "$script" "${2:-}" >"$work/out" 2>&1
rc=$?
out="$(cat "$work/out")"
}

check() { local label="$1" want="$2" got="$3"

Check warning on line 96 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWx&open=AaFvz9asMR3EMC2WMvWx&pullRequest=1337
if [ "$got" = "$want" ]; then pass=$((pass+1)); echo "PASS $label"

Check failure on line 97 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWw&open=AaFvz9asMR3EMC2WMvWw&pullRequest=1337
else fail=$((fail+1)); echo "FAIL $label — want exit $want, got $got"; fi; }

check_says() { local label="$1" want="$2" out="$3"

Check warning on line 100 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWy&open=AaFvz9asMR3EMC2WMvWy&pullRequest=1337
if printf '%s' "$out" | grep -qF "$want"; then pass=$((pass+1)); echo "PASS $label"
else fail=$((fail+1)); echo "FAIL $label — output lacks: $want"; printf '%s\n' "$out" | tail -3; fi; }

install_gh

# 1. report-only shows the single-line diff and writes nothing
mk_ruleset 1 0 >"$work/old-only.json"
run "$work/old-only.json"; check "report-only exits 0" 0 "$rc"
check_says "report-only names the target context" "Hypatia verdict grid / Hypatia Neurosymbolic Analysis" "$out"
check_says "report-only says it did not write" "REPORT-ONLY" "$out"
if [ -s "$work/written" ]; then fail=$((fail+1)); echo "FAIL report-only wrote to the ruleset"

Check failure on line 111 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvWz&open=AaFvz9asMR3EMC2WMvWz&pullRequest=1337
else pass=$((pass+1)); echo "PASS report-only wrote nothing"; fi

# 2. --apply writes, and the read-back is what is verified
run "$work/old-only.json" --apply; check "apply exits 0" 0 "$rc"
check_says "apply confirms the new context" "is now required" "$out"
n_written=$(jq -r '[.rules[]|select(.type=="required_status_checks")|.parameters.required_status_checks[]?]|length' "$work/written" 2>/dev/null)
check "apply preserves the context count (20)" 20 "$n_written"
n_old=$(jq -r '[.rules[]|select(.type=="required_status_checks")|.parameters.required_status_checks[]?|select(.context=="scan / Hypatia Neurosymbolic Analysis")]|length' "$work/written" 2>/dev/null)
check "apply removed the dead context" 0 "$n_old"
n_rules=$(jq -r '.rules|length' "$work/written" 2>/dev/null)
check "apply preserves the rule count (5)" 5 "$n_rules"
n_bypass=$(jq -r '.bypass_actors|length' "$work/written" 2>/dev/null)
check "apply preserves the bypass actors" 1 "$n_bypass"

# 3. already repaired: no-op success, and no write
mk_ruleset 0 1 >"$work/new-only.json"
run "$work/new-only.json" --apply; check "already-repaired exits 0" 0 "$rc"
check_says "already-repaired says so" "already repaired" "$out"
if [ -s "$work/written" ]; then fail=$((fail+1)); echo "FAIL already-repaired still wrote"

Check failure on line 130 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvW0&open=AaFvz9asMR3EMC2WMvW0&pullRequest=1337
else pass=$((pass+1)); echo "PASS already-repaired wrote nothing"; fi

# 4. neither name present: refuse rather than invent a change
mk_ruleset 0 0 >"$work/neither.json"
run "$work/neither.json" --apply; check "neither-present exits 1" 1 "$rc"
check_says "neither-present refuses to invent" "refusing to invent" "$out"

# 5. both present: refuse, this needs a human
mk_ruleset 1 1 >"$work/both.json"
run "$work/both.json" --apply; check "both-present exits 1" 1 "$rc"
check_says "both-present asks for a manual decision" "Remove" "$out"

# 6. inactive ruleset: editing it would change nothing while looking like it did
mk_ruleset 1 0 | jq '.enforcement="evaluate"' >"$work/inactive.json"
run "$work/inactive.json" --apply; check "inactive exits 1" 1 "$rc"
check_says "inactive is refused" "not 'active'" "$out"

# 7. the API refuses the write (installation token): say what it means
REFUSE=1; run "$work/old-only.json" --apply; check "403 exits 1" 1 "$rc"
REFUSE=0
check_says "403 explains the installation-token trap" "installation token" "$out"

# 8. unknown argument is not silently ignored
run "$work/old-only.json" --force; check "unknown arg exits 2" 2 "$rc"

echo
echo "self-test: $pass passed, $fail failed"
[ "$fail" -eq 0 ]

Check failure on line 158 in scripts/tests/fix-required-context-name-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=AaFvz9asMR3EMC2WMvW1&open=AaFvz9asMR3EMC2WMvW1&pullRequest=1337
Loading