55 branches : ["main"]
66 pull_request :
77
8+ permissions :
9+ contents : read
10+ issues : write
11+ pull-requests : write
12+
813jobs :
914 security :
1015 runs-on : ubuntu-latest
16+ timeout-minutes : 15
17+
1118 steps :
1219 - uses : actions/checkout@v4
20+ with :
21+ fetch-depth : 0
22+
23+ - name : Prepare artifacts directory
24+ run : mkdir -p artifacts/security
1325
1426 - name : Set up Go
1527 uses : actions/setup-go@v5
@@ -22,3 +34,132 @@ jobs:
2234 uses : returntocorp/semgrep-action@v1
2335 with :
2436 config : " p/ci"
37+ - name : Run Gitleaks
38+ uses : gitleaks/gitleaks-action@v2
39+ env :
40+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
41+ - name : Run Trivy FS Scan
42+ uses : aquasecurity/trivy-action@master
43+ with :
44+ scan-type : fs
45+ format : json
46+ output : artifacts/security/trivy-fs.json
47+ severity : HIGH,CRITICAL
48+
49+ - name : Generate security summary (JSON)
50+ if : always()
51+ run : |
52+ echo "Generating security summary..."
53+ mkdir -p artifacts/security
54+
55+ # Gitleaks: count total findings (supports array or {findings:[...]})
56+ if [ -f artifacts/security/gitleaks-report.json ]; then
57+ GITLEAKS_COUNT=$(jq 'if type=="array" then length else (.findings | length // 0) end' artifacts/security/gitleaks-report.json)
58+ else
59+ GITLEAKS_COUNT=0
60+ fi
61+
62+ # Trivy: group vulnerabilities by severity (CRITICAL/HIGH/etc.)
63+ if [ -f artifacts/security/trivy-fs.json ]; then
64+ TRIVY_SUMMARY=$(jq '
65+ ( [ .Results[].Vulnerabilities[]? | .Severity ]
66+ | group_by(.)
67+ | map({ (.[0]): length })
68+ | add
69+ ) // {}' artifacts/security/trivy-fs.json)
70+ else
71+ TRIVY_SUMMARY='{}'
72+ fi
73+
74+ jq -n \
75+ --argjson gitleaks_count "$GITLEAKS_COUNT" \
76+ --argjson trivy "$TRIVY_SUMMARY" \
77+ '{ gitleaks: { total: $gitleaks_count }, trivy: $trivy }' \
78+ > artifacts/security/summary.json
79+
80+ echo "Summary written to artifacts/security/summary.json"
81+
82+ - name : Post security summary as PR comment
83+ if : always() && github.event_name == 'pull_request'
84+ uses : actions/github-script@v7
85+ with :
86+ github-token : ${{ secrets.GITHUB_TOKEN }}
87+ script : |
88+ const fs = require('fs');
89+ const path = 'artifacts/security/summary.json';
90+ const marker = '<!-- devsecops-kit-security-summary -->';
91+
92+ let summary;
93+ try {
94+ const raw = fs.readFileSync(path, 'utf8');
95+ summary = JSON.parse(raw);
96+ } catch (err) {
97+ core.warning(`Could not read ${path}: ${err}`);
98+ summary = null;
99+ }
100+
101+ let body = `${marker}\n`;
102+ body += '### 🔐 DevSecOps Kit Security Summary\n\n';
103+
104+ if (!summary) {
105+ body += '_No summary.json available. Check workflow logs._\n';
106+ } else {
107+ const gitleaksTotal = summary?.gitleaks?.total ?? 0;
108+ const trivy = summary?.trivy || {};
109+
110+ body += `- **Gitleaks:** ${gitleaksTotal} leak(s)\n`;
111+
112+ const severities = Object.keys(trivy);
113+ if (severities.length > 0) {
114+ body += '- **Trivy vulnerabilities:**\n';
115+ for (const sev of severities.sort()) {
116+ body += ` - ${sev}: ${trivy[sev]}\n`;
117+ }
118+ } else {
119+ body += '- **Trivy vulnerabilities:** none counted in summary\n';
120+ }
121+
122+ const hasBlocking =
123+ gitleaksTotal > 0 ||
124+ (trivy.CRITICAL ?? 0) > 0 ||
125+ (trivy.HIGH ?? 0) > 0;
126+
127+ body += '\n';
128+ body += hasBlocking
129+ ? '🚨 _Status: Potential blocking issues detected._\n'
130+ : '✅ _Status: No blocking issues detected (HIGH/CRITICAL)._ \n';
131+ }
132+
133+ const { owner, repo } = context.repo;
134+ const issue_number = context.issue.number;
135+
136+ const comments = await github.rest.issues.listComments({
137+ owner,
138+ repo,
139+ issue_number,
140+ });
141+
142+ const existing = comments.data.find(c => c.body && c.body.includes(marker));
143+
144+ if (existing) {
145+ await github.rest.issues.updateComment({
146+ owner,
147+ repo,
148+ comment_id: existing.id,
149+ body,
150+ });
151+ } else {
152+ await github.rest.issues.createComment({
153+ owner,
154+ repo,
155+ issue_number,
156+ body,
157+ });
158+ }
159+
160+ - name : Upload security artifacts
161+ if : always()
162+ uses : actions/upload-artifact@v4
163+ with :
164+ name : security-reports
165+ path : artifacts/security/
0 commit comments