Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 2841d86

Browse files
Merge pull request #21 from mapup/add-security-scanning
Add automated security scanning (Gitleaks + Semgrep)
2 parents a735cd2 + 062a3f7 commit 2841d86

2 files changed

Lines changed: 271 additions & 0 deletions

File tree

.github/workflows/gitleaks.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Gitleaks Secret Scan
2+
on:
3+
pull_request:
4+
branches: [main, master]
5+
schedule:
6+
- cron: '0 4 * * *'
7+
workflow_dispatch: # Enables manual run
8+
inputs:
9+
reason:
10+
description: "Reason for manual run"
11+
required: false
12+
default: "Manual security scan"
13+
14+
jobs:
15+
gitleaks:
16+
name: Scan for secrets
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
23+
- name: Install gitleaks
24+
run: |
25+
GITLEAKS_VERSION=$(curl -s https://api.github.com/repos/gitleaks/gitleaks/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/')
26+
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar -xz -C /usr/local/bin gitleaks
27+
28+
- name: Run gitleaks
29+
run: |
30+
gitleaks detect --source . --verbose --redact --report-format sarif --report-path gitleaks-report.sarif || true
31+
gitleaks detect --source . --verbose --redact --report-format json --report-path gitleaks-report.json || true
32+
33+
# - name: Upload SARIF report
34+
# if: always()
35+
# uses: github/codeql-action/upload-sarif@v3
36+
# with:
37+
# sarif_file: gitleaks-report.sarif
38+
39+
- name: Send JSON to endpoint
40+
if: always()
41+
run: |
42+
curl -X POST "${{ secrets.SAST_GITLEAK_WEBHOOK_URL }}?branch=${{ github.head_ref || github.ref_name }}&&repo=${{ github.event.repository.name }}" \
43+
-H "Content-Type: application/json" \
44+
-H "Authorization: Bearer ${{ secrets.SAST_WEBHOOK_TOKEN }}" \
45+
-d @gitleaks-report.json
46+
47+
# name: Gitleaks Secret Scan
48+
# on:
49+
# pull_request:
50+
# branches: [main, master]
51+
# schedule:
52+
# - cron: '0 3 * * 1'
53+
# workflow_dispatch:
54+
55+
# jobs:
56+
# gitleaks:
57+
# name: Scan for secrets
58+
# runs-on: ubuntu-latest
59+
# steps:
60+
# - uses: actions/checkout@v4
61+
# with:
62+
# fetch-depth: 0
63+
64+
# - name: Install gitleaks
65+
# run: |
66+
# GITLEAKS_VERSION=$(curl -s https://api.github.com/repos/gitleaks/gitleaks/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/')
67+
# curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar -xz -C /usr/local/bin gitleaks
68+
69+
# - name: Run gitleaks
70+
# run: gitleaks detect --source . --verbose --redact --report-format sarif --report-path gitleaks-report.sarif
71+
72+
# - name: Upload SARIF report
73+
# if: always()
74+
# uses: github/codeql-action/upload-sarif@v3
75+
# with:
76+
# sarif_file: gitleaks-report.sarif
77+
78+
# name: Gitleaks Secret Scan
79+
# on:
80+
# pull_request:
81+
# branches: [main, master]
82+
# schedule:
83+
# - cron: '0 3 * * 1' # Weekly Monday 3am UTC
84+
# workflow_dispatch: # Allow manual trigger
85+
86+
# jobs:
87+
# gitleaks:
88+
# name: Scan for secrets
89+
# runs-on: ubuntu-latest
90+
# steps:
91+
# - uses: actions/checkout@v4
92+
# with:
93+
# fetch-depth: 0
94+
# - uses: gitleaks/gitleaks-action@v2
95+
# env:
96+
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
97+
# GITLEAKS_ENABLE_COMMENTS: false

.github/workflows/semgrep.yml

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
name: Semgrep SAST
2+
on:
3+
pull_request:
4+
branches: [main, master]
5+
schedule:
6+
- cron: '0 4 * * *'
7+
workflow_dispatch:
8+
inputs:
9+
reason:
10+
description: "Reason for manual run"
11+
required: false
12+
default: "Manual security scan"
13+
14+
jobs:
15+
semgrep:
16+
name: Static analysis
17+
runs-on: ubuntu-latest
18+
container:
19+
image: semgrep/semgrep
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Run Semgrep
24+
run: |
25+
semgrep scan --config auto --error --json --output semgrep-results.json || true
26+
semgrep scan --config auto --error --sarif --output semgrep-results.sarif || true
27+
28+
# - name: Upload SARIF to GitHub
29+
# if: always()
30+
# uses: github/codeql-action/upload-sarif@v3
31+
# with:
32+
# sarif_file: semgrep-results.sarif
33+
34+
- name: Wrap results with repo metadata and send
35+
if: always()
36+
run: |
37+
# Build a wrapper with repo/org info + semgrep results
38+
# jq may not be in semgrep image, so use python which is guaranteed
39+
python3 -c "
40+
import json, os
41+
42+
# GitHub context
43+
repo_full = os.environ.get('GITHUB_REPOSITORY', 'unknown/unknown') # e.g. mapup/tollguru-api
44+
parts = repo_full.split('/', 1)
45+
org = parts[0] if len(parts) > 1 else 'unknown'
46+
repo = parts[1] if len(parts) > 1 else repo_full
47+
48+
ref = os.environ.get('GITHUB_REF', 'unknown')
49+
sha = os.environ.get('GITHUB_SHA', 'unknown')
50+
actor = os.environ.get('GITHUB_ACTOR', 'unknown')
51+
event = os.environ.get('GITHUB_EVENT_NAME', 'unknown')
52+
run_id = os.environ.get('GITHUB_RUN_ID', 'unknown')
53+
server = os.environ.get('GITHUB_SERVER_URL', 'https://github.com')
54+
55+
# Load semgrep results
56+
try:
57+
with open('semgrep-results.json', 'r') as f:
58+
semgrep = json.load(f)
59+
except Exception:
60+
semgrep = {'results': [], 'errors': [], 'version': 'unknown'}
61+
62+
# Wrap payload
63+
payload = {
64+
'tool': 'semgrep',
65+
'org': org,
66+
'repo': repo,
67+
'ref': ref,
68+
'sha': sha,
69+
'actor': actor,
70+
'event': event,
71+
'run_id': run_id,
72+
'repo_url': f'{server}/{repo_full}',
73+
'results': semgrep.get('results', []),
74+
'errors': semgrep.get('errors', []),
75+
'version': semgrep.get('version', 'unknown')
76+
}
77+
78+
with open('semgrep-payload.json', 'w') as f:
79+
json.dump(payload, f)
80+
81+
print(f'✅ Wrapped {len(payload[\"results\"])} findings for {org}/{repo}')
82+
"
83+
84+
curl -X POST "${{ secrets.SAST_WEBHOOK_URL }}?branch=${{ github.head_ref || github.ref_name }}&&repo=${{ github.event.repository.name }}" \
85+
-H "Content-Type: application/json" \
86+
-H "Authorization: Bearer ${{ secrets.SAST_WEBHOOK_TOKEN }}" \
87+
-d @semgrep-payload.json
88+
89+
# name: Semgrep SAST
90+
# on:
91+
# pull_request:
92+
# branches: [main, master]
93+
# schedule:
94+
# - cron: '0 4 * * 1'
95+
# workflow_dispatch: # Enables manual run
96+
# inputs:
97+
# reason:
98+
# description: "Reason for manual run"
99+
# required: false
100+
# default: "Manual security scan"
101+
102+
# jobs:
103+
# semgrep:
104+
# name: Static analysis
105+
# runs-on: ubuntu-latest
106+
# container:
107+
# image: semgrep/semgrep
108+
# steps:
109+
# - uses: actions/checkout@v4
110+
111+
# - name: Run Semgrep
112+
# run: |
113+
# semgrep scan --config auto --error --json --output semgrep-results.json || true
114+
# semgrep scan --config auto --error --sarif --output semgrep-results.sarif || true
115+
116+
# # - name: Upload SARIF to GitHub
117+
# # if: always()
118+
# # uses: github/codeql-action/upload-sarif@v3
119+
# # with:
120+
# # sarif_file: semgrep-results.sarif
121+
122+
# - name: Send JSON to endpoint
123+
# if: always()
124+
# run: |
125+
# curl -X POST "${{ secrets.SAST_WEBHOOK_URL }}" \
126+
# -H "Content-Type: application/json" \
127+
# -H "Authorization: Bearer ${{ secrets.SAST_WEBHOOK_TOKEN }}" \
128+
# -d @semgrep-results.json
129+
130+
# # name: Semgrep SAST
131+
# # on:
132+
# # pull_request:
133+
# # branches: [main, master]
134+
# # schedule:
135+
# # - cron: '0 4 * * 1'
136+
# # workflow_dispatch:
137+
138+
# # jobs:
139+
# # semgrep:
140+
# # name: Static analysis
141+
# # runs-on: ubuntu-latest
142+
# # container:
143+
# # image: semgrep/semgrep
144+
# # steps:
145+
# # - uses: actions/checkout@v4
146+
147+
# # - name: Run Semgrep
148+
# # run: semgrep scan --config auto --error --json --output semgrep-results.json || true
149+
150+
# # - name: Send results to endpoint
151+
# # if: always()
152+
# # run: |
153+
# # curl -X POST "${{ secrets.SAST_WEBHOOK_URL }}" \
154+
# # -H "Content-Type: application/json" \
155+
# # -H "Authorization: Bearer ${{ secrets.SAST_WEBHOOK_TOKEN }}" \
156+
# # -d @semgrep-results.json
157+
158+
# # name: Semgrep SAST
159+
# # on:
160+
# # pull_request:
161+
# # branches: [main, master]
162+
# # schedule:
163+
# # - cron: '0 4 * * 1' # Weekly Monday 4am UTC
164+
# # workflow_dispatch: # Allow manual trigger
165+
166+
# # jobs:
167+
# # semgrep:
168+
# # name: Static analysis
169+
# # runs-on: ubuntu-latest
170+
# # container:
171+
# # image: semgrep/semgrep
172+
# # steps:
173+
# # - uses: actions/checkout@v4
174+
# # - run: semgrep scan --config auto --error --quiet

0 commit comments

Comments
 (0)