@build-astron-co/nimbus 0.2.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 (313) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +628 -0
  3. package/bin/nimbus +38 -0
  4. package/package.json +80 -0
  5. package/src/__tests__/app.test.ts +76 -0
  6. package/src/__tests__/audit.test.ts +877 -0
  7. package/src/__tests__/circuit-breaker.test.ts +116 -0
  8. package/src/__tests__/cli-run.test.ts +115 -0
  9. package/src/__tests__/context-manager.test.ts +502 -0
  10. package/src/__tests__/context.test.ts +242 -0
  11. package/src/__tests__/enterprise.test.ts +401 -0
  12. package/src/__tests__/generator.test.ts +433 -0
  13. package/src/__tests__/hooks.test.ts +582 -0
  14. package/src/__tests__/init.test.ts +436 -0
  15. package/src/__tests__/intent-parser.test.ts +229 -0
  16. package/src/__tests__/llm-router.test.ts +209 -0
  17. package/src/__tests__/lsp.test.ts +293 -0
  18. package/src/__tests__/modes.test.ts +336 -0
  19. package/src/__tests__/permissions.test.ts +338 -0
  20. package/src/__tests__/serve.test.ts +275 -0
  21. package/src/__tests__/sessions.test.ts +227 -0
  22. package/src/__tests__/sharing.test.ts +288 -0
  23. package/src/__tests__/snapshots.test.ts +581 -0
  24. package/src/__tests__/state-db.test.ts +334 -0
  25. package/src/__tests__/stream-with-tools.test.ts +732 -0
  26. package/src/__tests__/subagents.test.ts +176 -0
  27. package/src/__tests__/system-prompt.test.ts +169 -0
  28. package/src/__tests__/tool-converter.test.ts +256 -0
  29. package/src/__tests__/tool-schemas.test.ts +397 -0
  30. package/src/__tests__/tools.test.ts +143 -0
  31. package/src/__tests__/version.test.ts +49 -0
  32. package/src/agent/compaction-agent.ts +227 -0
  33. package/src/agent/context-manager.ts +435 -0
  34. package/src/agent/context.ts +427 -0
  35. package/src/agent/deploy-preview.ts +426 -0
  36. package/src/agent/index.ts +68 -0
  37. package/src/agent/loop.ts +717 -0
  38. package/src/agent/modes.ts +429 -0
  39. package/src/agent/permissions.ts +466 -0
  40. package/src/agent/subagents/base.ts +116 -0
  41. package/src/agent/subagents/cost.ts +51 -0
  42. package/src/agent/subagents/explore.ts +42 -0
  43. package/src/agent/subagents/general.ts +54 -0
  44. package/src/agent/subagents/index.ts +102 -0
  45. package/src/agent/subagents/infra.ts +59 -0
  46. package/src/agent/subagents/security.ts +69 -0
  47. package/src/agent/system-prompt.ts +436 -0
  48. package/src/app.ts +122 -0
  49. package/src/audit/activity-log.ts +290 -0
  50. package/src/audit/compliance-checker.ts +540 -0
  51. package/src/audit/cost-tracker.ts +318 -0
  52. package/src/audit/index.ts +23 -0
  53. package/src/audit/security-scanner.ts +596 -0
  54. package/src/auth/guard.ts +75 -0
  55. package/src/auth/index.ts +56 -0
  56. package/src/auth/oauth.ts +455 -0
  57. package/src/auth/providers.ts +470 -0
  58. package/src/auth/sso.ts +113 -0
  59. package/src/auth/store.ts +505 -0
  60. package/src/auth/types.ts +187 -0
  61. package/src/build.ts +141 -0
  62. package/src/cli/index.ts +16 -0
  63. package/src/cli/init.ts +854 -0
  64. package/src/cli/openapi-spec.ts +356 -0
  65. package/src/cli/run.ts +237 -0
  66. package/src/cli/serve-auth.ts +80 -0
  67. package/src/cli/serve.ts +462 -0
  68. package/src/cli/web.ts +67 -0
  69. package/src/cli.ts +1417 -0
  70. package/src/clients/core-engine-client.ts +227 -0
  71. package/src/clients/enterprise-client.ts +334 -0
  72. package/src/clients/generator-client.ts +351 -0
  73. package/src/clients/git-client.ts +627 -0
  74. package/src/clients/github-client.ts +410 -0
  75. package/src/clients/helm-client.ts +504 -0
  76. package/src/clients/index.ts +80 -0
  77. package/src/clients/k8s-client.ts +497 -0
  78. package/src/clients/llm-client.ts +161 -0
  79. package/src/clients/rest-client.ts +130 -0
  80. package/src/clients/service-discovery.ts +33 -0
  81. package/src/clients/terraform-client.ts +482 -0
  82. package/src/clients/tools-client.ts +1843 -0
  83. package/src/clients/ws-client.ts +115 -0
  84. package/src/commands/analyze/index.ts +352 -0
  85. package/src/commands/apply/helm.ts +473 -0
  86. package/src/commands/apply/index.ts +213 -0
  87. package/src/commands/apply/k8s.ts +454 -0
  88. package/src/commands/apply/terraform.ts +582 -0
  89. package/src/commands/ask.ts +167 -0
  90. package/src/commands/audit/index.ts +238 -0
  91. package/src/commands/auth-cloud.ts +294 -0
  92. package/src/commands/auth-list.ts +134 -0
  93. package/src/commands/auth-profile.ts +121 -0
  94. package/src/commands/auth-status.ts +141 -0
  95. package/src/commands/aws/ec2.ts +501 -0
  96. package/src/commands/aws/iam.ts +397 -0
  97. package/src/commands/aws/index.ts +133 -0
  98. package/src/commands/aws/lambda.ts +396 -0
  99. package/src/commands/aws/rds.ts +439 -0
  100. package/src/commands/aws/s3.ts +439 -0
  101. package/src/commands/aws/vpc.ts +393 -0
  102. package/src/commands/aws-discover.ts +649 -0
  103. package/src/commands/aws-terraform.ts +805 -0
  104. package/src/commands/azure/aks.ts +376 -0
  105. package/src/commands/azure/functions.ts +253 -0
  106. package/src/commands/azure/index.ts +116 -0
  107. package/src/commands/azure/storage.ts +478 -0
  108. package/src/commands/azure/vm.ts +355 -0
  109. package/src/commands/billing/index.ts +256 -0
  110. package/src/commands/chat.ts +314 -0
  111. package/src/commands/config.ts +346 -0
  112. package/src/commands/cost/cloud-cost-estimator.ts +266 -0
  113. package/src/commands/cost/estimator.ts +79 -0
  114. package/src/commands/cost/index.ts +594 -0
  115. package/src/commands/cost/parsers/terraform.ts +273 -0
  116. package/src/commands/cost/parsers/types.ts +25 -0
  117. package/src/commands/cost/pricing/aws.ts +544 -0
  118. package/src/commands/cost/pricing/azure.ts +499 -0
  119. package/src/commands/cost/pricing/gcp.ts +396 -0
  120. package/src/commands/cost/pricing/index.ts +40 -0
  121. package/src/commands/demo.ts +250 -0
  122. package/src/commands/doctor.ts +794 -0
  123. package/src/commands/drift/index.ts +439 -0
  124. package/src/commands/explain.ts +277 -0
  125. package/src/commands/feedback.ts +389 -0
  126. package/src/commands/fix.ts +324 -0
  127. package/src/commands/fs/index.ts +402 -0
  128. package/src/commands/gcp/compute.ts +325 -0
  129. package/src/commands/gcp/functions.ts +271 -0
  130. package/src/commands/gcp/gke.ts +438 -0
  131. package/src/commands/gcp/iam.ts +344 -0
  132. package/src/commands/gcp/index.ts +129 -0
  133. package/src/commands/gcp/storage.ts +284 -0
  134. package/src/commands/generate-helm.ts +1249 -0
  135. package/src/commands/generate-k8s.ts +1560 -0
  136. package/src/commands/generate-terraform.ts +1460 -0
  137. package/src/commands/gh/index.ts +863 -0
  138. package/src/commands/git/index.ts +1343 -0
  139. package/src/commands/helm/index.ts +1126 -0
  140. package/src/commands/help.ts +539 -0
  141. package/src/commands/history.ts +142 -0
  142. package/src/commands/import.ts +868 -0
  143. package/src/commands/index.ts +367 -0
  144. package/src/commands/init.ts +1046 -0
  145. package/src/commands/k8s/index.ts +1137 -0
  146. package/src/commands/login.ts +631 -0
  147. package/src/commands/logout.ts +83 -0
  148. package/src/commands/onboarding.ts +228 -0
  149. package/src/commands/plan/display.ts +279 -0
  150. package/src/commands/plan/index.ts +599 -0
  151. package/src/commands/preview.ts +452 -0
  152. package/src/commands/questionnaire.ts +1270 -0
  153. package/src/commands/resume.ts +55 -0
  154. package/src/commands/team/index.ts +346 -0
  155. package/src/commands/template.ts +232 -0
  156. package/src/commands/tf/index.ts +1034 -0
  157. package/src/commands/upgrade.ts +550 -0
  158. package/src/commands/usage/index.ts +134 -0
  159. package/src/commands/version.ts +170 -0
  160. package/src/compat/index.ts +2 -0
  161. package/src/compat/runtime.ts +12 -0
  162. package/src/compat/sqlite.ts +107 -0
  163. package/src/config/index.ts +17 -0
  164. package/src/config/manager.ts +530 -0
  165. package/src/config/safety-policy.ts +358 -0
  166. package/src/config/schema.ts +125 -0
  167. package/src/config/types.ts +527 -0
  168. package/src/context/context-db.ts +199 -0
  169. package/src/demo/index.ts +349 -0
  170. package/src/demo/scenarios/full-journey.ts +229 -0
  171. package/src/demo/scenarios/getting-started.ts +127 -0
  172. package/src/demo/scenarios/helm-release.ts +341 -0
  173. package/src/demo/scenarios/k8s-deployment.ts +194 -0
  174. package/src/demo/scenarios/terraform-vpc.ts +170 -0
  175. package/src/demo/types.ts +92 -0
  176. package/src/engine/cost-estimator.ts +438 -0
  177. package/src/engine/diagram-generator.ts +256 -0
  178. package/src/engine/drift-detector.ts +902 -0
  179. package/src/engine/executor.ts +1035 -0
  180. package/src/engine/index.ts +76 -0
  181. package/src/engine/orchestrator.ts +636 -0
  182. package/src/engine/planner.ts +720 -0
  183. package/src/engine/safety.ts +743 -0
  184. package/src/engine/verifier.ts +770 -0
  185. package/src/enterprise/audit.ts +348 -0
  186. package/src/enterprise/auth.ts +270 -0
  187. package/src/enterprise/billing.ts +822 -0
  188. package/src/enterprise/index.ts +17 -0
  189. package/src/enterprise/teams.ts +443 -0
  190. package/src/generator/best-practices.ts +1608 -0
  191. package/src/generator/helm.ts +630 -0
  192. package/src/generator/index.ts +37 -0
  193. package/src/generator/intent-parser.ts +514 -0
  194. package/src/generator/kubernetes.ts +976 -0
  195. package/src/generator/terraform.ts +1867 -0
  196. package/src/history/index.ts +8 -0
  197. package/src/history/manager.ts +322 -0
  198. package/src/history/types.ts +34 -0
  199. package/src/hooks/config.ts +432 -0
  200. package/src/hooks/engine.ts +391 -0
  201. package/src/hooks/index.ts +4 -0
  202. package/src/llm/auth-bridge.ts +198 -0
  203. package/src/llm/circuit-breaker.ts +140 -0
  204. package/src/llm/config-loader.ts +201 -0
  205. package/src/llm/cost-calculator.ts +171 -0
  206. package/src/llm/index.ts +8 -0
  207. package/src/llm/model-aliases.ts +115 -0
  208. package/src/llm/provider-registry.ts +63 -0
  209. package/src/llm/providers/anthropic.ts +433 -0
  210. package/src/llm/providers/bedrock.ts +477 -0
  211. package/src/llm/providers/google.ts +405 -0
  212. package/src/llm/providers/ollama.ts +767 -0
  213. package/src/llm/providers/openai-compatible.ts +340 -0
  214. package/src/llm/providers/openai.ts +328 -0
  215. package/src/llm/providers/openrouter.ts +338 -0
  216. package/src/llm/router.ts +1035 -0
  217. package/src/llm/types.ts +232 -0
  218. package/src/lsp/client.ts +298 -0
  219. package/src/lsp/languages.ts +116 -0
  220. package/src/lsp/manager.ts +278 -0
  221. package/src/mcp/client.ts +402 -0
  222. package/src/mcp/index.ts +5 -0
  223. package/src/mcp/manager.ts +133 -0
  224. package/src/nimbus.ts +214 -0
  225. package/src/plugins/index.ts +27 -0
  226. package/src/plugins/loader.ts +334 -0
  227. package/src/plugins/manager.ts +376 -0
  228. package/src/plugins/types.ts +284 -0
  229. package/src/scanners/cicd-scanner.ts +258 -0
  230. package/src/scanners/cloud-scanner.ts +466 -0
  231. package/src/scanners/framework-scanner.ts +469 -0
  232. package/src/scanners/iac-scanner.ts +388 -0
  233. package/src/scanners/index.ts +539 -0
  234. package/src/scanners/language-scanner.ts +276 -0
  235. package/src/scanners/package-manager-scanner.ts +277 -0
  236. package/src/scanners/types.ts +172 -0
  237. package/src/sessions/manager.ts +365 -0
  238. package/src/sessions/types.ts +44 -0
  239. package/src/sharing/sync.ts +296 -0
  240. package/src/sharing/viewer.ts +97 -0
  241. package/src/snapshots/index.ts +2 -0
  242. package/src/snapshots/manager.ts +530 -0
  243. package/src/state/artifacts.ts +147 -0
  244. package/src/state/audit.ts +137 -0
  245. package/src/state/billing.ts +240 -0
  246. package/src/state/checkpoints.ts +117 -0
  247. package/src/state/config.ts +67 -0
  248. package/src/state/conversations.ts +14 -0
  249. package/src/state/credentials.ts +154 -0
  250. package/src/state/db.ts +58 -0
  251. package/src/state/index.ts +26 -0
  252. package/src/state/messages.ts +115 -0
  253. package/src/state/projects.ts +123 -0
  254. package/src/state/schema.ts +236 -0
  255. package/src/state/sessions.ts +147 -0
  256. package/src/state/teams.ts +200 -0
  257. package/src/telemetry.ts +108 -0
  258. package/src/tools/aws-ops.ts +952 -0
  259. package/src/tools/azure-ops.ts +579 -0
  260. package/src/tools/file-ops.ts +593 -0
  261. package/src/tools/gcp-ops.ts +625 -0
  262. package/src/tools/git-ops.ts +773 -0
  263. package/src/tools/github-ops.ts +799 -0
  264. package/src/tools/helm-ops.ts +943 -0
  265. package/src/tools/index.ts +17 -0
  266. package/src/tools/k8s-ops.ts +819 -0
  267. package/src/tools/schemas/converter.ts +184 -0
  268. package/src/tools/schemas/devops.ts +612 -0
  269. package/src/tools/schemas/index.ts +73 -0
  270. package/src/tools/schemas/standard.ts +1144 -0
  271. package/src/tools/schemas/types.ts +705 -0
  272. package/src/tools/terraform-ops.ts +862 -0
  273. package/src/types/ambient.d.ts +193 -0
  274. package/src/types/config.ts +83 -0
  275. package/src/types/drift.ts +116 -0
  276. package/src/types/enterprise.ts +335 -0
  277. package/src/types/index.ts +20 -0
  278. package/src/types/plan.ts +44 -0
  279. package/src/types/request.ts +65 -0
  280. package/src/types/response.ts +54 -0
  281. package/src/types/service.ts +51 -0
  282. package/src/ui/App.tsx +997 -0
  283. package/src/ui/DeployPreview.tsx +169 -0
  284. package/src/ui/Header.tsx +68 -0
  285. package/src/ui/InputBox.tsx +350 -0
  286. package/src/ui/MessageList.tsx +585 -0
  287. package/src/ui/PermissionPrompt.tsx +151 -0
  288. package/src/ui/StatusBar.tsx +158 -0
  289. package/src/ui/ToolCallDisplay.tsx +409 -0
  290. package/src/ui/chat-ui.ts +853 -0
  291. package/src/ui/index.ts +33 -0
  292. package/src/ui/ink/index.ts +711 -0
  293. package/src/ui/streaming.ts +176 -0
  294. package/src/ui/types.ts +57 -0
  295. package/src/utils/analytics.ts +72 -0
  296. package/src/utils/cost-warning.ts +27 -0
  297. package/src/utils/env.ts +46 -0
  298. package/src/utils/errors.ts +69 -0
  299. package/src/utils/event-bus.ts +38 -0
  300. package/src/utils/index.ts +24 -0
  301. package/src/utils/logger.ts +171 -0
  302. package/src/utils/rate-limiter.ts +121 -0
  303. package/src/utils/service-auth.ts +49 -0
  304. package/src/utils/validation.ts +53 -0
  305. package/src/version.ts +4 -0
  306. package/src/watcher/index.ts +163 -0
  307. package/src/wizard/approval.ts +383 -0
  308. package/src/wizard/index.ts +25 -0
  309. package/src/wizard/prompts.ts +338 -0
  310. package/src/wizard/types.ts +171 -0
  311. package/src/wizard/ui.ts +556 -0
  312. package/src/wizard/wizard.ts +304 -0
  313. package/tsconfig.json +24 -0
@@ -0,0 +1,540 @@
1
+ /**
2
+ * Compliance Checker - Check infrastructure compliance against standard frameworks.
3
+ *
4
+ * Scans Terraform files (and other configuration) for compliance with SOC2,
5
+ * HIPAA, PCI-DSS, GDPR, and CIS benchmark controls. Each control is evaluated
6
+ * as pass, fail, warn, or skip based on the presence or absence of required
7
+ * Terraform configurations.
8
+ *
9
+ * Reports include per-framework pass/fail counts and an overall compliance
10
+ * score expressed as a percentage.
11
+ */
12
+
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Types
18
+ // ---------------------------------------------------------------------------
19
+
20
+ /** Supported compliance frameworks */
21
+ export type Framework = 'SOC2' | 'HIPAA' | 'PCI' | 'GDPR' | 'CIS';
22
+
23
+ /** A single compliance control evaluation */
24
+ export interface ComplianceControl {
25
+ /** Unique control identifier (e.g. SOC2-001) */
26
+ id: string;
27
+ /** Framework this control belongs to */
28
+ framework: Framework;
29
+ /** Human-readable control name */
30
+ name: string;
31
+ /** Detailed description of what is being checked */
32
+ description: string;
33
+ /** Evaluation result */
34
+ status: 'pass' | 'fail' | 'warn' | 'skip';
35
+ /** Evidence or explanation supporting the status */
36
+ evidence?: string;
37
+ }
38
+
39
+ /** Aggregate compliance report for a single framework */
40
+ export interface ComplianceReport {
41
+ /** Framework that was evaluated */
42
+ framework: Framework;
43
+ /** All controls evaluated */
44
+ controls: ComplianceControl[];
45
+ /** Number of controls that passed */
46
+ passCount: number;
47
+ /** Number of controls that failed */
48
+ failCount: number;
49
+ /** Number of controls with warnings */
50
+ warnCount: number;
51
+ /** Number of controls that were skipped */
52
+ skipCount: number;
53
+ /** Compliance score as a percentage (0-100) */
54
+ score: number;
55
+ /** Timestamp when the check completed */
56
+ timestamp: Date;
57
+ }
58
+
59
+ /** Options controlling the compliance check */
60
+ export interface ComplianceOptions {
61
+ /** Root directory to scan */
62
+ dir: string;
63
+ /** Frameworks to evaluate (defaults to all) */
64
+ frameworks?: Framework[];
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Control definitions
69
+ // ---------------------------------------------------------------------------
70
+
71
+ interface ControlDefinition {
72
+ id: string;
73
+ framework: Framework;
74
+ name: string;
75
+ description: string;
76
+ /** Pattern to search for in combined Terraform content -- presence means pass */
77
+ passPattern?: RegExp;
78
+ /** Pattern that indicates a failure if present */
79
+ failPattern?: RegExp;
80
+ /** If true, the control passes when the failPattern is NOT found */
81
+ invertFail?: boolean;
82
+ }
83
+
84
+ const CONTROL_DEFINITIONS: ControlDefinition[] = [
85
+ // -------------------------------------------------------------------------
86
+ // SOC2 Controls
87
+ // -------------------------------------------------------------------------
88
+ {
89
+ id: 'SOC2-001',
90
+ framework: 'SOC2',
91
+ name: 'Logging enabled',
92
+ description: 'CloudTrail, CloudWatch, or equivalent logging must be configured.',
93
+ passPattern:
94
+ /(?:aws_cloudtrail|aws_cloudwatch_log_group|google_logging_project_sink|azurerm_monitor_diagnostic_setting)/,
95
+ },
96
+ {
97
+ id: 'SOC2-002',
98
+ framework: 'SOC2',
99
+ name: 'Access controls defined',
100
+ description: 'IAM policies, roles, or access control resources must be present.',
101
+ passPattern: /(?:aws_iam_policy|aws_iam_role|google_project_iam|azurerm_role_assignment)/,
102
+ },
103
+ {
104
+ id: 'SOC2-003',
105
+ framework: 'SOC2',
106
+ name: 'Encryption at rest',
107
+ description: 'Storage resources must have encryption at rest enabled.',
108
+ passPattern:
109
+ /(?:server_side_encryption_configuration|storage_encrypted\s*=\s*true|encryption_configuration|kms_key_id|customer_managed_key)/,
110
+ },
111
+ {
112
+ id: 'SOC2-004',
113
+ framework: 'SOC2',
114
+ name: 'Backup configuration',
115
+ description: 'Automated backup or snapshot policies must be configured.',
116
+ passPattern:
117
+ /(?:backup_retention_period|aws_backup_plan|google_sql_database_instance.*backup_configuration|azurerm_backup_policy)/s,
118
+ },
119
+ {
120
+ id: 'SOC2-005',
121
+ framework: 'SOC2',
122
+ name: 'Network security groups',
123
+ description:
124
+ 'Network-level access controls (security groups, NACLs, firewall rules) must be present.',
125
+ passPattern: /(?:aws_security_group|google_compute_firewall|azurerm_network_security_group)/,
126
+ },
127
+
128
+ // -------------------------------------------------------------------------
129
+ // HIPAA Controls
130
+ // -------------------------------------------------------------------------
131
+ {
132
+ id: 'HIPAA-001',
133
+ framework: 'HIPAA',
134
+ name: 'Encryption required',
135
+ description: 'All data stores must use encryption at rest and in transit.',
136
+ passPattern:
137
+ /(?:server_side_encryption_configuration|storage_encrypted\s*=\s*true|ssl_enforcement_enabled|require_ssl)/,
138
+ },
139
+ {
140
+ id: 'HIPAA-002',
141
+ framework: 'HIPAA',
142
+ name: 'Audit logging',
143
+ description: 'Comprehensive audit logging must be enabled for all access to PHI.',
144
+ passPattern:
145
+ /(?:aws_cloudtrail|aws_cloudwatch_log_group|google_logging|azurerm_monitor_diagnostic_setting)/,
146
+ },
147
+ {
148
+ id: 'HIPAA-003',
149
+ framework: 'HIPAA',
150
+ name: 'Access controls',
151
+ description: 'Role-based access controls must restrict access to PHI.',
152
+ passPattern: /(?:aws_iam_policy|aws_iam_role|google_project_iam|azurerm_role_assignment)/,
153
+ },
154
+ {
155
+ id: 'HIPAA-004',
156
+ framework: 'HIPAA',
157
+ name: 'PHI data handling',
158
+ description: 'Data classification tags or labels must identify PHI resources.',
159
+ passPattern:
160
+ /(?:tags\s*=\s*\{[^}]*(?:phi|hipaa|sensitive|classification)[^}]*\}|labels\s*=\s*\{[^}]*(?:phi|hipaa|sensitive)[^}]*\})/is,
161
+ },
162
+ {
163
+ id: 'HIPAA-005',
164
+ framework: 'HIPAA',
165
+ name: 'Data backup and recovery',
166
+ description: 'PHI data must have backup and disaster recovery plans.',
167
+ passPattern: /(?:backup_retention_period|aws_backup_plan|point_in_time_recovery)/,
168
+ },
169
+
170
+ // -------------------------------------------------------------------------
171
+ // PCI-DSS Controls
172
+ // -------------------------------------------------------------------------
173
+ {
174
+ id: 'PCI-001',
175
+ framework: 'PCI',
176
+ name: 'Network segmentation',
177
+ description: 'Cardholder data environments must be segmented from other networks.',
178
+ passPattern:
179
+ /(?:aws_vpc|aws_subnet|google_compute_network|google_compute_subnetwork|azurerm_virtual_network|azurerm_subnet)/,
180
+ },
181
+ {
182
+ id: 'PCI-002',
183
+ framework: 'PCI',
184
+ name: 'Encryption in transit',
185
+ description: 'All cardholder data must be encrypted during transmission.',
186
+ passPattern:
187
+ /(?:ssl_policy|ssl_certificate|tls_policy|https_only|redirect_all_requests_to.*https|listener.*protocol\s*=\s*["']HTTPS)/s,
188
+ },
189
+ {
190
+ id: 'PCI-003',
191
+ framework: 'PCI',
192
+ name: 'Access logging',
193
+ description: 'All access to cardholder data must be logged.',
194
+ passPattern: /(?:access_log|logging\s*\{|enable_logging\s*=\s*true|log_analytics)/,
195
+ },
196
+ {
197
+ id: 'PCI-004',
198
+ framework: 'PCI',
199
+ name: 'No wildcard IAM permissions',
200
+ description: 'IAM policies must not use wildcard actions on cardholder data resources.',
201
+ failPattern: /["']Action["']\s*:\s*["']\*["']/,
202
+ invertFail: true,
203
+ },
204
+ {
205
+ id: 'PCI-005',
206
+ framework: 'PCI',
207
+ name: 'WAF or firewall configured',
208
+ description: 'Web application firewall or equivalent must protect public-facing applications.',
209
+ passPattern:
210
+ /(?:aws_wafv2|aws_waf|google_compute_security_policy|azurerm_web_application_firewall_policy)/,
211
+ },
212
+
213
+ // -------------------------------------------------------------------------
214
+ // GDPR Controls
215
+ // -------------------------------------------------------------------------
216
+ {
217
+ id: 'GDPR-001',
218
+ framework: 'GDPR',
219
+ name: 'Data retention policies',
220
+ description: 'Resources must define data retention or lifecycle policies.',
221
+ passPattern:
222
+ /(?:lifecycle_rule|retention_in_days|expiration|ttl|data_retention|lifecycle_policy)/,
223
+ },
224
+ {
225
+ id: 'GDPR-002',
226
+ framework: 'GDPR',
227
+ name: 'Consent mechanisms',
228
+ description: 'Infrastructure must support consent management workflows.',
229
+ passPattern: /(?:consent|gdpr|privacy|data_subject|right_to_erasure)/i,
230
+ },
231
+ {
232
+ id: 'GDPR-003',
233
+ framework: 'GDPR',
234
+ name: 'Data deletion capability',
235
+ description: 'Resources must support deletion of personal data (right to be forgotten).',
236
+ passPattern: /(?:lifecycle_rule|versioning|object_lock|deletion_protection|prevent_destroy)/,
237
+ },
238
+ {
239
+ id: 'GDPR-004',
240
+ framework: 'GDPR',
241
+ name: 'Data processing location',
242
+ description: 'Resources must specify their deployment region to ensure data residency.',
243
+ passPattern: /(?:region\s*=|location\s*=|availability_zone)/,
244
+ },
245
+ {
246
+ id: 'GDPR-005',
247
+ framework: 'GDPR',
248
+ name: 'Encryption of personal data',
249
+ description: 'Personal data must be encrypted at rest and in transit.',
250
+ passPattern: /(?:server_side_encryption|storage_encrypted|kms_key|encryption_configuration)/,
251
+ },
252
+
253
+ // -------------------------------------------------------------------------
254
+ // CIS Benchmark Controls
255
+ // -------------------------------------------------------------------------
256
+ {
257
+ id: 'CIS-001',
258
+ framework: 'CIS',
259
+ name: 'No public access',
260
+ description: 'Storage and database resources must not be publicly accessible.',
261
+ failPattern: /(?:publicly_accessible\s*=\s*true|acl\s*=\s*["']public-read)/,
262
+ invertFail: true,
263
+ },
264
+ {
265
+ id: 'CIS-002',
266
+ framework: 'CIS',
267
+ name: 'Minimal IAM permissions',
268
+ description: 'IAM policies should follow least privilege; no wildcard actions.',
269
+ failPattern: /["']Action["']\s*:\s*["']\*["']/,
270
+ invertFail: true,
271
+ },
272
+ {
273
+ id: 'CIS-003',
274
+ framework: 'CIS',
275
+ name: 'Encryption enabled',
276
+ description: 'All storage and database services must use encryption.',
277
+ passPattern:
278
+ /(?:server_side_encryption_configuration|storage_encrypted\s*=\s*true|encryption_configuration|kms_key_id)/,
279
+ },
280
+ {
281
+ id: 'CIS-004',
282
+ framework: 'CIS',
283
+ name: 'VPC flow logs enabled',
284
+ description: 'VPC flow logs must be enabled for network traffic monitoring.',
285
+ passPattern:
286
+ /(?:aws_flow_log|google_compute_subnetwork.*log_config|azurerm_network_watcher_flow_log)/s,
287
+ },
288
+ {
289
+ id: 'CIS-005',
290
+ framework: 'CIS',
291
+ name: 'Multi-factor authentication',
292
+ description: 'MFA should be required for IAM users with console access.',
293
+ passPattern: /(?:mfa_delete|mfa_device|condition.*mfa|multi_factor)/i,
294
+ },
295
+ ];
296
+
297
+ // ---------------------------------------------------------------------------
298
+ // Helpers
299
+ // ---------------------------------------------------------------------------
300
+
301
+ const DEFAULT_EXCLUDES = new Set(['node_modules', '.git', 'dist', 'coverage', '.next', 'build']);
302
+
303
+ /**
304
+ * Recursively collect Terraform file contents from a directory.
305
+ *
306
+ * @returns Concatenated content of all .tf and .tf.json files, plus a count
307
+ */
308
+ function collectTerraformContent(dir: string): { content: string; fileCount: number } {
309
+ const chunks: string[] = [];
310
+ let fileCount = 0;
311
+
312
+ function walk(currentDir: string): void {
313
+ let entries: fs.Dirent[];
314
+ try {
315
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
316
+ } catch {
317
+ return;
318
+ }
319
+
320
+ for (const entry of entries) {
321
+ if (entry.isDirectory()) {
322
+ if (DEFAULT_EXCLUDES.has(entry.name)) {
323
+ continue;
324
+ }
325
+ walk(path.join(currentDir, entry.name));
326
+ } else if (entry.isFile()) {
327
+ const ext = path.extname(entry.name).toLowerCase();
328
+ if (ext === '.tf' || entry.name.endsWith('.tf.json') || ext === '.tfvars') {
329
+ try {
330
+ const content = fs.readFileSync(path.join(currentDir, entry.name), 'utf-8');
331
+ chunks.push(content);
332
+ fileCount++;
333
+ } catch {
334
+ // skip unreadable files
335
+ }
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ walk(dir);
342
+ return { content: chunks.join('\n'), fileCount };
343
+ }
344
+
345
+ /**
346
+ * Evaluate a single control definition against the combined Terraform content.
347
+ */
348
+ function evaluateControl(
349
+ def: ControlDefinition,
350
+ terraformContent: string,
351
+ hasTerraformFiles: boolean
352
+ ): ComplianceControl {
353
+ // If no Terraform files exist, skip the control
354
+ if (!hasTerraformFiles) {
355
+ return {
356
+ id: def.id,
357
+ framework: def.framework,
358
+ name: def.name,
359
+ description: def.description,
360
+ status: 'skip',
361
+ evidence: 'No Terraform files found in the scanned directory.',
362
+ };
363
+ }
364
+
365
+ // Controls that use invertFail: pass when failPattern is NOT found
366
+ if (def.invertFail && def.failPattern) {
367
+ const match = def.failPattern.exec(terraformContent);
368
+ if (match) {
369
+ return {
370
+ id: def.id,
371
+ framework: def.framework,
372
+ name: def.name,
373
+ description: def.description,
374
+ status: 'fail',
375
+ evidence: `Found violation: "${match[0].slice(0, 80)}"`,
376
+ };
377
+ }
378
+ return {
379
+ id: def.id,
380
+ framework: def.framework,
381
+ name: def.name,
382
+ description: def.description,
383
+ status: 'pass',
384
+ evidence: 'No violations detected.',
385
+ };
386
+ }
387
+
388
+ // Standard passPattern check
389
+ if (def.passPattern) {
390
+ const match = def.passPattern.exec(terraformContent);
391
+ if (match) {
392
+ return {
393
+ id: def.id,
394
+ framework: def.framework,
395
+ name: def.name,
396
+ description: def.description,
397
+ status: 'pass',
398
+ evidence: `Found matching configuration: "${match[0].slice(0, 80)}"`,
399
+ };
400
+ }
401
+ return {
402
+ id: def.id,
403
+ framework: def.framework,
404
+ name: def.name,
405
+ description: def.description,
406
+ status: 'fail',
407
+ evidence: 'Required configuration not found in Terraform files.',
408
+ };
409
+ }
410
+
411
+ // No pattern defined -- warn
412
+ return {
413
+ id: def.id,
414
+ framework: def.framework,
415
+ name: def.name,
416
+ description: def.description,
417
+ status: 'warn',
418
+ evidence: 'Manual verification required -- no automated check available.',
419
+ };
420
+ }
421
+
422
+ // ---------------------------------------------------------------------------
423
+ // Public API
424
+ // ---------------------------------------------------------------------------
425
+
426
+ /**
427
+ * Check compliance of infrastructure configurations against one or more frameworks.
428
+ *
429
+ * Scans Terraform files in the specified directory and evaluates each control
430
+ * from the selected frameworks. Returns a compliance report per framework.
431
+ *
432
+ * @param options - Directory and framework selection
433
+ * @returns Array of compliance reports, one per framework
434
+ */
435
+ export async function checkCompliance(options: ComplianceOptions): Promise<ComplianceReport[]> {
436
+ const frameworks = options.frameworks ?? (['SOC2', 'HIPAA', 'PCI', 'GDPR', 'CIS'] as Framework[]);
437
+ const { content: terraformContent, fileCount } = collectTerraformContent(options.dir);
438
+ const hasTerraformFiles = fileCount > 0;
439
+
440
+ const reports: ComplianceReport[] = [];
441
+
442
+ for (const framework of frameworks) {
443
+ const definitions = CONTROL_DEFINITIONS.filter(d => d.framework === framework);
444
+ const controls = definitions.map(def =>
445
+ evaluateControl(def, terraformContent, hasTerraformFiles)
446
+ );
447
+
448
+ const passCount = controls.filter(c => c.status === 'pass').length;
449
+ const failCount = controls.filter(c => c.status === 'fail').length;
450
+ const warnCount = controls.filter(c => c.status === 'warn').length;
451
+ const skipCount = controls.filter(c => c.status === 'skip').length;
452
+
453
+ // Score = pass / (pass + fail + warn) * 100, skipped controls excluded
454
+ const evaluatedCount = passCount + failCount + warnCount;
455
+ const score = evaluatedCount > 0 ? Math.round((passCount / evaluatedCount) * 100) : 0;
456
+
457
+ reports.push({
458
+ framework,
459
+ controls,
460
+ passCount,
461
+ failCount,
462
+ warnCount,
463
+ skipCount,
464
+ score,
465
+ timestamp: new Date(),
466
+ });
467
+ }
468
+
469
+ return reports;
470
+ }
471
+
472
+ /**
473
+ * Generate a visual scorecard from one or more compliance reports.
474
+ *
475
+ * Produces a formatted text table showing framework scores, pass/fail counts,
476
+ * and individual control statuses.
477
+ *
478
+ * @param reports - Compliance reports to include in the scorecard
479
+ * @returns Multi-line formatted scorecard string
480
+ */
481
+ export function generateScorecard(reports: ComplianceReport[]): string {
482
+ if (reports.length === 0) {
483
+ return 'No compliance reports to display.';
484
+ }
485
+
486
+ const statusIcon: Record<string, string> = {
487
+ pass: '[PASS]',
488
+ fail: '[FAIL]',
489
+ warn: '[WARN]',
490
+ skip: '[SKIP]',
491
+ };
492
+
493
+ const lines: string[] = ['Compliance Scorecard', '='.repeat(60), ''];
494
+
495
+ // Overview table
496
+ lines.push(' Framework Score Pass Fail Warn Skip');
497
+ lines.push(` ${'-'.repeat(50)}`);
498
+
499
+ for (const report of reports) {
500
+ const fw = report.framework.padEnd(10);
501
+ const score = `${report.score}%`.padStart(5);
502
+ const pass = String(report.passCount).padStart(4);
503
+ const fail = String(report.failCount).padStart(4);
504
+ const warn = String(report.warnCount).padStart(4);
505
+ const skip = String(report.skipCount).padStart(4);
506
+ lines.push(` ${fw} ${score} ${pass} ${fail} ${warn} ${skip}`);
507
+ }
508
+
509
+ lines.push('');
510
+
511
+ // Detailed control results
512
+ for (const report of reports) {
513
+ lines.push(`--- ${report.framework} (${report.score}%) ---`);
514
+ lines.push('');
515
+
516
+ for (const control of report.controls) {
517
+ lines.push(` ${statusIcon[control.status]} ${control.id}: ${control.name}`);
518
+ lines.push(` ${control.description}`);
519
+ if (control.evidence) {
520
+ lines.push(` Evidence: ${control.evidence}`);
521
+ }
522
+ lines.push('');
523
+ }
524
+ }
525
+
526
+ // Overall summary
527
+ const totalPass = reports.reduce((s, r) => s + r.passCount, 0);
528
+ const totalFail = reports.reduce((s, r) => s + r.failCount, 0);
529
+ const totalWarn = reports.reduce((s, r) => s + r.warnCount, 0);
530
+ const totalSkip = reports.reduce((s, r) => s + r.skipCount, 0);
531
+ const totalEval = totalPass + totalFail + totalWarn;
532
+ const overallScore = totalEval > 0 ? Math.round((totalPass / totalEval) * 100) : 0;
533
+
534
+ lines.push('='.repeat(60));
535
+ lines.push(
536
+ `Overall: ${overallScore}% compliant (${totalPass} pass, ${totalFail} fail, ${totalWarn} warn, ${totalSkip} skip)`
537
+ );
538
+
539
+ return lines.join('\n');
540
+ }