From 1e89328fee9859ee4d7428166501fa31f47e0e6a Mon Sep 17 00:00:00 2001 From: Claude Code Date: Wed, 11 Nov 2026 12:41:26 +0100 Subject: [PATCH] =?UTF-8?q?fix(ci):=20begr=C3=A4nsa=20gitleaks=20i=20secur?= =?UTF-8?q?ity-workflowen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Samma riktade ändring som den kanoniska mallen (admin/siax-templates#205): fullhistorikskanningen (`git log -p --full-history --all`) körde på varje PR och push utan tidsgräns och kunde äta en delad runner-värd i timmar. - PR/push: blockerande "gitleaks commit range" över bara de införda commitarna (git-läge, --log-opts base..head, max 500 med varning). - Fullhistorik bara på schedule/workflow_dispatch med 40 min budget. - timeout-minutes på scan-jobbet, CPU/minne-tak och --redact på gitleaks-containrarna, kvarlämnade containrar dödas. Workflow-namn, job-id, runs-on och övriga steg är oförändrade, så krävda kontexter påverkas inte. Ändringen är maskinellt kontrollerad (YAML, bash -n per steg, invarianter för jobb, runs-on och stegordning). Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/security.yml | 87 +++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/security.yml b/.gitea/workflows/security.yml index 01961af..05232eb 100644 --- a/.gitea/workflows/security.yml +++ b/.gitea/workflows/security.yml @@ -26,6 +26,7 @@ on: pull_request: {} schedule: - cron: "17 2 * * *" + workflow_dispatch: {} permissions: { contents: read } # N6 (server-config ci/jobbstorm-2026-11-10 §4): en ny commit på samma PR/gren avbryter den inaktuella körningen. concurrency: @@ -35,6 +36,8 @@ concurrency: jobs: scan: runs-on: ubuntu-latest + # Övre gräns: ett scannerjobb får aldrig äta en delad runner-värd. + timeout-minutes: 60 steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: { fetch-depth: 0 } @@ -62,8 +65,8 @@ jobs: - name: gitleaks secret scan run: | set +e - docker run --rm -v "$SCAN_VOLUME:/repo" -w /repo \ - zricethezav/gitleaks:v8.30.1 detect --no-git --source /repo --no-banner --exit-code 1 > /tmp/scan.log 2>&1 + docker run --rm --cpus 2 --memory 4g -v "$SCAN_VOLUME:/repo" -w /repo \ + zricethezav/gitleaks:v8.30.1 detect --no-git --source /repo --no-banner --redact --exit-code 1 > /tmp/scan.log 2>&1 rc=$? set -e tail -n 120 /tmp/scan.log @@ -71,16 +74,81 @@ jobs: 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 - # Historiken scannas informativt. Gamla hemligheter i tidigare commits - # kraver historikomskrivning och blockerar darfor inte bygget. - - name: gitleaks history informational - continue-on-error: true + # gitleaks over just de commits som PR:en eller pushen inför. Blockerar på + # hemligheter som introduceras i intervallet, även om de raderas senare i + # samma PR (de finns kvar i historiken efter merge). Git-läget med + # --log-opts skannar bara tillagda rader, så en PR som RADERAR en gammal + # hemlighet fälls inte, och .gitleaks.toml/.gitleaksignore i repot gäller. + # Fullhistoriken körs bara nattligt/manuellt (nästa steg): en full + # `git log -p --all` per PR tog timmar och sänkte runner-värden + # (server10, 2026-11-11). + - name: gitleaks commit range + if: github.event_name == 'pull_request' || github.event_name == 'push' + timeout-minutes: 15 + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + BEFORE_SHA: ${{ github.event.before }} run: | - docker run --rm -v "$SCAN_VOLUME:/repo" -w /repo \ + set -eu + test -d .git || { echo "::error::ingen .git i $PWD"; exit 1; } + head="${PR_HEAD_SHA:-$GITHUB_SHA}" + base="" + if [ "$EVENT_NAME" = "pull_request" ] && [ -n "${BASE_SHA:-}" ]; then + base=$(git merge-base "$BASE_SHA" "$head" 2>/dev/null || echo "$BASE_SHA") + elif [ -n "${BEFORE_SHA:-}" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ] \ + && git cat-file -e "${BEFORE_SHA}^{commit}" 2>/dev/null; then + base="$BEFORE_SHA" + fi + MAX=500 + if [ -n "$base" ]; then + count=$(git rev-list --count "$base..$head") + echo "intervall $base..$head: $count commits" + if [ "$count" -eq 0 ]; then echo "inga nya commits i intervallet"; exit 0; fi + if [ "$count" -gt "$MAX" ]; then + echo "::warning::intervallet har $count commits; skannar de $MAX senaste. Resten täcks av den nattliga fullhistorikskanningen." + fi + logopts="-n $MAX $base..$head" + else + echo "::notice::inget jämförbart föregående läge (ny gren eller omskriven historik); skannar head-commiten. Fullhistoriken täcks nattligt." + logopts="-n 1 $head" + fi + name="siax-gitleaks-range-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + set +e + timeout --signal=TERM 12m docker run --rm --name "$name" --cpus 2 --memory 4g \ + -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 --log-opts="$logopts" \ + --no-banner --redact --exit-code 1 > /tmp/scan.log 2>&1 + rc=$? + set -e + docker kill "$name" >/dev/null 2>&1 || true + tail -n 120 /tmp/scan.log + if [ $rc -eq 0 ]; then echo "gitleaks commit range ren"; exit 0; fi + if [ $rc -eq 1 ]; then echo "::error::gitleaks commit range hittade fynd i införda commits"; exit 1; fi + if [ $rc -eq 124 ]; then echo "::error::gitleaks commit range nådde tidsgränsen - intervallet är EJ skannat"; exit 1; fi + echo "::warning::gitleaks commit range kunde inte köras (rc=$rc) - verktygsfel, inte fynd"; exit 0 + + # Hela historiken scannas informativt, bara nattligt eller manuellt och + # med tidsbudget. Gamla hemligheter i tidigare commits kräver + # historikomskrivning och blockerar därför inte bygget. + - name: gitleaks history informational + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + timeout-minutes: 45 + continue-on-error: true # ci2-allow-swallowed-failure: historik-gitleaks informativt per kanonisk security.yml + run: | + name="siax-gitleaks-history-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + rc=0 + timeout --signal=TERM 40m docker run --rm --name "$name" --cpus 2 --memory 6g \ + -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 \ - || echo "::notice::historiska traffar loggas informativt" + zricethezav/gitleaks:v8.30.1 detect --source /repo --no-banner --redact --exit-code 1 || rc=$? + docker kill "$name" >/dev/null 2>&1 || true + if [ "$rc" -eq 124 ]; then echo "::warning::fullhistorikskanningen nådde tidsbudgeten (40 min) - historiken är EJ fullständigt skannad"; fi + if [ "$rc" -ne 0 ]; then echo "::notice::historiska träffar eller avbrott loggas informativt (rc=$rc)"; fi + # Trivy filsystem, blockerar pa HIGH och CRITICAL sarbarheter och hemligheter (SUP-*) - name: Trivy filesystem scan @@ -142,4 +210,5 @@ jobs: - name: Remove scan volume if: always() run: | + for c in $(docker ps -q --filter "name=siax-gitleaks-.*-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"); do docker kill "$c" >/dev/null 2>&1 || true; done docker volume rm -f "${SCAN_VOLUME:-none}" >/dev/null 2>&1 || true