Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
fix: the Hypatia gate could never fire — 2>&1 made it unconditionally vacuous#7
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
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -44,14 +44,28 @@ jobs: | ||
| if: steps.install.outputs.installed == 'true' | ||
| run: | | ||
| set +e | ||
| panic-attack assail --format json . > panic-attack-findings.json 2>&1 | ||
| panic-attack assail --format json . > panic-attack-findings.json | ||
| PA_EXIT=$? | ||
| set -e | ||
| # Same defect class as the Hypatia job below: `2>&1` folded the | ||
| # scanner's stderr into the JSON payload, so every jq parse failed, | ||
| # every count silently became 0 via `|| echo 0`, and "Fail on critical | ||
| # findings" could never fire on any input. Keep stderr on the log. | ||
| if [ ! -s panic-attack-findings.json ]; then | ||
| echo "[]" > panic-attack-findings.json | ||
| fi | ||
| # Deliberately a WARNING, not a failure. panic-attack is a downloaded | ||
| # release binary whose exit-code and output contract are not verified | ||
| # here, and it has no confirmed --exit-zero equivalent, so we surface a | ||
| # malformed payload in the log rather than block on an unverified tool. | ||
| # Promote to `exit 1` (as the Hypatia job does) once that contract is | ||
| # confirmed -- see the follow-up issue linked from this PR. | ||
| if ! jq -e 'type == "array"' panic-attack-findings.json >/dev/null 2>&1; then | ||
| echo "::warning::panic-attack output is not a JSON array (exit ${PA_EXIT}); counts below are unreliable" | ||
| fi | ||
| # Parse finding counts | ||
| TOTAL=$(jq '. | length' panic-attack-findings.json 2>/dev/null || echo 0) | ||
| CRITICAL=$(jq '[.[] | select(.severity == "critical")] | length' panic-attack-findings.json 2>/dev/null || echo 0) | ||
| @@ -69,13 +83,19 @@ jobs: | ||
| if: steps.install.outputs.installed == 'true' | ||
| run: | | ||
| # Convert JSON findings into GitHub Actions annotations | ||
| jq -r '.[] | select(.file != null) | | ||
| # Findings carry no `.message` (keys: action,file,line,reason,rule_module, | ||
| # severity,type), so every annotation read "null". `.file` is an absolute | ||
| # runner path, which GitHub cannot anchor to the diff, so it is made | ||
| # workspace-relative here. | ||
| jq -r --arg ws "$GITHUB_WORKSPACE" '.[] | select(.file != null) | | ||
| (.file | ltrimstr($ws + "/")) as $f | | ||
| (.reason // .message // .type // "finding") as $m | | ||
Comment on lines
+90
to
+92
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. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🏁 Script executed: #!/bin/bashset -e
printf'%s\n''--- workflow lines 70-110 ---'
sed -n '70,110p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- workflow lines 205-245 ---'
sed -n '205,245p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- scanner/report references ---'
rg -n -S 'panic.attack|panic-attack|hypatia|weak_points|description|static-analysis' .github README.md 2>/dev/null | head -200Repository: hyperpolymath/trigger Length of output: 22294 🏁 Script executed: #!/bin/bashset -e
printf'%s\n''--- panic-attack producer and validation ---'
sed -n '1,78p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- hypatia producer and validation ---'
sed -n '144,218p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- deposit consumer ---'
sed -n '350,405p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- repository files mentioning report fields ---'
rg -n -S 'weak_points|rule_module|panic-attack-findings|hypatia-findings|HYPATIA_FORMAT|--format json' --glob '!*.lock'.| head -200Repository: hyperpolymath/trigger Length of output: 9802 🏁 Script executed: #!/bin/bashset -e
printf'%s\n''--- panic-attack report fixtures ---'forfin panic-attack-report.json panic-attack-report-2026-08-13.json;doif [ -f"$f" ];thenecho"FILE: $f"
jq '{top_type: type, top_keys: (keys), weak_points_type: (.weak_points | type), weak_points_count: (.weak_points | length), weak_point_sample: .weak_points[0]}'"$f"fidoneprintf'%s\n''--- fixture references and scanner contract clues ---'
rg -n -S 'panic-attack-report|weak_points|description|Hypatia.*JSON|findings array|severity' --glob '*.md' --glob '*.json' --glob '*.yml' --glob '*.yaml' --glob '*.ex' --glob '*.exs' --glob '*.erl'.| head -240Repository: hyperpolymath/trigger Length of output: 4672 Handle the panic-attack report as an object.
📍 Affects 1 file
🤖 Prompt for AI Agents | ||
| if .severity == "critical" then | ||
| "::error file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" | ||
| "::error file=\($f),line=\(.line // 1)::[panic-attack] \($m)" | ||
| elif .severity == "high" then | ||
| "::error file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" | ||
| "::error file=\($f),line=\(.line // 1)::[panic-attack] \($m)" | ||
| else | ||
| "::warning file=\(.file),line=\(.line // 1)::[panic-attack] \(.message)" | ||
| "::warning file=\($f),line=\(.line // 1)::[panic-attack] \($m)" | ||
| end | ||
| ' panic-attack-findings.json || true | ||
| - name: Write step summary | ||
| @@ -159,12 +179,28 @@ jobs: | ||
| if: steps.build.outputs.ready == 'true' | ||
| run: | | ||
| set +e | ||
| HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . > hypatia-findings.json 2>&1 | ||
| HYPATIA_FORMAT=json "$HOME/hypatia/hypatia-cli.sh" scan . --exit-zero > hypatia-findings.json | ||
| HYP_EXIT=$? | ||
| set -e | ||
| if [ ! -s hypatia-findings.json ] || ! jq empty hypatia-findings.json 2>/dev/null; then | ||
| echo "[]" > hypatia-findings.json | ||
| # --exit-zero is Hypatia's own documented CI recipe (lib/hypatia/cli.ex), | ||
| # for exactly this case: "use in CI when a downstream step gates on | ||
| # severity counts". Findings go to stdout, the one-line summary to | ||
| # stderr, and the process exits 0 unless the SCANNER itself failed. | ||
| # | ||
| # Do NOT redirect stderr into the payload with `2>&1`: that folds the | ||
| # summary line into the JSON, so every parse fails, the old `[]` | ||
| # fallback substituted a clean result, CRITICAL was always 0, and the | ||
| # gate below could never fire on any input. Keep stderr on the log. | ||
| if [ "$HYP_EXIT" -ne 0 ]; then | ||
| echo "::error::Hypatia scanner execution failed with exit ${HYP_EXIT}" | ||
| exit "$HYP_EXIT" | ||
Comment on lines
+195
to
+197
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. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bashset -e
printf'%s\n''--- workflow lines 35-80 ---'
sed -n '35,80p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- workflow lines 165-210 ---'
sed -n '165,210p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- relevant step names and conditions ---'
rg -n -C 3 'Upload hypatia findings|deposit-findings|hypatia-findings|HYP_EXIT|always\\(\\)|if:' .github/workflows/static-analysis-gate.ymlRepository: hyperpolymath/trigger Length of output: 13691 🏁 Script executed: #!/bin/bashset -e
printf'%s\n''--- workflow lines 338-410 ---'
sed -n '338,410p' .github/workflows/static-analysis-gate.yml
printf'%s\n''--- job headers and job-level conditions ---'
sed -n '1,35p' .github/workflows/static-analysis-gate.yml
sed -n '125,165p' .github/workflows/static-analysis-gate.yml
rg -n -C 4 'if:.*(always|cancelled|success)|needs:|Upload .*findings|Download .*findings|Ensure both files|artifact' .github/workflows/static-analysis-gate.ymlRepository: hyperpolymath/trigger Length of output: 10575 🌐 Web query:
💡 Result: In GitHub Actions, the Citations:
Keep the Hypatia artefact available when the scan fails.
🤖 Prompt for AI Agents | ||
| fi | ||
| # `jq empty` is NOT sufficient -- it succeeds on any valid JSON, | ||
| # including a bare string, object or null. Assert the array. | ||
| if [ ! -s hypatia-findings.json ] || ! jq -e 'type == "array"' hypatia-findings.json >/dev/null; then | ||
| echo "::error::Hypatia did not produce a valid JSON findings array" | ||
| exit 1 | ||
| fi | ||
| TOTAL=$(jq '. | length' hypatia-findings.json 2>/dev/null || echo 0) | ||
| @@ -181,13 +217,19 @@ jobs: | ||
| - name: Emit check annotations | ||
| if: steps.build.outputs.ready == 'true' | ||
| run: | | ||
| jq -r '.[] | select(.file != null) | | ||
| # Findings carry no `.message` (keys: action,file,line,reason,rule_module, | ||
| # severity,type), so every annotation read "null". `.file` is an absolute | ||
| # runner path, which GitHub cannot anchor to the diff, so it is made | ||
| # workspace-relative here. | ||
| jq -r --arg ws "$GITHUB_WORKSPACE" '.[] | select(.file != null) | | ||
| (.file | ltrimstr($ws + "/")) as $f | | ||
| (.reason // .message // .type // "finding") as $m | | ||
| if .severity == "critical" then | ||
| "::error file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" | ||
| "::error file=\($f),line=\(.line // 1)::[hypatia] \($m)" | ||
| elif .severity == "high" then | ||
| "::error file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" | ||
| "::error file=\($f),line=\(.line // 1)::[hypatia] \($m)" | ||
| else | ||
| "::warning file=\(.file),line=\(.line // 1)::[hypatia] \(.message)" | ||
| "::warning file=\($f),line=\(.line // 1)::[hypatia] \($m)" | ||
| end | ||
| ' hypatia-findings.json || true | ||
| - name: Write step summary | ||
Uh oh!
There was an error while loading. Please reload this page.
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.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: hyperpolymath/trigger
Length of output: 5711
🏁 Script executed:
Repository: hyperpolymath/trigger
Length of output: 8881
🏁 Script executed:
Repository: hyperpolymath/trigger
Length of output: 337
Normalise non-array
panic-attackoutput before deposit.When the output is valid non-array JSON,
deposit-findingsaccepts it withjq empty, then.[] | . + {"scanner": "panic-attack"}can fail on error objects with string values. Replace non-array output with[], or enforce the array check indeposit-findings.🤖 Prompt for AI Agents