Skip to content

Commit cbe670b

Browse files
SK-3156-added-CI-checks
1 parent 538c8da commit cbe670b

3 files changed

Lines changed: 186 additions & 1 deletion

File tree

‎.githooks/pre-commit‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fi
8181

8282
if ! command -v gitleaks >/dev/null 2>&1; then
8383
echo "[leak-guard] tier 2 skipped: 'gitleaks' binary not found locally."
84-
echo "[leak-guard] CI will still scan this PR - install gitleaks locally to catch issues before pushing."
84+
echo "[leak-guard] CI will still block this PR on any finding (see Gitleaks.yml) - install gitleaks locally to catch issues before pushing instead of waiting on CI."
8585
exit 0
8686
fi
8787

‎.github/workflows/Gitleaks.yml‎

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: Gitleaks secrets scan
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
contents: read
13+
14+
jobs:
15+
gitleaks:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0 # Required to get full commit history for diffing
23+
24+
25+
- name: Get base and head commit SHAs
26+
run: |
27+
echo "BASE_SHA=${{ github.event.pull_request.base.sha }}" >> $GITHUB_ENV
28+
echo "HEAD_SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
29+
30+
31+
- name: Run Gitleaks on PR changes via Docker
32+
run: |
33+
docker run --rm -v $(pwd):/repo -w /repo zricethezav/gitleaks:latest detect \
34+
--config="/repo/.gitleaks.toml" \
35+
--log-opts="--no-merges $BASE_SHA..$HEAD_SHA" \
36+
--verbose \
37+
--exit-code=0 \
38+
--report-format=json \
39+
--report-path="/repo/gitleaks-report.json" \
40+
--redact
41+
42+
- name: Upload Gitleaks report
43+
uses: actions/upload-artifact@v4
44+
with:
45+
name: gitleaks-report
46+
path: gitleaks-report.json
47+
48+
- name: Format and comment findings on PR
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
run: |
52+
if [ ! -f gitleaks-report.json ]; then
53+
echo "Report file not found!"
54+
exit 1
55+
fi
56+
57+
FINDINGS_JSON=$(cat gitleaks-report.json)
58+
COUNT=$(echo "$FINDINGS_JSON" | jq 'length')
59+
SHA="${{ github.event.pull_request.head.sha }}"
60+
REPO="${{ github.repository }}"
61+
PR_NUMBER="${{ github.event.pull_request.number }}"
62+
MAX=10
63+
64+
if [ "$COUNT" -gt 0 ]; then
65+
COMMENT="**🔐 Gitleaks Findings: $COUNT issue(s) detected**\n\n"
66+
i=0
67+
while [ "$i" -lt "$COUNT" ] && [ "$i" -lt "$MAX" ]; do
68+
ITEM=$(echo "$FINDINGS_JSON" | jq ".[$i]")
69+
RULE=$(echo "$ITEM" | jq -r '.RuleID')
70+
DESC=$(echo "$ITEM" | jq -r '.Description')
71+
FILE=$(echo "$ITEM" | jq -r '.File')
72+
LINE=$(echo "$ITEM" | jq -r '.Line')
73+
LINK="https://github.com/$REPO/blob/$SHA/$FILE#L$LINE"
74+
SECRET_MASKED="**********"
75+
COMMENT+="🔸 **Rule**: \`$RULE\`\n"
76+
COMMENT+="📄 **File**: \`$FILE:$LINE\`\n"
77+
COMMENT+="📝 **Description**: $DESC\n"
78+
COMMENT+="🔑 **Secret**: \`$SECRET_MASKED\`\n"
79+
COMMENT+="🔗 **Path**: [$FILE:$LINE]($LINK)\n\n"
80+
i=$((i + 1))
81+
done
82+
83+
if [ "$COUNT" -gt "$MAX" ]; then
84+
COMMENT+="...and more. Only showing first $MAX findings.\n"
85+
fi
86+
else
87+
COMMENT="✅ **Gitleaks Findings:** No secrets detected. Safe to proceed!"
88+
fi
89+
90+
# Escape newlines for GitHub API
91+
COMMENT=$(echo "$COMMENT" | sed ':a;N;$!ba;s/\n/\\n/g')
92+
93+
curl -X POST \
94+
-H "Authorization: token $GITHUB_TOKEN" \
95+
-H "Accept: application/vnd.github.v3+json" \
96+
-d "{\"body\":\"$COMMENT\"}" \
97+
"https://api.github.com/repos/${REPO}/issues/${PR_NUMBER}/comments"
98+
99+
- name: Fail if secrets were found
100+
# The scan step above runs with --exit-code=0 so it always reaches
101+
# the comment step regardless of findings - reporting and
102+
# enforcement are deliberately separate steps. This is the
103+
# enforcement half: without it, this whole workflow only ever
104+
# comments and never blocks a PR, even when it finds a real
105+
# secret. gitleaks-auto-redact.yml pushes an auto-fix commit for
106+
# fake secrets in generated code, which re-triggers this workflow
107+
# and clears this failure on its own once that commit lands - a
108+
# failure here that persists past that point means a human needs
109+
# to look at it.
110+
run: |
111+
if [ ! -f gitleaks-report.json ]; then
112+
echo "Report file not found!"
113+
exit 1
114+
fi
115+
COUNT=$(jq 'length' gitleaks-report.json)
116+
if [ "$COUNT" -gt 0 ]; then
117+
echo "::error::Gitleaks found $COUNT secret(s) in this PR - see the PR comment above, or download the gitleaks-report artifact."
118+
exit 1
119+
fi
120+
echo "No secrets detected - safe to proceed."
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Gitleaks Auto-Redact
2+
3+
# Runs scripts/patch_generated_secrets.py on every push to a PR and, if it
4+
# finds anything to redact in the Fern-generated code, commits and pushes
5+
# the fix straight to the PR branch - the same "run in CI, commit the
6+
# result back" pattern shared-build-and-deploy.yml uses for its version
7+
# bump. This closes the gap where a contributor without gitleaks installed
8+
# locally never gets tier 1's local auto-redaction (see
9+
# .githooks/pre-commit): CI now does it for them instead of only warning.
10+
#
11+
# This is the first gitleaks-related CI automation in this repo, but it's
12+
# additive by design: it only ever adds a redaction commit, it doesn't
13+
# gate or block anything else in the PR.
14+
15+
on:
16+
pull_request:
17+
types: [opened, synchronize, reopened]
18+
branches:
19+
- main
20+
21+
permissions:
22+
contents: write
23+
24+
jobs:
25+
auto-redact:
26+
runs-on: ubuntu-latest
27+
# A fork PR's checkout token can't push back to someone else's fork -
28+
# GitHub blocks that regardless of what token this job holds - so skip
29+
# cleanly rather than fail noisily. This job only ever adds a
30+
# redaction commit for same-repo branches.
31+
if: github.event.pull_request.head.repo.full_name == github.repository
32+
steps:
33+
- uses: actions/checkout@v4
34+
with:
35+
token: ${{ secrets.PAT_ACTIONS }}
36+
ref: ${{ github.head_ref }}
37+
38+
- uses: actions/setup-python@v2
39+
with:
40+
python-version: '3.9'
41+
42+
- name: Install gitleaks
43+
run: |
44+
GITLEAKS_VERSION="$(curl -fsSL https://api.github.com/repos/gitleaks/gitleaks/releases/latest | grep -m1 '"tag_name"' | cut -d '"' -f4 | sed 's/^v//')"
45+
curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
46+
tar -xzf gitleaks.tar.gz gitleaks
47+
sudo install -m 0755 gitleaks /usr/local/bin/gitleaks
48+
rm -f gitleaks.tar.gz gitleaks
49+
gitleaks version
50+
51+
- name: Auto-redact generated code
52+
run: python3 scripts/patch_generated_secrets.py
53+
54+
- name: Commit and push redaction, if any
55+
run: |
56+
git config user.name "${{ github.actor }}"
57+
git config user.email "${{ github.actor }}@users.noreply.github.com"
58+
git checkout "${{ github.head_ref }}"
59+
if git diff --quiet -- common/generated skyflow/generated skyvault/skyflow/generated flowvault/skyflow/generated; then
60+
echo "No fake secrets found to redact."
61+
else
62+
git add -- common/generated skyflow/generated skyvault/skyflow/generated flowvault/skyflow/generated
63+
git commit -m "[AUTOMATED] redact fake secrets in generated code"
64+
git push origin "HEAD:${{ github.head_ref }}"
65+
fi

0 commit comments

Comments
 (0)