From 82a33f6d3249046a531a001b583adfc9a2a3b8f1 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 15:39:31 +0100 Subject: [PATCH 01/27] feat: add secret-scan and trufflehog-scan actions Extracts the secret_scanner and trufflehog-package-analysis jobs from the flutter-security-checks workflow into reusable composite actions. --- secret-scan/action.yml | 18 ++++++++++++++++++ trufflehog-scan/action.yml | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 secret-scan/action.yml create mode 100644 trufflehog-scan/action.yml diff --git a/secret-scan/action.yml b/secret-scan/action.yml new file mode 100644 index 0000000..b737943 --- /dev/null +++ b/secret-scan/action.yml @@ -0,0 +1,18 @@ +name: 'Secret Scan' +description: 'Scans source files for secrets using max/secret-scan.' +inputs: + include-path: + description: 'Path to include in the scan.' + required: false + default: '' + exclude-path: + description: 'Path to exclude from the scan.' + required: false + default: '' +runs: + using: "composite" + steps: + - uses: max/secret-scan@master + with: + include_path: ${{ inputs.include-path }} + exclude_path: ${{ inputs.exclude-path }} diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml new file mode 100644 index 0000000..eb2dc2e --- /dev/null +++ b/trufflehog-scan/action.yml @@ -0,0 +1,33 @@ +name: 'TruffleHog Scan' +description: 'Scans for verified secrets using TruffleHog OSS.' +inputs: + base: + description: 'Base branch to compare against. Defaults to the repository default branch.' + required: false + default: '' + exclude-paths: + description: 'Path to a file listing paths to exclude from the scan.' + required: false + default: '' + include-paths: + description: 'Path to a file listing paths to include in the scan.' + required: false + default: '' +runs: + using: "composite" + steps: + - name: Set exclude paths + if: inputs.exclude-paths != '' + shell: bash + run: echo 'TH_EXCLUDE_PATHS=--exclude-paths=${{ inputs.exclude-paths }}' >> $GITHUB_ENV + - name: Set include paths + if: inputs.include-paths != '' + shell: bash + run: echo 'TH_INCLUDE_PATHS=--include-paths=${{ inputs.include-paths }}' >> $GITHUB_ENV + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@main + with: + path: ./ + base: ${{ inputs.base || github.event.repository.default_branch }} + head: HEAD + extra_args: --debug --only-verified ${{ env.TH_EXCLUDE_PATHS }} ${{ env.TH_INCLUDE_PATHS }} From b832fdd083ff0a22412f6e0eb57f5e5717acbfd5 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 15:58:50 +0100 Subject: [PATCH 02/27] fix: install trufflehog binary instead of Docker action Docker-based trufflesecurity/trufflehog@main fails on k8s runners because the workspace volume mount is not accessible inside the container. Install the binary directly and run it via a shell script. --- trufflehog-scan/action.yml | 25 ++++++++++------------ trufflehog-scan/scripts/trufflehog_scan.sh | 15 +++++++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 trufflehog-scan/scripts/trufflehog_scan.sh diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index eb2dc2e..bbbff70 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -2,7 +2,7 @@ name: 'TruffleHog Scan' description: 'Scans for verified secrets using TruffleHog OSS.' inputs: base: - description: 'Base branch to compare against. Defaults to the repository default branch.' + description: 'Base branch to compare against. Defaults to the PR base or repository default branch.' required: false default: '' exclude-paths: @@ -16,18 +16,15 @@ inputs: runs: using: "composite" steps: - - name: Set exclude paths - if: inputs.exclude-paths != '' + - name: Install TruffleHog shell: bash - run: echo 'TH_EXCLUDE_PATHS=--exclude-paths=${{ inputs.exclude-paths }}' >> $GITHUB_ENV - - name: Set include paths - if: inputs.include-paths != '' + run: curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + - name: Run TruffleHog shell: bash - run: echo 'TH_INCLUDE_PATHS=--include-paths=${{ inputs.include-paths }}' >> $GITHUB_ENV - - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@main - with: - path: ./ - base: ${{ inputs.base || github.event.repository.default_branch }} - head: HEAD - extra_args: --debug --only-verified ${{ env.TH_EXCLUDE_PATHS }} ${{ env.TH_INCLUDE_PATHS }} + env: + INPUT_BASE: ${{ inputs.base }} + INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} + INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} + GITHUB_BASE_REF: ${{ github.base_ref }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh new file mode 100644 index 0000000..9773d98 --- /dev/null +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Resolve the base commit to scan from +BASE="${INPUT_BASE:-}" +if [[ -z "$BASE" ]]; then + REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" + BASE="$(git rev-parse "origin/$REF")" +fi + +ARGS="--only-verified --fail --no-update" +[[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" +[[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" + +trufflehog git file://. --since-commit "$BASE" --branch HEAD $ARGS From 61cdc6a3a4115853d600d98d9d4763f9aa0df89a Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:30:39 +0100 Subject: [PATCH 03/27] fix: install trufflehog to RUNNER_TEMP/bin (writable on k8s runner) /usr/local/bin is not writable on the k8s self-hosted runner. RUNNER_TEMP is always writable; adding it to GITHUB_PATH makes trufflehog available in subsequent steps. --- trufflehog-scan/action.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index bbbff70..abd755c 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -18,7 +18,10 @@ runs: steps: - name: Install TruffleHog shell: bash - run: curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + run: | + mkdir -p "$RUNNER_TEMP/bin" + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b "$RUNNER_TEMP/bin" + echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" - name: Run TruffleHog shell: bash env: From f55a32613404079301793437efa0f31fb9062048 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:39:05 +0100 Subject: [PATCH 04/27] fix: revert to official trufflesecurity/trufflehog Docker action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Docker mounting works fine on the k8s runner. The actual failure was a git safe.directory mismatch — git 2.35.2+ refuses repos owned by a different uid inside the container. Adding a safe.directory config step before the action resolves this. Also adds a head input and simplifies path args inline. --- trufflehog-scan/action.yml | 27 +++++++++++----------- trufflehog-scan/scripts/trufflehog_scan.sh | 15 ------------ 2 files changed, 13 insertions(+), 29 deletions(-) delete mode 100644 trufflehog-scan/scripts/trufflehog_scan.sh diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index abd755c..875bd2f 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -5,6 +5,10 @@ inputs: description: 'Base branch to compare against. Defaults to the PR base or repository default branch.' required: false default: '' + head: + description: 'Head commit or branch to scan to. Defaults to HEAD.' + required: false + default: 'HEAD' exclude-paths: description: 'Path to a file listing paths to exclude from the scan.' required: false @@ -16,18 +20,13 @@ inputs: runs: using: "composite" steps: - - name: Install TruffleHog - shell: bash - run: | - mkdir -p "$RUNNER_TEMP/bin" - curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b "$RUNNER_TEMP/bin" - echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" - - name: Run TruffleHog + - name: Configure git safe directory shell: bash - env: - INPUT_BASE: ${{ inputs.base }} - INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} - INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} - GITHUB_BASE_REF: ${{ github.base_ref }} - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@main + with: + path: ./ + base: ${{ inputs.base || github.event.repository.default_branch }} + head: ${{ inputs.head }} + extra_args: --only-verified ${{ inputs.exclude-paths != '' && format('--exclude-paths={0}', inputs.exclude-paths) || '' }} ${{ inputs.include-paths != '' && format('--include-paths={0}', inputs.include-paths) || '' }} diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh deleted file mode 100644 index 9773d98..0000000 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Resolve the base commit to scan from -BASE="${INPUT_BASE:-}" -if [[ -z "$BASE" ]]; then - REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" - BASE="$(git rev-parse "origin/$REF")" -fi - -ARGS="--only-verified --fail --no-update" -[[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" -[[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" - -trufflehog git file://. --since-commit "$BASE" --branch HEAD $ARGS From f190f1daaae1a95e7213ba64fa205c6a591b87e1 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:44:27 +0100 Subject: [PATCH 05/27] fix: write safe.directory into container HOME gitconfig The runner mounts RUNNER_TEMP/_github_home as /github/home inside the Docker container and sets HOME to that path. Writing safe.directory /tmp into that gitconfig makes git inside the TruffleHog container trust the mounted workspace. --- trufflehog-scan/action.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 875bd2f..8d786cc 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -20,9 +20,11 @@ inputs: runs: using: "composite" steps: - - name: Configure git safe directory + - name: Configure git safe directory for TruffleHog container shell: bash - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + run: | + mkdir -p "$RUNNER_TEMP/_github_home" + git config -f "$RUNNER_TEMP/_github_home/.gitconfig" --add safe.directory /tmp - name: TruffleHog OSS uses: trufflesecurity/trufflehog@main with: From 964e425429e560bb88504f1c29b83dccc4453aef Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:49:05 +0100 Subject: [PATCH 06/27] fix: run trufflehog Docker image with explicit workspace mount Use docker run directly with -v $GITHUB_WORKSPACE:/repo so the absolute path is mounted explicitly instead of relying on the official action's -v .:/tmp which doesn't resolve correctly on this runner. --- trufflehog-scan/action.yml | 19 ++++++++----------- trufflehog-scan/scripts/trufflehog_scan.sh | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 trufflehog-scan/scripts/trufflehog_scan.sh diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 8d786cc..9d21fcb 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -20,15 +20,12 @@ inputs: runs: using: "composite" steps: - - name: Configure git safe directory for TruffleHog container + - name: Run TruffleHog shell: bash - run: | - mkdir -p "$RUNNER_TEMP/_github_home" - git config -f "$RUNNER_TEMP/_github_home/.gitconfig" --add safe.directory /tmp - - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@main - with: - path: ./ - base: ${{ inputs.base || github.event.repository.default_branch }} - head: ${{ inputs.head }} - extra_args: --only-verified ${{ inputs.exclude-paths != '' && format('--exclude-paths={0}', inputs.exclude-paths) || '' }} ${{ inputs.include-paths != '' && format('--include-paths={0}', inputs.include-paths) || '' }} + env: + INPUT_BASE: ${{ inputs.base }} + INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} + INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} + GITHUB_BASE_REF: ${{ github.base_ref }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh new file mode 100644 index 0000000..58e3559 --- /dev/null +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +BASE="${INPUT_BASE:-}" +if [[ -z "$BASE" ]]; then + REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" + BASE="$(git rev-parse "origin/$REF")" +fi + +ARGS="--only-verified --fail --no-update" +[[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" +[[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" + +docker run --rm \ + -v "$GITHUB_WORKSPACE:/repo" \ + ghcr.io/trufflesecurity/trufflehog:latest \ + git file:///repo \ + --since-commit "$BASE" \ + --branch HEAD \ + $ARGS From 9d9c0c71c063c2d93802c762dcf7a3491a442514 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:51:43 +0100 Subject: [PATCH 07/27] =?UTF-8?q?fix:=20use=20github=20scanner=20mode=20?= =?UTF-8?q?=E2=80=94=20no=20volume=20mount=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run trufflehog in 'github' mode so it fetches directly from the GitHub API using GITHUB_TOKEN. Avoids all Docker volume mounting entirely. --- trufflehog-scan/scripts/trufflehog_scan.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 58e3559..aade8c8 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -12,9 +12,10 @@ ARGS="--only-verified --fail --no-update" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" docker run --rm \ - -v "$GITHUB_WORKSPACE:/repo" \ ghcr.io/trufflesecurity/trufflehog:latest \ - git file:///repo \ - --since-commit "$BASE" \ - --branch HEAD \ + github \ + --repo="https://github.com/$GITHUB_REPOSITORY" \ + --token="$GITHUB_TOKEN" \ + --branch="$GITHUB_HEAD_REF" \ + --since-commit="$BASE" \ $ARGS From 80b4622ef65b8db9c530300eae89a1b257057ee0 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 16:59:27 +0100 Subject: [PATCH 08/27] Fix TruffleHog scan to use github scanner mode with PR number Use --pr flag with the pull request number so TruffleHog fetches directly via GitHub API, avoiding Docker volume mount issues on k8s runners. --- trufflehog-scan/action.yml | 1 + trufflehog-scan/scripts/trufflehog_scan.sh | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 9d21fcb..fd96695 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -28,4 +28,5 @@ runs: INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index aade8c8..b349787 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -16,6 +16,5 @@ docker run --rm \ github \ --repo="https://github.com/$GITHUB_REPOSITORY" \ --token="$GITHUB_TOKEN" \ - --branch="$GITHUB_HEAD_REF" \ - --since-commit="$BASE" \ + --pr="$GITHUB_PR_NUMBER" \ $ARGS From df152a85cd45c1d9b14bce562ea2602ee2ffa5be Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 17:03:35 +0100 Subject: [PATCH 09/27] Switch TruffleHog to git subcommand with remote clone Use 'trufflehog git ' with --since-commit and --branch instead of the github subcommand, which doesn't support PR-scoped scanning in the OSS version. This clones directly from GitHub via the API token and avoids Docker volume mount issues on k8s runners. --- trufflehog-scan/action.yml | 2 +- trufflehog-scan/scripts/trufflehog_scan.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index fd96695..77a6969 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -28,5 +28,5 @@ runs: INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_HEAD_REF: ${{ github.head_ref }} run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index b349787..12fafae 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -13,8 +13,8 @@ ARGS="--only-verified --fail --no-update" docker run --rm \ ghcr.io/trufflesecurity/trufflehog:latest \ - github \ - --repo="https://github.com/$GITHUB_REPOSITORY" \ - --token="$GITHUB_TOKEN" \ - --pr="$GITHUB_PR_NUMBER" \ + git \ + "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ + --since-commit="$BASE" \ + --branch="$GITHUB_HEAD_REF" \ $ARGS From d32f9a7053a5054110ba5ab0ac06915c9bff4680 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 17:14:09 +0100 Subject: [PATCH 10/27] Temporarily remove --only-verified for TruffleHog pattern-match test --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 12fafae..e012e40 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -7,7 +7,7 @@ if [[ -z "$BASE" ]]; then BASE="$(git rev-parse "origin/$REF")" fi -ARGS="--only-verified --fail --no-update" +ARGS="--fail --no-update" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" From d248778ef53717dd0b92d7c048c04e7d848e8082 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Mon, 16 Mar 2026 17:25:19 +0100 Subject: [PATCH 11/27] Add --no-verification to catch all pattern matches --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index e012e40..4608160 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -7,7 +7,7 @@ if [[ -z "$BASE" ]]; then BASE="$(git rev-parse "origin/$REF")" fi -ARGS="--fail --no-update" +ARGS="--no-verification --fail --no-update" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" From 2d418d31be5c91a511cbda5b220acdee0394fb98 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 06:29:57 +0100 Subject: [PATCH 12/27] Add trace logging to debug TruffleHog detection --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 4608160..d6a2d19 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -7,7 +7,7 @@ if [[ -z "$BASE" ]]; then BASE="$(git rev-parse "origin/$REF")" fi -ARGS="--no-verification --fail --no-update" +ARGS="--no-verification --fail --no-update --log-level=5" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" From cf89b6e8c5a3eb9fa4d302621f238884a87eef68 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 06:35:59 +0100 Subject: [PATCH 13/27] Restore --only-verified after testing --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index d6a2d19..12fafae 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -7,7 +7,7 @@ if [[ -z "$BASE" ]]; then BASE="$(git rev-parse "origin/$REF")" fi -ARGS="--no-verification --fail --no-update --log-level=5" +ARGS="--only-verified --fail --no-update" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" From 8a5fce0070f8c9dd7ce479d15f71d9bd0f7c7129 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 06:55:11 +0100 Subject: [PATCH 14/27] Emit inline PR annotations for TruffleHog findings Parse JSON output and emit ::error file=...,line=...:: annotations so findings appear inline in the PR diff view. --- trufflehog-scan/scripts/trufflehog_scan.sh | 39 ++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 12fafae..9ade555 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -7,14 +7,49 @@ if [[ -z "$BASE" ]]; then BASE="$(git rev-parse "origin/$REF")" fi -ARGS="--only-verified --fail --no-update" +ARGS="--only-verified --no-update --json" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" +TMPFILE=$(mktemp) +trap 'rm -f "$TMPFILE"' EXIT + docker run --rm \ ghcr.io/trufflesecurity/trufflehog:latest \ git \ "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ --since-commit="$BASE" \ --branch="$GITHUB_HEAD_REF" \ - $ARGS + $ARGS > "$TMPFILE" + +python3 - "$TMPFILE" << 'PYEOF' +import sys, json + +count = 0 +with open(sys.argv[1]) as f: + for line in f: + line = line.strip() + if not line: + continue + try: + d = json.loads(line) + except json.JSONDecodeError: + continue + git = d.get('SourceMetadata', {}).get('Data', {}).get('Git', {}) + file_path = git.get('file', '') + line_num = git.get('line', 1) + detector = d.get('DetectorName', 'Unknown') + verified = 'verified' if d.get('Verified', False) else 'unverified' + msg = f"TruffleHog [{detector}]: {verified} secret detected" + if file_path: + print(f"::error file={file_path},line={line_num}::{msg}") + else: + print(f"::error::{msg}") + count += 1 + +if count > 0: + print(f"TruffleHog found {count} secret(s).") + sys.exit(1) +else: + print("No secrets detected.") +PYEOF From 86c7b75db5a81084415f780409631db5e3bf8549 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 06:59:58 +0100 Subject: [PATCH 15/27] Temporarily tee JSON output for debugging --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 9ade555..b4dc144 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -20,7 +20,7 @@ docker run --rm \ "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ --since-commit="$BASE" \ --branch="$GITHUB_HEAD_REF" \ - $ARGS > "$TMPFILE" + $ARGS | tee "$TMPFILE" python3 - "$TMPFILE" << 'PYEOF' import sys, json From 0bbcaaa065c0d4dfe64fcaf445be3b8eb38d78d3 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:08:17 +0100 Subject: [PATCH 16/27] Remove debug tee, capture TruffleHog output to tempfile only --- trufflehog-scan/scripts/trufflehog_scan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index b4dc144..9ade555 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -20,7 +20,7 @@ docker run --rm \ "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ --since-commit="$BASE" \ --branch="$GITHUB_HEAD_REF" \ - $ARGS | tee "$TMPFILE" + $ARGS > "$TMPFILE" python3 - "$TMPFILE" << 'PYEOF' import sys, json From b14d13270f09dee59f8765f0f027e0aa8505a87e Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:15:34 +0100 Subject: [PATCH 17/27] Fix JSON key lookup to handle both camelCase and capitalized variants --- trufflehog-scan/scripts/trufflehog_scan.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 9ade555..406081f 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -35,9 +35,10 @@ with open(sys.argv[1]) as f: d = json.loads(line) except json.JSONDecodeError: continue - git = d.get('SourceMetadata', {}).get('Data', {}).get('Git', {}) - file_path = git.get('file', '') - line_num = git.get('line', 1) + src = d.get('SourceMetadata', {}).get('Data', {}) + git = src.get('Git', src.get('git', {})) + file_path = git.get('file', git.get('File', '')) + line_num = git.get('line', git.get('Line', 1)) or 1 detector = d.get('DetectorName', 'Unknown') verified = 'verified' if d.get('Verified', False) else 'unverified' msg = f"TruffleHog [{detector}]: {verified} secret detected" From 5fb3179472b42d153e198ebe573ea14eca6021bb Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:23:55 +0100 Subject: [PATCH 18/27] Use recursive search to find file/line in TruffleHog JSON output --- trufflehog-scan/scripts/trufflehog_scan.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 406081f..27e8eea 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -25,6 +25,17 @@ docker run --rm \ python3 - "$TMPFILE" << 'PYEOF' import sys, json +def find_git_metadata(node): + """Recursively search for the dict that contains a 'file' key.""" + if isinstance(node, dict): + if 'file' in node or 'File' in node: + return node + for v in node.values(): + result = find_git_metadata(v) + if result: + return result + return {} + count = 0 with open(sys.argv[1]) as f: for line in f: @@ -35,8 +46,7 @@ with open(sys.argv[1]) as f: d = json.loads(line) except json.JSONDecodeError: continue - src = d.get('SourceMetadata', {}).get('Data', {}) - git = src.get('Git', src.get('git', {})) + git = find_git_metadata(d.get('SourceMetadata', {})) file_path = git.get('file', git.get('File', '')) line_num = git.get('line', git.get('Line', 1)) or 1 detector = d.get('DetectorName', 'Unknown') From 019b1d29810ecee2c19c17927f593ab3f3c9ee6a Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:29:51 +0100 Subject: [PATCH 19/27] Debug: print SourceMetadata structure --- trufflehog-scan/scripts/trufflehog_scan.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 27e8eea..b54f772 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -46,6 +46,7 @@ with open(sys.argv[1]) as f: d = json.loads(line) except json.JSONDecodeError: continue + print(json.dumps(d.get('SourceMetadata')), file=sys.stderr) git = find_git_metadata(d.get('SourceMetadata', {})) file_path = git.get('file', git.get('File', '')) line_num = git.get('line', git.get('Line', 1)) or 1 From 398e863bd881a3adb1ecd404f20f00dc075f7f28 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:34:25 +0100 Subject: [PATCH 20/27] Remove debug print --- trufflehog-scan/scripts/trufflehog_scan.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index b54f772..27e8eea 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -46,7 +46,6 @@ with open(sys.argv[1]) as f: d = json.loads(line) except json.JSONDecodeError: continue - print(json.dumps(d.get('SourceMetadata')), file=sys.stderr) git = find_git_metadata(d.get('SourceMetadata', {})) file_path = git.get('file', git.get('File', '')) line_num = git.get('line', git.get('Line', 1)) or 1 From 29d15ce6badb8e1cf7a425434f24aa49ea0a0fb4 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:46:26 +0100 Subject: [PATCH 21/27] Mount workspace into TruffleHog container instead of pulling via token Use -v GITHUB_WORKSPACE:/repo and file:///repo so TruffleHog scans the already-checked-out repo. GITHUB_TOKEN is no longer required. --- trufflehog-scan/action.yml | 1 - trufflehog-scan/scripts/trufflehog_scan.sh | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 77a6969..9d21fcb 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -28,5 +28,4 @@ runs: INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GITHUB_HEAD_REF: ${{ github.head_ref }} run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 27e8eea..bab1c8e 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -15,11 +15,14 @@ TMPFILE=$(mktemp) trap 'rm -f "$TMPFILE"' EXIT docker run --rm \ + -v "$GITHUB_WORKSPACE:/repo" \ + -e GIT_CONFIG_COUNT=1 \ + -e GIT_CONFIG_KEY_0=safe.directory \ + -e GIT_CONFIG_VALUE_0=/repo \ ghcr.io/trufflesecurity/trufflehog:latest \ git \ - "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ + file:///repo \ --since-commit="$BASE" \ - --branch="$GITHUB_HEAD_REF" \ $ARGS > "$TMPFILE" python3 - "$TMPFILE" << 'PYEOF' From 755ce8058679a8c4feb49f4b2c3c2ab52706ba92 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 07:58:11 +0100 Subject: [PATCH 22/27] Switch TruffleHog to use trufflesecurity/trufflehog@main action The official Docker action gets the workspace mounted by GitHub's runner infrastructure directly, bypassing DinD. No GITHUB_TOKEN needed. --- trufflehog-scan/action.yml | 24 +++++--- trufflehog-scan/scripts/trufflehog_scan.sh | 69 ---------------------- 2 files changed, 16 insertions(+), 77 deletions(-) delete mode 100644 trufflehog-scan/scripts/trufflehog_scan.sh diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 9d21fcb..0e742fe 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -5,10 +5,6 @@ inputs: description: 'Base branch to compare against. Defaults to the PR base or repository default branch.' required: false default: '' - head: - description: 'Head commit or branch to scan to. Defaults to HEAD.' - required: false - default: 'HEAD' exclude-paths: description: 'Path to a file listing paths to exclude from the scan.' required: false @@ -20,12 +16,24 @@ inputs: runs: using: "composite" steps: - - name: Run TruffleHog + - name: Compute base SHA + id: base shell: bash env: INPUT_BASE: ${{ inputs.base }} - INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} - INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" + run: | + BASE="${INPUT_BASE:-}" + if [[ -z "$BASE" ]]; then + REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" + BASE="$(git rev-parse "origin/$REF")" + fi + echo "sha=$BASE" >> "$GITHUB_OUTPUT" + + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@main + with: + path: ./ + base: ${{ steps.base.outputs.sha }} + extra_args: --only-verified --fail diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh deleted file mode 100644 index bab1c8e..0000000 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -BASE="${INPUT_BASE:-}" -if [[ -z "$BASE" ]]; then - REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" - BASE="$(git rev-parse "origin/$REF")" -fi - -ARGS="--only-verified --no-update --json" -[[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" -[[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" - -TMPFILE=$(mktemp) -trap 'rm -f "$TMPFILE"' EXIT - -docker run --rm \ - -v "$GITHUB_WORKSPACE:/repo" \ - -e GIT_CONFIG_COUNT=1 \ - -e GIT_CONFIG_KEY_0=safe.directory \ - -e GIT_CONFIG_VALUE_0=/repo \ - ghcr.io/trufflesecurity/trufflehog:latest \ - git \ - file:///repo \ - --since-commit="$BASE" \ - $ARGS > "$TMPFILE" - -python3 - "$TMPFILE" << 'PYEOF' -import sys, json - -def find_git_metadata(node): - """Recursively search for the dict that contains a 'file' key.""" - if isinstance(node, dict): - if 'file' in node or 'File' in node: - return node - for v in node.values(): - result = find_git_metadata(v) - if result: - return result - return {} - -count = 0 -with open(sys.argv[1]) as f: - for line in f: - line = line.strip() - if not line: - continue - try: - d = json.loads(line) - except json.JSONDecodeError: - continue - git = find_git_metadata(d.get('SourceMetadata', {})) - file_path = git.get('file', git.get('File', '')) - line_num = git.get('line', git.get('Line', 1)) or 1 - detector = d.get('DetectorName', 'Unknown') - verified = 'verified' if d.get('Verified', False) else 'unverified' - msg = f"TruffleHog [{detector}]: {verified} secret detected" - if file_path: - print(f"::error file={file_path},line={line_num}::{msg}") - else: - print(f"::error::{msg}") - count += 1 - -if count > 0: - print(f"TruffleHog found {count} secret(s).") - sys.exit(1) -else: - print("No secrets detected.") -PYEOF From 89da3a065c0c811e7f7dd9fdde0acb6b45fd1684 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 08:04:38 +0100 Subject: [PATCH 23/27] Remove --fail from extra_args, the action already passes it --- trufflehog-scan/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 0e742fe..a2e50fc 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -36,4 +36,4 @@ runs: with: path: ./ base: ${{ steps.base.outputs.sha }} - extra_args: --only-verified --fail + extra_args: --only-verified From 3706ae8232ea1a90aaaf3da994e9aa1385ea74c3 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 08:16:53 +0100 Subject: [PATCH 24/27] Revert TruffleHog to remote clone approach Replaces the failed DinD volume-mount experiment with the working remote git clone strategy: TruffleHog clones the repo via oauth2 token URL, scans since the PR base commit, and emits inline GitHub Actions annotations via Python JSON parsing. --- trufflehog-scan/action.yml | 25 +++----- trufflehog-scan/scripts/trufflehog_scan.sh | 66 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 trufflehog-scan/scripts/trufflehog_scan.sh diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index a2e50fc..77a6969 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -5,6 +5,10 @@ inputs: description: 'Base branch to compare against. Defaults to the PR base or repository default branch.' required: false default: '' + head: + description: 'Head commit or branch to scan to. Defaults to HEAD.' + required: false + default: 'HEAD' exclude-paths: description: 'Path to a file listing paths to exclude from the scan.' required: false @@ -16,24 +20,13 @@ inputs: runs: using: "composite" steps: - - name: Compute base SHA - id: base + - name: Run TruffleHog shell: bash env: INPUT_BASE: ${{ inputs.base }} + INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} + INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: | - BASE="${INPUT_BASE:-}" - if [[ -z "$BASE" ]]; then - REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" - BASE="$(git rev-parse "origin/$REF")" - fi - echo "sha=$BASE" >> "$GITHUB_OUTPUT" - - - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@main - with: - path: ./ - base: ${{ steps.base.outputs.sha }} - extra_args: --only-verified + GITHUB_HEAD_REF: ${{ github.head_ref }} + run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh new file mode 100644 index 0000000..27e8eea --- /dev/null +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +BASE="${INPUT_BASE:-}" +if [[ -z "$BASE" ]]; then + REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" + BASE="$(git rev-parse "origin/$REF")" +fi + +ARGS="--only-verified --no-update --json" +[[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" +[[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" + +TMPFILE=$(mktemp) +trap 'rm -f "$TMPFILE"' EXIT + +docker run --rm \ + ghcr.io/trufflesecurity/trufflehog:latest \ + git \ + "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ + --since-commit="$BASE" \ + --branch="$GITHUB_HEAD_REF" \ + $ARGS > "$TMPFILE" + +python3 - "$TMPFILE" << 'PYEOF' +import sys, json + +def find_git_metadata(node): + """Recursively search for the dict that contains a 'file' key.""" + if isinstance(node, dict): + if 'file' in node or 'File' in node: + return node + for v in node.values(): + result = find_git_metadata(v) + if result: + return result + return {} + +count = 0 +with open(sys.argv[1]) as f: + for line in f: + line = line.strip() + if not line: + continue + try: + d = json.loads(line) + except json.JSONDecodeError: + continue + git = find_git_metadata(d.get('SourceMetadata', {})) + file_path = git.get('file', git.get('File', '')) + line_num = git.get('line', git.get('Line', 1)) or 1 + detector = d.get('DetectorName', 'Unknown') + verified = 'verified' if d.get('Verified', False) else 'unverified' + msg = f"TruffleHog [{detector}]: {verified} secret detected" + if file_path: + print(f"::error file={file_path},line={line_num}::{msg}") + else: + print(f"::error::{msg}") + count += 1 + +if count > 0: + print(f"TruffleHog found {count} secret(s).") + sys.exit(1) +else: + print("No secrets detected.") +PYEOF From 9184769b6b817ef395a1ba667915a3aabdc005ed Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 08:29:33 +0100 Subject: [PATCH 25/27] Switch TruffleHog from Docker to downloaded binary Downloads the TruffleHog Linux binary from GitHub Releases at run time and scans the locally checked-out repo (file:// URL). This removes the need for Docker volume mounts (which fail on DinD k8s runners) and removes the GITHUB_TOKEN requirement from the action entirely. --- trufflehog-scan/action.yml | 10 ++--- trufflehog-scan/scripts/trufflehog_scan.sh | 51 ++++++++++++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/trufflehog-scan/action.yml b/trufflehog-scan/action.yml index 77a6969..28a6b89 100644 --- a/trufflehog-scan/action.yml +++ b/trufflehog-scan/action.yml @@ -1,14 +1,14 @@ name: 'TruffleHog Scan' description: 'Scans for verified secrets using TruffleHog OSS.' inputs: + version: + description: 'TruffleHog version to download (e.g. "3.88.1"). Defaults to the latest release.' + required: false + default: '' base: description: 'Base branch to compare against. Defaults to the PR base or repository default branch.' required: false default: '' - head: - description: 'Head commit or branch to scan to. Defaults to HEAD.' - required: false - default: 'HEAD' exclude-paths: description: 'Path to a file listing paths to exclude from the scan.' required: false @@ -23,10 +23,10 @@ runs: - name: Run TruffleHog shell: bash env: + INPUT_VERSION: ${{ inputs.version }} INPUT_BASE: ${{ inputs.base }} INPUT_EXCLUDE_PATHS: ${{ inputs.exclude-paths }} INPUT_INCLUDE_PATHS: ${{ inputs.include-paths }} GITHUB_BASE_REF: ${{ github.base_ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GITHUB_HEAD_REF: ${{ github.head_ref }} run: bash "$GITHUB_ACTION_PATH/scripts/trufflehog_scan.sh" diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 27e8eea..055c6c5 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -1,32 +1,55 @@ #!/usr/bin/env bash set -euo pipefail +# ── Resolve base commit ────────────────────────────────────────────────────── BASE="${INPUT_BASE:-}" if [[ -z "$BASE" ]]; then REF="${GITHUB_BASE_REF:-$DEFAULT_BRANCH}" BASE="$(git rev-parse "origin/$REF")" fi +HEAD_SHA="$(git rev-parse HEAD)" + +# ── Download TruffleHog binary ─────────────────────────────────────────────── +VERSION="${INPUT_VERSION:-}" +if [[ -z "$VERSION" ]]; then + VERSION=$(curl -sSf "https://api.github.com/repos/trufflesecurity/trufflehog/releases/latest" \ + | python3 -c "import sys, json; print(json.load(sys.stdin)['tag_name'].lstrip('v'))") +fi + +ARCH=$(uname -m) +[[ "$ARCH" == "x86_64" ]] && ARCH="amd64" +[[ "$ARCH" == "aarch64" ]] && ARCH="arm64" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +curl -sSfL \ + "https://github.com/trufflesecurity/trufflehog/releases/download/v${VERSION}/trufflehog_${VERSION}_linux_${ARCH}.tar.gz" \ + | tar -xz -C "$TMPDIR" + +TRUFFLEHOG="$TMPDIR/trufflehog" +chmod +x "$TRUFFLEHOG" + +# ── Build scan args ─────────────────────────────────────────────────────────── ARGS="--only-verified --no-update --json" [[ -n "${INPUT_EXCLUDE_PATHS:-}" ]] && ARGS="$ARGS --exclude-paths=$INPUT_EXCLUDE_PATHS" [[ -n "${INPUT_INCLUDE_PATHS:-}" ]] && ARGS="$ARGS --include-paths=$INPUT_INCLUDE_PATHS" -TMPFILE=$(mktemp) -trap 'rm -f "$TMPFILE"' EXIT +# ── Run scan ────────────────────────────────────────────────────────────────── +OUTFILE="$TMPDIR/findings.json" -docker run --rm \ - ghcr.io/trufflesecurity/trufflehog:latest \ - git \ - "https://oauth2:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" \ - --since-commit="$BASE" \ - --branch="$GITHUB_HEAD_REF" \ - $ARGS > "$TMPFILE" +"$TRUFFLEHOG" git \ + "file://$GITHUB_WORKSPACE" \ + --since-commit="$BASE" \ + --branch="$HEAD_SHA" \ + $ARGS > "$OUTFILE" || true -python3 - "$TMPFILE" << 'PYEOF' +# ── Emit annotations ────────────────────────────────────────────────────────── +python3 - "$OUTFILE" << 'PYEOF' import sys, json def find_git_metadata(node): - """Recursively search for the dict that contains a 'file' key.""" if isinstance(node, dict): if 'file' in node or 'File' in node: return node @@ -48,9 +71,9 @@ with open(sys.argv[1]) as f: continue git = find_git_metadata(d.get('SourceMetadata', {})) file_path = git.get('file', git.get('File', '')) - line_num = git.get('line', git.get('Line', 1)) or 1 - detector = d.get('DetectorName', 'Unknown') - verified = 'verified' if d.get('Verified', False) else 'unverified' + line_num = git.get('line', git.get('Line', 1)) or 1 + detector = d.get('DetectorName', 'Unknown') + verified = 'verified' if d.get('Verified', False) else 'unverified' msg = f"TruffleHog [{detector}]: {verified} secret detected" if file_path: print(f"::error file={file_path},line={line_num}::{msg}") From c7a1350ac61c5e6fee429165ef60cca6f4c7112a Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 08:56:58 +0100 Subject: [PATCH 26/27] Add artifact signature verification to TruffleHog download Before running TruffleHog, the script now: 1. Downloads cosign v3.0.5 (pinned, SHA256-verified as trust anchor) 2. Uses cosign to verify TruffleHog's checksums.txt against its cosign certificate + signature from the release 3. Verifies the tarball SHA256 against the verified checksums file --- trufflehog-scan/scripts/trufflehog_scan.sh | 44 +++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 055c6c5..8e5750f 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -10,7 +10,10 @@ fi HEAD_SHA="$(git rev-parse HEAD)" -# ── Download TruffleHog binary ─────────────────────────────────────────────── +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +# ── Resolve TruffleHog version ─────────────────────────────────────────────── VERSION="${INPUT_VERSION:-}" if [[ -z "$VERSION" ]]; then VERSION=$(curl -sSf "https://api.github.com/repos/trufflesecurity/trufflehog/releases/latest" \ @@ -21,13 +24,44 @@ ARCH=$(uname -m) [[ "$ARCH" == "x86_64" ]] && ARCH="amd64" [[ "$ARCH" == "aarch64" ]] && ARCH="arm64" -TMPDIR=$(mktemp -d) -trap 'rm -rf "$TMPDIR"' EXIT +# ── Download cosign (pinned, SHA256-verified) ───────────────────────────────── +# Pinned to cosign v3.0.5 — update both values together when bumping. +COSIGN_VERSION="3.0.5" +declare -A COSIGN_SHA256=( + [amd64]="db15cc99e6e4837daabab023742aaddc3841ce57f193d11b7c3e06c8003642b2" + [arm64]="d098f3168ae4b3aa70b4ca78947329b953272b487727d1722cb3cb098a1a20ab" +) +COSIGN_BIN="$TMPDIR/cosign" curl -sSfL \ - "https://github.com/trufflesecurity/trufflehog/releases/download/v${VERSION}/trufflehog_${VERSION}_linux_${ARCH}.tar.gz" \ - | tar -xz -C "$TMPDIR" + "https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-linux-${ARCH}" \ + -o "$COSIGN_BIN" + +echo "${COSIGN_SHA256[$ARCH]} $COSIGN_BIN" | sha256sum -c +chmod +x "$COSIGN_BIN" + +# ── Download TruffleHog artifacts ──────────────────────────────────────────── +RELEASE_BASE="https://github.com/trufflesecurity/trufflehog/releases/download/v${VERSION}" +TARBALL_NAME="trufflehog_${VERSION}_linux_${ARCH}.tar.gz" + +curl -sSfL "${RELEASE_BASE}/${TARBALL_NAME}" -o "$TMPDIR/trufflehog.tar.gz" +curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt" -o "$TMPDIR/checksums.txt" +curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt.pem" -o "$TMPDIR/checksums.txt.pem" +curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt.sig" -o "$TMPDIR/checksums.txt.sig" + +# ── Verify cosign signature on checksums file ───────────────────────────────── +"$COSIGN_BIN" verify-blob \ + --certificate "$TMPDIR/checksums.txt.pem" \ + --signature "$TMPDIR/checksums.txt.sig" \ + --certificate-identity-regexp "https://github.com/trufflesecurity/trufflehog/" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + "$TMPDIR/checksums.txt" + +# ── Verify tarball SHA256 against checksums ─────────────────────────────────── +(cd "$TMPDIR" && grep "${TARBALL_NAME}" checksums.txt | sha256sum -c) +# ── Extract binary ──────────────────────────────────────────────────────────── +tar -xz -C "$TMPDIR" -f "$TMPDIR/trufflehog.tar.gz" TRUFFLEHOG="$TMPDIR/trufflehog" chmod +x "$TRUFFLEHOG" From 1d1ddcdf30d3f4ec27c855ae74bb2e80901c6575 Mon Sep 17 00:00:00 2001 From: Klaus Niedermair Date: Tue, 17 Mar 2026 10:14:08 +0100 Subject: [PATCH 27/27] Fix tarball filename for sha256sum verification --- trufflehog-scan/scripts/trufflehog_scan.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trufflehog-scan/scripts/trufflehog_scan.sh b/trufflehog-scan/scripts/trufflehog_scan.sh index 8e5750f..a055605 100644 --- a/trufflehog-scan/scripts/trufflehog_scan.sh +++ b/trufflehog-scan/scripts/trufflehog_scan.sh @@ -44,7 +44,7 @@ chmod +x "$COSIGN_BIN" RELEASE_BASE="https://github.com/trufflesecurity/trufflehog/releases/download/v${VERSION}" TARBALL_NAME="trufflehog_${VERSION}_linux_${ARCH}.tar.gz" -curl -sSfL "${RELEASE_BASE}/${TARBALL_NAME}" -o "$TMPDIR/trufflehog.tar.gz" +curl -sSfL "${RELEASE_BASE}/${TARBALL_NAME}" -o "$TMPDIR/${TARBALL_NAME}" curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt" -o "$TMPDIR/checksums.txt" curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt.pem" -o "$TMPDIR/checksums.txt.pem" curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt.sig" -o "$TMPDIR/checksums.txt.sig" @@ -61,7 +61,7 @@ curl -sSfL "${RELEASE_BASE}/trufflehog_${VERSION}_checksums.txt.sig" -o "$TMPDI (cd "$TMPDIR" && grep "${TARBALL_NAME}" checksums.txt | sha256sum -c) # ── Extract binary ──────────────────────────────────────────────────────────── -tar -xz -C "$TMPDIR" -f "$TMPDIR/trufflehog.tar.gz" +tar -xz -C "$TMPDIR" -f "$TMPDIR/${TARBALL_NAME}" TRUFFLEHOG="$TMPDIR/trufflehog" chmod +x "$TRUFFLEHOG"