-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathgosec-test.sh
More file actions
executable file
·203 lines (170 loc) · 6.44 KB
/
gosec-test.sh
File metadata and controls
executable file
·203 lines (170 loc) · 6.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/bin/bash
# Go SAST security scanner — runs gosec against the entire Go codebase to detect
# security vulnerabilities (SQL injection, hardcoded credentials, insecure crypto,
# path traversal, etc.).
#
# Usage:
# ./scripts/gosec-test.sh # Run gosec, fail on HIGH severity
# ./scripts/gosec-test.sh --strict # Fail on MEDIUM and above
#
# Prerequisites:
# - Go 1.18+ installed
# - gosec will be auto-installed if missing
#
# Output:
# /tmp/gosec-report.json — full JSON data
# /tmp/gosec-summary.md — human-readable summary
#
# Exit code:
# 0 — no issues found (or only LOW in non-strict mode)
# 1 — HIGH (or MEDIUM in strict mode) issues found
set -euo pipefail
cd "$(dirname "$0")/.."
# ============================================================================
# Colors & argument parsing
# ============================================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
STRICT_MODE=""
for arg in "$@"; do
case "$arg" in
--strict) STRICT_MODE="1"; echo -e "${YELLOW}Strict mode: MEDIUM findings are errors${NC}" ;;
esac
done
# ============================================================================
# Prerequisites
# ============================================================================
if ! command -v go &>/dev/null; then
echo -e "${RED}ERROR: Go is not installed${NC}"
exit 1
fi
if ! command -v gosec &>/dev/null; then
echo -e "${YELLOW}Installing gosec...${NC}"
go install github.com/securego/gosec/v2/cmd/gosec@latest
fi
# ============================================================================
# Run gosec
# ============================================================================
REPORT_JSON="/tmp/gosec-report.json"
REPORT_MD="/tmp/gosec-summary.md"
echo -e "${BOLD}Running gosec security scanner...${NC}"
echo ""
# Taint-analysis rules (G702-G704) produce false positives in admin CLI tools
# that intentionally operate on user-specified paths/URLs/commands.
# G101 flags k8s type constants like "kubernetes.io/service-account-token" as hardcoded creds.
# G407 flags AES-GCM nonce generation — our nonce IS random (crypto/rand.Read), not hardcoded.
GOSEC_EXCLUDE="G101,G407,G702,G703,G704"
# Run gosec with JSON output; gosec exits non-zero on findings, so we capture the exit code
GOSEC_EXIT=0
gosec -fmt=json -out="$REPORT_JSON" -exclude="${GOSEC_EXCLUDE}" -exclude-dir=vendor -exclude-dir=node_modules ./... 2>/dev/null || GOSEC_EXIT=$?
# ============================================================================
# Parse results
# ============================================================================
HIGH_COUNT=0
MEDIUM_COUNT=0
LOW_COUNT=0
TOTAL_COUNT=0
if [ -f "$REPORT_JSON" ]; then
# Extract counts using python3 (available on macOS/Linux)
read -r HIGH_COUNT MEDIUM_COUNT LOW_COUNT TOTAL_COUNT < <(python3 -c "
import json, sys
try:
with open('$REPORT_JSON') as f:
data = json.load(f)
issues = data.get('Issues', []) or []
high = sum(1 for i in issues if i.get('severity') == 'HIGH')
med = sum(1 for i in issues if i.get('severity') == 'MEDIUM')
low = sum(1 for i in issues if i.get('severity') == 'LOW')
print(high, med, low, len(issues))
except Exception:
print(0, 0, 0, 0)
" 2>/dev/null || echo "0 0 0 0")
fi
# ============================================================================
# Print results
# ============================================================================
echo -e "${BOLD}═══════════════════════════════════════════════════${NC}"
echo -e "${BOLD} Go Security Analysis (gosec)${NC}"
echo -e "${BOLD}═══════════════════════════════════════════════════${NC}"
echo ""
if [ "$TOTAL_COUNT" -eq 0 ]; then
echo -e " ${GREEN}✓ No security issues found${NC}"
else
[ "$HIGH_COUNT" -gt 0 ] && echo -e " ${RED}❌ HIGH: ${HIGH_COUNT} finding(s)${NC}"
[ "$MEDIUM_COUNT" -gt 0 ] && echo -e " ${YELLOW}⚠️ MEDIUM: ${MEDIUM_COUNT} finding(s)${NC}"
[ "$LOW_COUNT" -gt 0 ] && echo -e " ${DIM}ℹ LOW: ${LOW_COUNT} finding(s)${NC}"
echo ""
echo -e " ${BOLD}Total: ${TOTAL_COUNT} finding(s)${NC}"
# Print top findings
if [ -f "$REPORT_JSON" ]; then
echo ""
python3 -c "
import json
with open('$REPORT_JSON') as f:
data = json.load(f)
issues = data.get('Issues', []) or []
for i, issue in enumerate(issues[:10]):
sev = issue.get('severity', '?')
desc = issue.get('details', 'Unknown')
fpath = issue.get('file', '?')
line = issue.get('line', '?')
marker = '❌' if sev == 'HIGH' else '⚠️ ' if sev == 'MEDIUM' else 'ℹ '
print(f' {marker} {fpath}:{line} {desc}')
if len(issues) > 10:
print(f' ... and {len(issues) - 10} more (see full report)')
" 2>/dev/null || true
fi
fi
echo ""
# ============================================================================
# Generate Markdown summary
# ============================================================================
cat > "$REPORT_MD" << EOF
# Go Security Analysis (gosec)
**Date:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
## Summary
| Severity | Count |
|----------|-------|
| HIGH | ${HIGH_COUNT} |
| MEDIUM | ${MEDIUM_COUNT} |
| LOW | ${LOW_COUNT} |
| **Total** | **${TOTAL_COUNT}** |
## Details
See \`/tmp/gosec-report.json\` for full findings.
EOF
if [ -f "$REPORT_JSON" ] && [ "$TOTAL_COUNT" -gt 0 ]; then
python3 -c "
import json
with open('$REPORT_JSON') as f:
data = json.load(f)
issues = data.get('Issues', []) or []
print()
print('### Findings')
print()
for issue in issues:
sev = issue.get('severity', '?')
desc = issue.get('details', 'Unknown')
fpath = issue.get('file', '?')
line = issue.get('line', '?')
cwe = issue.get('cwe', {}).get('id', '')
print(f'- **[{sev}]** \`{fpath}:{line}\` — {desc}' + (f' (CWE-{cwe})' if cwe else ''))
" >> "$REPORT_MD" 2>/dev/null || true
fi
# ============================================================================
# Report locations & exit
# ============================================================================
echo "Reports:"
echo " JSON: $REPORT_JSON"
echo " Summary: $REPORT_MD"
EXIT_CODE=0
if [ "$HIGH_COUNT" -gt 0 ]; then
EXIT_CODE=1
fi
if [ -n "$STRICT_MODE" ] && [ "$MEDIUM_COUNT" -gt 0 ]; then
EXIT_CODE=1
fi
exit $EXIT_CODE