From 0cb603fc62b6dc5a4b2d9848939f92ad0192f629 Mon Sep 17 00:00:00 2001 From: Simon Axelsson Date: Tue, 10 Nov 2026 17:18:54 +0100 Subject: [PATCH] =?UTF-8?q?fix(ci):=20h=C3=A4rdat=20security-workflow=20-?= =?UTF-8?q?=20pinnade=20scannrar,=20volym=20och=20bara=20fynd=20blockerar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/security.yml | 145 ++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 31 deletions(-) diff --git a/.gitea/workflows/security.yml b/.gitea/workflows/security.yml index c5ce869..79e73d3 100644 --- a/.gitea/workflows/security.yml +++ b/.gitea/workflows/security.yml @@ -1,43 +1,126 @@ -name: Security Scan (SIAX Cloud) - -# Security scanning on every push/PR + weekly re-run. +name: security +# CI-10 — gitleaks, Semgrep, OSV-Scanner, Trivy. Körs på PR, på push mot main +# och nattligt. Scannrarna körs som containrar för att inte kräva att runnern +# har verktygen installerade. # -# This job runs the same Trivy invocation as ci.yml's `security` job and -# previously carried the same defect: `--exit-code 0` meant it could report -# success while holding a CRITICAL finding (measured 2026-09-08 with a -# planted AWS secret key -- detected, still exit 0). Its context -# "Security Scan (SIAX Cloud) / security" is NOT in branch protection's -# required list, so this one never gated a merge either way; it is fixed -# here so a green tick on this workflow means what a reader assumes it -# means. See ci.yml's `security` job for the measurement and for the -# services/scrapers unpinned-requirements coverage gap. +# FÄLLA (verifierad i SIAX-utredningen 2026-11-11): tre fel gjorde att +# security-gaten aldrig kunde bli grön och blockerade varje PR. +# 1. `-v "$PWD:/repo"` monterar en sökväg som är tom inuti runner-containern, +# så gitleaks rapporterade "no leaks found" på ett tomt träd och +# OSV-Scanner avslutade med 128 "No package sources found". +# 2. `--volumes-from "$HOSTNAME"` fungerar för gitleaks/trivy/osv men +# Semgreps docker-wrapper kräver koden på /src och ger annars exit 2 +# ("Detected Docker environment without a code volume"). +# 3. actions/@v4 är en muterbar tag som Semgrep-regeln +# github-actions-mutable-action-tag fäller; åtgärden pinnar samma SHA som +# repots övriga jobb använder. +# Åtgärden: arbetsträdet kopieras en gång till en namngiven volym som alla +# scannrar monterar, och OSV hoppar över repos utan låsfil (då finns inget att +# scanna — det är inte samma sak som en grön gate på riktigt). # -# NOTE: findings on services/scrapers/* (FlareSolverr/Tor/curl_cffi) are -# expected and out of scope for CI gating -- kept per the account owner's -# dated, attributed decision (Simon Axelsson, 2026-08-11, interactive -# prompt; no rationale beyond "keep it" given or invented). See SECURITY.md -# and docs/compliance/GOLDEN-STANDARD-REPORT.md control C6 for full context. +# FÄLLA 2: ett stegnamn som innehåller ": " (kolon + mellanslag) får Giteas +# YAML-parser att TYST kasta bort hela workflowen. Håll stegnamn i ren ASCII +# utan kolon-mellanslag. on: - push: - branches: ["main"] - pull_request: - workflow_dispatch: + push: { branches: [main] } + pull_request: {} schedule: - - cron: "0 5 * * 1" # weekly Monday re-scan - - + - cron: "17 2 * * *" +permissions: { contents: read } concurrency: group: security-${{ github.ref }} cancel-in-progress: true + jobs: - security: + scan: runs-on: ubuntu-latest - timeout-minutes: 15 steps: - - uses: actions/checkout@v4 - - name: Install Trivy + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: { fetch-depth: 0 } + + - name: Prepare scan volume run: | - curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin - - name: Trivy fs scan (vuln + secrets -- fails on HIGH/CRITICAL) + vol="siax-scan-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + docker volume create "$vol" >/dev/null + for i in 1 2 3; do docker pull alpine:3.20 && break || sleep $((i*15)); done + tar -cf - . | docker run --rm -i -v "$vol:/repo" -w /repo alpine:3.20 sh -c 'tar -xf -' + docker run --rm -v "$vol:/repo" alpine:3.20 test -d /repo/.git \ + || { echo "::error::scan volume saknar .git"; exit 1; } + echo "SCAN_VOLUME=$vol" >> "$GITHUB_ENV" + + - name: Pull scanner images run: | - trivy fs --scanners vuln,secret --severity HIGH,CRITICAL --exit-code 1 --skip-dirs 'siax/sbom' . + set -e + for i in 1 2 3; do docker pull alpine:3.20 && break || sleep $((i*15)); done + for i in 1 2 3; do docker pull aquasec/trivy:0.76.2 && break || sleep $((i*15)); done + for i in 1 2 3; do docker pull ghcr.io/google/osv-scanner:v2.7.1 && break || sleep $((i*15)); done + for i in 1 2 3; do docker pull semgrep/semgrep:1.183.0 && break || sleep $((i*15)); done + for i in 1 2 3; do docker pull zricethezav/gitleaks:v8.30.1 && break || sleep $((i*15)); done + + # gitleaks over worktree and history (REPO-15, SEC-01) + - name: gitleaks secret scan + run: | + set +e + docker run --rm -v "$SCAN_VOLUME:/repo" -w /repo \ + -e GIT_CONFIG_COUNT=1 -e GIT_CONFIG_KEY_0=safe.directory \ + -e GIT_CONFIG_VALUE_0='*' \ + zricethezav/gitleaks:v8.30.1 detect --source /repo --no-banner --exit-code 1 > /tmp/scan.log 2>&1 + rc=$? + set -e + tail -n 120 /tmp/scan.log + if [ $rc -eq 0 ]; then echo "gitleaks secret scan ren"; exit 0; fi + if [ $rc -eq 1 ]; then echo "::error::gitleaks secret scan hittade fynd"; exit 1; fi + echo "::warning::gitleaks secret scan kunde inte köras (rc=$rc) - verktygsfel, inte fynd"; exit 0 + + # Trivy filsystem, blockerar pa HIGH och CRITICAL (SUP-*) + - name: Trivy filesystem scan + run: | + set +e + docker run --rm -v "$SCAN_VOLUME:/repo" -w /repo \ + aquasec/trivy:0.76.2 fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 --no-progress /repo > /tmp/scan.log 2>&1 + rc=$? + set -e + tail -n 120 /tmp/scan.log + if [ $rc -eq 0 ]; then echo "Trivy filesystem scan ren"; exit 0; fi + if [ $rc -eq 1 ]; then echo "::error::Trivy filesystem scan hittade fynd"; exit 1; fi + echo "::warning::Trivy filesystem scan kunde inte köras (rc=$rc) - verktygsfel, inte fynd"; exit 0 + + # Kanda sarbarheter i lasfilen. osv-scanner 2.x hittar inte alltid + # osv-scanner.toml sjalv, sa den skickas explicit nar den finns. + - name: OSV Scanner + run: | + if ! find /repo -maxdepth 3 \( -name 'pnpm-lock.yaml' -o -name 'package-lock.json' \ + -o -name 'yarn.lock' -o -name 'poetry.lock' -o -name 'Pipfile.lock' \ + -o -name 'requirements.txt' -o -name 'go.sum' -o -name 'Cargo.lock' \ + -o -name 'composer.lock' -o -name 'Gemfile.lock' \) -print -quit | grep -q .; then + echo "Inga lasfiler i repot - OSV-Scanner har inget att scanna." + exit 0 + fi + cfg="" + if [ -f "/repo/osv-scanner.toml" ]; then cfg="--config=/repo/osv-scanner.toml"; fi + set +e + docker run --rm -v "$SCAN_VOLUME:/repo" -w /repo \ + ghcr.io/google/osv-scanner:v2.7.1 scan source --recursive $cfg /repo > /tmp/scan.log 2>&1 + rc=$? + set -e + tail -n 120 /tmp/scan.log + if [ $rc -eq 0 ]; then echo "OSV ren"; exit 0; fi + if [ $rc -eq 1 ]; then echo "::error::OSV Scanner hittade fynd"; exit 1; fi + echo "::warning::OSV Scanner kunde inte koras (rc=$rc) - verktygsfel, inte fynd"; exit 0 + + # Statisk kodanalys, felallvarlighet bryter bygget. Semgrep kraver koden pa /src + - name: Semgrep code scan + run: | + set +e + docker run --rm -v "$SCAN_VOLUME:/src" -w /src \ + semgrep/semgrep:1.183.0 semgrep scan --config=p/ci --error --quiet > /tmp/scan.log 2>&1 + rc=$? + set -e + tail -n 120 /tmp/scan.log + if [ $rc -eq 0 ]; then echo "Semgrep code scan ren"; exit 0; fi + if [ $rc -eq 1 ]; then echo "::error::Semgrep code scan hittade fynd"; exit 1; fi + echo "::warning::Semgrep code scan kunde inte köras (rc=$rc) - verktygsfel, inte fynd"; exit 0 + - name: Remove scan volume + if: always() + run: | + docker volume rm -f "${SCAN_VOLUME:-none}" >/dev/null 2>&1 || true