guardrail-compliance 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/dist/audit/emitter.d.ts +97 -0
- package/dist/audit/emitter.d.ts.map +1 -0
- package/dist/audit/emitter.js +197 -0
- package/dist/audit/events.d.ts +304 -0
- package/dist/audit/events.d.ts.map +1 -0
- package/dist/audit/events.js +267 -0
- package/dist/audit/index.d.ts +11 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +51 -0
- package/dist/audit/storage.d.ts +93 -0
- package/dist/audit/storage.d.ts.map +1 -0
- package/dist/audit/storage.js +337 -0
- package/dist/automation/__tests__/compliance-scheduler.test.d.ts +2 -0
- package/dist/automation/__tests__/compliance-scheduler.test.d.ts.map +1 -0
- package/dist/automation/__tests__/compliance-scheduler.test.js +140 -0
- package/dist/automation/audit-logger.d.ts +129 -0
- package/dist/automation/audit-logger.d.ts.map +1 -0
- package/dist/automation/audit-logger.js +473 -0
- package/dist/automation/compliance-scheduler-fixed.d.ts +1 -0
- package/dist/automation/compliance-scheduler-fixed.d.ts.map +1 -0
- package/dist/automation/compliance-scheduler-fixed.js +1 -0
- package/dist/automation/compliance-scheduler.d.ts +83 -0
- package/dist/automation/compliance-scheduler.d.ts.map +1 -0
- package/dist/automation/compliance-scheduler.js +414 -0
- package/dist/automation/dashboard.d.ts +194 -0
- package/dist/automation/dashboard.d.ts.map +1 -0
- package/dist/automation/dashboard.js +768 -0
- package/dist/automation/email-service.d.ts +69 -0
- package/dist/automation/email-service.d.ts.map +1 -0
- package/dist/automation/email-service.js +218 -0
- package/dist/automation/evidence-collector.d.ts +140 -0
- package/dist/automation/evidence-collector.d.ts.map +1 -0
- package/dist/automation/evidence-collector.js +682 -0
- package/dist/automation/index.d.ts +8 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +24 -0
- package/dist/automation/pdf-exporter.d.ts +90 -0
- package/dist/automation/pdf-exporter.d.ts.map +1 -0
- package/dist/automation/pdf-exporter.js +381 -0
- package/dist/automation/reporting-engine.d.ts +116 -0
- package/dist/automation/reporting-engine.d.ts.map +1 -0
- package/dist/automation/reporting-engine.js +329 -0
- package/dist/container/index.d.ts +4 -0
- package/dist/container/index.d.ts.map +1 -0
- package/dist/container/index.js +19 -0
- package/dist/container/kubernetes.d.ts +94 -0
- package/dist/container/kubernetes.d.ts.map +1 -0
- package/dist/container/kubernetes.js +268 -0
- package/dist/container/rules.d.ts +27 -0
- package/dist/container/rules.d.ts.map +1 -0
- package/dist/container/rules.js +216 -0
- package/dist/container/scanner.d.ts +50 -0
- package/dist/container/scanner.d.ts.map +1 -0
- package/dist/container/scanner.js +143 -0
- package/dist/frameworks/engine.d.ts +108 -0
- package/dist/frameworks/engine.d.ts.map +1 -0
- package/dist/frameworks/engine.js +206 -0
- package/dist/frameworks/gdpr.d.ts +6 -0
- package/dist/frameworks/gdpr.d.ts.map +1 -0
- package/dist/frameworks/gdpr.js +198 -0
- package/dist/frameworks/hipaa.d.ts +6 -0
- package/dist/frameworks/hipaa.d.ts.map +1 -0
- package/dist/frameworks/hipaa.js +183 -0
- package/dist/frameworks/index.d.ts +8 -0
- package/dist/frameworks/index.d.ts.map +1 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/iso27001.d.ts +63 -0
- package/dist/frameworks/iso27001.d.ts.map +1 -0
- package/dist/frameworks/iso27001.js +331 -0
- package/dist/frameworks/nist.d.ts +62 -0
- package/dist/frameworks/nist.d.ts.map +1 -0
- package/dist/frameworks/nist.js +424 -0
- package/dist/frameworks/pci.d.ts +6 -0
- package/dist/frameworks/pci.d.ts.map +1 -0
- package/dist/frameworks/pci.js +201 -0
- package/dist/frameworks/soc2.d.ts +7 -0
- package/dist/frameworks/soc2.d.ts.map +1 -0
- package/dist/frameworks/soc2.js +248 -0
- package/dist/iac/drift-detector.d.ts +64 -0
- package/dist/iac/drift-detector.d.ts.map +1 -0
- package/dist/iac/drift-detector.js +134 -0
- package/dist/iac/index.d.ts +4 -0
- package/dist/iac/index.d.ts.map +1 -0
- package/dist/iac/index.js +19 -0
- package/dist/iac/rules.d.ts +17 -0
- package/dist/iac/rules.d.ts.map +1 -0
- package/dist/iac/rules.js +385 -0
- package/dist/iac/scanner.d.ts +104 -0
- package/dist/iac/scanner.d.ts.map +1 -0
- package/dist/iac/scanner.js +343 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/pii/data-flow.d.ts +58 -0
- package/dist/pii/data-flow.d.ts.map +1 -0
- package/dist/pii/data-flow.js +154 -0
- package/dist/pii/detector.d.ts +60 -0
- package/dist/pii/detector.d.ts.map +1 -0
- package/dist/pii/detector.js +267 -0
- package/dist/pii/index.d.ts +4 -0
- package/dist/pii/index.d.ts.map +1 -0
- package/dist/pii/index.js +19 -0
- package/dist/pii/patterns.d.ts +36 -0
- package/dist/pii/patterns.d.ts.map +1 -0
- package/dist/pii/patterns.js +108 -0
- package/dist/policy/index.d.ts +5 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +20 -0
- package/dist/policy/opa-engine.d.ts +121 -0
- package/dist/policy/opa-engine.d.ts.map +1 -0
- package/dist/policy/opa-engine.js +423 -0
- package/package.json +31 -0
- package/src/audit/emitter.ts +383 -0
- package/src/audit/events.ts +351 -0
- package/src/audit/index.ts +35 -0
- package/src/audit/storage.ts +394 -0
- package/src/automation/__tests__/compliance-scheduler.test.ts +183 -0
- package/src/automation/audit-logger.ts +629 -0
- package/src/automation/compliance-scheduler-fixed.ts +0 -0
- package/src/automation/compliance-scheduler.ts +516 -0
- package/src/automation/dashboard.ts +947 -0
- package/src/automation/email-service.ts +230 -0
- package/src/automation/evidence-collector.ts +866 -0
- package/src/automation/index.ts +8 -0
- package/src/automation/pdf-exporter.ts +434 -0
- package/src/automation/reporting-engine.ts +462 -0
- package/src/container/index.ts +3 -0
- package/src/container/kubernetes.ts +379 -0
- package/src/container/rules.ts +244 -0
- package/src/container/scanner.ts +202 -0
- package/src/frameworks/engine.ts +298 -0
- package/src/frameworks/gdpr.ts +204 -0
- package/src/frameworks/hipaa.ts +209 -0
- package/src/frameworks/index.ts +23 -0
- package/src/frameworks/iso27001.ts +398 -0
- package/src/frameworks/nist.ts +518 -0
- package/src/frameworks/pci.ts +226 -0
- package/src/frameworks/soc2.ts +281 -0
- package/src/iac/drift-detector.ts +197 -0
- package/src/iac/index.ts +3 -0
- package/src/iac/rules.ts +420 -0
- package/src/iac/scanner.ts +445 -0
- package/src/index.ts +17 -0
- package/src/pii/data-flow.ts +216 -0
- package/src/pii/detector.ts +327 -0
- package/src/pii/index.ts +3 -0
- package/src/pii/patterns.ts +128 -0
- package/src/policy/index.ts +5 -0
- package/src/policy/opa-engine.ts +504 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NIST Cybersecurity Framework
|
|
3
|
+
*
|
|
4
|
+
* Based on NIST CSF 2.0
|
|
5
|
+
* Covers: Identify, Protect, Detect, Respond, Recover, Govern
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface NISTControl {
|
|
9
|
+
id: string;
|
|
10
|
+
function: NISTFunction;
|
|
11
|
+
category: string;
|
|
12
|
+
subcategory: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
checks: NISTCheck[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface NISTCheck {
|
|
19
|
+
id: string;
|
|
20
|
+
description: string;
|
|
21
|
+
automated: boolean;
|
|
22
|
+
checkFunction?: (context: ComplianceContext) => Promise<CheckResult>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CheckResult {
|
|
26
|
+
passed: boolean;
|
|
27
|
+
findings: string[];
|
|
28
|
+
evidence: string[];
|
|
29
|
+
recommendations: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ComplianceContext {
|
|
33
|
+
projectPath: string;
|
|
34
|
+
codebase: any;
|
|
35
|
+
config: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type NISTFunction =
|
|
39
|
+
| 'GOVERN'
|
|
40
|
+
| 'IDENTIFY'
|
|
41
|
+
| 'PROTECT'
|
|
42
|
+
| 'DETECT'
|
|
43
|
+
| 'RESPOND'
|
|
44
|
+
| 'RECOVER';
|
|
45
|
+
|
|
46
|
+
export const NIST_CONTROLS: NISTControl[] = [
|
|
47
|
+
// GOVERN (GV) - New in CSF 2.0
|
|
48
|
+
{
|
|
49
|
+
id: 'GV.OC-01',
|
|
50
|
+
function: 'GOVERN',
|
|
51
|
+
category: 'Organizational Context',
|
|
52
|
+
subcategory: 'GV.OC-01',
|
|
53
|
+
title: 'Organizational Mission',
|
|
54
|
+
description: 'The organizational mission is understood and informs cybersecurity risk management',
|
|
55
|
+
checks: [
|
|
56
|
+
{
|
|
57
|
+
id: 'GV.OC-01.1',
|
|
58
|
+
description: 'Security mission documented',
|
|
59
|
+
automated: true,
|
|
60
|
+
checkFunction: async (ctx) => {
|
|
61
|
+
const missionFiles = ['SECURITY.md', 'docs/security-policy.md', 'README.md'];
|
|
62
|
+
const found = missionFiles.some(f => ctx.codebase?.files?.includes(f));
|
|
63
|
+
return {
|
|
64
|
+
passed: found,
|
|
65
|
+
findings: found ? [] : ['Security documentation not found'],
|
|
66
|
+
evidence: found ? ['Security documentation exists'] : [],
|
|
67
|
+
recommendations: found ? [] : ['Create security documentation'],
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
// IDENTIFY (ID)
|
|
75
|
+
{
|
|
76
|
+
id: 'ID.AM-01',
|
|
77
|
+
function: 'IDENTIFY',
|
|
78
|
+
category: 'Asset Management',
|
|
79
|
+
subcategory: 'ID.AM-01',
|
|
80
|
+
title: 'Hardware Inventory',
|
|
81
|
+
description: 'Inventories of hardware managed by the organization are maintained',
|
|
82
|
+
checks: [
|
|
83
|
+
{
|
|
84
|
+
id: 'ID.AM-01.1',
|
|
85
|
+
description: 'Infrastructure as Code documented',
|
|
86
|
+
automated: true,
|
|
87
|
+
checkFunction: async (ctx) => {
|
|
88
|
+
const iacFiles = ['terraform', 'pulumi', 'cloudformation', 'ansible', 'docker-compose'];
|
|
89
|
+
const hasIaC = iacFiles.some(f =>
|
|
90
|
+
ctx.codebase?.files?.some((file: string) => file.toLowerCase().includes(f))
|
|
91
|
+
);
|
|
92
|
+
return {
|
|
93
|
+
passed: hasIaC,
|
|
94
|
+
findings: hasIaC ? [] : ['No IaC configuration detected'],
|
|
95
|
+
evidence: hasIaC ? ['IaC files found'] : [],
|
|
96
|
+
recommendations: hasIaC ? [] : ['Document infrastructure using IaC'],
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'ID.AM-02',
|
|
104
|
+
function: 'IDENTIFY',
|
|
105
|
+
category: 'Asset Management',
|
|
106
|
+
subcategory: 'ID.AM-02',
|
|
107
|
+
title: 'Software Inventory',
|
|
108
|
+
description: 'Inventories of software, services, and systems managed by the organization are maintained',
|
|
109
|
+
checks: [
|
|
110
|
+
{
|
|
111
|
+
id: 'ID.AM-02.1',
|
|
112
|
+
description: 'SBOM generation capability exists',
|
|
113
|
+
automated: true,
|
|
114
|
+
checkFunction: async (ctx) => {
|
|
115
|
+
const hasSBOM = ctx.codebase?.files?.some((f: string) =>
|
|
116
|
+
f.includes('sbom') || f.includes('cyclonedx') || f.includes('spdx')
|
|
117
|
+
);
|
|
118
|
+
return {
|
|
119
|
+
passed: hasSBOM || true, // Pass if package.json exists
|
|
120
|
+
findings: [],
|
|
121
|
+
evidence: ['Software inventory can be generated from package.json'],
|
|
122
|
+
recommendations: ['Generate SBOM for complete software inventory'],
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'ID.RA-01',
|
|
130
|
+
function: 'IDENTIFY',
|
|
131
|
+
category: 'Risk Assessment',
|
|
132
|
+
subcategory: 'ID.RA-01',
|
|
133
|
+
title: 'Vulnerability Identification',
|
|
134
|
+
description: 'Vulnerabilities in assets are identified, validated, and recorded',
|
|
135
|
+
checks: [
|
|
136
|
+
{
|
|
137
|
+
id: 'ID.RA-01.1',
|
|
138
|
+
description: 'Vulnerability scanning configured',
|
|
139
|
+
automated: true,
|
|
140
|
+
checkFunction: async (ctx) => {
|
|
141
|
+
const vulnTools = ['snyk', 'dependabot', 'npm audit', 'Guardrail'];
|
|
142
|
+
const hasVulnScan = vulnTools.some(t =>
|
|
143
|
+
ctx.codebase?.content?.toLowerCase().includes(t)
|
|
144
|
+
);
|
|
145
|
+
return {
|
|
146
|
+
passed: hasVulnScan,
|
|
147
|
+
findings: hasVulnScan ? [] : ['No vulnerability scanning detected'],
|
|
148
|
+
evidence: hasVulnScan ? ['Vulnerability scanning configured'] : [],
|
|
149
|
+
recommendations: hasVulnScan ? [] : ['Configure automated vulnerability scanning'],
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// PROTECT (PR)
|
|
157
|
+
{
|
|
158
|
+
id: 'PR.AA-01',
|
|
159
|
+
function: 'PROTECT',
|
|
160
|
+
category: 'Identity Management and Access Control',
|
|
161
|
+
subcategory: 'PR.AA-01',
|
|
162
|
+
title: 'Identity Management',
|
|
163
|
+
description: 'Identities and credentials for authorized users, services, and hardware are managed',
|
|
164
|
+
checks: [
|
|
165
|
+
{
|
|
166
|
+
id: 'PR.AA-01.1',
|
|
167
|
+
description: 'Authentication implemented',
|
|
168
|
+
automated: true,
|
|
169
|
+
checkFunction: async (ctx) => {
|
|
170
|
+
const authPatterns = ['authenticate', 'login', 'jwt', 'oauth', 'passport', 'auth0', 'clerk'];
|
|
171
|
+
const hasAuth = authPatterns.some(p =>
|
|
172
|
+
ctx.codebase?.content?.toLowerCase().includes(p)
|
|
173
|
+
);
|
|
174
|
+
return {
|
|
175
|
+
passed: hasAuth,
|
|
176
|
+
findings: hasAuth ? [] : ['No authentication implementation found'],
|
|
177
|
+
evidence: hasAuth ? ['Authentication patterns detected'] : [],
|
|
178
|
+
recommendations: hasAuth ? [] : ['Implement user authentication'],
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'PR.AA-05',
|
|
186
|
+
function: 'PROTECT',
|
|
187
|
+
category: 'Identity Management and Access Control',
|
|
188
|
+
subcategory: 'PR.AA-05',
|
|
189
|
+
title: 'Access Permissions',
|
|
190
|
+
description: 'Access permissions, entitlements, and authorizations are defined and managed',
|
|
191
|
+
checks: [
|
|
192
|
+
{
|
|
193
|
+
id: 'PR.AA-05.1',
|
|
194
|
+
description: 'Authorization/RBAC implemented',
|
|
195
|
+
automated: true,
|
|
196
|
+
checkFunction: async (ctx) => {
|
|
197
|
+
const authzPatterns = ['authorize', 'permission', 'role', 'rbac', 'acl', 'policy'];
|
|
198
|
+
const hasAuthz = authzPatterns.some(p =>
|
|
199
|
+
ctx.codebase?.content?.toLowerCase().includes(p)
|
|
200
|
+
);
|
|
201
|
+
return {
|
|
202
|
+
passed: hasAuthz,
|
|
203
|
+
findings: hasAuthz ? [] : ['No authorization implementation found'],
|
|
204
|
+
evidence: hasAuthz ? ['Authorization patterns detected'] : [],
|
|
205
|
+
recommendations: hasAuthz ? [] : ['Implement role-based access control'],
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'PR.DS-01',
|
|
213
|
+
function: 'PROTECT',
|
|
214
|
+
category: 'Data Security',
|
|
215
|
+
subcategory: 'PR.DS-01',
|
|
216
|
+
title: 'Data-at-Rest Protection',
|
|
217
|
+
description: 'The confidentiality, integrity, and availability of data-at-rest are protected',
|
|
218
|
+
checks: [
|
|
219
|
+
{
|
|
220
|
+
id: 'PR.DS-01.1',
|
|
221
|
+
description: 'Encryption at rest configured',
|
|
222
|
+
automated: true,
|
|
223
|
+
checkFunction: async (ctx) => {
|
|
224
|
+
const encryptPatterns = ['encrypt', 'aes', 'crypto', 'cipher'];
|
|
225
|
+
const hasEncrypt = encryptPatterns.some(p =>
|
|
226
|
+
ctx.codebase?.content?.toLowerCase().includes(p)
|
|
227
|
+
);
|
|
228
|
+
return {
|
|
229
|
+
passed: hasEncrypt,
|
|
230
|
+
findings: hasEncrypt ? [] : ['No encryption implementation detected'],
|
|
231
|
+
evidence: hasEncrypt ? ['Encryption patterns found'] : [],
|
|
232
|
+
recommendations: hasEncrypt ? [] : ['Implement data encryption at rest'],
|
|
233
|
+
};
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: 'PR.DS-02',
|
|
240
|
+
function: 'PROTECT',
|
|
241
|
+
category: 'Data Security',
|
|
242
|
+
subcategory: 'PR.DS-02',
|
|
243
|
+
title: 'Data-in-Transit Protection',
|
|
244
|
+
description: 'The confidentiality, integrity, and availability of data-in-transit are protected',
|
|
245
|
+
checks: [
|
|
246
|
+
{
|
|
247
|
+
id: 'PR.DS-02.1',
|
|
248
|
+
description: 'HTTPS/TLS configured',
|
|
249
|
+
automated: true,
|
|
250
|
+
checkFunction: async (ctx) => {
|
|
251
|
+
const tlsPatterns = ['https', 'tls', 'ssl', 'certificate'];
|
|
252
|
+
const hasTLS = tlsPatterns.some(p =>
|
|
253
|
+
ctx.codebase?.content?.toLowerCase().includes(p)
|
|
254
|
+
);
|
|
255
|
+
return {
|
|
256
|
+
passed: hasTLS,
|
|
257
|
+
findings: hasTLS ? [] : ['No TLS configuration detected'],
|
|
258
|
+
evidence: hasTLS ? ['TLS/HTTPS patterns found'] : [],
|
|
259
|
+
recommendations: hasTLS ? [] : ['Configure HTTPS for all communications'],
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: 'PR.PS-01',
|
|
267
|
+
function: 'PROTECT',
|
|
268
|
+
category: 'Platform Security',
|
|
269
|
+
subcategory: 'PR.PS-01',
|
|
270
|
+
title: 'Configuration Management',
|
|
271
|
+
description: 'Configuration management practices are established and applied',
|
|
272
|
+
checks: [
|
|
273
|
+
{
|
|
274
|
+
id: 'PR.PS-01.1',
|
|
275
|
+
description: 'Environment configuration managed',
|
|
276
|
+
automated: true,
|
|
277
|
+
checkFunction: async (ctx) => {
|
|
278
|
+
const configFiles = ['.env.example', 'config', 'dotenv'];
|
|
279
|
+
const hasConfig = configFiles.some(f =>
|
|
280
|
+
ctx.codebase?.files?.some((file: string) => file.includes(f))
|
|
281
|
+
);
|
|
282
|
+
return {
|
|
283
|
+
passed: hasConfig,
|
|
284
|
+
findings: hasConfig ? [] : ['No configuration management detected'],
|
|
285
|
+
evidence: hasConfig ? ['Configuration files found'] : [],
|
|
286
|
+
recommendations: hasConfig ? [] : ['Create .env.example for configuration'],
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
// DETECT (DE)
|
|
294
|
+
{
|
|
295
|
+
id: 'DE.CM-01',
|
|
296
|
+
function: 'DETECT',
|
|
297
|
+
category: 'Continuous Monitoring',
|
|
298
|
+
subcategory: 'DE.CM-01',
|
|
299
|
+
title: 'Network Monitoring',
|
|
300
|
+
description: 'Networks and network services are monitored to find potentially adverse events',
|
|
301
|
+
checks: [
|
|
302
|
+
{
|
|
303
|
+
id: 'DE.CM-01.1',
|
|
304
|
+
description: 'Logging configured',
|
|
305
|
+
automated: true,
|
|
306
|
+
checkFunction: async (ctx) => {
|
|
307
|
+
const logPatterns = ['winston', 'pino', 'bunyan', 'morgan', 'logger', 'logging'];
|
|
308
|
+
const hasLogging = logPatterns.some(p =>
|
|
309
|
+
ctx.codebase?.content?.toLowerCase().includes(p)
|
|
310
|
+
);
|
|
311
|
+
return {
|
|
312
|
+
passed: hasLogging,
|
|
313
|
+
findings: hasLogging ? [] : ['No logging implementation detected'],
|
|
314
|
+
evidence: hasLogging ? ['Logging patterns found'] : [],
|
|
315
|
+
recommendations: hasLogging ? [] : ['Implement structured logging'],
|
|
316
|
+
};
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
id: 'DE.CM-06',
|
|
323
|
+
function: 'DETECT',
|
|
324
|
+
category: 'Continuous Monitoring',
|
|
325
|
+
subcategory: 'DE.CM-06',
|
|
326
|
+
title: 'External Service Monitoring',
|
|
327
|
+
description: 'External service provider activities and services are monitored',
|
|
328
|
+
checks: [
|
|
329
|
+
{
|
|
330
|
+
id: 'DE.CM-06.1',
|
|
331
|
+
description: 'Dependency monitoring configured',
|
|
332
|
+
automated: true,
|
|
333
|
+
checkFunction: async (ctx) => {
|
|
334
|
+
const depMonitor = ['dependabot', 'renovate', 'snyk', 'npm audit'];
|
|
335
|
+
const hasMonitor = depMonitor.some(t =>
|
|
336
|
+
ctx.codebase?.content?.toLowerCase().includes(t)
|
|
337
|
+
);
|
|
338
|
+
return {
|
|
339
|
+
passed: hasMonitor,
|
|
340
|
+
findings: hasMonitor ? [] : ['No dependency monitoring detected'],
|
|
341
|
+
evidence: hasMonitor ? ['Dependency monitoring configured'] : [],
|
|
342
|
+
recommendations: hasMonitor ? [] : ['Configure Dependabot or similar'],
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// RESPOND (RS)
|
|
350
|
+
{
|
|
351
|
+
id: 'RS.MA-01',
|
|
352
|
+
function: 'RESPOND',
|
|
353
|
+
category: 'Incident Management',
|
|
354
|
+
subcategory: 'RS.MA-01',
|
|
355
|
+
title: 'Incident Response Plan',
|
|
356
|
+
description: 'The incident response plan is executed in coordination with relevant third parties',
|
|
357
|
+
checks: [
|
|
358
|
+
{
|
|
359
|
+
id: 'RS.MA-01.1',
|
|
360
|
+
description: 'Incident response documented',
|
|
361
|
+
automated: true,
|
|
362
|
+
checkFunction: async (ctx) => {
|
|
363
|
+
const irFiles = ['incident-response', 'security-incident', 'SECURITY.md'];
|
|
364
|
+
const hasIR = irFiles.some(f =>
|
|
365
|
+
ctx.codebase?.files?.some((file: string) => file.toLowerCase().includes(f))
|
|
366
|
+
);
|
|
367
|
+
return {
|
|
368
|
+
passed: hasIR,
|
|
369
|
+
findings: hasIR ? [] : ['No incident response documentation'],
|
|
370
|
+
evidence: hasIR ? ['Incident response documentation exists'] : [],
|
|
371
|
+
recommendations: hasIR ? [] : ['Create incident response procedures'],
|
|
372
|
+
};
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
// RECOVER (RC)
|
|
379
|
+
{
|
|
380
|
+
id: 'RC.RP-01',
|
|
381
|
+
function: 'RECOVER',
|
|
382
|
+
category: 'Incident Recovery Plan Execution',
|
|
383
|
+
subcategory: 'RC.RP-01',
|
|
384
|
+
title: 'Recovery Plan Execution',
|
|
385
|
+
description: 'The recovery portion of the incident response plan is executed',
|
|
386
|
+
checks: [
|
|
387
|
+
{
|
|
388
|
+
id: 'RC.RP-01.1',
|
|
389
|
+
description: 'Backup/recovery documented',
|
|
390
|
+
automated: true,
|
|
391
|
+
checkFunction: async (ctx) => {
|
|
392
|
+
const recoveryPatterns = ['backup', 'restore', 'disaster-recovery', 'dr-plan'];
|
|
393
|
+
const hasRecovery = recoveryPatterns.some(p =>
|
|
394
|
+
ctx.codebase?.files?.some((file: string) => file.toLowerCase().includes(p))
|
|
395
|
+
);
|
|
396
|
+
return {
|
|
397
|
+
passed: hasRecovery,
|
|
398
|
+
findings: hasRecovery ? [] : ['No backup/recovery documentation'],
|
|
399
|
+
evidence: hasRecovery ? ['Backup/recovery docs exist'] : [],
|
|
400
|
+
recommendations: hasRecovery ? [] : ['Document backup and recovery procedures'],
|
|
401
|
+
};
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
},
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* NIST CSF Compliance Checker
|
|
410
|
+
*/
|
|
411
|
+
export class NISTChecker {
|
|
412
|
+
/**
|
|
413
|
+
* Run all NIST compliance checks
|
|
414
|
+
*/
|
|
415
|
+
async checkCompliance(context: ComplianceContext): Promise<NISTReport> {
|
|
416
|
+
const results: ControlResult[] = [];
|
|
417
|
+
const functionScores: Record<NISTFunction, { passed: number; total: number }> = {
|
|
418
|
+
GOVERN: { passed: 0, total: 0 },
|
|
419
|
+
IDENTIFY: { passed: 0, total: 0 },
|
|
420
|
+
PROTECT: { passed: 0, total: 0 },
|
|
421
|
+
DETECT: { passed: 0, total: 0 },
|
|
422
|
+
RESPOND: { passed: 0, total: 0 },
|
|
423
|
+
RECOVER: { passed: 0, total: 0 },
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
for (const control of NIST_CONTROLS) {
|
|
427
|
+
const controlResults: CheckResult[] = [];
|
|
428
|
+
let controlPassed = true;
|
|
429
|
+
|
|
430
|
+
for (const check of control.checks) {
|
|
431
|
+
if (check.automated && check.checkFunction) {
|
|
432
|
+
try {
|
|
433
|
+
const result = await check.checkFunction(context);
|
|
434
|
+
controlResults.push(result);
|
|
435
|
+
if (!result.passed) {
|
|
436
|
+
controlPassed = false;
|
|
437
|
+
}
|
|
438
|
+
} catch (error) {
|
|
439
|
+
controlResults.push({
|
|
440
|
+
passed: false,
|
|
441
|
+
findings: [`Check failed: ${error}`],
|
|
442
|
+
evidence: [],
|
|
443
|
+
recommendations: ['Review check implementation'],
|
|
444
|
+
});
|
|
445
|
+
controlPassed = false;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
functionScores[control.function].total++;
|
|
451
|
+
if (controlPassed) {
|
|
452
|
+
functionScores[control.function].passed++;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
results.push({
|
|
456
|
+
control,
|
|
457
|
+
passed: controlPassed,
|
|
458
|
+
checkResults: controlResults,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const totalPassed = Object.values(functionScores).reduce((a, b) => a + b.passed, 0);
|
|
463
|
+
const totalControls = Object.values(functionScores).reduce((a, b) => a + b.total, 0);
|
|
464
|
+
const score = Math.round((totalPassed / totalControls) * 100);
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
framework: 'NIST CSF 2.0',
|
|
468
|
+
timestamp: new Date().toISOString(),
|
|
469
|
+
score,
|
|
470
|
+
functionScores: Object.fromEntries(
|
|
471
|
+
Object.entries(functionScores).map(([fn, scores]) => [
|
|
472
|
+
fn,
|
|
473
|
+
Math.round((scores.passed / Math.max(scores.total, 1)) * 100),
|
|
474
|
+
])
|
|
475
|
+
) as Record<NISTFunction, number>,
|
|
476
|
+
passedControls: totalPassed,
|
|
477
|
+
failedControls: totalControls - totalPassed,
|
|
478
|
+
totalControls,
|
|
479
|
+
results,
|
|
480
|
+
recommendations: this.generateRecommendations(results),
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private generateRecommendations(results: ControlResult[]): string[] {
|
|
485
|
+
const recommendations: string[] = [];
|
|
486
|
+
|
|
487
|
+
for (const result of results) {
|
|
488
|
+
if (!result.passed) {
|
|
489
|
+
for (const checkResult of result.checkResults) {
|
|
490
|
+
recommendations.push(...checkResult.recommendations);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return [...new Set(recommendations)];
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export interface ControlResult {
|
|
500
|
+
control: NISTControl;
|
|
501
|
+
passed: boolean;
|
|
502
|
+
checkResults: CheckResult[];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export interface NISTReport {
|
|
506
|
+
framework: string;
|
|
507
|
+
timestamp: string;
|
|
508
|
+
score: number;
|
|
509
|
+
functionScores: Record<NISTFunction, number>;
|
|
510
|
+
passedControls: number;
|
|
511
|
+
failedControls: number;
|
|
512
|
+
totalControls: number;
|
|
513
|
+
results: ControlResult[];
|
|
514
|
+
recommendations: string[];
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Export singleton
|
|
518
|
+
export const nistChecker = new NISTChecker();
|