Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 50 additions & 22 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ jobs:
env:
SECRET_SCAN_SLACK_BOT_TOKEN: ${{ secrets.SECRET_SCAN_SLACK_BOT_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set +e
Expand Down Expand Up @@ -85,20 +84,35 @@ jobs:
# commits contain findings. Historical findings alerted when they
# were introduced and stay visible in the check run + step summary;
# re-posting them on every push drowned the channel.
# Anchor on the current base tip, not event base.sha: base.sha is
# frozen at PR creation, so after a merge-from-main the stale range
# would re-attribute main's findings to this PR. gitleaks exits 0 on
# an unresolvable range, so validate it here and fall back to
# full-history alerting (fail closed) on any doubt.
notify=/tmp/credentials.json
scope="in git history"
if [ -n "$PR_BASE_SHA" ]; then
set +e
gitleaks git --redact --exit-code 2 . \
--log-opts "${PR_BASE_SHA}..${PR_HEAD_SHA}" \
--report-format json --report-path /tmp/credentials-new.json
set -e
notify=/tmp/credentials-new.json
scope="new in this PR, ${count} total in history"
if [ -n "$PR_HEAD_SHA" ] && [ -n "$SECRET_SCAN_SLACK_BOT_TOKEN" ]; then
base=$(git merge-base "origin/${GITHUB_BASE_REF}" "$PR_HEAD_SHA" 2>/dev/null || true)
if [ -n "$base" ]; then
set +e
gitleaks git --redact --exit-code 2 . \
--log-opts "${base}..${PR_HEAD_SHA}" \
--report-format json --report-path /tmp/credentials-new.json
inc_status=$?
set -e
if { [ "$inc_status" -eq 0 ] || [ "$inc_status" -eq 2 ]; } && [ -s /tmp/credentials-new.json ]; then
notify=/tmp/credentials-new.json
scope="new in this PR, ${count} total in history"
fi
fi
fi
notify_count=$(jq length "$notify" 2>/dev/null || echo 0)
notify_count=${notify_count:-0}
if [ -n "$SECRET_SCAN_SLACK_BOT_TOKEN" ] && [ "$notify_count" -gt 0 ]; then
sample=$(jq -r '.[:5][] | "> \(.RuleID) \(.File):\(.StartLine)"' "$notify")
# Escape Slack mrkdwn entities: a crafted file name could otherwise
# render as a disguised clickable link in the alert channel.
sample=$(jq -r 'def esc: tostring | gsub("&";"&amp;") | gsub("<";"&lt;") | gsub(">";"&gt;");
.[:5][] | "> \(.RuleID|esc) \(.File|esc):\(.StartLine)"' "$notify")
txt=":rotating_light: *Credential leak detected* in \`${GITHUB_REPOSITORY}\` (${notify_count} ${scope}). Rotate immediately.
${sample}
${PR_URL:+PR: ${PR_URL}
Expand All @@ -109,7 +123,7 @@ jobs:
-d "$(jq -n --arg ch "$SLACK_CHANNEL_ID" --arg txt "$txt" \
'{channel: $ch, text: $txt}')" | jq -r '.ok // "post failed"'
else
echo "Slack: skipped (no token, or findings are historical only)"
echo "Slack: skipped (no token or nothing new to report; notify_count=${notify_count})"
fi
elif [ "$status" -ne 0 ]; then
exit "$status"
Expand Down Expand Up @@ -151,7 +165,6 @@ jobs:
env:
SECRET_SCAN_SLACK_BOT_TOKEN: ${{ secrets.SECRET_SCAN_SLACK_BOT_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set +e
Expand Down Expand Up @@ -180,20 +193,35 @@ jobs:
|| echo "could not create check run (read-only token?)"
# Slack dedup: same rule as the credentials job: on PRs,
# notify only for findings introduced by the PR's own commits.
# Anchor on the current base tip, not event base.sha: base.sha is
# frozen at PR creation, so after a merge-from-main the stale range
# would re-attribute main's findings to this PR. gitleaks exits 0 on
# an unresolvable range, so validate it here and fall back to
# full-history alerting (fail closed) on any doubt.
notify=/tmp/internal-refs.json
scope="in git history"
if [ -n "$PR_BASE_SHA" ]; then
set +e
gitleaks git --config /tmp/gitleaks-internal.toml --exit-code 2 . \
--log-opts "${PR_BASE_SHA}..${PR_HEAD_SHA}" \
--report-format json --report-path /tmp/internal-refs-new.json
set -e
notify=/tmp/internal-refs-new.json
scope="new in this PR, ${count} total in history"
if [ -n "$PR_HEAD_SHA" ] && [ -n "$SECRET_SCAN_SLACK_BOT_TOKEN" ]; then
base=$(git merge-base "origin/${GITHUB_BASE_REF}" "$PR_HEAD_SHA" 2>/dev/null || true)
if [ -n "$base" ]; then
set +e
gitleaks git --config /tmp/gitleaks-internal.toml --exit-code 2 . \
--log-opts "${base}..${PR_HEAD_SHA}" \
--report-format json --report-path /tmp/internal-refs-new.json
inc_status=$?
set -e
if { [ "$inc_status" -eq 0 ] || [ "$inc_status" -eq 2 ]; } && [ -s /tmp/internal-refs-new.json ]; then
notify=/tmp/internal-refs-new.json
scope="new in this PR, ${count} total in history"
fi
fi
fi
notify_count=$(jq length "$notify" 2>/dev/null || echo 0)
notify_count=${notify_count:-0}
if [ -n "$SECRET_SCAN_SLACK_BOT_TOKEN" ] && [ "$notify_count" -gt 0 ]; then
sample=$(jq -r '.[:5][] | "> \(.RuleID) \(.File):\(.StartLine)"' "$notify")
# Escape Slack mrkdwn entities: a crafted file name could otherwise
# render as a disguised clickable link in the alert channel.
sample=$(jq -r 'def esc: tostring | gsub("&";"&amp;") | gsub("<";"&lt;") | gsub(">";"&gt;");
.[:5][] | "> \(.RuleID|esc) \(.File|esc):\(.StartLine)"' "$notify")
txt=":warning: Internal Astera references in \`${GITHUB_REPOSITORY}\` (${notify_count} ${scope}). Fine while private; must be resolved before the repo goes public.
${sample}
${PR_URL:+PR: ${PR_URL}
Expand All @@ -204,7 +232,7 @@ jobs:
-d "$(jq -n --arg ch "$SLACK_CHANNEL_ID" --arg txt "$txt" \
'{channel: $ch, text: $txt}')" | jq -r '.ok // "post failed"'
else
echo "Slack: skipped (no token, or findings are historical only)"
echo "Slack: skipped (no token or nothing new to report; notify_count=${notify_count})"
fi
elif [ "$status" -ne 0 ]; then
echo "gitleaks failed with status $status" >&2
Expand Down
Loading