@samahlstrom/forge-cli 0.1.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.
Files changed (100) hide show
  1. package/README.md +175 -0
  2. package/bin/forge.js +2 -0
  3. package/dist/addons/index.d.ts +25 -0
  4. package/dist/addons/index.js +139 -0
  5. package/dist/addons/index.js.map +1 -0
  6. package/dist/commands/add.d.ts +1 -0
  7. package/dist/commands/add.js +61 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/doctor.d.ts +1 -0
  10. package/dist/commands/doctor.js +177 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/ingest.d.ts +24 -0
  13. package/dist/commands/ingest.js +316 -0
  14. package/dist/commands/ingest.js.map +1 -0
  15. package/dist/commands/init.d.ts +8 -0
  16. package/dist/commands/init.js +557 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/remove.d.ts +1 -0
  19. package/dist/commands/remove.js +42 -0
  20. package/dist/commands/remove.js.map +1 -0
  21. package/dist/commands/status.d.ts +1 -0
  22. package/dist/commands/status.js +48 -0
  23. package/dist/commands/status.js.map +1 -0
  24. package/dist/commands/upgrade.d.ts +5 -0
  25. package/dist/commands/upgrade.js +190 -0
  26. package/dist/commands/upgrade.js.map +1 -0
  27. package/dist/detect/features.d.ts +10 -0
  28. package/dist/detect/features.js +33 -0
  29. package/dist/detect/features.js.map +1 -0
  30. package/dist/detect/go.d.ts +3 -0
  31. package/dist/detect/go.js +38 -0
  32. package/dist/detect/go.js.map +1 -0
  33. package/dist/detect/index.d.ts +25 -0
  34. package/dist/detect/index.js +32 -0
  35. package/dist/detect/index.js.map +1 -0
  36. package/dist/detect/node.d.ts +3 -0
  37. package/dist/detect/node.js +99 -0
  38. package/dist/detect/node.js.map +1 -0
  39. package/dist/detect/python.d.ts +3 -0
  40. package/dist/detect/python.js +86 -0
  41. package/dist/detect/python.js.map +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +51 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/render/engine.d.ts +8 -0
  46. package/dist/render/engine.js +71 -0
  47. package/dist/render/engine.js.map +1 -0
  48. package/dist/render/merge.d.ts +5 -0
  49. package/dist/render/merge.js +33 -0
  50. package/dist/render/merge.js.map +1 -0
  51. package/dist/utils/fs.d.ts +8 -0
  52. package/dist/utils/fs.js +42 -0
  53. package/dist/utils/fs.js.map +1 -0
  54. package/dist/utils/git.d.ts +3 -0
  55. package/dist/utils/git.js +31 -0
  56. package/dist/utils/git.js.map +1 -0
  57. package/dist/utils/hash.d.ts +8 -0
  58. package/dist/utils/hash.js +22 -0
  59. package/dist/utils/hash.js.map +1 -0
  60. package/dist/utils/yaml.d.ts +3 -0
  61. package/dist/utils/yaml.js +12 -0
  62. package/dist/utils/yaml.js.map +1 -0
  63. package/package.json +53 -0
  64. package/templates/addons/beads-dolt-backend/files/dolt-setup.sh +267 -0
  65. package/templates/addons/beads-dolt-backend/manifest.yaml +13 -0
  66. package/templates/addons/browser-testing/files/browser-smoke.sh +196 -0
  67. package/templates/addons/browser-testing/files/visual-qa.md +103 -0
  68. package/templates/addons/browser-testing/manifest.yaml +20 -0
  69. package/templates/addons/compliance-hipaa/files/hipaa-checks.sh +184 -0
  70. package/templates/addons/compliance-hipaa/files/hipaa-context.md +91 -0
  71. package/templates/addons/compliance-hipaa/manifest.yaml +15 -0
  72. package/templates/addons/compliance-soc2/files/soc2-checks.sh +232 -0
  73. package/templates/addons/compliance-soc2/files/soc2-context.md +147 -0
  74. package/templates/addons/compliance-soc2/manifest.yaml +15 -0
  75. package/templates/core/CLAUDE.md.hbs +70 -0
  76. package/templates/core/agents/architect.md.hbs +68 -0
  77. package/templates/core/agents/backend.md.hbs +27 -0
  78. package/templates/core/agents/frontend.md.hbs +25 -0
  79. package/templates/core/agents/quality.md.hbs +40 -0
  80. package/templates/core/agents/security.md.hbs +53 -0
  81. package/templates/core/context/project.md.hbs +60 -0
  82. package/templates/core/forge.yaml.hbs +69 -0
  83. package/templates/core/hooks/post-edit.sh.hbs +8 -0
  84. package/templates/core/hooks/pre-edit.sh.hbs +41 -0
  85. package/templates/core/hooks/session-start.sh.hbs +34 -0
  86. package/templates/core/pipeline/classify.sh.hbs +159 -0
  87. package/templates/core/pipeline/decompose.md.hbs +100 -0
  88. package/templates/core/pipeline/deliver.sh.hbs +171 -0
  89. package/templates/core/pipeline/execute.md.hbs +138 -0
  90. package/templates/core/pipeline/intake.sh.hbs +152 -0
  91. package/templates/core/pipeline/orchestrator.sh.hbs +361 -0
  92. package/templates/core/pipeline/verify.sh.hbs +160 -0
  93. package/templates/core/settings.json.hbs +55 -0
  94. package/templates/core/skill-creator.md.hbs +151 -0
  95. package/templates/core/skill-deliver.md.hbs +46 -0
  96. package/templates/core/skill-ingest.md.hbs +245 -0
  97. package/templates/presets/go/stack.md.hbs +133 -0
  98. package/templates/presets/python-fastapi/stack.md.hbs +101 -0
  99. package/templates/presets/react-next-ts/stack.md.hbs +77 -0
  100. package/templates/presets/sveltekit-ts/stack.md.hbs +116 -0
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # hipaa-checks.sh — HIPAA compliance scanning for forge projects
5
+ # Checks for PHI leaks, auth gaps, and encryption issues
6
+
7
+ RESULTS_FILE=".forge/state/hipaa-results.json"
8
+ PASS=0
9
+ FAIL=0
10
+ WARN=0
11
+ FINDINGS=()
12
+
13
+ mkdir -p "$(dirname "$RESULTS_FILE")"
14
+
15
+ # --- Helpers ---
16
+
17
+ log() { echo "[hipaa] $*"; }
18
+ finding() {
19
+ local severity="$1" file="$2" line="$3" rule="$4" detail="$5"
20
+ FINDINGS+=("{\"severity\":\"${severity}\",\"file\":\"${file}\",\"line\":${line},\"rule\":\"${rule}\",\"detail\":\"${detail}\"}")
21
+ if [ "$severity" = "fail" ]; then
22
+ FAIL=$((FAIL + 1))
23
+ else
24
+ WARN=$((WARN + 1))
25
+ fi
26
+ }
27
+
28
+ # --- Check 1: PHI in log statements ---
29
+
30
+ log "Checking for PHI in log statements..."
31
+
32
+ # Patterns that suggest logging PHI fields
33
+ PHI_LOG_PATTERNS=(
34
+ 'console\.\(log\|error\|warn\|info\|debug\).*\(patient\|ssn\|dob\|dateOfBirth\|diagnosis\|mrn\|medicalRecord\|socialSecurity\)'
35
+ 'logger\.\(info\|warn\|error\|debug\).*\(patient\|ssn\|dob\|dateOfBirth\|diagnosis\|mrn\|medicalRecord\|socialSecurity\)'
36
+ )
37
+
38
+ for pattern in "${PHI_LOG_PATTERNS[@]}"; do
39
+ while IFS=: read -r file line _match; do
40
+ [ -z "$file" ] && continue
41
+ finding "fail" "$file" "$line" "phi-in-logs" "Potential PHI logged — review this log statement"
42
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' --include='*.svelte' --include='*.py' . 2>/dev/null | head -50 || true)
43
+ done
44
+
45
+ # --- Check 2: PHI in URLs / route params ---
46
+
47
+ log "Checking for PHI in URL patterns..."
48
+
49
+ URL_PHI_PATTERNS=(
50
+ 'patient[Ii]d.*params\|params.*patient[Ii]d'
51
+ 'ssn.*query\|query.*ssn'
52
+ 'dob.*searchParams\|searchParams.*dob'
53
+ '\$page\.params.*\(patient\|ssn\|dob\|mrn\)'
54
+ )
55
+
56
+ for pattern in "${URL_PHI_PATTERNS[@]}"; do
57
+ while IFS=: read -r file line _match; do
58
+ [ -z "$file" ] && continue
59
+ finding "fail" "$file" "$line" "phi-in-url" "Potential PHI in URL parameter"
60
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' --include='*.svelte' . 2>/dev/null | head -50 || true)
61
+ done
62
+
63
+ # --- Check 3: PHI in browser storage ---
64
+
65
+ log "Checking for PHI in browser storage usage..."
66
+
67
+ STORAGE_PATTERNS=(
68
+ 'localStorage\.set.*\(patient\|ssn\|dob\|diagnosis\|mrn\)'
69
+ 'sessionStorage\.set.*\(patient\|ssn\|dob\|diagnosis\|mrn\)'
70
+ 'indexedDB.*\(patient\|ssn\|dob\|diagnosis\|mrn\)'
71
+ )
72
+
73
+ for pattern in "${STORAGE_PATTERNS[@]}"; do
74
+ while IFS=: read -r file line _match; do
75
+ [ -z "$file" ] && continue
76
+ finding "fail" "$file" "$line" "phi-in-storage" "Potential PHI in browser storage"
77
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' --include='*.svelte' . 2>/dev/null | head -50 || true)
78
+ done
79
+
80
+ # --- Check 4: Unprotected endpoints ---
81
+
82
+ log "Checking for endpoints without auth guards..."
83
+
84
+ # Look for API endpoints / server routes missing auth checks
85
+ if [ -d "src/routes" ]; then
86
+ while IFS= read -r file; do
87
+ if ! grep -q 'locals\.\(user\|session\|auth\)\|getSession\|requireAuth\|authenticate\|verifyToken\|event\.locals' "$file" 2>/dev/null; then
88
+ finding "warn" "$file" 0 "no-auth-guard" "Server endpoint may lack authentication — verify manually"
89
+ fi
90
+ done < <(find . -path '*/routes/*' \( -name '+server.ts' -o -name '+server.js' \) -not -path '*/node_modules/*' 2>/dev/null | head -100)
91
+ fi
92
+
93
+ # --- Check 5: Wildcard Firestore rules ---
94
+
95
+ log "Checking Firestore security rules..."
96
+
97
+ RULES_FILES=$(find . -name 'firestore.rules' -o -name '*.rules' -not -path '*/node_modules/*' 2>/dev/null || true)
98
+ for rules_file in $RULES_FILES; do
99
+ while IFS=: read -r _ line _match; do
100
+ [ -z "$line" ] && continue
101
+ finding "fail" "$rules_file" "$line" "wildcard-rules" "Overly permissive Firestore rule — never allow unrestricted access to PHI"
102
+ done < <(grep -n 'allow.*:.*if true\|allow.*:.*if request\.auth != null' "$rules_file" 2>/dev/null || true)
103
+ done
104
+
105
+ # --- Check 6: HTTP (non-TLS) API calls ---
106
+
107
+ log "Checking for non-HTTPS API calls..."
108
+
109
+ while IFS=: read -r file line _match; do
110
+ [ -z "$file" ] && continue
111
+ # Skip localhost and test files
112
+ if echo "$_match" | grep -q 'localhost\|127\.0\.0\.1\|0\.0\.0\.0'; then
113
+ continue
114
+ fi
115
+ finding "fail" "$file" "$line" "no-tls" "HTTP (non-TLS) API call detected — use HTTPS"
116
+ done < <(grep -rn "fetch(['\"]http:" --include='*.ts' --include='*.js' --include='*.svelte' . 2>/dev/null | grep -v node_modules | grep -v '\.test\.' | head -50 || true)
117
+
118
+ # --- Check 7: Secrets in code ---
119
+
120
+ log "Checking for hardcoded secrets..."
121
+
122
+ SECRET_PATTERNS=(
123
+ 'password\s*=\s*["\x27][^"\x27]\{8,\}'
124
+ 'api[_-]\?key\s*=\s*["\x27][A-Za-z0-9]\{20,\}'
125
+ 'secret\s*=\s*["\x27][^"\x27]\{8,\}'
126
+ 'PRIVATE.KEY'
127
+ )
128
+
129
+ for pattern in "${SECRET_PATTERNS[@]}"; do
130
+ while IFS=: read -r file line _match; do
131
+ [ -z "$file" ] && continue
132
+ finding "warn" "$file" "$line" "hardcoded-secret" "Possible hardcoded secret — use environment variables or secret manager"
133
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' --include='*.svelte' --include='*.py' --include='*.env*' . 2>/dev/null | grep -v node_modules | grep -v '\.test\.' | grep -v '\.example' | head -50 || true)
134
+ done
135
+
136
+ # --- Check 8: Semgrep HIPAA rules (if available) ---
137
+
138
+ if command -v semgrep > /dev/null 2>&1; then
139
+ log "Running semgrep HIPAA rules..."
140
+ semgrep --config "p/hipaa" --json --quiet . 2>/dev/null > /tmp/forge-semgrep-hipaa.json || true
141
+
142
+ SEMGREP_COUNT=$(jq '.results | length' /tmp/forge-semgrep-hipaa.json 2>/dev/null || echo "0")
143
+ if [ "$SEMGREP_COUNT" -gt 0 ]; then
144
+ log "Semgrep found ${SEMGREP_COUNT} HIPAA findings"
145
+ FAIL=$((FAIL + SEMGREP_COUNT))
146
+ # Merge semgrep findings
147
+ while IFS= read -r sg_finding; do
148
+ FINDINGS+=("$sg_finding")
149
+ done < <(jq -c '.results[] | {severity:"fail",file:.path,line:.start.line,rule:.check_id,detail:.extra.message}' /tmp/forge-semgrep-hipaa.json 2>/dev/null || true)
150
+ fi
151
+ else
152
+ log "Semgrep not installed — skipping advanced HIPAA rules (install with: pip install semgrep)"
153
+ fi
154
+
155
+ # --- Passed checks ---
156
+
157
+ # Count passes for checks that found no issues
158
+ TOTAL_CHECKS=8
159
+ PASS=$((TOTAL_CHECKS - (FAIL > 0 ? 1 : 0) - (WARN > 0 ? 1 : 0)))
160
+ [ "$PASS" -lt 0 ] && PASS=0
161
+
162
+ # --- Write results ---
163
+
164
+ FINDINGS_JSON=$(printf '%s,' "${FINDINGS[@]}" 2>/dev/null | sed 's/,$//')
165
+ [ -z "$FINDINGS_JSON" ] && FINDINGS_JSON=""
166
+
167
+ cat > "$RESULTS_FILE" <<EOF
168
+ {
169
+ "addon": "compliance-hipaa",
170
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
171
+ "summary": {
172
+ "total_checks": ${TOTAL_CHECKS},
173
+ "pass": $((TOTAL_CHECKS - (FAIL > 0 ? 1 : 0) - (WARN > 0 ? 1 : 0))),
174
+ "fail": ${FAIL},
175
+ "warn": ${WARN}
176
+ },
177
+ "findings": [${FINDINGS_JSON}]
178
+ }
179
+ EOF
180
+
181
+ log "Results written to ${RESULTS_FILE}"
182
+ log "Summary: ${FAIL} failures, ${WARN} warnings"
183
+
184
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1
@@ -0,0 +1,91 @@
1
+ # HIPAA Compliance Context
2
+
3
+ This context overlay applies to all agents working on code in this project. The codebase handles Protected Health Information (PHI) and must comply with the HIPAA Security Rule and Privacy Rule.
4
+
5
+ ## PHI Field Rules
6
+
7
+ PHI includes any individually identifiable health information: names, dates of birth, medical record numbers, diagnoses, treatment records, SSNs, email addresses, phone numbers, IP addresses (when linked to a patient), and any combination of fields that could identify a patient.
8
+
9
+ ### Absolute Rules (Never Violate)
10
+
11
+ 1. **Never log PHI.** No patient names, DOBs, MRNs, diagnoses, or identifiers in `console.log`, `console.error`, `logger.*`, or any logging output. Use opaque identifiers (e.g., hashed IDs) in logs.
12
+
13
+ 2. **Never store PHI in client-side state** that persists beyond the session. No `localStorage`, `sessionStorage`, `IndexedDB`, or cookies containing PHI. In-memory state (e.g., Svelte stores) is acceptable only during an active authenticated session.
14
+
15
+ 3. **Never include PHI in URLs.** No patient identifiers in route params, query strings, or URL fragments. Use opaque tokens that resolve server-side.
16
+
17
+ 4. **Never expose PHI in browser storage.** This includes service worker caches, browser history entries, and `window.name`.
18
+
19
+ 5. **Encrypt PHI at rest.** Firestore data containing PHI must use encrypted fields or be stored in collections with server-side encryption enabled. Backups must be encrypted.
20
+
21
+ 6. **Encrypt PHI in transit.** All API calls must use HTTPS. Verify TLS configuration. No HTTP fallbacks.
22
+
23
+ 7. **Minimum Necessary principle.** Only fetch and display the PHI fields required for the current operation. Do not load full patient records when only a name is needed.
24
+
25
+ 8. **Audit all PHI access.** Every read/write of PHI must produce an audit log entry with: who accessed it, when, what was accessed, and why (purpose/context).
26
+
27
+ ## Authentication Requirements
28
+
29
+ - All endpoints serving PHI require authentication
30
+ - Sessions must time out after 15 minutes of inactivity
31
+ - Re-authentication required for sensitive operations (viewing full records, exporting data)
32
+ - Multi-factor authentication required for administrative access
33
+ - Failed login attempts must be logged and rate-limited
34
+ - Password requirements: minimum 12 characters, complexity rules enforced
35
+
36
+ ## Authorization Patterns
37
+
38
+ - Role-based access control (RBAC) for all PHI access
39
+ - Principle of least privilege: default deny, explicit grants
40
+ - Provider-patient relationships must be verified before granting access
41
+ - Administrative overrides must be logged and auditable
42
+ - Authorization checks happen server-side, never client-only
43
+ - Firestore security rules must enforce access control at the document level
44
+
45
+ ## Session Security
46
+
47
+ - Session tokens must be cryptographically random, minimum 128 bits
48
+ - Bind sessions to client fingerprint (IP + user-agent) where feasible
49
+ - Invalidate sessions on password change
50
+ - Provide explicit logout that clears all session artifacts
51
+ - No session data in URLs
52
+
53
+ ## Secret Management
54
+
55
+ - No secrets in source code, environment files committed to VCS, or client bundles
56
+ - Use environment variables or a secret manager (e.g., GCP Secret Manager)
57
+ - Rotate secrets on a schedule and after any suspected compromise
58
+ - API keys for PHI-serving endpoints must be scoped and rotatable
59
+
60
+ ## Firestore Security Rules
61
+
62
+ When writing or modifying Firestore security rules for PHI collections:
63
+
64
+ - Require `request.auth != null` on all PHI documents
65
+ - Validate `request.auth.token` claims for role-based access
66
+ - Use `resource.data` checks to enforce ownership/relationship constraints
67
+ - Never use wildcard rules (`allow read, write: if true`) on PHI collections
68
+ - Log rule denials for security monitoring
69
+
70
+ ## Encryption Requirements
71
+
72
+ - AES-256 for data at rest
73
+ - TLS 1.2+ for data in transit
74
+ - Field-level encryption for highly sensitive PHI (SSN, full medical records)
75
+ - Key management via cloud KMS; never store encryption keys alongside encrypted data
76
+ - Key rotation policy: at least annually, immediately after suspected compromise
77
+
78
+ ## Code Review Checklist
79
+
80
+ When reviewing code that touches PHI, verify:
81
+
82
+ - [ ] No PHI in log statements
83
+ - [ ] No PHI in URLs or query parameters
84
+ - [ ] No PHI in client-side persistent storage
85
+ - [ ] Authentication required on all PHI endpoints
86
+ - [ ] Authorization checks are server-side
87
+ - [ ] Minimum necessary data fetched
88
+ - [ ] Audit logging present for PHI access
89
+ - [ ] Error responses do not leak PHI
90
+ - [ ] Input validation prevents injection attacks
91
+ - [ ] HTTPS enforced, no mixed content
@@ -0,0 +1,15 @@
1
+ name: compliance-hipaa
2
+ description: "HIPAA compliance checks, PHI detection, and security controls"
3
+ version: 1
4
+ patches:
5
+ forge_yaml:
6
+ verification.security.enabled: true
7
+ addons:
8
+ - "+compliance-hipaa"
9
+ files:
10
+ - source: hipaa-context.md
11
+ target: .forge/addons/hipaa-context.md
12
+ - source: hipaa-checks.sh
13
+ target: .forge/addons/hipaa-checks.sh
14
+ post_install:
15
+ - "pip install semgrep 2>/dev/null || echo 'Install semgrep for full HIPAA scanning: pip install semgrep'"
@@ -0,0 +1,232 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # soc2-checks.sh — SOC2 compliance scanning for forge projects
5
+ # Verifies audit logging, access controls, and change management practices
6
+
7
+ RESULTS_FILE=".forge/state/soc2-results.json"
8
+ PASS=0
9
+ FAIL=0
10
+ WARN=0
11
+ FINDINGS=()
12
+
13
+ mkdir -p "$(dirname "$RESULTS_FILE")"
14
+
15
+ # --- Helpers ---
16
+
17
+ log() { echo "[soc2] $*"; }
18
+ finding() {
19
+ local severity="$1" file="$2" line="$3" rule="$4" detail="$5"
20
+ FINDINGS+=("{\"severity\":\"${severity}\",\"file\":\"${file}\",\"line\":${line},\"rule\":\"${rule}\",\"detail\":\"${detail}\"}")
21
+ if [ "$severity" = "fail" ]; then
22
+ FAIL=$((FAIL + 1))
23
+ else
24
+ WARN=$((WARN + 1))
25
+ fi
26
+ }
27
+
28
+ # --- Check 1: Audit logging presence ---
29
+
30
+ log "Checking for audit logging infrastructure..."
31
+
32
+ HAS_AUDIT=false
33
+ AUDIT_PATTERNS=("auditLog\|audit_log\|AuditLog" "createAuditEntry\|logAudit\|writeAuditLog" "audit.*collection\|audit.*table")
34
+
35
+ for pattern in "${AUDIT_PATTERNS[@]}"; do
36
+ if grep -rq "$pattern" --include='*.ts' --include='*.js' --include='*.py' . 2>/dev/null; then
37
+ HAS_AUDIT=true
38
+ break
39
+ fi
40
+ done
41
+
42
+ if [ "$HAS_AUDIT" = false ]; then
43
+ finding "fail" "project" 0 "no-audit-logging" "No audit logging infrastructure detected — SOC2 requires comprehensive audit trails"
44
+ else
45
+ PASS=$((PASS + 1))
46
+ log " Audit logging infrastructure found"
47
+ fi
48
+
49
+ # --- Check 2: Auth on server endpoints ---
50
+
51
+ log "Checking server endpoints for authentication..."
52
+
53
+ UNPROTECTED=0
54
+ if [ -d "src/routes" ]; then
55
+ while IFS= read -r file; do
56
+ if ! grep -q 'locals\.\(user\|session\|auth\)\|getSession\|requireAuth\|authenticate\|verifyToken\|event\.locals\|isAuthenticated' "$file" 2>/dev/null; then
57
+ finding "warn" "$file" 0 "endpoint-no-auth" "Server endpoint may lack authentication guard"
58
+ UNPROTECTED=$((UNPROTECTED + 1))
59
+ fi
60
+ done < <(find . -path '*/routes/*' \( -name '+server.ts' -o -name '+server.js' \) -not -path '*/node_modules/*' 2>/dev/null | head -100)
61
+ fi
62
+
63
+ if [ "$UNPROTECTED" -eq 0 ]; then
64
+ PASS=$((PASS + 1))
65
+ log " All server endpoints appear to have auth guards"
66
+ fi
67
+
68
+ # --- Check 3: No secrets in code ---
69
+
70
+ log "Checking for hardcoded secrets..."
71
+
72
+ SECRET_HITS=0
73
+ SECRET_PATTERNS=(
74
+ 'password\s*=\s*["\x27][^"\x27]\{8,\}'
75
+ 'api[_-]\?key\s*=\s*["\x27][A-Za-z0-9]\{20,\}'
76
+ 'secret\s*=\s*["\x27][^"\x27]\{8,\}'
77
+ 'PRIVATE.KEY.*BEGIN'
78
+ 'token\s*=\s*["\x27][A-Za-z0-9]\{30,\}'
79
+ )
80
+
81
+ for pattern in "${SECRET_PATTERNS[@]}"; do
82
+ while IFS=: read -r file line _match; do
83
+ [ -z "$file" ] && continue
84
+ finding "fail" "$file" "$line" "hardcoded-secret" "Possible hardcoded secret — use environment variables or secret manager"
85
+ SECRET_HITS=$((SECRET_HITS + 1))
86
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' --include='*.py' --include='*.env*' . 2>/dev/null | grep -v node_modules | grep -v '\.test\.\|\.spec\.\|\.example\|\.sample' | head -50 || true)
87
+ done
88
+
89
+ if [ "$SECRET_HITS" -eq 0 ]; then
90
+ PASS=$((PASS + 1))
91
+ log " No hardcoded secrets detected"
92
+ fi
93
+
94
+ # --- Check 4: Change management — branch protection evidence ---
95
+
96
+ log "Checking change management practices..."
97
+
98
+ if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
99
+ # Check if there are direct commits to main (not merge commits)
100
+ DIRECT_COMMITS=$(git log --first-parent --no-merges --oneline main 2>/dev/null | head -10 | wc -l | tr -d ' ')
101
+ if [ "$DIRECT_COMMITS" -gt 3 ]; then
102
+ finding "warn" ".git" 0 "direct-commits-to-main" "Found ${DIRECT_COMMITS} direct (non-merge) commits on main — use PRs for all changes"
103
+ else
104
+ PASS=$((PASS + 1))
105
+ log " Change management: main branch uses merge commits (PRs)"
106
+ fi
107
+
108
+ # Check for unsigned commits (optional but recommended)
109
+ UNSIGNED=$(git log --format='%G?' -10 2>/dev/null | grep -c 'N' || true)
110
+ if [ "$UNSIGNED" -gt 5 ]; then
111
+ finding "warn" ".git" 0 "unsigned-commits" "Most recent commits are unsigned — consider requiring commit signing"
112
+ fi
113
+ else
114
+ finding "warn" "." 0 "no-git" "Not a git repository — cannot verify change management"
115
+ fi
116
+
117
+ # --- Check 5: Error handling — no internal details leaked ---
118
+
119
+ log "Checking for leaked internal details in error responses..."
120
+
121
+ ERROR_LEAK_PATTERNS=(
122
+ 'res\.\(status\|json\).*stack\|stack.*res\.\(status\|json\)'
123
+ 'response.*error\.message\|error\.message.*response'
124
+ 'catch.*res\..*500.*err\.\(message\|stack\)'
125
+ )
126
+
127
+ LEAK_HITS=0
128
+ for pattern in "${ERROR_LEAK_PATTERNS[@]}"; do
129
+ while IFS=: read -r file line _match; do
130
+ [ -z "$file" ] && continue
131
+ finding "warn" "$file" "$line" "error-info-leak" "Error response may expose internal details — sanitize before sending to client"
132
+ LEAK_HITS=$((LEAK_HITS + 1))
133
+ done < <(grep -rn "$pattern" --include='*.ts' --include='*.js' . 2>/dev/null | grep -v node_modules | grep -v '\.test\.\|\.spec\.' | head -30 || true)
134
+ done
135
+
136
+ if [ "$LEAK_HITS" -eq 0 ]; then
137
+ PASS=$((PASS + 1))
138
+ log " No obvious error info leaks detected"
139
+ fi
140
+
141
+ # --- Check 6: HTTPS enforcement ---
142
+
143
+ log "Checking for non-HTTPS API calls..."
144
+
145
+ HTTP_HITS=0
146
+ while IFS=: read -r file line _match; do
147
+ [ -z "$file" ] && continue
148
+ if echo "$_match" | grep -q 'localhost\|127\.0\.0\.1\|0\.0\.0\.0'; then
149
+ continue
150
+ fi
151
+ finding "fail" "$file" "$line" "no-tls" "HTTP (non-TLS) API call — use HTTPS"
152
+ HTTP_HITS=$((HTTP_HITS + 1))
153
+ done < <(grep -rn "fetch(['\"]http:" --include='*.ts' --include='*.js' --include='*.svelte' . 2>/dev/null | grep -v node_modules | grep -v '\.test\.\|\.spec\.' | head -50 || true)
154
+
155
+ if [ "$HTTP_HITS" -eq 0 ]; then
156
+ PASS=$((PASS + 1))
157
+ log " All API calls use HTTPS"
158
+ fi
159
+
160
+ # --- Check 7: Dependency vulnerabilities ---
161
+
162
+ log "Checking for known dependency vulnerabilities..."
163
+
164
+ if [ -f "package-lock.json" ] || [ -f "yarn.lock" ]; then
165
+ AUDIT_OUTPUT=$(npm audit --json 2>/dev/null || true)
166
+ VULN_COUNT=$(echo "$AUDIT_OUTPUT" | jq '.metadata.vulnerabilities.high + .metadata.vulnerabilities.critical' 2>/dev/null || echo "0")
167
+ if [ "$VULN_COUNT" -gt 0 ] 2>/dev/null; then
168
+ finding "fail" "package.json" 0 "vulnerable-deps" "${VULN_COUNT} high/critical dependency vulnerabilities found — run npm audit fix"
169
+ else
170
+ PASS=$((PASS + 1))
171
+ log " No high/critical dependency vulnerabilities"
172
+ fi
173
+ elif [ -f "requirements.txt" ]; then
174
+ if command -v pip-audit > /dev/null 2>&1; then
175
+ pip-audit -r requirements.txt --format json 2>/dev/null > /tmp/forge-pip-audit.json || true
176
+ PY_VULNS=$(jq 'length' /tmp/forge-pip-audit.json 2>/dev/null || echo "0")
177
+ if [ "$PY_VULNS" -gt 0 ]; then
178
+ finding "fail" "requirements.txt" 0 "vulnerable-deps" "${PY_VULNS} Python dependency vulnerabilities found"
179
+ else
180
+ PASS=$((PASS + 1))
181
+ fi
182
+ else
183
+ finding "warn" "requirements.txt" 0 "no-dep-audit" "pip-audit not installed — cannot check Python dependencies"
184
+ fi
185
+ fi
186
+
187
+ # --- Check 8: Semgrep SOC2-relevant rules ---
188
+
189
+ if command -v semgrep > /dev/null 2>&1; then
190
+ log "Running semgrep security rules..."
191
+ semgrep --config "p/security-audit" --json --quiet . 2>/dev/null > /tmp/forge-semgrep-soc2.json || true
192
+
193
+ SEMGREP_COUNT=$(jq '.results | length' /tmp/forge-semgrep-soc2.json 2>/dev/null || echo "0")
194
+ if [ "$SEMGREP_COUNT" -gt 0 ]; then
195
+ log "Semgrep found ${SEMGREP_COUNT} security findings"
196
+ while IFS= read -r sg_finding; do
197
+ FINDINGS+=("$sg_finding")
198
+ FAIL=$((FAIL + 1))
199
+ done < <(jq -c '.results[] | {severity:"fail",file:.path,line:.start.line,rule:.check_id,detail:.extra.message}' /tmp/forge-semgrep-soc2.json 2>/dev/null || true)
200
+ else
201
+ PASS=$((PASS + 1))
202
+ log " Semgrep: no security findings"
203
+ fi
204
+ else
205
+ log "Semgrep not installed — skipping advanced security rules (install with: pip install semgrep)"
206
+ fi
207
+
208
+ # --- Write results ---
209
+
210
+ FINDINGS_JSON=$(printf '%s,' "${FINDINGS[@]}" 2>/dev/null | sed 's/,$//')
211
+ [ -z "$FINDINGS_JSON" ] && FINDINGS_JSON=""
212
+
213
+ TOTAL=$((PASS + FAIL + WARN))
214
+
215
+ cat > "$RESULTS_FILE" <<EOF
216
+ {
217
+ "addon": "compliance-soc2",
218
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
219
+ "summary": {
220
+ "total_checks": ${TOTAL},
221
+ "pass": ${PASS},
222
+ "fail": ${FAIL},
223
+ "warn": ${WARN}
224
+ },
225
+ "findings": [${FINDINGS_JSON}]
226
+ }
227
+ EOF
228
+
229
+ log "Results written to ${RESULTS_FILE}"
230
+ log "Summary: ${PASS} passed, ${FAIL} failures, ${WARN} warnings"
231
+
232
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1
@@ -0,0 +1,147 @@
1
+ # SOC2 Compliance Context
2
+
3
+ This context overlay applies to all agents working on code in this project. The codebase must meet SOC2 Type II Trust Services Criteria across Security, Availability, Processing Integrity, Confidentiality, and Privacy.
4
+
5
+ ## Access Control (CC6)
6
+
7
+ ### Authentication
8
+
9
+ - All user-facing endpoints require authentication
10
+ - Service-to-service calls use short-lived tokens or mutual TLS
11
+ - No shared accounts or credentials
12
+ - Password policy: minimum 12 characters, complexity enforced, no reuse of last 12 passwords
13
+ - MFA required for all administrative and production access
14
+ - SSO integration required for enterprise users where available
15
+
16
+ ### Authorization
17
+
18
+ - Role-based access control (RBAC) enforced server-side
19
+ - Principle of least privilege: users get minimum permissions for their role
20
+ - Privilege escalation requires approval and is logged
21
+ - API keys are scoped to specific resources and operations
22
+ - Regularly review and revoke unused access grants
23
+ - Document all roles and their permission boundaries
24
+
25
+ ### Session Management
26
+
27
+ - Session timeout after 30 minutes of inactivity (15 minutes for admin sessions)
28
+ - Sessions invalidated on logout, password change, and role change
29
+ - Concurrent session limits enforced where appropriate
30
+ - Session tokens are cryptographically random, not guessable
31
+
32
+ ## Audit Logging (CC7)
33
+
34
+ ### What to Log
35
+
36
+ Every security-relevant event must produce a structured audit log entry:
37
+
38
+ - **Authentication events**: login, logout, failed login, MFA challenge, password change
39
+ - **Authorization events**: access granted, access denied, privilege escalation
40
+ - **Data events**: create, read, update, delete of sensitive records
41
+ - **Admin events**: configuration changes, user management, role changes
42
+ - **System events**: deployments, restarts, error spikes, health check failures
43
+
44
+ ### Log Format
45
+
46
+ Each audit log entry must include:
47
+
48
+ - `timestamp` (ISO 8601, UTC)
49
+ - `actor` (user ID or service identity)
50
+ - `action` (what was done)
51
+ - `resource` (what was affected)
52
+ - `result` (success/failure)
53
+ - `ip_address` (source IP)
54
+ - `context` (additional relevant metadata)
55
+
56
+ ### Log Protection
57
+
58
+ - Audit logs are append-only; never delete or modify in place
59
+ - Logs stored in a separate system/collection from application data
60
+ - Log retention: minimum 1 year
61
+ - Logs must not contain secrets, passwords, tokens, or PII beyond user IDs
62
+ - Alerting on log tampering or gaps
63
+
64
+ ## Change Management (CC8)
65
+
66
+ ### Code Changes
67
+
68
+ - All changes go through pull requests with at least one reviewer
69
+ - CI/CD pipeline must pass before merge (tests, lint, type checks)
70
+ - No direct commits to main/production branches
71
+ - Commit messages reference the ticket/issue being addressed
72
+ - Changes to security-sensitive code require security-aware reviewer
73
+
74
+ ### Deployment
75
+
76
+ - All deployments are automated via CI/CD
77
+ - No manual production deployments
78
+ - Deployment artifacts are immutable and versioned
79
+ - Rollback procedure documented and tested
80
+ - Deployment logs captured for audit trail
81
+
82
+ ### Infrastructure Changes
83
+
84
+ - Infrastructure as Code (IaC) for all environments
85
+ - Infrastructure changes go through the same review process as code
86
+ - Environment parity: staging mirrors production configuration
87
+ - Secrets rotated on schedule and after incidents
88
+
89
+ ## Data Protection (CC6.1)
90
+
91
+ ### Encryption
92
+
93
+ - Data at rest: AES-256 or equivalent
94
+ - Data in transit: TLS 1.2+ for all connections
95
+ - Database connections use TLS
96
+ - Backup encryption required
97
+ - Key management via cloud KMS
98
+
99
+ ### Data Classification
100
+
101
+ - Classify data by sensitivity: public, internal, confidential, restricted
102
+ - Apply controls proportional to classification
103
+ - Document data flows showing where each classification level is stored and transmitted
104
+ - Data retention policies enforced per classification
105
+
106
+ ### Data Disposal
107
+
108
+ - Secure deletion when data retention period expires
109
+ - Cryptographic erasure acceptable for encrypted data
110
+ - Document disposal procedures and evidence
111
+
112
+ ## Availability (CC9)
113
+
114
+ ### Uptime
115
+
116
+ - Define and monitor SLA targets
117
+ - Health check endpoints for all services
118
+ - Automated alerting on downtime or degradation
119
+ - Incident response runbook documented
120
+
121
+ ### Disaster Recovery
122
+
123
+ - Backup frequency: at least daily for critical data
124
+ - Backup restoration tested quarterly
125
+ - Recovery Time Objective (RTO) and Recovery Point Objective (RPO) documented
126
+ - Multi-region or multi-zone deployment for critical services
127
+
128
+ ### Capacity
129
+
130
+ - Monitor resource utilization (CPU, memory, storage, network)
131
+ - Auto-scaling configured where applicable
132
+ - Capacity planning reviewed quarterly
133
+
134
+ ## Code Review Checklist
135
+
136
+ When reviewing code for SOC2 compliance, verify:
137
+
138
+ - [ ] Authentication required on all endpoints
139
+ - [ ] Authorization checks are server-side with least privilege
140
+ - [ ] Audit logging present for security-relevant operations
141
+ - [ ] Audit logs do not contain secrets or excessive PII
142
+ - [ ] Error responses do not leak internal details
143
+ - [ ] Input validation prevents injection attacks
144
+ - [ ] HTTPS enforced, no mixed content
145
+ - [ ] Secrets managed via environment variables or secret manager
146
+ - [ ] Change goes through standard PR review process
147
+ - [ ] Tests cover the new functionality
@@ -0,0 +1,15 @@
1
+ name: compliance-soc2
2
+ description: "SOC2 compliance checks — audit logging, access control, and change management evidence"
3
+ version: 1
4
+ patches:
5
+ forge_yaml:
6
+ verification.security.enabled: true
7
+ addons:
8
+ - "+compliance-soc2"
9
+ files:
10
+ - source: soc2-context.md
11
+ target: .forge/addons/soc2-context.md
12
+ - source: soc2-checks.sh
13
+ target: .forge/addons/soc2-checks.sh
14
+ post_install:
15
+ - "pip install semgrep 2>/dev/null || echo 'Install semgrep for full SOC2 scanning: pip install semgrep'"