-
-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): cure the AC4 currency gate's false positives, and wire it #990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1ef422f
418662f
013fa07
0c4858a
dfb928f
113cf84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -996,9 +996,98 @@ jobs: | |||||||||||||||||||||||
| # CONTRIBUTING (54/412 missing) warns until the cutoff baked into the | ||||||||||||||||||||||||
| # script, then blocks. See scripts/check-docs-presence.sh. | ||||||||||||||||||||||||
| cp .standards-checkout/scripts/check-docs-presence.sh "$RUNNER_TEMP/" | ||||||||||||||||||||||||
| # The launcher-standard currency gate (standards#960 AC4) is copied | ||||||||||||||||||||||||
| # out here too, because this step deletes the checkout. Prefer the | ||||||||||||||||||||||||
| # CALLER's own copy when present (self-lint: standards validating | ||||||||||||||||||||||||
| # itself must run the tree under test, not main's copy -- a gate fix | ||||||||||||||||||||||||
| # in flight would otherwise be judged by the version it replaces). | ||||||||||||||||||||||||
| # Callers without the script keep the main-pinned fallback. | ||||||||||||||||||||||||
| if [ -f scripts/check-launcher-standard-currency.sh ]; then | ||||||||||||||||||||||||
| cp scripts/check-launcher-standard-currency.sh "$RUNNER_TEMP/" | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| cp .standards-checkout/scripts/check-launcher-standard-currency.sh "$RUNNER_TEMP/" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| rm -rf .standards-checkout | ||||||||||||||||||||||||
| bash "$RUNNER_TEMP/check-docs-presence.sh" . | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| - name: Check launcher-standard currency | ||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||
| set -eo pipefail | ||||||||||||||||||||||||
| # Arming policy, and the evidence it rests on: standards#991. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # retired-filename -> BLOCKS. A STABLE predicate: | ||||||||||||||||||||||||
| # the retired `.a2ml` spelling of the launcher standard was | ||||||||||||||||||||||||
| # deleted upstream on 2026-09-22 | ||||||||||||||||||||||||
| # (standards#952) and stays deleted, so a caller that is clean | ||||||||||||||||||||||||
| # today cannot become defective without editing the citation | ||||||||||||||||||||||||
| # itself. Measured 2026-09-22 over EVERY clone in the estate -- | ||||||||||||||||||||||||
| # 595 scanned, 553 carrying an origin/main. 432 reference this | ||||||||||||||||||||||||
| # reusable workflow, but only 12 do so at a MUTABLE ref (@main), | ||||||||||||||||||||||||
| # and a new step reaches ONLY those 12: a caller pinned at a SHA | ||||||||||||||||||||||||
| # freezes this whole file, this step included, so it can never | ||||||||||||||||||||||||
| # receive the step at all. The real gate was run against all 12: | ||||||||||||||||||||||||
| # 12/12 rc=0, retired=0. Five slugs do carry the retired literal | ||||||||||||||||||||||||
| # (tma-mark2, canonical-ums, the-nash-equilibrium, | ||||||||||||||||||||||||
| # launch-scaffolder, trigger) and their overlap with the armed 12 | ||||||||||||||||||||||||
| # is ZERO -- so arming this tier reds ZERO live callers. A | ||||||||||||||||||||||||
| # known-answer positive control fired (rc=1) on three of those | ||||||||||||||||||||||||
| # defective repos through the identical harness, so the twelve | ||||||||||||||||||||||||
| # zeros are a real measurement and not a broken probe. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # stale-version -> WARNS, and does not block. A TIME-DEPENDENT | ||||||||||||||||||||||||
| # predicate: the gate compares against its own CURRENT_VERSION, so | ||||||||||||||||||||||||
| # every correctly-citing caller flips to defect the moment the | ||||||||||||||||||||||||
| # standard bumps, having done nothing. A baked-in cutoff DATE does | ||||||||||||||||||||||||
| # not cure that -- the #505 split above can use one because its | ||||||||||||||||||||||||
| # missing-CONTRIBUTING population is static, while this population | ||||||||||||||||||||||||
| # is regenerated at every bump. Each CURRENT_VERSION bump is a | ||||||||||||||||||||||||
| # measure-then-arm event, not a date. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # Deliberately no --standard / --expect-version: the gate arrives | ||||||||||||||||||||||||
| # from the standard's own tree, so its CURRENT_VERSION is current by | ||||||||||||||||||||||||
| # construction. Pointing it at a caller's vendored copy of the deed | ||||||||||||||||||||||||
| # would red that caller for citing an older canon. | ||||||||||||||||||||||||
| rc=0 | ||||||||||||||||||||||||
| bash "$RUNNER_TEMP/check-launcher-standard-currency.sh" --root . \ | ||||||||||||||||||||||||
| >"$RUNNER_TEMP/launcher-currency.out" 2>&1 || rc=$? | ||||||||||||||||||||||||
| cat "$RUNNER_TEMP/launcher-currency.out" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # rc=2 is a usage error OR a seeded self-test mutant that survived. A broken | ||||||||||||||||||||||||
| # invocation must never read as a clean pass, so it fails before the tier split. | ||||||||||||||||||||||||
| if [ "$rc" -eq 2 ]; then | ||||||||||||||||||||||||
| echo "::error::check-launcher-standard-currency exited 2: usage error, or a seeded self-test mutant survived. A broken invocation is a failure, not a pass." | ||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # The tiers are split on the gate's own typed stdout lines, not on its exit | ||||||||||||||||||||||||
| # code -- rc=1 means "some defect", and the two classes are armed differently. | ||||||||||||||||||||||||
| retired=0 | ||||||||||||||||||||||||
| if grep -q '^DEFECT retired-filename' "$RUNNER_TEMP/launcher-currency.out"; then retired=1; fi | ||||||||||||||||||||||||
| stale=0 | ||||||||||||||||||||||||
| if grep -q '^DEFECT stale-version' "$RUNNER_TEMP/launcher-currency.out"; then stale=1; fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [ "$retired" -eq 1 ]; then | ||||||||||||||||||||||||
| # ⚠ Do NOT name the retired filename literally here. This workflow | ||||||||||||||||||||||||
| # is part of the caller's scanned tree, so the gate reads its own | ||||||||||||||||||||||||
| # error message and reports it as a defect -- measured: two | ||||||||||||||||||||||||
| # defects on this file, from a comment and from this very echo. | ||||||||||||||||||||||||
| # Nothing is lost by staying general: the gate has already printed | ||||||||||||||||||||||||
| # both the offending file:line and its own cure text above. | ||||||||||||||||||||||||
| echo "::error::This repository names the retired .a2ml spelling of the launcher standard, deleted upstream on 2026-09-22 (standards#952). The offending file:line and the cure are printed above." | ||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [ "$stale" -eq 1 ]; then | ||||||||||||||||||||||||
| echo "::warning::This repository cites a launcher-standard version that is no longer current. NOT blocking, by policy (standards#991): the expected version moves with the standard, so a correct citation goes stale with no action of yours. Refresh it when convenient." | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Any other non-zero rc is the gate failing in a way this wrapper does not | ||||||||||||||||||||||||
| # classify; fail rather than guess. | ||||||||||||||||||||||||
| if [ "$rc" -ne 0 ] && [ "$retired" -eq 0 ] && [ "$stale" -eq 0 ]; then | ||||||||||||||||||||||||
| echo "::error::check-launcher-standard-currency exited $rc but emitted no recognised DEFECT line. Failing closed." | ||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||
|
Comment on lines
+1086
to
+1088
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Reject exit codes outside the documented contract. The condition accepts an unexpected exit code when the log contains either recognised defect type. For example, exit code Fail immediately when Proposed status validation+ if [ "$rc" -ne 0 ] && [ "$rc" -ne 1 ]; then
+ echo "::error::check-launcher-standard-currency exited with unexpected status $rc."
+ exit 1
+ fi
+
if [ "$rc" -ne 0 ] && [ "$retired" -eq 0 ] && [ "$stale" -eq 0 ]; then
echo "::error::check-launcher-standard-currency exited $rc but emitted no recognised DEFECT line. Failing closed."
exit 1
fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| wellknown: | ||||||||||||||||||||||||
| name: Well-Known (RFC 9116 + RSR) | ||||||||||||||||||||||||
| runs-on: ${{ inputs.runs-on }} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,7 +73,15 @@ | |
| 'dev-notes/*' # working notes, not compliance claims | ||
| '*HANDOVER*' # handover documents record prior state | ||
| '*CHANGELOG*' # a changelog that cannot name the old file is useless | ||
| 'launcher/launcher-standard_praxis.deed' # the canon itself; its ;; header records its own provenance | ||
| 'launcher-standard_praxis.deed' # the canon itself, at a repo root; its ;; header records its own provenance | ||
| '*/launcher-standard_praxis.deed' # ...and the same canon VENDORED at any depth by a consumer (G2) | ||
| '*/descriptiles/META.a2ml' # descriptiles ADR carriers: dated architecture decision records | ||
| # (G3, AC1's exemption). Canonical spelling, 0-canon/CANONICAL-NAMES.adoc. | ||
| '*/6a2/META.a2ml' # ...and the deprecated '6a2' spelling of descriptiles. Both are needed: | ||
| # the estate migration is chartered separately and BOTH are on disk today | ||
| # (measured 2026-09-22: descriptiles 164 dirs, the deprecated one 770). | ||
| # NARROW BY DESIGN: matches only META.a2ml under those dirs, never | ||
| # `.machine_readable/launcher/*.launcher.a2ml`, which are live descriptors. | ||
| 'scripts/check-launcher-standard-currency.sh' # this file | ||
| 'scripts/tests/check-launcher-standard-currency-test.sh' | ||
| ) | ||
|
|
@@ -116,9 +124,11 @@ | |
| return 1 | ||
| } | ||
|
|
||
| # Scan a tree. Prints one defect per line; returns 1 if any were found. | ||
| # Scan $1 recursively for retired filenames and document-version claims that | ||
| # differ from $2. Allowlisted paths and DEED grammar/schema versions are ignored. | ||
| # Prints one typed record per defect; returns 0 when clean and 1 otherwise. | ||
| scan() { | ||
| local root="$1" expect="$2" defects=0 hit file lineno text rel found | ||
| local root="$1" expect="$2" defects=0 hit file lineno text rel found gap gaplc | ||
|
|
||
| while IFS= read -r hit; do | ||
| file="${hit%%:*}"; hit="${hit#*:}" | ||
|
|
@@ -132,9 +142,22 @@ | |
| defects=$((defects + 1)) | ||
| fi | ||
|
|
||
| if [[ "$text" =~ launcher-standard(\.a2ml|_praxis\.deed)[^0-9]{0,24}v?([0-9]+\.[0-9]+\.[0-9]+) ]]; then | ||
| found="${BASH_REMATCH[2]}" | ||
| if [ "$found" != "$expect" ]; then | ||
| if [[ "$text" =~ launcher-standard(\.a2ml|_praxis\.deed)([^0-9]{0,24})v?([0-9]+\.[0-9]+\.[0-9]+) ]]; then | ||
| gap="${BASH_REMATCH[2]}" | ||
| found="${BASH_REMATCH[3]}" | ||
| # G1 -- THE TWO VERSIONS ARE NOT INTERCHANGEABLE, AND THIS GATE TRACKS ONE. | ||
| # The header above says :schema-version is the GRAMMAR (1.0.0) and | ||
| # :standard-version is the DOCUMENT (0.4.0). This test used to accept any | ||
| # number within 24 non-digit characters of the filename, so a line reading | ||
| # `launcher-standard_praxis.deed` (DEED v1.0.0). Per-app config: | ||
| # captured the GRAMMAR version and reported it as document drift -- the gate | ||
| # asking a different question than its consumer, in its own implementation. | ||
| # The gap between filename and number says which version is being named, so | ||
| # read it rather than discarding it. | ||
| gaplc="${gap,,}" | ||
| if [[ "$gaplc" == *deed* || "$gaplc" == *schema* || "$gaplc" == *grammar* ]]; then | ||
| : # a grammar/schema version, not a document-version claim -- not a defect | ||
| elif [ "$found" != "$expect" ]; then | ||
|
Check failure on line 160 in scripts/check-launcher-standard-currency.sh
|
||
|
Comment on lines
+158
to
+160
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '120,170p' scripts/check-launcher-standard-currency.sh
bash -c 's="launcher-standard_praxis.deed (DEED v1.0.0), standard v0.3.0"; re="launcher-standard_praxis[.]deed([^[:digit:]]|[[:digit:]]*[^vV[:digit:]])*[vV]([0-9]+([.][0-9]+)+)"; if [[ "$s" =~ $re ]]; then declare -p BASH_REMATCH; fi'Repository: hyperpolymath/standards Length of output: 2459 🏁 Script executed: set -eu
python3 - <<'PY'
from pathlib import Path
p = Path("scripts/check-launcher-standard-currency.sh")
lines = p.read_text().splitlines()
for start, end in ((145, 166), (1, 119), (167, 260)):
print(f"--- lines {start}-{end} ---")
for i in range(start, min(end, len(lines)) + 1):
print(f"{i}:{lines[i-1]}")
PY
bash -c '
text="launcher-standard_praxis.deed (DEED v1.0.0), standard v0.3.0"
re="launcher-standard(\.a2ml|_praxis\.deed)([^0-9]{0,24})v?([0-9]+\.[0-9]+\.[0-9]+)"
if [[ "$text" =~ $re ]]; then
declare -p BASH_REMATCH
gap="${BASH_REMATCH[2]}"
found="${BASH_REMATCH[3]}"
gaplc="${gap,,}"
if [[ "$gaplc" == *deed* || "$gaplc" == *schema* || "$gaplc" == *grammar* ]]; then
printf "suppressed gap=%q found=%q\n" "$gap" "$found"
else
printf "checked gap=%q found=%q\n" "$gap" "$found"
fi
fi
'Repository: hyperpolymath/standards Length of output: 13485 Continue scanning after a grammar-version match. For Process each subsequent version candidate on the line. Add the combined case to the self-test. Suggested fix- local root="$1" expect="$2" defects=0 hit file lineno text rel found gap gaplc
+ local root="$1" expect="$2" defects=0 hit file lineno text rel found gap gaplc
+ local version_tail candidate
...
- gap="${BASH_REMATCH[2]}"
- found="${BASH_REMATCH[3]}"
- # G1 -- THE TWO VERSIONS ARE NOT INTERCHANGEABLE, AND THIS GATE TRACKS ONE.
...
- gaplc="${gap,,}"
- if [[ "$gaplc" == *deed* || "$gaplc" == *schema* || "$gaplc" == *grammar* ]]; then
- : # a grammar/schema version, not a document-version claim -- not a defect
- elif [ "$found" != "$expect" ]; then
- printf 'DEFECT stale-version %s:%s claims v%s, current is v%s\n' \
- "$rel" "$lineno" "$found" "$expect"
- defects=$((defects + 1))
- fi
+ case "${BASH_REMATCH[1]}" in
+ _praxis.deed) version_tail="${text#*"$CANONICAL_FILE"}" ;;
+ .a2ml) version_tail="${text#*"$RETIRED_FILE"}" ;;
+ esac
+ while IFS= read -r candidate; do
+ [[ "$candidate" =~ ^([^0-9]{0,24})v?([0-9]+\.[0-9]+\.[0-9]+)$ ]] || continue
+ gap="${BASH_REMATCH[1]}"
+ found="${BASH_REMATCH[2]}"
+ gaplc="${gap,,}"
+ if [[ "$gaplc" == *deed* || "$gaplc" == *schema* || "$gaplc" == *grammar* ]]; then
+ continue
+ elif [ "$found" != "$expect" ]; then
+ printf 'DEFECT stale-version %s:%s claims v%s, current is v%s\n' \
+ "$rel" "$lineno" "$found" "$expect"
+ defects=$((defects + 1))
+ fi
+ done < <(printf '%s\n' "$version_tail" |
+ command grep -oE '[^0-9]{0,24}v?[0-9]+\.[0-9]+\.[0-9]+')🤖 Prompt for AI Agents |
||
| printf 'DEFECT stale-version %s:%s claims v%s, current is v%s\n' \ | ||
| "$rel" "$lineno" "$found" "$expect" | ||
| defects=$((defects + 1)) | ||
|
|
@@ -170,21 +193,59 @@ | |
| # allowlist control: the worst mutant, under a dated-audit path -- must NOT be reported | ||
| printf '# Compliant with %s v0.1.0\n' "$RETIRED_FILE" > "$tmp/docs/audits/old-2026-05-26.adoc" | ||
|
|
||
| # ---- G1/G2/G3 controls. Each of the three cures below silenced a MEASURED | ||
| # false positive on hyperpolymath/launch-scaffolder (4 of them). An exclusion | ||
| # without a mutant proving it is narrow is the vacuous-gate pattern, so the | ||
| # last fixture here MUST still fire: it is the one that proves the three | ||
| # exclusions did not also spare a true positive. | ||
| mkdir -p "$tmp/vendor" "$tmp/.machine_readable/descriptiles" \ | ||
| "$tmp/.machine_readable/6a2" "$tmp/.machine_readable/launcher" # canonical + deprecated spellings | ||
|
|
||
| # G1 control: the DEED GRAMMAR version, not the document version. Must NOT fire. | ||
| printf '| Standard: `%s` (DEED v1.0.0). Per-app config:\n' "$CANONICAL_FILE" > "$tmp/g1-grammar.adoc" | ||
|
|
||
| # G2 control: the canon VENDORED by a consumer, carrying its own provenance | ||
| # header naming the retired file. The allowlist used to name only this repo's | ||
| # own `launcher/` path, so a consumer got a false defect on the canon itself. | ||
| printf ';; translated from %s\n' "$RETIRED_FILE" > "$tmp/vendor/launcher-standard_praxis.deed" | ||
|
|
||
| # G3 control: dated ADR carriers. AC1 exempts a dated historical record, and | ||
| # META.a2ml under a descriptiles dir is an estate-wide convention. BOTH | ||
| # spellings are seeded because both are on disk: the canonical `descriptiles` | ||
| # and the deprecated one it replaces (0-canon/CANONICAL-NAMES.adoc). Neither | ||
| # must fire. | ||
| printf 'adr = "ADR-003" ;; superseded; named %s\n' "$RETIRED_FILE" \ | ||
| > "$tmp/.machine_readable/descriptiles/META.a2ml" | ||
| printf 'adr = "ADR-003" ;; superseded; named %s\n' "$RETIRED_FILE" \ | ||
| > "$tmp/.machine_readable/6a2/META.a2ml" # the deprecated spelling of descriptiles | ||
|
|
||
| # G3 NARROWNESS control -- THIS ONE MUST STILL FIRE. A live launcher descriptor | ||
| # lives under the same .machine_readable/ tree as the ADR carrier above, so a | ||
| # blanket '.machine_readable/*' exemption would have spared it. It is a real | ||
| # compliance claim against a deleted file and a dead version. | ||
| printf '# Compliant with %s v0.3.0\n' "$RETIRED_FILE" \ | ||
| > "$tmp/.machine_readable/launcher/demo-app.launcher.a2ml"; seeded=$((seeded+1)) | ||
|
|
||
| if [ "$seeded" -eq 0 ]; then | ||
| echo "SELF-TEST ERROR: zero fixtures seeded -- the self-test is vacuous." >&2 | ||
| return 2 | ||
| fi | ||
|
|
||
| out="$(scan "$tmp" "$CURRENT_VERSION")" || rc=1 | ||
|
|
||
| local fail=0 | ||
| # Coverage counters. These are INCREMENTED BY THE CHECKS THEMSELVES so the | ||
| # summary line can never drift from the controls actually run -- the previous | ||
| # version printed a hardcoded "2 controls clean" while seven were present. | ||
| local fail=0 ndet=0 nabs=0 | ||
| check_detects() { | ||
| ndet=$((ndet + 1)) | ||
| if ! printf '%s' "$out" | command grep -q "$1"; then | ||
| echo "SELF-TEST FAIL: mutant survived -- expected to detect: $1" >&2 | ||
| fail=1 | ||
| fi | ||
| } | ||
| check_absent() { | ||
| nabs=$((nabs + 1)) | ||
| if printf '%s' "$out" | command grep -q "$1"; then | ||
| echo "SELF-TEST FAIL: false positive on: $1" >&2 | ||
| fail=1 | ||
|
|
@@ -197,6 +258,13 @@ | |
| check_absent 'm3.toml.*stale-version' # m3 is current; only the filename is wrong | ||
| check_absent 'clean.toml' | ||
| check_absent 'docs/audits' | ||
| check_absent 'g1-grammar.adoc' # G1: grammar version is not document drift | ||
| check_absent 'vendor/launcher-standard_praxis.deed' # G2: a vendored canon is still the canon | ||
| check_absent 'descriptiles/META.a2ml' # G3: a dated ADR carrier is a historical record | ||
| check_absent '6a2/META.a2ml' # ...same, in the deprecated spelling of descriptiles | ||
| # ...and the exclusions above must NOT have spared a live descriptor: | ||
| check_detects 'retired-filename .machine_readable/launcher/demo-app.launcher.a2ml' | ||
| check_detects 'stale-version .machine_readable/launcher/demo-app.launcher.a2ml' | ||
|
|
||
| if [ "$rc" -ne 1 ]; then | ||
| echo "SELF-TEST FAIL: scan returned 0 with mutants present." >&2 | ||
|
|
@@ -209,7 +277,11 @@ | |
| return 2 | ||
| fi | ||
|
|
||
| printf 'self-test: %s mutants killed, 2 controls clean, OK\n' "$seeded" | ||
| if [ "$ndet" -eq 0 ] || [ "$nabs" -eq 0 ]; then | ||
|
Check failure on line 280 in scripts/check-launcher-standard-currency.sh
|
||
| echo "SELF-TEST ERROR: a whole check tier is empty (detects=$ndet absent=$nabs)." >&2 | ||
| return 2 | ||
| fi | ||
| printf 'self-test: %s mutants seeded, %s detections asserted, %s false-positive controls clean, OK\n' "$seeded" "$ndet" "$nabs" | ||
| return 0 | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🛡️ Detected with Advanced Tier | 🟠 Major | ⚡ Quick win
Security Misconfiguration
Reachability: External
Exploitability: Trivial
CWE: CWE-693
Restrict the caller-local checker to the standards repository.
The event-SHA checkout supplies PR-controlled content. Any caller can add
scripts/check-launcher-standard-currency.sh, which this branch copies and later executes. A no-op script can therefore bypass the centrally managed governance gate.Use the local copy only when
GITHUB_REPOSITORYishyperpolymath/standards. Use the main-pinned copy for every consumer repository. Thecontents: readpermission limits token access, but it does not prevent this policy bypass.Proposed restriction
📝 Committable suggestion
🤖 Prompt for AI Agents