Skip to content

Update checkmarx-ast-cli binaries with 2.3.58 #3

Update checkmarx-ast-cli binaries with 2.3.58

Update checkmarx-ast-cli binaries with 2.3.58 #3

name: Security
on:
pull_request:
branches: [main, master]
# One run per PR; a new push cancels the in-progress scan (no duplicate
# comments, no wasted runner minutes).
concurrency:
group: secret-scan-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions: {} # no broad grants at workflow level
jobs:
secret-scan:
name: TruffleHog Secret Scan
runs-on: cx-public-ubuntu-x64
timeout-minutes: 5
permissions:
contents: read # required to check out the PR head
pull-requests: write # required to upsert the findings comment
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Run TruffleHog
id: trufflehog
shell: bash
env:
# Pinned by immutable digest (tag 3.96.0). Bump digest + comment on upgrade.
TRUFFLEHOG_IMAGE: "ghcr.io/trufflesecurity/trufflehog@sha256:aa821cf4ace8861c7d096d83818cdf7bb9719028a52d37a52eaad44086a52577" # 3.96.0
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
# --no-fail: findings exit 0, so TruffleHog only exits nonzero on real
# breakage (image pull, daemon, bad flags). With `set -e` and no `|| true`,
# that breakage fails the step (and, with no continue-on-error, the job) —
# instead of silently producing empty results. We block on VERIFIED secrets
# ourselves in a later step.
ARGS=(git "file:///repo" --json --no-update --no-fail)
if [[ -n "${BASE_SHA}" && ! "${BASE_SHA}" =~ ^0+$ ]]; then
ARGS+=(--since-commit "${BASE_SHA}")
fi
echo "Running: trufflehog ${ARGS[*]}"
docker run --rm -v "${GITHUB_WORKSPACE}:/repo:ro" -w /repo \
"${TRUFFLEHOG_IMAGE}" "${ARGS[@]}" > trufflehog-results.json
echo "--- raw results ---"; cat trufflehog-results.json
- name: Parse results
id: parse
if: always()
shell: bash
run: |
set -uo pipefail
grep -E '"DetectorName"' trufflehog-results.json > findings.ndjson || true
# Count non-empty lines. grep -c prints "0" AND exits 1 on no match, so
# capture once and only reset on failure (avoids a duplicate "0").
COUNT=$(grep -c . findings.ndjson 2>/dev/null) || COUNT=0
# Verified = confirmed-live by the provider (compact JSON -> "Verified":true).
# These are what we BLOCK on; everything else is a warning.
VERIFIED=$(grep -c '"Verified":true' findings.ndjson 2>/dev/null) || VERIFIED=0
echo "count=${COUNT}" >> "$GITHUB_OUTPUT"
echo "verified=${VERIFIED}" >> "$GITHUB_OUTPUT"
echo "Total=${COUNT} verified(blocking)=${VERIFIED} unverified(warn)=$((COUNT - VERIFIED))"
- name: Upsert single PR comment
if: always()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const fs = require('fs');
const MARKER = '<!-- trufflehog-secret-scan -->';
const server = process.env.GITHUB_SERVER_URL;
const { owner, repo } = context.repo;
const issue_number = context.payload.pull_request.number;
const findings = fs.existsSync('findings.ndjson')
? fs.readFileSync('findings.ndjson', 'utf8').split('\n').filter(Boolean).map(l => JSON.parse(l))
: [];
const n = findings.length;
const verifiedCount = findings.filter(f => f.Verified === true).length;
const unverifiedCount = n - verifiedCount;
let body;
if (n > 0) {
const seen = new Set();
const rows = [];
for (const f of findings) {
const g = f.SourceMetadata?.Data?.Git || {};
const type = f.DetectorName || 'Unknown';
const status = f.Verified ? '✅ verified' : '⚠️ unverified';
const commit = g.commit || '';
const file = g.file || '(unknown)';
const line = g.line || 0;
let view = '—';
if (commit && file !== '(unknown)') {
const anchor = line > 0 ? `#L${line}` : '';
view = `[🔎 View secret](${server}/${owner}/${repo}/blob/${commit}/${file}${anchor})`;
}
const key = `${type}|${file}|${line}|${commit}`;
if (seen.has(key)) continue;
seen.add(key);
rows.push(`| ${type} | ${status} | \`${commit.slice(0,10)}\` | \`${file}\` | ${view} |`);
}
const author = context.payload.pull_request.user.login;
// Tiered: VERIFIED secrets block the merge; unverified are warnings.
const header = verifiedCount > 0
? '## 🚨 Verified secret(s) detected — merge blocked'
: '## ⚠️ Potential secret(s) detected (unverified)';
const footer = verifiedCount > 0
? '> ⛔ This PR is **blocked**: a verified, live secret was found. Remove it and re-scan to merge.'
: '> ⚠️ These are **unverified** matches and do **not** block the merge — please review and confirm they are not real secrets.';
body = [
MARKER,
header,
'',
`@${author} — TruffleHog found **${n}** potential secret(s) in this PR ` +
`(**${verifiedCount} verified**, ${unverifiedCount} unverified).`,
'',
'| Secret Type | Status | Commit | File Path | View |',
'| --- | --- | --- | --- | --- |',
...rows,
'',
'### 🛠 Guidelines to remediate hardcoded secrets',
'- Understand the implications of revoking this secret by investigating where it is used in your code.',
'- **Immediately rotate/revoke** the exposed secret. (https://howtorotate.com/docs/introduction/getting-started/)',
'- Remove it from git history ( **a new "remove secret" commit is NOT enough** e.g. with [`git-filter-repo`](https://github.com/newren/git-filter-repo)).',
'',
'To avoid such incidents in the future consider:',
'- Following the best practices for managing and storing secrets, including API keys and other credentials.',
'- Re-scan after cleanup before merging.',
'',
footer,
].join('\n');
} else {
body = [
MARKER,
'## ✅ No secrets detected',
'',
'TruffleHog found no secrets in the current commits of this PR.',
].join('\n');
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number, per_page: 100,
});
const existing = comments.find(c => c.body && c.body.includes(MARKER));
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else if (n > 0) {
await github.rest.issues.createComment({ owner, repo, issue_number, body });
}
# Block the merge ONLY on verified (confirmed-live) secrets. Unverified
# findings are surfaced in the PR comment but do not fail the check.
- name: Fail if verified secrets were found
if: steps.parse.outputs.verified != '0'
env:
VERIFIED: ${{ steps.parse.outputs.verified }} # <-- add
run: |
echo "::error::TruffleHog found ${VERIFIED} VERIFIED secret(s). Merge is blocked."
exit 1