From 5c4b8b0738629bb0ae1a7a98b4a2e8869139ac40 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Mon, 3 Aug 2026 23:33:56 +0200 Subject: [PATCH 1/6] fix(frontend): patch npm audit high-severity advisories in lockfile brace-expansion (GHSA-rgw5-rvv9-x895) and fast-uri (GHSA-7p8r-x3mc-p8w7) were flagged as high severity by npm audit, failing Security Scanning on every PR regardless of frontend changes. Both are transitive dependencies; npm audit fix bumps only the lockfile entries (brace-expansion 5.0.8 -> 5.0.9, fast-uri 3.1.4 -> 3.1.5) with no change to package.json's direct dependency ranges. npm audit --audit-level=high now exits 0, and the frontend build and test suite are unaffected by the bump. --- frontend/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4af53c2ce..84f09122d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -4006,9 +4006,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -5752,9 +5752,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { From 3e8d478fd207a1a873dbc0e4db0b590f416d8b14 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Mon, 3 Aug 2026 23:45:57 +0200 Subject: [PATCH 2/6] fix(ci): stop one security scanner from disabling the others The Security Scanning job ran govulncheck, npm audit, gosec, and two Trivy scans as sequential steps in one job. GitHub Actions skips every step after a failing one by default, so a single frontend npm advisory silently disabled Go SAST (gosec) and Terraform IaC scanning (Trivy config) repo-wide, while the resulting failure pointed at a missing SARIF upload rather than the actual cause. Give govulncheck, npm audit, gosec, and both Trivy scans `if: always()` so each one runs independent of whether an earlier scanner passed. The job still fails overall if any scanner step fails, since always() does not suppress a step's own failure. Also tighten the SARIF upload steps for gosec and both Trivy scans: each now checks `steps..outcome != 'skipped'` before uploading, so a genuinely unrun scanner (skipped upstream of the scanner steps themselves) is tolerated without a confusing "Path does not exist" failure, while a scanner that ran and left no file still fails loud. --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ea4ae5a4..8a0776e33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -299,6 +299,12 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Run govulncheck CVE scanner (all modules) + # always(): each scanner step below is independent evidence for the + # Security tab. Without this, one scanner failing (e.g. a live npm + # advisory) skips every scanner after it in the same job, silently + # disabling Go SAST and Terraform IaC coverage repo-wide. The job + # still fails overall if any scanner step here fails. + if: always() run: | # Pinned (not @latest): a govulncheck release with new # detection logic could silently change the gate's verdict @@ -315,12 +321,19 @@ jobs: done - name: Run npm audit (frontend) + # always(): must not skip the scanners below it just because + # govulncheck failed, and its own failure must not skip gosec/Trivy. + if: always() run: | if [ -f frontend/package.json ]; then cd frontend && npm audit --audit-level=high fi - name: Run gosec Security Scanner + id: gosec + # always(): don't let an earlier scanner's failure (e.g. npm audit) + # skip Go SAST coverage. The job still fails if gosec itself fails. + if: always() run: | # Install pinned gosec using the job's existing setup-go. # The securego/gosec Docker action bundles its own Go toolchain which @@ -348,12 +361,21 @@ jobs: echo "Merged $(jq '.runs | length' gosec-results.sarif) SARIF runs" - name: Upload gosec results to GitHub Security - if: always() + # Tolerate a missing SARIF only when the gosec step itself never ran + # (e.g. an earlier infra step like checkout/setup-go failed). If + # gosec ran and the file is still missing, fail loud instead of + # masking it as a skip. + if: always() && steps.gosec.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: gosec-results.sarif - name: Run Trivy vulnerability scanner (filesystem) + id: trivy_fs + # always(): don't let an earlier scanner's failure skip Trivy fs + # coverage. This scan uses the default exit-code 0 (see the IaC + # scan comment below), so it does not gate the job on its own. + if: always() uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: 'fs' @@ -370,6 +392,8 @@ jobs: version: 'v0.72.0' - name: Upload Trivy results to GitHub Security + # Tolerate a missing SARIF only when the Trivy fs step never ran. + if: always() && steps.trivy_fs.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: 'trivy-results.sarif' @@ -384,6 +408,10 @@ jobs: # to the Security tab without gating the job -- matching tfsec's prior # soft_fail: true behaviour while preserving Terraform IaC coverage. - name: Run Trivy IaC misconfiguration scanner (Terraform) + id: trivy_iac + # always(): don't let an earlier scanner's failure skip Terraform + # IaC coverage. + if: always() uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: 'config' @@ -396,7 +424,8 @@ jobs: version: 'v0.72.0' - name: Upload Trivy IaC results to GitHub Security - if: always() + # Tolerate a missing SARIF only when the Trivy IaC step never ran. + if: always() && steps.trivy_iac.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: 'trivy-config-results.sarif' From ced1ecd1df314fb4af99b159829381978880c37b Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 4 Aug 2026 18:40:11 +0200 Subject: [PATCH 3/6] fix(ci): preserve gosec SARIF on real findings, gate scanners on infra success Two related CodeRabbit findings on PR #1716, both in the Security Scanning job: Closes #1717. The gosec step's per-module loop ran under `set -e`, and gosec itself exits non-zero both for a real finding and for a processing error. The first module with a finding aborted the loop before the later modules were scanned and before the final SARIF merge ran, so the upload step failed on a missing gosec-results.sarif instead of surfacing the actual finding -- the same failure class this PR's first commit fixed for cross-scanner coupling, one level in. Guard the gosec invocation in `if ! ( ... )` so a non-zero exit is recorded in a `status` variable instead of aborting the script; every module still gets scanned, the SARIF files still get merged, and the job still exits non-zero at the end if any module reported a finding. Verified locally against a two-module fixture (one clean module, one with a deliberate weak-crypto finding) using the exact script logic: the old script aborted after the second module and never produced a merged SARIF file at all; the new script scans both modules, merges both SARIF runs, and still exits 1. Separately, `if: always()` on each scanner step also let a scanner run (and report "no findings") even when checkout or Go setup had failed, which is a false-clean signal rather than real scan coverage. Add `id: checkout` / `id: setup_go` and require both to have succeeded before any scanner step (and its matching upload step) runs, while keeping the always()-based decoupling between scanners from the previous commit. --- .github/workflows/ci.yml | 65 ++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a0776e33..599283d24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,11 +289,13 @@ jobs: steps: - name: Checkout code + id: checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false - name: Set up Go + id: setup_go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -303,8 +305,10 @@ jobs: # Security tab. Without this, one scanner failing (e.g. a live npm # advisory) skips every scanner after it in the same job, silently # disabling Go SAST and Terraform IaC coverage repo-wide. The job - # still fails overall if any scanner step here fails. - if: always() + # still fails overall if any scanner step here fails. Still requires + # checkout and Go setup to have actually succeeded -- an infra + # failure there must not be papered over as "scanner found nothing". + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' run: | # Pinned (not @latest): a govulncheck release with new # detection logic could silently change the gate's verdict @@ -323,7 +327,8 @@ jobs: - name: Run npm audit (frontend) # always(): must not skip the scanners below it just because # govulncheck failed, and its own failure must not skip gosec/Trivy. - if: always() + # Still requires checkout to have succeeded (see govulncheck above). + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' run: | if [ -f frontend/package.json ]; then cd frontend && npm audit --audit-level=high @@ -333,7 +338,8 @@ jobs: id: gosec # always(): don't let an earlier scanner's failure (e.g. npm audit) # skip Go SAST coverage. The job still fails if gosec itself fails. - if: always() + # Still requires checkout and Go setup to have succeeded. + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' run: | # Install pinned gosec using the job's existing setup-go. # The securego/gosec Docker action bundles its own Go toolchain which @@ -342,12 +348,29 @@ jobs: # Multi-module repo: each ./... only walks the current module so scanning root # alone silently misses pkg/ and providers/*. Mirror the govulncheck per-module # loop, collect per-module SARIF, then merge for the upload step. + # + # gosec exits non-zero both for real findings and for a processing + # error. A bare `set -e` loop aborts at the first non-zero module, + # skipping the merge below entirely -- the upload step then fails + # on a missing file instead of surfacing the actual finding + # (issue #1717). Guarding the gosec call in `if ! ( ... )` exempts + # it from errexit so every module still gets scanned and merged; + # `status` records whether the job should still fail at the end. set -e + status=0 for mod in . pkg providers/aws providers/azure providers/gcp tests/e2e; do tag=$(echo "$mod" | tr './' '--' | sed 's/^-/root/') out="$RUNNER_TEMP/gosec-${tag}.sarif" echo "==> gosec in $mod" - (cd "$mod" && gosec -fmt sarif -out "$out" ./...) + if ! (cd "$mod" && gosec -fmt sarif -out "$out" ./...); then + echo "::warning::gosec exited non-zero in $mod (findings or a scan error)" + status=1 + fi + if [ ! -f "$out" ]; then + echo "::error::gosec produced no SARIF output for $mod" + status=1 + continue + fi # Code scanning rejects a SARIF file whose runs share a category # (github.blog changelog 2025-07-21), so give each module's run a # unique automationDetails.id before merging. @@ -355,17 +378,27 @@ jobs: "$out" > "$out.tmp" && mv "$out.tmp" "$out" done # Merge per-module SARIF runs into one file for the upload step. + # Only modules that actually produced a file are included; if + # gosec crashed before writing any of them, fail loud here rather + # than uploading an empty result silently. + shopt -s nullglob + sarif_files=("$RUNNER_TEMP"/gosec-*.sarif) + if [ "${#sarif_files[@]}" -eq 0 ]; then + echo "::error::no gosec SARIF output was produced by any module" >&2 + exit 1 + fi # jq is preinstalled on the GitHub Ubuntu runner image (no new deps). jq -s '{version: "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", runs: [.[].runs[]]}' \ - "$RUNNER_TEMP"/gosec-*.sarif > gosec-results.sarif + "${sarif_files[@]}" > gosec-results.sarif echo "Merged $(jq '.runs | length' gosec-results.sarif) SARIF runs" + exit "$status" - name: Upload gosec results to GitHub Security # Tolerate a missing SARIF only when the gosec step itself never ran - # (e.g. an earlier infra step like checkout/setup-go failed). If - # gosec ran and the file is still missing, fail loud instead of - # masking it as a skip. - if: always() && steps.gosec.outcome != 'skipped' + # (e.g. checkout/setup-go failed, so gosec's own `if:` above skipped + # it). If gosec ran and the file is still missing, fail loud instead + # of masking it as a skip. + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.gosec.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: gosec-results.sarif @@ -375,7 +408,8 @@ jobs: # always(): don't let an earlier scanner's failure skip Trivy fs # coverage. This scan uses the default exit-code 0 (see the IaC # scan comment below), so it does not gate the job on its own. - if: always() + # Still requires checkout and Go setup to have succeeded. + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: 'fs' @@ -393,7 +427,7 @@ jobs: - name: Upload Trivy results to GitHub Security # Tolerate a missing SARIF only when the Trivy fs step never ran. - if: always() && steps.trivy_fs.outcome != 'skipped' + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.trivy_fs.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: 'trivy-results.sarif' @@ -410,8 +444,9 @@ jobs: - name: Run Trivy IaC misconfiguration scanner (Terraform) id: trivy_iac # always(): don't let an earlier scanner's failure skip Terraform - # IaC coverage. - if: always() + # IaC coverage. Still requires checkout and Go setup to have + # succeeded. + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: 'config' @@ -425,7 +460,7 @@ jobs: - name: Upload Trivy IaC results to GitHub Security # Tolerate a missing SARIF only when the Trivy IaC step never ran. - if: always() && steps.trivy_iac.outcome != 'skipped' + if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.trivy_iac.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: 'trivy-config-results.sarif' From f5468b42d7432ce2fc40e2ab640cfa28baf5bfb0 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 4 Aug 2026 18:40:31 +0200 Subject: [PATCH 4/6] fix(ci): align pre-commit.yml's cached gosec pin with the CI gate CodeRabbit finding on PR #1716: .github/workflows/pre-commit.yml's tool-cache priming step pinned gosec to v2.22.4 (cache key and go install), while ci.yml's Security Scanning job and the local pre-commit hook (scripts/gosec-hook.sh) both already run v2.28.0. GO_VERSION (1.26.5) already meets v2.28.0's toolchain requirement in both workflows, so nothing else needs to change to align upward. Bump the cache key and install version to v2.28.0 so the cached binary this step primes cannot be a stale, weaker gosec than what actually gates the build -- a developer whose local gate used the newer ruleset should not be able to pass CI on an older one, or vice versa. --- .github/workflows/pre-commit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index dab68fe8d..4fbf6e347 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -127,14 +127,14 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/go/bin - key: go-tools-${{ runner.os }}-gosec-v2.22.4-gocyclo-v0.6.0 + key: go-tools-${{ runner.os }}-gosec-v2.28.0-gocyclo-v0.6.0 - name: Install gosec if: steps.cache-go-tools.outputs.cache-hit != 'true' # Pinned to the same version ci.yml's `securego/gosec` Action uses, # so an upstream gosec release with rule changes can't silently # downgrade the gate between the two workflows. - run: go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4 + run: go install github.com/securego/gosec/v2/cmd/gosec@v2.28.0 - name: Install gocyclo if: steps.cache-go-tools.outputs.cache-hit != 'true' From b046a6f15a08b2dec4a4613a7e869af6ca97fd33 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 4 Aug 2026 23:06:55 +0200 Subject: [PATCH 5/6] fix(ci): align Makefile's GOSEC_VERSION with the CI/pre-commit pin CodeRabbit finding on PR #1716: Makefile:16 still pinned GOSEC_VERSION to v2.22.4, the third location carrying this pin after ci.yml and pre-commit.yml (already fixed in a prior commit on this PR). `make install-dev-tools` (Makefile:244) hands a developer this version directly, so this was the one a human actually invokes. Bump to v2.28.0, keeping the `?=` so an override still works. Confirmed via repo-wide grep that no other file, Makefile target, or doc still cites v2.22.4 after this change. Full pin inventory, all five locations now agreeing: Makefile:16 GOSEC_VERSION?=v2.28.0 .github/workflows/pre-commit.yml v2.28.0 (cache key :130, install :137) .github/workflows/ci.yml v2.28.0 (:347) scripts/gosec-hook.sh 2.28.0 (:35) .pre-commit-config.yaml v2.28.0 (comments :125-126) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3b390f79f..4d3a65848 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ GIT_SHA?=$(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) # Dev tool versions - keep in sync with the CI pins in # .github/workflows/ci.yml, pre-commit.yml and database-migration.yml GOLANGCI_LINT_VERSION?=v2.10.1 -GOSEC_VERSION?=v2.22.4 +GOSEC_VERSION?=v2.28.0 GOCYCLO_VERSION?=v0.6.0 MIGRATE_VERSION?=v4.19.1 # staticcheck has no CI pin; it is used by scripts/security-scan.sh From 21473bf13b796d9e8f0fbf4dbd143930d038b1bb Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Wed, 5 Aug 2026 00:12:03 +0200 Subject: [PATCH 6/6] fix(ci): write scanner SARIF output outside the checkout root CodeRabbit finding on PR #1716, ci.yml:392: the merged gosec SARIF was written to gosec-results.sarif in the checkout root, violating the repo's own coding guideline ("never save working files, text, Markdown files, or tests in the repository root"). A file sitting there is visible to any later step that walks the tree, which cuts against this PR's whole point of scanners behaving predictably. Grepped the rest of the job rather than fixing only the cited line: both Trivy scans had the same problem (trivy-results.sarif and trivy-config-results.sarif also landed in the checkout root). Moved all three merge/scan outputs to $RUNNER_TEMP (the run: steps) / ${{ runner.temp }} (the trivy-action `output:` inputs and the upload-sarif `sarif_file:` inputs) -- the env var and the context expression resolve to the same path, so the writer and reader always agree. Confirmed via repo-wide grep that nothing else reads any of the three filenames from their old checkout-root location. Re-ran the gosec set -e fixture (one clean module, one with a deliberate crypto/md5 finding) against the updated script: the merged SARIF is now written under $RUNNER_TEMP, both modules are still scanned and merged, the script still exits 1 on the real finding, and the checkout root has no stray .sarif file. --- .github/workflows/ci.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 599283d24..fdddbd0f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -388,9 +388,13 @@ jobs: exit 1 fi # jq is preinstalled on the GitHub Ubuntu runner image (no new deps). + # Written to $RUNNER_TEMP, not the checkout root: never save working + # files in the repository root (repo coding guideline), and this + # file is purely a hand-off to the upload step below. + merged="$RUNNER_TEMP/gosec-results.sarif" jq -s '{version: "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", runs: [.[].runs[]]}' \ - "${sarif_files[@]}" > gosec-results.sarif - echo "Merged $(jq '.runs | length' gosec-results.sarif) SARIF runs" + "${sarif_files[@]}" > "$merged" + echo "Merged $(jq '.runs | length' "$merged") SARIF runs" exit "$status" - name: Upload gosec results to GitHub Security @@ -401,7 +405,7 @@ jobs: if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.gosec.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: - sarif_file: gosec-results.sarif + sarif_file: ${{ runner.temp }}/gosec-results.sarif - name: Run Trivy vulnerability scanner (filesystem) id: trivy_fs @@ -415,7 +419,9 @@ jobs: scan-type: 'fs' scan-ref: '.' format: 'sarif' - output: 'trivy-results.sarif' + # $RUNNER_TEMP, not the checkout root (repo coding guideline: never + # save working files in the repository root). + output: '${{ runner.temp }}/trivy-results.sarif' severity: 'CRITICAL,HIGH' # Pin the Trivy binary independently of the action SHA. v0.36.0 is # the latest trivy-action release but bundles Trivy v0.70.0, which @@ -430,7 +436,7 @@ jobs: if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.trivy_fs.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: - sarif_file: 'trivy-results.sarif' + sarif_file: '${{ runner.temp }}/trivy-results.sarif' # Terraform IaC misconfiguration scanning. Replaces the deprecated # aquasecurity/tfsec-action, whose bundled HCL parser rejects Terraform @@ -452,7 +458,9 @@ jobs: scan-type: 'config' scan-ref: 'terraform/' format: 'sarif' - output: 'trivy-config-results.sarif' + # $RUNNER_TEMP, not the checkout root (repo coding guideline: never + # save working files in the repository root). + output: '${{ runner.temp }}/trivy-config-results.sarif' severity: 'CRITICAL,HIGH' # Same pinned Trivy binary as the filesystem scan above (>= v0.72.0 # avoids the adaptDefaultTags panic on null default_tags vars). @@ -463,7 +471,7 @@ jobs: if: always() && steps.checkout.outcome == 'success' && steps.setup_go.outcome == 'success' && steps.trivy_iac.outcome != 'skipped' uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: - sarif_file: 'trivy-config-results.sarif' + sarif_file: '${{ runner.temp }}/trivy-config-results.sarif' # Distinct category so this IaC analysis does not overwrite the # filesystem Trivy analysis uploaded above (both report as "Trivy"). category: 'trivy-iac'