From bdbcf132c0e9ce1b76fb1bf9be004dadb7f374e3 Mon Sep 17 00:00:00 2001 From: rldyourmnd Date: Mon, 31 Aug 2026 15:54:02 +0500 Subject: [PATCH] fix(security): upload evidence only when the scan ran A job that died in its own bootstrap ended by reporting ##[error]Path does not exist: .../_temp/private-security-zizmor.sarif which is a true statement about a file and a false statement about the run. The real failure was three steps earlier, in `Fetch exact called-workflow implementation`, and the message that reached the reviewer named the wrong thing entirely. Two people reported the missing SARIF as the defect; both were reading the last error rather than the first. The evidence uploads were `always()`, so they ran after a bootstrap that produced no scanners and no output. They are now guarded on the scan step having run at all. Evidence is still uploaded when the scan runs and finds problems, which is the case `always()` existed for. private-security-bundle-free.yml carried the same guard and had no id on its scan step; it has one now, so the condition resolves there too. This is the reporting half of #76, which fixed the cause. Together the bootstrap stops failing one run in five, and when anything else fails the job names the step that failed. --- .github/workflows/nddev-security-bundle.yml | 12 ++++++++++-- .github/workflows/private-security-bundle-free.yml | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nddev-security-bundle.yml b/.github/workflows/nddev-security-bundle.yml index 970fee9..f224222 100644 --- a/.github/workflows/nddev-security-bundle.yml +++ b/.github/workflows/nddev-security-bundle.yml @@ -147,7 +147,15 @@ jobs: run: "$NDDEV_SECURITY_BUNDLE_SCRIPT" - name: Upload redacted security evidence - if: ${{ always() }} + # Only when the gates actually ran. These uploads were `always()`, so a + # job that died in its own bootstrap -- before any scanner existed -- + # ended by reporting `Path does not exist: + # .../private-security-zizmor.sarif`. That is a true statement about a + # file and a false statement about the run: the real failure was three + # steps earlier, and the message that reached the reviewer named the + # wrong thing entirely. Evidence is still uploaded when the scan runs + # and finds problems, which is the case `always()` was there for. + if: ${{ !cancelled() && steps.scan.conclusion != 'skipped' }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: nddev-private-security-evidence-${{ github.run_id }}-${{ github.run_attempt }} @@ -161,7 +169,7 @@ jobs: compression-level: 9 - name: Upload zizmor SARIF - if: ${{ always() }} + if: ${{ !cancelled() && steps.scan.conclusion != 'skipped' }} uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 with: sarif_file: ${{ runner.temp }}/private-security-zizmor.sarif diff --git a/.github/workflows/private-security-bundle-free.yml b/.github/workflows/private-security-bundle-free.yml index 6979b7e..a2133b3 100644 --- a/.github/workflows/private-security-bundle-free.yml +++ b/.github/workflows/private-security-bundle-free.yml @@ -184,6 +184,7 @@ jobs: max-bytes: '16777216' - name: Run consolidated security gates without SARIF upload + id: scan shell: bash env: GH_TOKEN: ${{ github.token }} @@ -201,7 +202,10 @@ jobs: run: "$PRIVATE_SECURITY_BUNDLE_SCRIPT" - name: Upload redacted security evidence - if: ${{ always() }} + # Only when the gates actually ran; see the note in + # nddev-security-bundle.yml. `always()` here turned a bootstrap failure + # into a missing-SARIF message that named the wrong step. + if: ${{ !cancelled() && steps.scan.conclusion != 'skipped' }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ inputs.evidence_artifact_name }}