From 139212482e89ee79c1a15df1181f8b4941df8a28 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 22 Sep 2026 12:36:36 +0100 Subject: [PATCH 1/2] fix(baseline): collapse the two invalid_actions_lock acks into one #971 made `rule_module` list-valued precisely so one acknowledgement can name every module that emits a defect. This spends it: hypatia emits `invalid_actions_lock` from BOTH `workflow_audit` (file `actions.lock`) and WH004/`workflow_hardening` (full path), and the estate carried two entries for one decision -- two expiry dates, so the half that expires first silently reopens a gate while the ledger still looks correct. 212 -> 211 entries, so the exemption ratchet is satisfied with no `Ratchet-exception` trailer. DELIBERATE WIDENING, stated because it is not a refactor. One entry carries one matcher, and the two emissions carry different `file` values, so the surviving entry must match by `file_pattern`. The `workflow_hardening` half therefore moves from the exact path `.github/workflows/actions.lock` to `**actions.lock` -- the breadth the `workflow_audit` half already had at the same severity and type. Measured: a `workflow_hardening` `invalid_actions_lock` at `vendor/actions.lock` was KEPT before this commit and is SUPPRESSED after. Accepted because both halves are the same defect with the same exit criteria; the note says to narrow the entry if a second `actions.lock` is ever vendored. Three assertions added (26 -> 29), and they read the SHIPPED `.hypatia-baseline.json` rather than a fixture, so the collapse itself is pinned. Two mutants, each killed by the right assertion: * split the entry back into two -> the "one entry naming two modules" assertion reds; * swap `file_pattern` for an exact `file` -> the "suppresses BOTH emission paths" assertion reds at 1,1, which is exactly the half-suppression that reddens main. An over-match control asserts the ack is not a blanket amnesty: a different `type`, and a different `rule_module`, are both still kept. Verified: 52/52 local suites green; the collapsed ledger validates against the schema and suppresses both real emissions when run through the real `scripts/apply-baseline.sh`. Refs: hyperpolymath/standards#966, hyperpolymath/standards#951 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --- .hypatia-baseline.json | 16 +++------ scripts/tests/apply-baseline-test.sh | 52 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/.hypatia-baseline.json b/.hypatia-baseline.json index 3cd5de9b..fe1e686f 100644 --- a/.hypatia-baseline.json +++ b/.hypatia-baseline.json @@ -1726,19 +1726,13 @@ }, { "severity": "high", - "rule_module": "workflow_audit", + "rule_module": [ + "workflow_audit", + "workflow_hardening" + ], "type": "invalid_actions_lock", "file_pattern": "**actions.lock", - "note": "TRIAGED (round-2 fix-forward 2026-09-22): Hypatia workflow_audit fails the lock closed with transitive_dependencies_missing -- asana/push-signed-commits@d615 (immutable pin, ref v1.3) declares transitive actions/setup-python@v2, which floats upstream and can never be a lock key. gh-actions-lock v0.1.6 verify says valid:true on the same file; Hypatia is stricter than the authoritative tool. Exposure is upstream float only. Exit: Asana pins setup-python, we replace the action, or Hypatia downgrades float-transitives. #947 deleted the metadata to silence the scanner; round 2 restored it verbatim and acked honestly.", - "expires_at": "2026-12-22", - "tracking_issue": "hyperpolymath/standards#951" - }, - { - "severity": "high", - "rule_module": "workflow_hardening", - "type": "invalid_actions_lock", - "file": ".github/workflows/actions.lock", - "note": "TRIAGED (round-2 fix-forward 2026-09-22): second emission path of the same asana float-transitive as the workflow_audit ack (see #951). Hypatia emits invalid_actions_lock TWICE: workflow_audit/parse_actions_lock (file actions.lock) and WH004 standalone (rule_module workflow_hardening, full path). Both verified by running the real scanner locally. Same exit criteria as #951.", + "note": "TRIAGED (round-2 fix-forward 2026-09-22; collapsed 2026-09-22 per #966): Hypatia emits invalid_actions_lock from TWO rule modules for ONE defect -- workflow_audit/parse_actions_lock (file `actions.lock`) and WH004 standalone (workflow_hardening, full path `.github/workflows/actions.lock`). Both verified by running the real scanner locally. The defect: asana/push-signed-commits@d615 (immutable pin, ref v1.3) declares transitive actions/setup-python@v2, which floats upstream and can never be a lock key. gh-actions-lock v0.1.6 verify says valid:true on the same file; Hypatia is stricter than the authoritative tool. Exposure is upstream float only. Exit: Asana pins setup-python, we replace the action, or Hypatia downgrades float-transitives. #947 deleted the metadata to silence the scanner; round 2 restored it verbatim and acked honestly. This was two entries until list-valued rule_module landed (#971) -- two entries meant two expiry dates for one decision, which is how a half-expired acknowledgement silently reopens a gate. DELIBERATE SCOPE CHANGE, recorded because it is a widening and not a refactor: the workflow_hardening half previously matched the exact path `.github/workflows/actions.lock`, and one entry carries one matcher, so it now matches `**actions.lock` -- the breadth the workflow_audit half already had at the same severity and type. Measured consequence: a workflow_hardening invalid_actions_lock at e.g. `vendor/actions.lock` was KEPT before and is SUPPRESSED now. Accepted because both halves are the same defect with the same exit criteria; if a second actions.lock is ever vendored, narrow this entry rather than trusting it.", "expires_at": "2026-12-22", "tracking_issue": "hyperpolymath/standards#951" } diff --git a/scripts/tests/apply-baseline-test.sh b/scripts/tests/apply-baseline-test.sh index a5098968..1dc10e83 100755 --- a/scripts/tests/apply-baseline-test.sh +++ b/scripts/tests/apply-baseline-test.sh @@ -258,6 +258,58 @@ else pass=$((pass + 1)) fi +# --- The SHIPPED ledger, not a fixture ------------------------------------- +# #966: hypatia emits invalid_actions_lock from BOTH workflow_audit and +# workflow_hardening for one defect. It was acked twice, which meant two +# expiry dates for one decision — the shape in which a half-expired ack +# silently reopens a gate. #971 made rule_module list-valued; this collapses +# the pair into one entry. These assertions run against the real +# .hypatia-baseline.json so that splitting it back, or narrowing the matcher, +# reds this suite instead of quietly un-suppressing a live finding. +SHIPPED="$SCRIPT_DIR/../../.hypatia-baseline.json" +if [ ! -f "$SHIPPED" ]; then + echo "FAIL: shipped baseline not found at $SHIPPED" + fail=$((fail + 1)) +else + # Exactly one entry, and it must name BOTH modules. + got=$(jq -r '[.[] | select(.type == "invalid_actions_lock")] as $e + | "\($e | length),\($e[0].rule_module | if type == "array" then length else 1 end)"' "$SHIPPED") + if [ "$got" = "1,2" ]; then + echo "PASS: shipped ledger holds ONE invalid_actions_lock ack naming TWO modules" + pass=$((pass + 1)) + else + echo "FAIL: shipped invalid_actions_lock acks: expected 1 entry / 2 modules, got $got" + fail=$((fail + 1)) + fi + + # ⚠ The two emissions carry DIFFERENT file values — `actions.lock` from + # workflow_audit and the full path from WH004 — so the surviving entry must + # match by file_pattern. An exact `file` key would suppress only one of + # them and the other would red main. Both, or the collapse is unsound. + cat > "$WORK/findings-shipped-pair.json" <<'EOF' +[{"severity":"high","rule_module":"workflow_audit","type":"invalid_actions_lock","file":"actions.lock"}, + {"severity":"high","rule_module":"workflow_hardening","type":"invalid_actions_lock","file":".github/workflows/actions.lock"}] +EOF + assert_status "shipped ledger suppresses BOTH emission paths" \ + "$WORK/findings-shipped-pair.json" "$SHIPPED" "2,0" + + # Over-match control: the collapse must not have turned the ack into a + # blanket amnesty for anything hypatia says about actions.lock. + cat > "$WORK/findings-shipped-other.json" <<'EOF' +[{"severity":"high","rule_module":"workflow_audit","type":"shell_download","file":"actions.lock"}, + {"severity":"high","rule_module":"workflow_lint","type":"invalid_actions_lock","file":"actions.lock"}] +EOF + got=$(bash "$APPLY" "$WORK/findings-shipped-other.json" "$SHIPPED" advisory \ + | jq -r '"\(.findings_suppressed | length),\(.findings_kept | length)"') + if [ "$got" = "0,2" ]; then + echo "PASS: shipped ledger does NOT suppress other types or modules" + pass=$((pass + 1)) + else + echo "FAIL: shipped ledger over-matches: expected 0,2 got $got" + fail=$((fail + 1)) + fi +fi + assert_invalid_option "invalid mode" bypass high assert_invalid_option "invalid threshold" blocking nonsense From 48415f6b013a2eb953bdeb74c33bc26a1511e884 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 22 Sep 2026 12:39:21 +0100 Subject: [PATCH 2/2] fix(baseline): repoint the lock ack at its live tracking issue The collapsed ack cited #951, which is CLOSED/COMPLETED with zero comments -- while the defect it acknowledges is demonstrably live: `.github/workflows/actions.lock:210` still declares the floating transitive `actions/setup-python@v2` under the asana pin, and setup-python is never a top-level lock key (0 occurrences), so hypatia's `transitive_dependencies_missing` still fires. #951 was not closed in error -- #963 superseded it and is OPEN ("main is red: actions.lock omits a transitive dependency of asana/push-signed-commits"). The ack simply never followed. This matters because the ack expires 2026-12-22. An acknowledgement pointing at a closed issue keeps suppressing perfectly well while the cure stops being anyone's job, and then reds main on its expiry date with no owner and no live thread to read. The suppression is the part that goes on working; that is what makes it hard to see. Measured while checking this one: 19 acks across 7 closed tracking issues are orphaned the same way (#254 x1, #378 x3, #399 x6, #492 x5, #494 x2, #496 x1, #951 x1). Deliberately NOT swept here -- the other 18 are filed separately so each repoint is reviewed against the issue that actually superseded it, rather than bulk-rewritten. Refs: hyperpolymath/standards#963, hyperpolymath/standards#951 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --- .hypatia-baseline.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.hypatia-baseline.json b/.hypatia-baseline.json index fe1e686f..fcd874c2 100644 --- a/.hypatia-baseline.json +++ b/.hypatia-baseline.json @@ -1732,8 +1732,8 @@ ], "type": "invalid_actions_lock", "file_pattern": "**actions.lock", - "note": "TRIAGED (round-2 fix-forward 2026-09-22; collapsed 2026-09-22 per #966): Hypatia emits invalid_actions_lock from TWO rule modules for ONE defect -- workflow_audit/parse_actions_lock (file `actions.lock`) and WH004 standalone (workflow_hardening, full path `.github/workflows/actions.lock`). Both verified by running the real scanner locally. The defect: asana/push-signed-commits@d615 (immutable pin, ref v1.3) declares transitive actions/setup-python@v2, which floats upstream and can never be a lock key. gh-actions-lock v0.1.6 verify says valid:true on the same file; Hypatia is stricter than the authoritative tool. Exposure is upstream float only. Exit: Asana pins setup-python, we replace the action, or Hypatia downgrades float-transitives. #947 deleted the metadata to silence the scanner; round 2 restored it verbatim and acked honestly. This was two entries until list-valued rule_module landed (#971) -- two entries meant two expiry dates for one decision, which is how a half-expired acknowledgement silently reopens a gate. DELIBERATE SCOPE CHANGE, recorded because it is a widening and not a refactor: the workflow_hardening half previously matched the exact path `.github/workflows/actions.lock`, and one entry carries one matcher, so it now matches `**actions.lock` -- the breadth the workflow_audit half already had at the same severity and type. Measured consequence: a workflow_hardening invalid_actions_lock at e.g. `vendor/actions.lock` was KEPT before and is SUPPRESSED now. Accepted because both halves are the same defect with the same exit criteria; if a second actions.lock is ever vendored, narrow this entry rather than trusting it.", + "note": "TRIAGED (round-2 fix-forward 2026-09-22; collapsed 2026-09-22 per #966): Hypatia emits invalid_actions_lock from TWO rule modules for ONE defect -- workflow_audit/parse_actions_lock (file `actions.lock`) and WH004 standalone (workflow_hardening, full path `.github/workflows/actions.lock`). Both verified by running the real scanner locally. The defect: asana/push-signed-commits@d615 (immutable pin, ref v1.3) declares transitive actions/setup-python@v2, which floats upstream and can never be a lock key. gh-actions-lock v0.1.6 verify says valid:true on the same file; Hypatia is stricter than the authoritative tool. Exposure is upstream float only. Exit: Asana pins setup-python, we replace the action, or Hypatia downgrades float-transitives. #947 deleted the metadata to silence the scanner; round 2 restored it verbatim and acked honestly. Tracking moved from #951 to #963 on 2026-09-22: #951 was closed COMPLETED with zero comments while the defect is demonstrably live (actions.lock:210 still declares the floating transitive under the asana pin, and setup-python is never a top-level lock key), because #963 superseded it. An acknowledgement expiring 2026-12-22 against a CLOSED issue has nobody owning its exit criteria -- the ack keeps working and the cure stops being anyone job. This was two entries until list-valued rule_module landed (#971) -- two entries meant two expiry dates for one decision, which is how a half-expired acknowledgement silently reopens a gate. DELIBERATE SCOPE CHANGE, recorded because it is a widening and not a refactor: the workflow_hardening half previously matched the exact path `.github/workflows/actions.lock`, and one entry carries one matcher, so it now matches `**actions.lock` -- the breadth the workflow_audit half already had at the same severity and type. Measured consequence: a workflow_hardening invalid_actions_lock at e.g. `vendor/actions.lock` was KEPT before and is SUPPRESSED now. Accepted because both halves are the same defect with the same exit criteria; if a second actions.lock is ever vendored, narrow this entry rather than trusting it.", "expires_at": "2026-12-22", - "tracking_issue": "hyperpolymath/standards#951" + "tracking_issue": "hyperpolymath/standards#963" } ]