Skip to content

Commit ef72e9c

Browse files
Update secret-scan-gitleaks.yml
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent 123ee55 commit ef72e9c

1 file changed

Lines changed: 79 additions & 35 deletions

File tree

.github/workflows/secret-scan-gitleaks.yml

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# .github/workflows/secret-scan-gitleaks.yml
12
name: Secret Scan (Gitleaks) [Report-Only]
23

34
on:
@@ -23,11 +24,11 @@ jobs:
2324

2425
env:
2526
GITLEAKS_VERSION: "8.30.0"
26-
OUT_DIR: secret-scan-reports
27-
OUT_SARIF: gitleaks.sarif
28-
OUT_JSON: gitleaks.json
29-
OUT_LOG: gitleaks.log
30-
CONFIG_FILE: .gitleaks.toml
27+
OUT_DIR: "secret-scan-reports"
28+
OUT_SARIF: "gitleaks.sarif"
29+
OUT_JSON: "gitleaks.json"
30+
OUT_LOG: "gitleaks.log"
31+
CONFIG_FILE: ".gitleaks.toml"
3132

3233
steps:
3334
- name: Checkout (full history)
@@ -36,52 +37,95 @@ jobs:
3637
fetch-depth: 0
3738

3839
- name: Ensure output folder exists
39-
run: mkdir -p "${{ env.OUT_DIR }}"
40-
41-
- name: Initialize empty SARIF baseline
42-
if: always()
40+
shell: bash
4341
run: |
44-
cat > "${{ env.OUT_DIR }}/${{ env.OUT_SARIF }}" << 'EOF'
45-
{
46-
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
47-
"version": "2.1.0",
48-
"runs": [
49-
{ "tool": { "driver": { "name": "gitleaks", "version": "0" } }, "results": [] }
50-
]
51-
}
52-
EOF
42+
set -euo pipefail
43+
mkdir -p "${OUT_DIR}"
5344
5445
- name: Install Gitleaks (pinned)
55-
if: always()
46+
shell: bash
5647
run: |
5748
set -euo pipefail
58-
VER="${{ env.GITLEAKS_VERSION }}"
49+
VER="${GITLEAKS_VERSION}"
5950
curl -sSL -o /tmp/gitleaks.tar.gz "https://github.com/gitleaks/gitleaks/releases/download/v${VER}/gitleaks_${VER}_linux_x64.tar.gz"
6051
tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
6152
sudo mv /tmp/gitleaks /usr/local/bin/gitleaks
6253
gitleaks version
6354
64-
- name: Run Gitleaks (SARIF + JSON + Log) [Report-Only]
55+
- name: Run Gitleaks (single run) [Report-Only]
6556
if: always()
57+
shell: bash
6658
run: |
59+
# Report-only: never fail the job
6760
set +e
6861
69-
CFG=""
70-
if [ -f "${{ env.CONFIG_FILE }}" ]; then
71-
CFG="--config=${{ env.CONFIG_FILE }}"
62+
CFG=()
63+
if [ -f "${CONFIG_FILE}" ]; then
64+
CFG=(--config="${CONFIG_FILE}")
7265
fi
7366
74-
# SARIF
75-
gitleaks detect --source="." --redact $CFG \
76-
--report-format=sarif \
77-
--report-path="${{ env.OUT_DIR }}/${{ env.OUT_SARIF }}" \
78-
2>&1 | tee "${{ env.OUT_DIR }}/${{ env.OUT_LOG }}"
79-
80-
# JSON (second report output; keep report-only)
81-
gitleaks detect --source="." --redact $CFG \
82-
--report-format=json \
83-
--report-path="${{ env.OUT_DIR }}/${{ env.OUT_JSON }}" \
84-
>/dev/null 2>&1
67+
# Run once, produce JSON, and capture log. Exit code is ignored intentionally.
68+
gitleaks detect \
69+
--source="." \
70+
--redact \
71+
"${CFG[@]}" \
72+
--report-format="json" \
73+
--report-path="${OUT_DIR}/${OUT_JSON}" \
74+
2>&1 | tee "${OUT_DIR}/${OUT_LOG}"
75+
76+
# Create SARIF from JSON (single scan, dual outputs)
77+
python3 - << 'PY'
78+
import json, os, sys
79+
out_dir = os.environ["OUT_DIR"]
80+
json_path = os.path.join(out_dir, os.environ["OUT_JSON"])
81+
sarif_path = os.path.join(out_dir, os.environ["OUT_SARIF"])
82+
83+
# Baseline SARIF skeleton
84+
sarif = {
85+
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
86+
"version": "2.1.0",
87+
"runs": [{
88+
"tool": {"driver": {"name": "gitleaks", "version": os.environ.get("GITLEAKS_VERSION","0")}},
89+
"results": []
90+
}]
91+
}
92+
93+
try:
94+
with open(json_path, "r", encoding="utf-8") as f:
95+
data = json.load(f)
96+
except Exception:
97+
# If JSON missing or invalid, still write baseline SARIF
98+
with open(sarif_path, "w", encoding="utf-8") as f:
99+
json.dump(sarif, f, ensure_ascii=False, indent=2)
100+
sys.exit(0)
101+
102+
# Gitleaks JSON is typically a list of findings
103+
if isinstance(data, list):
104+
for item in data:
105+
file_path = item.get("File") or item.get("file") or item.get("Path") or ""
106+
start_line = item.get("StartLine") or item.get("startLine") or item.get("Line") or item.get("line") or 1
107+
rule_id = item.get("RuleID") or item.get("ruleID") or item.get("Rule") or "gitleaks"
108+
desc = item.get("Description") or item.get("description") or "Potential secret detected"
109+
secret = item.get("Secret") or item.get("secret") or ""
110+
# Keep message minimal (avoid reproducing secrets)
111+
msg = f"{desc} (rule: {rule_id})"
112+
113+
res = {
114+
"ruleId": str(rule_id),
115+
"level": "error",
116+
"message": {"text": msg},
117+
"locations": [{
118+
"physicalLocation": {
119+
"artifactLocation": {"uri": file_path},
120+
"region": {"startLine": int(start_line) if str(start_line).isdigit() else 1}
121+
}
122+
}]
123+
}
124+
sarif["runs"][0]["results"].append(res)
125+
126+
with open(sarif_path, "w", encoding="utf-8") as f:
127+
json.dump(sarif, f, ensure_ascii=False, indent=2)
128+
PY
85129
86130
exit 0
87131

0 commit comments

Comments
 (0)