From 1e422b07cdfddbfe97ed680c0c27058efe640186 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 11 Jul 2026 16:21:36 +0900 Subject: [PATCH] fix(secret-scan): limit default-branch gitleaks history scope --- .github/workflows/secret-scan.yml | 32 ++++++++++--------- .../test_required_workflow_queue_contract.py | 10 ++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index d785546bd..9e081a237 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -9,7 +9,8 @@ # # Coverage split (mirrors the removed local behaviour): # - pull_request : scan only the PR's new commits (base..head) — fast, diff-scoped -# - schedule/push: scan the FULL git history — catches secrets committed earlier +# - schedule/push: scan the current protected branch history — catches secrets +# committed earlier without importing unrelated fetched remote branch refs. # # Tool license: gitleaks core is MIT. We download the pinned release BINARY # (checksum-verified) rather than gitleaks-action so no org license key is @@ -76,6 +77,7 @@ jobs: IS_PR: ${{ github.event_name == 'pull_request' }} BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} + CURRENT_SHA: ${{ github.sha }} run: | set +e config_args=() @@ -84,22 +86,22 @@ jobs: fi if [ "${IS_PR}" = "true" ]; then # Diff-scoped: only the commits this PR introduces. - ./gitleaks git . \ - "${config_args[@]}" \ - --log-opts="${BASE_SHA}..${HEAD_SHA}" \ - --redact \ - --report-format sarif \ - --report-path gitleaks-results.sarif \ - --exit-code 2 + log_opts="${BASE_SHA}..${HEAD_SHA}" + echo "::notice::gitleaks scanning pull request commit range ${log_opts}." else - # Full git history on schedule / push to a protected branch. - ./gitleaks git . \ - "${config_args[@]}" \ - --redact \ - --report-format sarif \ - --report-path gitleaks-results.sarif \ - --exit-code 2 + # Full history reachable from the protected-branch HEAD only. A full + # checkout may contain unrelated remote branch refs; scanning all of + # them reopens stale non-main fixture findings on the main analysis. + log_opts="${CURRENT_SHA}" + echo "::notice::gitleaks scanning protected branch history reachable from ${log_opts}; unrelated remote refs are excluded." fi + ./gitleaks git . \ + "${config_args[@]}" \ + --log-opts="${log_opts}" \ + --redact \ + --report-format sarif \ + --report-path gitleaks-results.sarif \ + --exit-code 2 echo "rc=$?" >> "$GITHUB_OUTPUT" set -e - name: Summarize redacted gitleaks findings diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 51646bae0..14a080b28 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -229,6 +229,16 @@ def test_security_scan_allows_repositories_without_supported_lockfiles() -> None assert "test -s new-results.json" in workflow +def test_secret_scan_push_limits_gitleaks_to_current_branch_history() -> None: + workflow = workflow_text("secret-scan.yml") + + assert 'CURRENT_SHA: ${{ github.sha }}' in workflow + assert 'log_opts="${BASE_SHA}..${HEAD_SHA}"' in workflow + assert 'log_opts="${CURRENT_SHA}"' in workflow + assert '--log-opts="${log_opts}"' in workflow + assert "unrelated remote refs are excluded" in workflow + + def test_osv_pr_workflow_has_one_startup_safe_scan_args_block() -> None: workflow = workflow_text("osv-scanner-pr.yml") concurrency_contract = workflow.split("permissions:", 1)[0]