@kaademos/secure-sdlc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/ai-security-engineer.md +209 -0
- package/.claude/agents/appsec-engineer.md +131 -0
- package/.claude/agents/cloud-platform-engineer.md +119 -0
- package/.claude/agents/dev-lead.md +138 -0
- package/.claude/agents/grc-analyst.md +143 -0
- package/.claude/agents/product-manager.md +100 -0
- package/.claude/agents/release-manager.md +126 -0
- package/.claude/agents/security-champion.md +148 -0
- package/.cursor/rules/secure-sdlc.mdc +98 -0
- package/.github/workflows/secure-sdlc-gate.yml +325 -0
- package/CHANGELOG.md +49 -0
- package/CLAUDE.md +195 -0
- package/LICENSE +21 -0
- package/README.md +394 -0
- package/cli/bin/secure-sdlc.js +95 -0
- package/cli/src/commands/gate.js +129 -0
- package/cli/src/commands/init.js +219 -0
- package/cli/src/commands/install-mcp.js +121 -0
- package/cli/src/commands/kickoff.js +261 -0
- package/cli/src/commands/paths.js +33 -0
- package/cli/src/commands/review.js +53 -0
- package/cli/src/commands/status.js +122 -0
- package/cli/src/utils/banner.js +43 -0
- package/cli/src/utils/package-root.js +23 -0
- package/cli/src/utils/phase-detect.js +107 -0
- package/cli/src/utils/stack-detect.js +138 -0
- package/docs/templates/compliance-attestation.md +159 -0
- package/docs/templates/infra-security-review.md +133 -0
- package/docs/templates/release-sign-off.md +119 -0
- package/docs/templates/risk-register.md +72 -0
- package/docs/templates/sast-findings.md +110 -0
- package/docs/templates/security-requirements.md +98 -0
- package/docs/templates/test-security-report.md +143 -0
- package/docs/templates/threat-model.md +129 -0
- package/hooks/install.sh +37 -0
- package/hooks/pre-commit +208 -0
- package/hooks/pre-push +127 -0
- package/mcp/README.md +116 -0
- package/mcp/package.json +23 -0
- package/mcp/src/server.js +638 -0
- package/package.json +67 -0
- package/stacks/django.md +216 -0
- package/stacks/express.md +229 -0
- package/stacks/fastapi.md +247 -0
- package/stacks/nextjs.md +198 -0
- package/stacks/nodejs.md +28 -0
- package/stacks/rails.md +247 -0
- package/warp-workflows/README.md +25 -0
- package/warp-workflows/feature-kickoff.yaml +49 -0
- package/warp-workflows/pr-security-review.yaml +47 -0
- package/warp-workflows/release-gate.yaml +44 -0
- package/warp-workflows/sdlc-status.yaml +48 -0
- package/warp-workflows/threat-model.yaml +56 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Threat Model — [Feature / System Name]
|
|
2
|
+
|
|
3
|
+
**Feature / System:** [Description]
|
|
4
|
+
**Date:** [YYYY-MM-DD]
|
|
5
|
+
**Author:** AppSec Engineer Agent + [Human reviewer]
|
|
6
|
+
**Methodology:** STRIDE (+ LINDDUN if PII in scope)
|
|
7
|
+
**Status:** Draft / Review / Approved
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
### In scope
|
|
14
|
+
|
|
15
|
+
- [Component or data flow 1]
|
|
16
|
+
- [Component or data flow 2]
|
|
17
|
+
|
|
18
|
+
### Out of scope
|
|
19
|
+
|
|
20
|
+
- [What is explicitly not modelled and why]
|
|
21
|
+
|
|
22
|
+
### Assumptions
|
|
23
|
+
|
|
24
|
+
- [e.g. The underlying cloud platform is trusted and hardened by the Cloud/Platform team]
|
|
25
|
+
- [e.g. The database server is not directly internet-accessible]
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Architecture Overview
|
|
30
|
+
|
|
31
|
+
Describe or embed a diagram of the system being modelled. At minimum, document:
|
|
32
|
+
|
|
33
|
+
**Components:**
|
|
34
|
+
|
|
35
|
+
| ID | Component | Type | Description |
|
|
36
|
+
|----|-----------|------|-------------|
|
|
37
|
+
| C1 | [e.g. Web frontend] | [Web app / API / DB / Queue / etc.] | [What it does] |
|
|
38
|
+
| C2 | | | |
|
|
39
|
+
|
|
40
|
+
**Data flows:**
|
|
41
|
+
|
|
42
|
+
| ID | From | To | Data | Protocol | Authentication |
|
|
43
|
+
|----|----|------|------|------|------|
|
|
44
|
+
| F1 | C1 | C2 | [e.g. User credentials] | HTTPS | None (pre-auth) |
|
|
45
|
+
| F2 | | | | | |
|
|
46
|
+
|
|
47
|
+
**Trust boundaries:**
|
|
48
|
+
|
|
49
|
+
| ID | Boundary | Description |
|
|
50
|
+
|----|----------|-------------|
|
|
51
|
+
| TB1 | [e.g. Internet / DMZ] | [Traffic crossing from public internet to internal network] |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## STRIDE Threat Analysis
|
|
56
|
+
|
|
57
|
+
For each component and data flow, enumerate applicable threats.
|
|
58
|
+
|
|
59
|
+
### [Component / Flow name — e.g. Login endpoint (F1)]
|
|
60
|
+
|
|
61
|
+
| ID | Threat Category | Threat Description | Affected Asset | Likelihood | Impact | Risk Rating | Mitigation | Status |
|
|
62
|
+
|----|-----------------|-------------------|----------------|------------|--------|-------------|------------|--------|
|
|
63
|
+
| T-001 | Spoofing | Attacker submits forged credentials as another user | User account | High | Critical | CRITICAL | MFA, account lockout, rate limiting | Open |
|
|
64
|
+
| T-002 | Tampering | Request body modified in transit | Credentials | Low | Critical | HIGH | TLS enforced, HSTS | Mitigated |
|
|
65
|
+
| T-003 | Repudiation | No audit log of failed login attempts | Audit trail | Medium | Medium | MEDIUM | Log all auth attempts with timestamp, IP, outcome | Open |
|
|
66
|
+
| T-004 | Info Disclosure | Verbose error reveals whether username exists | User enumeration | High | Medium | HIGH | Generic error: "Invalid credentials" | Open |
|
|
67
|
+
| T-005 | Denial of Service | Credential stuffing exhausts login endpoint | Availability | High | High | HIGH | Rate limiting, CAPTCHA after N failures | Open |
|
|
68
|
+
| T-006 | Elevation of Privilege | Session token not invalidated after logout | Session | Medium | Critical | HIGH | Invalidate server-side session on logout | Open |
|
|
69
|
+
|
|
70
|
+
**Threat categories (STRIDE):**
|
|
71
|
+
- **S**poofing — pretending to be someone or something else
|
|
72
|
+
- **T**ampering — modifying data or code
|
|
73
|
+
- **R**epudiation — denying an action was performed
|
|
74
|
+
- **I**nformation disclosure — exposing data to unauthorised parties
|
|
75
|
+
- **D**enial of service — making a system unavailable
|
|
76
|
+
- **E**levation of privilege — gaining access beyond what is authorised
|
|
77
|
+
|
|
78
|
+
### [Next component / flow — repeat section]
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## LINDDUN Privacy Threat Analysis
|
|
83
|
+
|
|
84
|
+
Complete this section if the feature handles personal data (PII, PHI, etc.).
|
|
85
|
+
|
|
86
|
+
| ID | Threat Category | Threat Description | Affected Data | Risk Rating | Mitigation | Status |
|
|
87
|
+
|----|-----------------|-------------------|---------------|-------------|------------|--------|
|
|
88
|
+
| L-001 | Linking | User behaviour across sessions can be correlated via persistent identifiers | Session data | MEDIUM | Rotate session IDs on privilege change | Open |
|
|
89
|
+
| L-002 | Identifying | Profile data sufficient to uniquely re-identify anonymised records | User profile | HIGH | K-anonymity for analytics exports | Open |
|
|
90
|
+
|
|
91
|
+
**LINDDUN categories:**
|
|
92
|
+
- **L**inking — combining data to learn more than intended
|
|
93
|
+
- **I**dentifying — identifying a person from supposedly anonymous data
|
|
94
|
+
- **N**on-repudiation — inability of a person to deny an action
|
|
95
|
+
- **D**etecting — inferring information from observable behaviour
|
|
96
|
+
- **D**ata disclosure — exposing personal data
|
|
97
|
+
- **U**nawareness — user unaware of data collection or use
|
|
98
|
+
- **N**on-compliance — violation of privacy regulations
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Threat Summary
|
|
103
|
+
|
|
104
|
+
| Rating | Count | Blocked (gate) |
|
|
105
|
+
|--------|-------|----------------|
|
|
106
|
+
| CRITICAL | [N] | Yes — must resolve before build |
|
|
107
|
+
| HIGH | [N] | Yes — must resolve before release |
|
|
108
|
+
| MEDIUM | [N] | Resolve or accept risk before release |
|
|
109
|
+
| LOW | [N] | Track in risk register |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Mitigations Recommended
|
|
114
|
+
|
|
115
|
+
Priority list of mitigations to carry into the build phase:
|
|
116
|
+
|
|
117
|
+
| Priority | Threat ID(s) | Mitigation | Owner | ASVS Ref |
|
|
118
|
+
|----------|-------------|------------|-------|----------|
|
|
119
|
+
| 1 | T-001, T-004 | Implement account lockout and generic error responses | Dev Lead | V2.2.1, V8.3.4 |
|
|
120
|
+
| 2 | | | | |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Sign-off
|
|
125
|
+
|
|
126
|
+
| Role | Name | Date | Status |
|
|
127
|
+
|------|------|------|--------|
|
|
128
|
+
| AppSec Engineer | | | Approved / Pending |
|
|
129
|
+
| Engineering Lead | | | Approved / Pending |
|
package/hooks/install.sh
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install Secure SDLC git hooks into the current git repository.
|
|
3
|
+
# Run from your project root: bash /path/to/secure-sdlc-agents/hooks/install.sh
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
HOOKS_DIR="$(git rev-parse --git-dir 2>/dev/null)/hooks"
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
|
|
10
|
+
if [ ! -d "$HOOKS_DIR" ]; then
|
|
11
|
+
echo "Error: Not a git repository. Run from your project root."
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
for hook in pre-commit pre-push; do
|
|
16
|
+
src="$SCRIPT_DIR/$hook"
|
|
17
|
+
dest="$HOOKS_DIR/$hook"
|
|
18
|
+
|
|
19
|
+
if [ ! -f "$src" ]; then
|
|
20
|
+
echo "Warning: $src not found — skipping"
|
|
21
|
+
continue
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if [ -f "$dest" ] && ! grep -q "Secure SDLC" "$dest" 2>/dev/null; then
|
|
25
|
+
echo "Existing $hook hook found (not from Secure SDLC). Backing up to $dest.bak"
|
|
26
|
+
cp "$dest" "$dest.bak"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
cp "$src" "$dest"
|
|
30
|
+
chmod +x "$dest"
|
|
31
|
+
echo "✓ Installed $hook hook"
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "Secure SDLC hooks installed successfully."
|
|
36
|
+
echo "To verify: ls -la $(git rev-parse --git-dir)/hooks/"
|
|
37
|
+
echo "To remove: rm $(git rev-parse --git-dir)/hooks/pre-commit $(git rev-parse --git-dir)/hooks/pre-push"
|
package/hooks/pre-commit
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Secure SDLC — Pre-Commit Hook
|
|
3
|
+
#
|
|
4
|
+
# Runs lightweight security checks before every commit:
|
|
5
|
+
# 1. Secret pattern detection (blocks on high-confidence patterns)
|
|
6
|
+
# 2. Dependency lock file consistency check
|
|
7
|
+
# 3. Presence check for security artefacts on first commit to protected branches
|
|
8
|
+
#
|
|
9
|
+
# To bypass in emergencies (document the reason): git commit --no-verify
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
RED='\033[0;31m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
BLUE='\033[0;34m'
|
|
17
|
+
NC='\033[0m' # No Color
|
|
18
|
+
BOLD='\033[1m'
|
|
19
|
+
|
|
20
|
+
print_header() {
|
|
21
|
+
echo -e "\n${BLUE}${BOLD}[Secure SDLC]${NC} $1"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
print_pass() {
|
|
25
|
+
echo -e " ${GREEN}✓${NC} $1"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
print_warn() {
|
|
29
|
+
echo -e " ${YELLOW}⚠${NC} $1"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
print_fail() {
|
|
33
|
+
echo -e " ${RED}✗${NC} $1"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)
|
|
37
|
+
BLOCKERS=0
|
|
38
|
+
|
|
39
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# ──────────────────────────────────────────────────────────────────
|
|
44
|
+
# 1. SECRET DETECTION
|
|
45
|
+
# Pattern-based scan on staged changes.
|
|
46
|
+
# High-confidence patterns = block commit.
|
|
47
|
+
# Medium-confidence patterns = warn.
|
|
48
|
+
# ──────────────────────────────────────────────────────────────────
|
|
49
|
+
print_header "Secret Detection"
|
|
50
|
+
|
|
51
|
+
STAGED_DIFF=$(git diff --cached 2>/dev/null || true)
|
|
52
|
+
|
|
53
|
+
# High-confidence patterns — block on match
|
|
54
|
+
HIGH_PATTERNS=(
|
|
55
|
+
# AWS credentials
|
|
56
|
+
'AKIA[0-9A-Z]{16}'
|
|
57
|
+
'aws_secret_access_key\s*=\s*["\x27][A-Za-z0-9/+=]{40}["\x27]'
|
|
58
|
+
# Generic API key assignments with long values
|
|
59
|
+
'(api_key|apikey|api_secret|client_secret|access_token)\s*[:=]\s*["\x27][A-Za-z0-9_\-]{32,}["\x27]'
|
|
60
|
+
# Private keys
|
|
61
|
+
'-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY'
|
|
62
|
+
# GitHub tokens
|
|
63
|
+
'ghp_[A-Za-z0-9]{36}'
|
|
64
|
+
'github_pat_[A-Za-z0-9_]{82}'
|
|
65
|
+
# Stripe live keys
|
|
66
|
+
'sk_live_[A-Za-z0-9]{24,}'
|
|
67
|
+
# Twilio
|
|
68
|
+
'SK[a-z0-9]{32}'
|
|
69
|
+
# Hardcoded connection strings with credentials
|
|
70
|
+
'(mysql|postgresql|mongodb|redis):\/\/[^:@\s]+:[^@\s]+@'
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Medium-confidence patterns — warn only
|
|
74
|
+
MEDIUM_PATTERNS=(
|
|
75
|
+
'password\s*=\s*["\x27][^"\x27]{8,}["\x27]'
|
|
76
|
+
'passwd\s*=\s*["\x27][^"\x27]{8,}["\x27]'
|
|
77
|
+
'secret\s*=\s*["\x27][^"\x27]{8,}["\x27]'
|
|
78
|
+
'token\s*=\s*["\x27][^"\x27]{20,}["\x27]'
|
|
79
|
+
'Authorization:\s*Bearer\s+[A-Za-z0-9._\-]+'
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
SECRET_FOUND=0
|
|
83
|
+
|
|
84
|
+
for pattern in "${HIGH_PATTERNS[@]}"; do
|
|
85
|
+
if echo "$STAGED_DIFF" | grep -qE "$pattern" 2>/dev/null; then
|
|
86
|
+
MATCH=$(echo "$STAGED_DIFF" | grep -E "$pattern" | head -1)
|
|
87
|
+
print_fail "CRITICAL SECRET DETECTED — pattern: ${pattern:0:40}..."
|
|
88
|
+
echo -e " ${RED}Match context: ${MATCH:0:120}${NC}"
|
|
89
|
+
echo ""
|
|
90
|
+
SECRET_FOUND=1
|
|
91
|
+
BLOCKERS=$((BLOCKERS + 1))
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
for pattern in "${MEDIUM_PATTERNS[@]}"; do
|
|
96
|
+
if echo "$STAGED_DIFF" | grep -qE "$pattern" 2>/dev/null; then
|
|
97
|
+
MATCH=$(echo "$STAGED_DIFF" | grep -E "$pattern" | head -1)
|
|
98
|
+
# Skip if it's clearly a test/example file
|
|
99
|
+
if echo "$STAGED_DIFF" | grep -B5 -A5 "$pattern" | grep -qiE "(test|spec|example|fixture|mock|fake|dummy)"; then
|
|
100
|
+
print_warn "Possible secret in test/example file — verify this is not a real credential"
|
|
101
|
+
else
|
|
102
|
+
print_warn "Possible secret detected — verify this is not a real credential"
|
|
103
|
+
echo " Pattern: ${pattern:0:60}"
|
|
104
|
+
BLOCKERS=$((BLOCKERS + 1))
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
if [ $SECRET_FOUND -eq 0 ] && [ $BLOCKERS -eq 0 ]; then
|
|
110
|
+
print_pass "No secrets detected"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# ──────────────────────────────────────────────────────────────────
|
|
114
|
+
# 2. LOCK FILE CONSISTENCY
|
|
115
|
+
# If package.json changed, package-lock.json / yarn.lock should too.
|
|
116
|
+
# ──────────────────────────────────────────────────────────────────
|
|
117
|
+
print_header "Dependency Lock File Check"
|
|
118
|
+
|
|
119
|
+
if echo "$STAGED_FILES" | grep -q "^package\.json$"; then
|
|
120
|
+
if ! echo "$STAGED_FILES" | grep -qE "^(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$"; then
|
|
121
|
+
print_warn "package.json changed but no lock file updated"
|
|
122
|
+
print_warn "Run: npm install (or yarn/pnpm install) and stage the lock file"
|
|
123
|
+
# This is a warning, not a block, as the workflow might intentionally not commit lock files
|
|
124
|
+
else
|
|
125
|
+
print_pass "Lock file updated with package.json"
|
|
126
|
+
fi
|
|
127
|
+
elif echo "$STAGED_FILES" | grep -qE "^(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$"; then
|
|
128
|
+
if ! echo "$STAGED_FILES" | grep -q "^package\.json$"; then
|
|
129
|
+
print_pass "Lock file update (no package.json change — likely npm install/upgrade)"
|
|
130
|
+
fi
|
|
131
|
+
else
|
|
132
|
+
print_pass "No package manifest changes"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
if echo "$STAGED_FILES" | grep -q "requirements.*\.txt\|pyproject\.toml\|Pipfile$"; then
|
|
136
|
+
if ! echo "$STAGED_FILES" | grep -q "Pipfile\.lock\|poetry\.lock\|uv\.lock"; then
|
|
137
|
+
print_warn "Python dependencies changed but no lock file (Pipfile.lock/poetry.lock) updated"
|
|
138
|
+
else
|
|
139
|
+
print_pass "Python lock file updated"
|
|
140
|
+
fi
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# ──────────────────────────────────────────────────────────────────
|
|
144
|
+
# 3. DANGEROUS PATTERNS IN CODE
|
|
145
|
+
# Catch common security anti-patterns before they're committed.
|
|
146
|
+
# ──────────────────────────────────────────────────────────────────
|
|
147
|
+
print_header "Security Anti-Pattern Check"
|
|
148
|
+
|
|
149
|
+
# Files to scan (exclude vendor/deps/generated)
|
|
150
|
+
SCAN_FILES=$(echo "$STAGED_FILES" | grep -vE "node_modules|\.min\.|vendor/|dist/|generated/|\.lock$|\.snap$" || true)
|
|
151
|
+
|
|
152
|
+
if [ -n "$SCAN_FILES" ]; then
|
|
153
|
+
CODE_ISSUES=0
|
|
154
|
+
|
|
155
|
+
# eval() with non-literal arguments — common code injection vector
|
|
156
|
+
if echo "$STAGED_DIFF" | grep -qE 'eval\s*\([^)]{5,}\)' 2>/dev/null; then
|
|
157
|
+
# Exclude template literals that are clearly constant
|
|
158
|
+
if echo "$STAGED_DIFF" | grep -E 'eval\s*\(' | grep -qvE "eval\s*\(['\"]"; then
|
|
159
|
+
print_warn "eval() with dynamic argument detected — review for code injection risk"
|
|
160
|
+
CODE_ISSUES=$((CODE_ISSUES + 1))
|
|
161
|
+
fi
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# SQL string concatenation patterns
|
|
165
|
+
if echo "$STAGED_DIFF" | grep -qE '(SELECT|INSERT|UPDATE|DELETE|WHERE).*\+.*\$|f"(SELECT|INSERT|UPDATE|DELETE|WHERE)' 2>/dev/null; then
|
|
166
|
+
print_warn "Possible SQL string concatenation — use parameterised queries"
|
|
167
|
+
CODE_ISSUES=$((CODE_ISSUES + 1))
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# TODO/FIXME security markers
|
|
171
|
+
if echo "$STAGED_DIFF" | grep -qiE '\+.*(TODO|FIXME).*(auth|security|inject|password|secret|token)' 2>/dev/null; then
|
|
172
|
+
print_warn "Security-related TODO/FIXME in staged changes — review before shipping"
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# debug/console.log with sensitive keywords
|
|
176
|
+
if echo "$STAGED_DIFF" | grep -qiE '\+(console\.log|print|debugger).*(password|secret|token|key|credential)' 2>/dev/null; then
|
|
177
|
+
print_warn "Possible sensitive data in log statement — review before committing"
|
|
178
|
+
CODE_ISSUES=$((CODE_ISSUES + 1))
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
if [ $CODE_ISSUES -eq 0 ]; then
|
|
182
|
+
print_pass "No obvious security anti-patterns detected"
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# ──────────────────────────────────────────────────────────────────
|
|
187
|
+
# RESULT
|
|
188
|
+
# ──────────────────────────────────────────────────────────────────
|
|
189
|
+
echo ""
|
|
190
|
+
|
|
191
|
+
if [ $BLOCKERS -gt 0 ]; then
|
|
192
|
+
echo -e "${RED}${BOLD}[Secure SDLC] Pre-commit hook BLOCKED — $BLOCKERS issue(s) must be resolved.${NC}"
|
|
193
|
+
echo ""
|
|
194
|
+
echo -e "${YELLOW}If a secret was detected:${NC}"
|
|
195
|
+
echo " 1. Remove it from staged files"
|
|
196
|
+
echo " 2. Rotate the secret immediately — assume it is compromised even on a private branch"
|
|
197
|
+
echo " 3. Move it to a secrets manager (Vault, AWS Secrets Manager, etc.)"
|
|
198
|
+
echo ""
|
|
199
|
+
echo -e "${YELLOW}For help with secrets management:${NC}"
|
|
200
|
+
echo " claude --agent cloud-platform-engineer 'Advise on secrets management for [your stack]'"
|
|
201
|
+
echo " # OR: sdlc_security_champion({ question_or_code: 'How do I manage secrets for [stack]?' })"
|
|
202
|
+
echo ""
|
|
203
|
+
exit 1
|
|
204
|
+
else
|
|
205
|
+
echo -e "${GREEN}${BOLD}[Secure SDLC] Pre-commit checks passed.${NC}"
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
exit 0
|
package/hooks/pre-push
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Secure SDLC — Pre-Push Hook
|
|
3
|
+
#
|
|
4
|
+
# Runs before pushing to remote. Heavier checks than pre-commit:
|
|
5
|
+
# 1. Full secret scan on all changed commits (not just staged)
|
|
6
|
+
# 2. Security artefact gate for pushes to protected branches
|
|
7
|
+
# 3. Nudge to run SAST if pushing to main/master
|
|
8
|
+
#
|
|
9
|
+
# To bypass in emergencies: git push --no-verify
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
RED='\033[0;31m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
BLUE='\033[0;34m'
|
|
17
|
+
NC='\033[0m'
|
|
18
|
+
BOLD='\033[1m'
|
|
19
|
+
|
|
20
|
+
print_header() {
|
|
21
|
+
echo -e "\n${BLUE}${BOLD}[Secure SDLC]${NC} $1"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
print_pass() { echo -e " ${GREEN}✓${NC} $1"; }
|
|
25
|
+
print_warn() { echo -e " ${YELLOW}⚠${NC} $1"; }
|
|
26
|
+
print_fail() { echo -e " ${RED}✗${NC} $1"; }
|
|
27
|
+
|
|
28
|
+
# Read the push destination
|
|
29
|
+
while read local_ref local_sha remote_ref remote_sha; do
|
|
30
|
+
REMOTE_BRANCH="${remote_ref##refs/heads/}"
|
|
31
|
+
LOCAL_BRANCH="${local_ref##refs/heads/}"
|
|
32
|
+
|
|
33
|
+
# Determine if pushing to a protected branch
|
|
34
|
+
PROTECTED=false
|
|
35
|
+
if [[ "$REMOTE_BRANCH" =~ ^(main|master|develop|staging|release/.*)$ ]]; then
|
|
36
|
+
PROTECTED=true
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# ──────────────────────────────────────────────────────────────
|
|
40
|
+
# 1. SECURITY ARTEFACT CHECK (protected branches only)
|
|
41
|
+
# ──────────────────────────────────────────────────────────────
|
|
42
|
+
if [ "$PROTECTED" = true ]; then
|
|
43
|
+
print_header "Security Artefact Gate (push to $REMOTE_BRANCH)"
|
|
44
|
+
|
|
45
|
+
MISSING=()
|
|
46
|
+
WARNINGS=()
|
|
47
|
+
|
|
48
|
+
# Plan artefacts — required for any push to protected branches
|
|
49
|
+
for f in "docs/security-requirements.md" "docs/risk-register.md"; do
|
|
50
|
+
if [ ! -f "$f" ]; then
|
|
51
|
+
WARNINGS+=("$f")
|
|
52
|
+
else
|
|
53
|
+
print_pass "$f"
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
# Stricter check for main/master
|
|
58
|
+
if [[ "$REMOTE_BRANCH" =~ ^(main|master)$ ]]; then
|
|
59
|
+
for f in "docs/threat-model.md" "docs/sast-findings.md"; do
|
|
60
|
+
if [ ! -f "$f" ]; then
|
|
61
|
+
MISSING+=("$f")
|
|
62
|
+
else
|
|
63
|
+
print_pass "$f"
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
if [ ${#MISSING[@]} -gt 0 ]; then
|
|
69
|
+
echo ""
|
|
70
|
+
print_fail "Missing required security artefacts for push to $REMOTE_BRANCH:"
|
|
71
|
+
for m in "${MISSING[@]}"; do
|
|
72
|
+
echo " ✗ $m"
|
|
73
|
+
done
|
|
74
|
+
echo ""
|
|
75
|
+
echo -e " Generate them:"
|
|
76
|
+
echo -e " ${YELLOW}secure-sdlc kickoff${NC} — interactive wizard"
|
|
77
|
+
echo -e " ${YELLOW}claude --agent product-manager 'Define security requirements for ...'${NC}"
|
|
78
|
+
echo ""
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [ ${#WARNINGS[@]} -gt 0 ]; then
|
|
83
|
+
for w in "${WARNINGS[@]}"; do
|
|
84
|
+
print_warn "$w is missing — run 'secure-sdlc kickoff' to generate it"
|
|
85
|
+
done
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ──────────────────────────────────────────────────────────────
|
|
90
|
+
# 2. CHECK FOR UNRESOLVED CRITICAL/HIGH FINDINGS
|
|
91
|
+
# ──────────────────────────────────────────────────────────────
|
|
92
|
+
if [ "$PROTECTED" = true ]; then
|
|
93
|
+
print_header "Open Finding Check"
|
|
94
|
+
|
|
95
|
+
OPEN_CRITICALS=0
|
|
96
|
+
|
|
97
|
+
for doc in "docs/sast-findings.md" "docs/test-security-report.md"; do
|
|
98
|
+
if [ -f "$doc" ]; then
|
|
99
|
+
COUNT=$(grep -icE 'CRITICAL' "$doc" 2>/dev/null | tr -d ' ' || echo "0")
|
|
100
|
+
RESOLVED=$(grep -icE 'resolved|mitigated|false positive|closed' "$doc" 2>/dev/null | tr -d ' ' || echo "0")
|
|
101
|
+
UNRESOLVED=$(( COUNT - RESOLVED ))
|
|
102
|
+
|
|
103
|
+
if [ "$UNRESOLVED" -gt 0 ]; then
|
|
104
|
+
OPEN_CRITICALS=$((OPEN_CRITICALS + UNRESOLVED))
|
|
105
|
+
print_warn "Possible open CRITICAL findings in $doc — verify status"
|
|
106
|
+
else
|
|
107
|
+
print_pass "$doc — no obvious open CRITICAL findings"
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# ──────────────────────────────────────────────────────────────
|
|
114
|
+
# 3. SAST NUDGE (main/master pushes)
|
|
115
|
+
# ──────────────────────────────────────────────────────────────
|
|
116
|
+
if [[ "$REMOTE_BRANCH" =~ ^(main|master)$ ]]; then
|
|
117
|
+
print_header "Pre-Push Security Reminder"
|
|
118
|
+
echo -e " You are pushing to ${BOLD}$REMOTE_BRANCH${NC}. Consider running:\n"
|
|
119
|
+
echo -e " ${YELLOW}claude --agent dev-lead 'Review recent commits for security issues'${NC}"
|
|
120
|
+
echo -e " ${YELLOW}claude --agent appsec-engineer 'Triage any SAST findings'${NC}"
|
|
121
|
+
echo -e " ${YELLOW}secure-sdlc status${NC} — check which SDLC phases are complete"
|
|
122
|
+
echo ""
|
|
123
|
+
fi
|
|
124
|
+
done
|
|
125
|
+
|
|
126
|
+
echo -e "${GREEN}${BOLD}[Secure SDLC] Pre-push checks passed.${NC}\n"
|
|
127
|
+
exit 0
|
package/mcp/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Secure SDLC — MCP Server
|
|
2
|
+
|
|
3
|
+
This MCP server exposes the full Secure SDLC agent team as structured tools, compatible with **any MCP-compliant AI coding tool**:
|
|
4
|
+
|
|
5
|
+
- **Cursor** (via MCP settings JSON)
|
|
6
|
+
- **Claude Code** (via `claude mcp add`)
|
|
7
|
+
- **Windsurf / Cascade**
|
|
8
|
+
- **Zed AI**
|
|
9
|
+
- **Continue.dev**
|
|
10
|
+
- Any other tool implementing the [Model Context Protocol](https://modelcontextprotocol.io)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Available tools
|
|
15
|
+
|
|
16
|
+
| Tool | What it does |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `sdlc_plan_feature` | ASVS requirements + risk register for a new feature |
|
|
19
|
+
| `sdlc_threat_model` | STRIDE (+ LINDDUN) threat model against your architecture |
|
|
20
|
+
| `sdlc_review_pr` | Security review a PR — dev-lead + appsec-engineer |
|
|
21
|
+
| `sdlc_review_infra` | IaC security review (Terraform, Helm, K8s, etc.) |
|
|
22
|
+
| `sdlc_triage_sast` | Triage SAST findings from any tool |
|
|
23
|
+
| `sdlc_release_gate` | Pre-release go/no-go security gate |
|
|
24
|
+
| `sdlc_check_compliance` | Map controls to SOC 2, ISO 27001, GDPR, PCI DSS, etc. |
|
|
25
|
+
| `sdlc_init_project` | Scaffold a new project with Secure SDLC structure |
|
|
26
|
+
| `sdlc_security_champion` | Quick security Q&A and lightweight code review |
|
|
27
|
+
| `sdlc_ai_security_review` | Security review for AI/LLM features |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### Prerequisites
|
|
34
|
+
|
|
35
|
+
- Node.js 18+
|
|
36
|
+
|
|
37
|
+
### Dependencies
|
|
38
|
+
|
|
39
|
+
If you use the **published npm package** `@kaademos/secure-sdlc`, install it globally (or use `npx`); the Model Context Protocol SDK is installed as a dependency of that package, and the server path is shown by `secure-sdlc paths`.
|
|
40
|
+
|
|
41
|
+
If you **cloned the repository**, install from the **repo root** (not only `mcp/`):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd /path/to/secure-sdlc-agents
|
|
45
|
+
npm install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The `mcp/` folder alone is not meant to be published; `mcp/package.json` is marked `private`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Cursor setup
|
|
53
|
+
|
|
54
|
+
Add to your Cursor MCP settings (`~/.cursor/mcp.json` or workspace `.cursor/mcp.json`):
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"secure-sdlc": {
|
|
60
|
+
"command": "node",
|
|
61
|
+
"args": ["/absolute/path/to/secure-sdlc-agents/mcp/src/server.js"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then restart Cursor. The `sdlc_*` tools will appear in Cursor's agent tool list.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Claude Code setup
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
claude mcp add secure-sdlc -- node /absolute/path/to/secure-sdlc-agents/mcp/src/server.js
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Windsurf / Cascade setup
|
|
80
|
+
|
|
81
|
+
Add to your Windsurf MCP config:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"secure-sdlc": {
|
|
87
|
+
"command": "node",
|
|
88
|
+
"args": ["/absolute/path/to/secure-sdlc-agents/mcp/src/server.js"]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Usage examples
|
|
97
|
+
|
|
98
|
+
### In any MCP-enabled chat/agent session:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Use sdlc_plan_feature to define security requirements for a user authentication
|
|
102
|
+
feature with email/password + TOTP. Stack is Next.js + Supabase. ASVS L2.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Use sdlc_review_pr to security review this code diff: [paste diff]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
Use sdlc_threat_model on this architecture: React SPA → API Gateway →
|
|
111
|
+
Lambda functions → RDS PostgreSQL. Auth via Cognito User Pools.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Use sdlc_release_gate for v2.1.0. Docs are at ./docs/
|
|
116
|
+
```
|
package/mcp/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@secure-sdlc/mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "MCP server exposing the Secure SDLC agent team to any MCP-compatible AI coding tool",
|
|
7
|
+
"main": "src/server.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"secure-sdlc-mcp": "src/server.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "node src/server.js",
|
|
13
|
+
"dev": "node --watch src/server.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["mcp", "security", "sdlc", "appsec", "compliance", "claude", "cursor"],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|