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,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.containerScanner = exports.ContainerScanner = void 0;
|
|
4
|
+
const database_1 = require("@guardrail/database");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const rules_1 = require("./rules");
|
|
7
|
+
class ContainerScanner {
|
|
8
|
+
/**
|
|
9
|
+
* Scan Docker image for vulnerabilities
|
|
10
|
+
* In production, would integrate with Trivy or Grype
|
|
11
|
+
*/
|
|
12
|
+
async scanImage(imageName, tag, projectId) {
|
|
13
|
+
// Simulate vulnerability scanning
|
|
14
|
+
// In production, would execute: trivy image imageName:tag --format json
|
|
15
|
+
const vulnerabilities = [];
|
|
16
|
+
// Example vulnerabilities (in production, parsed from Trivy/Grype output)
|
|
17
|
+
// const exampleVulns: Vulnerability[] = [
|
|
18
|
+
// {
|
|
19
|
+
// id: 'CVE-2024-1234',
|
|
20
|
+
// severity: 'high',
|
|
21
|
+
// package: 'openssl',
|
|
22
|
+
// installedVersion: '1.1.1k',
|
|
23
|
+
// fixedVersion: '1.1.1w',
|
|
24
|
+
// description: 'OpenSSL vulnerability'
|
|
25
|
+
// }
|
|
26
|
+
// ];
|
|
27
|
+
const summary = {
|
|
28
|
+
critical: vulnerabilities.filter(v => v.severity === 'critical').length,
|
|
29
|
+
high: vulnerabilities.filter(v => v.severity === 'high').length,
|
|
30
|
+
medium: vulnerabilities.filter(v => v.severity === 'medium').length,
|
|
31
|
+
low: vulnerabilities.filter(v => v.severity === 'low').length
|
|
32
|
+
};
|
|
33
|
+
// Save to database
|
|
34
|
+
try {
|
|
35
|
+
await database_1.prisma.containerScan.create({
|
|
36
|
+
data: {
|
|
37
|
+
projectId
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// Table may not exist - continue
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
projectId,
|
|
46
|
+
imageName,
|
|
47
|
+
imageTag: tag,
|
|
48
|
+
summary,
|
|
49
|
+
vulnerabilities
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Scan Dockerfile for security issues
|
|
54
|
+
*/
|
|
55
|
+
async scanDockerfile(dockerfilePath) {
|
|
56
|
+
if (!(0, fs_1.existsSync)(dockerfilePath)) {
|
|
57
|
+
throw new Error(`Dockerfile not found: ${dockerfilePath}`);
|
|
58
|
+
}
|
|
59
|
+
const content = (0, fs_1.readFileSync)(dockerfilePath, 'utf-8');
|
|
60
|
+
const lines = content.split('\n');
|
|
61
|
+
const findings = [];
|
|
62
|
+
let hasHealthcheck = false;
|
|
63
|
+
let hasUser = false;
|
|
64
|
+
let fromCount = 0;
|
|
65
|
+
for (let i = 0; i < lines.length; i++) {
|
|
66
|
+
const line = lines[i]?.trim();
|
|
67
|
+
if (!line)
|
|
68
|
+
continue;
|
|
69
|
+
// Skip comments and empty lines
|
|
70
|
+
if (line.startsWith('#')) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Parse instruction
|
|
74
|
+
const parts = line.split(/\s+/);
|
|
75
|
+
const instruction = parts[0]?.toUpperCase();
|
|
76
|
+
const value = parts.slice(1).join(' ');
|
|
77
|
+
// Track special instructions
|
|
78
|
+
if (instruction === 'HEALTHCHECK')
|
|
79
|
+
hasHealthcheck = true;
|
|
80
|
+
if (instruction === 'USER')
|
|
81
|
+
hasUser = true;
|
|
82
|
+
if (instruction === 'FROM')
|
|
83
|
+
fromCount++;
|
|
84
|
+
// Check against rules
|
|
85
|
+
for (const rule of rules_1.DOCKERFILE_RULES) {
|
|
86
|
+
if (rule.check(instruction, value || '')) {
|
|
87
|
+
findings.push({
|
|
88
|
+
ruleId: rule.id,
|
|
89
|
+
title: rule.title,
|
|
90
|
+
description: rule.description,
|
|
91
|
+
severity: rule.severity,
|
|
92
|
+
line: i + 1,
|
|
93
|
+
instruction: instruction,
|
|
94
|
+
value: value || '',
|
|
95
|
+
recommendation: rule.recommendation
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Check for missing HEALTHCHECK
|
|
101
|
+
if (!hasHealthcheck) {
|
|
102
|
+
findings.push({
|
|
103
|
+
ruleId: 'DOCKER-003',
|
|
104
|
+
title: 'Missing Health Check',
|
|
105
|
+
description: 'No HEALTHCHECK instruction defined',
|
|
106
|
+
severity: 'low',
|
|
107
|
+
line: 0,
|
|
108
|
+
instruction: 'HEALTHCHECK',
|
|
109
|
+
value: '',
|
|
110
|
+
recommendation: 'Add HEALTHCHECK instruction'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// Check for missing USER (running as root)
|
|
114
|
+
if (!hasUser) {
|
|
115
|
+
findings.push({
|
|
116
|
+
ruleId: 'DOCKER-001',
|
|
117
|
+
title: 'Running as Root',
|
|
118
|
+
description: 'No USER instruction - container runs as root',
|
|
119
|
+
severity: 'high',
|
|
120
|
+
line: 0,
|
|
121
|
+
instruction: 'USER',
|
|
122
|
+
value: '',
|
|
123
|
+
recommendation: 'Add USER instruction to run as non-root'
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Check for multi-stage builds
|
|
127
|
+
if (fromCount === 1) {
|
|
128
|
+
findings.push({
|
|
129
|
+
ruleId: 'DOCKER-006',
|
|
130
|
+
title: 'Missing Multi-Stage Build',
|
|
131
|
+
description: 'Single-stage build - consider using multi-stage',
|
|
132
|
+
severity: 'low',
|
|
133
|
+
line: 0,
|
|
134
|
+
instruction: 'FROM',
|
|
135
|
+
value: '',
|
|
136
|
+
recommendation: 'Use multi-stage builds to reduce image size'
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return findings;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.ContainerScanner = ContainerScanner;
|
|
143
|
+
exports.containerScanner = new ContainerScanner();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export interface ComplianceControl {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
category: string;
|
|
6
|
+
requirements: string[];
|
|
7
|
+
automatedChecks?: AutomatedCheck[];
|
|
8
|
+
manualSteps?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface AutomatedCheck {
|
|
11
|
+
id: string;
|
|
12
|
+
description: string;
|
|
13
|
+
check: (projectPath: string) => Promise<CheckResult>;
|
|
14
|
+
}
|
|
15
|
+
export interface CheckResult {
|
|
16
|
+
passed: boolean;
|
|
17
|
+
details: string;
|
|
18
|
+
evidence?: any;
|
|
19
|
+
}
|
|
20
|
+
export interface ComplianceFramework {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
version: string;
|
|
24
|
+
description: string;
|
|
25
|
+
controls: ComplianceControl[];
|
|
26
|
+
}
|
|
27
|
+
export interface ControlAssessment {
|
|
28
|
+
controlId: string;
|
|
29
|
+
title: string;
|
|
30
|
+
status: 'compliant' | 'partial' | 'non-compliant' | 'not-assessed';
|
|
31
|
+
score: number;
|
|
32
|
+
findings: string[];
|
|
33
|
+
evidence: any[];
|
|
34
|
+
gaps: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface ComplianceGap {
|
|
37
|
+
controlId: string;
|
|
38
|
+
severity: 'high' | 'medium' | 'low';
|
|
39
|
+
description: string;
|
|
40
|
+
recommendation: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ComplianceEvidence {
|
|
43
|
+
controlId: string;
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
data: any;
|
|
47
|
+
timestamp: Date;
|
|
48
|
+
}
|
|
49
|
+
export interface ComplianceAssessmentResult {
|
|
50
|
+
projectId: string;
|
|
51
|
+
frameworkId: string;
|
|
52
|
+
summary: {
|
|
53
|
+
totalControls: number;
|
|
54
|
+
compliant: number;
|
|
55
|
+
partial: number;
|
|
56
|
+
nonCompliant: number;
|
|
57
|
+
score: number;
|
|
58
|
+
};
|
|
59
|
+
controls: ControlAssessment[];
|
|
60
|
+
gaps: ComplianceGap[];
|
|
61
|
+
evidence: ComplianceEvidence[];
|
|
62
|
+
}
|
|
63
|
+
export declare class ComplianceAutomationEngine {
|
|
64
|
+
private frameworks;
|
|
65
|
+
constructor();
|
|
66
|
+
/**
|
|
67
|
+
* Load all compliance frameworks
|
|
68
|
+
*/
|
|
69
|
+
private loadFrameworks;
|
|
70
|
+
/**
|
|
71
|
+
* Get available frameworks
|
|
72
|
+
*/
|
|
73
|
+
getFrameworks(): ComplianceFramework[];
|
|
74
|
+
/**
|
|
75
|
+
* Get specific framework
|
|
76
|
+
*/
|
|
77
|
+
getFramework(frameworkId: string): ComplianceFramework | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Run compliance assessment
|
|
80
|
+
*/
|
|
81
|
+
assess(projectPath: string, frameworkId: string, projectId: string): Promise<ComplianceAssessmentResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Assess single control
|
|
84
|
+
*/
|
|
85
|
+
private assessControl;
|
|
86
|
+
/**
|
|
87
|
+
* Run automated check
|
|
88
|
+
*/
|
|
89
|
+
private runCheck;
|
|
90
|
+
/**
|
|
91
|
+
* Generate evidence for control
|
|
92
|
+
*/
|
|
93
|
+
generateEvidence(projectPath: string, _frameworkId: string, _controlId: string): Promise<ComplianceEvidence[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Calculate overall compliance score
|
|
96
|
+
*/
|
|
97
|
+
private calculateOverallScore;
|
|
98
|
+
/**
|
|
99
|
+
* Determine gap severity based on control category
|
|
100
|
+
*/
|
|
101
|
+
private determineGapSeverity;
|
|
102
|
+
/**
|
|
103
|
+
* Get recommendation for gap
|
|
104
|
+
*/
|
|
105
|
+
private getRecommendation;
|
|
106
|
+
}
|
|
107
|
+
export declare const complianceAutomationEngine: ComplianceAutomationEngine;
|
|
108
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/frameworks/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.complianceAutomationEngine = exports.ComplianceAutomationEngine = void 0;
|
|
4
|
+
const database_1 = require("@guardrail/database");
|
|
5
|
+
const soc2_1 = require("./soc2");
|
|
6
|
+
const gdpr_1 = require("./gdpr");
|
|
7
|
+
const hipaa_1 = require("./hipaa");
|
|
8
|
+
const pci_1 = require("./pci");
|
|
9
|
+
class ComplianceAutomationEngine {
|
|
10
|
+
frameworks;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.frameworks = new Map();
|
|
13
|
+
this.loadFrameworks();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Load all compliance frameworks
|
|
17
|
+
*/
|
|
18
|
+
loadFrameworks() {
|
|
19
|
+
this.frameworks.set('soc2', soc2_1.SOC2_FRAMEWORK);
|
|
20
|
+
this.frameworks.set('gdpr', gdpr_1.GDPR_FRAMEWORK);
|
|
21
|
+
this.frameworks.set('hipaa', hipaa_1.HIPAA_FRAMEWORK);
|
|
22
|
+
this.frameworks.set('pci', pci_1.PCI_FRAMEWORK);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get available frameworks
|
|
26
|
+
*/
|
|
27
|
+
getFrameworks() {
|
|
28
|
+
return Array.from(this.frameworks.values());
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get specific framework
|
|
32
|
+
*/
|
|
33
|
+
getFramework(frameworkId) {
|
|
34
|
+
return this.frameworks.get(frameworkId);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Run compliance assessment
|
|
38
|
+
*/
|
|
39
|
+
async assess(projectPath, frameworkId, projectId) {
|
|
40
|
+
const framework = this.frameworks.get(frameworkId);
|
|
41
|
+
if (!framework) {
|
|
42
|
+
throw new Error(`Framework ${frameworkId} not found`);
|
|
43
|
+
}
|
|
44
|
+
const controlAssessments = [];
|
|
45
|
+
const allGaps = [];
|
|
46
|
+
const allEvidence = [];
|
|
47
|
+
// Assess each control
|
|
48
|
+
for (const control of framework.controls) {
|
|
49
|
+
const assessment = await this.assessControl(projectPath, control);
|
|
50
|
+
controlAssessments.push(assessment);
|
|
51
|
+
// Generate evidence
|
|
52
|
+
const evidence = await this.generateEvidence(projectPath, frameworkId, control.id);
|
|
53
|
+
allEvidence.push(...evidence);
|
|
54
|
+
// Identify gaps
|
|
55
|
+
if (assessment.status === 'non-compliant' || assessment.status === 'partial') {
|
|
56
|
+
allGaps.push(...assessment.gaps.map(gap => ({
|
|
57
|
+
controlId: control.id,
|
|
58
|
+
severity: this.determineGapSeverity(control.category),
|
|
59
|
+
description: gap,
|
|
60
|
+
recommendation: this.getRecommendation(control.id, gap)
|
|
61
|
+
})));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Calculate summary
|
|
65
|
+
const summary = {
|
|
66
|
+
totalControls: controlAssessments.length,
|
|
67
|
+
compliant: controlAssessments.filter(a => a.status === 'compliant').length,
|
|
68
|
+
partial: controlAssessments.filter(a => a.status === 'partial').length,
|
|
69
|
+
nonCompliant: controlAssessments.filter(a => a.status === 'non-compliant').length,
|
|
70
|
+
score: this.calculateOverallScore(controlAssessments)
|
|
71
|
+
};
|
|
72
|
+
const result = {
|
|
73
|
+
projectId,
|
|
74
|
+
frameworkId,
|
|
75
|
+
summary,
|
|
76
|
+
controls: controlAssessments,
|
|
77
|
+
gaps: allGaps,
|
|
78
|
+
evidence: allEvidence
|
|
79
|
+
};
|
|
80
|
+
// Save to database
|
|
81
|
+
await database_1.prisma.complianceAssessment.create({
|
|
82
|
+
data: {
|
|
83
|
+
projectId,
|
|
84
|
+
frameworkId,
|
|
85
|
+
summary: summary,
|
|
86
|
+
controls: controlAssessments,
|
|
87
|
+
gaps: allGaps,
|
|
88
|
+
evidence: allEvidence
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Assess single control
|
|
95
|
+
*/
|
|
96
|
+
async assessControl(projectPath, control) {
|
|
97
|
+
const findings = [];
|
|
98
|
+
const evidence = [];
|
|
99
|
+
const gaps = [];
|
|
100
|
+
let passedChecks = 0;
|
|
101
|
+
let totalChecks = control.automatedChecks?.length || 0;
|
|
102
|
+
// Run automated checks
|
|
103
|
+
if (control.automatedChecks) {
|
|
104
|
+
for (const check of control.automatedChecks) {
|
|
105
|
+
try {
|
|
106
|
+
const result = await this.runCheck(projectPath, check);
|
|
107
|
+
if (result.passed) {
|
|
108
|
+
passedChecks++;
|
|
109
|
+
findings.push(`✓ ${check.description}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
findings.push(`✗ ${check.description}: ${result.details}`);
|
|
113
|
+
gaps.push(result.details);
|
|
114
|
+
}
|
|
115
|
+
if (result.evidence) {
|
|
116
|
+
evidence.push(result.evidence);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
findings.push(`✗ ${check.description}: Error running check`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Calculate score and status
|
|
125
|
+
const score = totalChecks > 0 ? (passedChecks / totalChecks) * 100 : 0;
|
|
126
|
+
let status;
|
|
127
|
+
if (totalChecks === 0) {
|
|
128
|
+
status = 'not-assessed';
|
|
129
|
+
}
|
|
130
|
+
else if (score === 100) {
|
|
131
|
+
status = 'compliant';
|
|
132
|
+
}
|
|
133
|
+
else if (score >= 50) {
|
|
134
|
+
status = 'partial';
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
status = 'non-compliant';
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
controlId: control.id,
|
|
141
|
+
title: control.title,
|
|
142
|
+
status,
|
|
143
|
+
score,
|
|
144
|
+
findings,
|
|
145
|
+
evidence,
|
|
146
|
+
gaps
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Run automated check
|
|
151
|
+
*/
|
|
152
|
+
async runCheck(projectPath, check) {
|
|
153
|
+
return await check.check(projectPath);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Generate evidence for control
|
|
157
|
+
*/
|
|
158
|
+
async generateEvidence(projectPath, _frameworkId, _controlId) {
|
|
159
|
+
const evidence = [];
|
|
160
|
+
// Generate evidence based on control type
|
|
161
|
+
// This is a simplified version - in production would collect actual artifacts
|
|
162
|
+
evidence.push({
|
|
163
|
+
controlId: _controlId,
|
|
164
|
+
type: 'automated-scan',
|
|
165
|
+
description: `Automated compliance scan for ${_controlId}`,
|
|
166
|
+
data: {
|
|
167
|
+
timestamp: new Date(),
|
|
168
|
+
projectPath
|
|
169
|
+
},
|
|
170
|
+
timestamp: new Date()
|
|
171
|
+
});
|
|
172
|
+
return evidence;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Calculate overall compliance score
|
|
176
|
+
*/
|
|
177
|
+
calculateOverallScore(assessments) {
|
|
178
|
+
if (assessments.length === 0)
|
|
179
|
+
return 0;
|
|
180
|
+
const totalScore = assessments.reduce((sum, a) => sum + a.score, 0);
|
|
181
|
+
return Math.round(totalScore / assessments.length);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Determine gap severity based on control category
|
|
185
|
+
*/
|
|
186
|
+
determineGapSeverity(category) {
|
|
187
|
+
const highSeverityCategories = ['access-control', 'data-protection', 'security'];
|
|
188
|
+
const mediumSeverityCategories = ['logging', 'monitoring', 'change-management'];
|
|
189
|
+
if (highSeverityCategories.includes(category)) {
|
|
190
|
+
return 'high';
|
|
191
|
+
}
|
|
192
|
+
else if (mediumSeverityCategories.includes(category)) {
|
|
193
|
+
return 'medium';
|
|
194
|
+
}
|
|
195
|
+
return 'low';
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get recommendation for gap
|
|
199
|
+
*/
|
|
200
|
+
getRecommendation(_controlId, gap) {
|
|
201
|
+
// In production, would have specific recommendations for each control
|
|
202
|
+
return `Implement controls to address: ${gap}`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.ComplianceAutomationEngine = ComplianceAutomationEngine;
|
|
206
|
+
exports.complianceAutomationEngine = new ComplianceAutomationEngine();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gdpr.d.ts","sourceRoot":"","sources":["../../src/frameworks/gdpr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAe,MAAM,UAAU,CAAC;AAI5D;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,mBAoM5B,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GDPR_FRAMEWORK = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
/**
|
|
7
|
+
* GDPR (General Data Protection Regulation) Compliance Framework
|
|
8
|
+
*/
|
|
9
|
+
exports.GDPR_FRAMEWORK = {
|
|
10
|
+
id: 'gdpr',
|
|
11
|
+
name: 'GDPR',
|
|
12
|
+
version: '2018',
|
|
13
|
+
description: 'General Data Protection Regulation',
|
|
14
|
+
controls: [
|
|
15
|
+
{
|
|
16
|
+
id: 'ART5',
|
|
17
|
+
title: 'Principles of Processing Personal Data',
|
|
18
|
+
description: 'Personal data shall be processed lawfully, fairly and in a transparent manner',
|
|
19
|
+
category: 'data-protection',
|
|
20
|
+
requirements: [
|
|
21
|
+
'Lawfulness, fairness and transparency',
|
|
22
|
+
'Purpose limitation',
|
|
23
|
+
'Data minimisation',
|
|
24
|
+
'Accuracy',
|
|
25
|
+
'Storage limitation',
|
|
26
|
+
'Integrity and confidentiality'
|
|
27
|
+
],
|
|
28
|
+
automatedChecks: [
|
|
29
|
+
{
|
|
30
|
+
id: 'ART5-001',
|
|
31
|
+
description: 'Check for PII data collection documentation',
|
|
32
|
+
check: async (projectPath) => {
|
|
33
|
+
const privacyDocs = [
|
|
34
|
+
'PRIVACY.md',
|
|
35
|
+
'privacy-policy.md',
|
|
36
|
+
'docs/privacy',
|
|
37
|
+
'GDPR.md'
|
|
38
|
+
];
|
|
39
|
+
for (const doc of privacyDocs) {
|
|
40
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, doc))) {
|
|
41
|
+
return {
|
|
42
|
+
passed: true,
|
|
43
|
+
details: 'Privacy documentation found',
|
|
44
|
+
evidence: { document: doc }
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
passed: false,
|
|
50
|
+
details: 'No privacy policy documentation found'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
manualSteps: [
|
|
56
|
+
'Document legal basis for processing',
|
|
57
|
+
'Implement data retention policies',
|
|
58
|
+
'Ensure data accuracy mechanisms'
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'ART25',
|
|
63
|
+
title: 'Data Protection by Design and by Default',
|
|
64
|
+
description: 'Implement appropriate technical and organisational measures for data protection',
|
|
65
|
+
category: 'data-protection',
|
|
66
|
+
requirements: [
|
|
67
|
+
'Data protection by design',
|
|
68
|
+
'Data protection by default',
|
|
69
|
+
'Minimisation of personal data',
|
|
70
|
+
'Pseudonymisation where possible'
|
|
71
|
+
],
|
|
72
|
+
automatedChecks: [
|
|
73
|
+
{
|
|
74
|
+
id: 'ART25-001',
|
|
75
|
+
description: 'Verify data encryption at rest',
|
|
76
|
+
check: async (projectPath) => {
|
|
77
|
+
// Check for database encryption configuration
|
|
78
|
+
const envExample = (0, path_1.join)(projectPath, '.env.example');
|
|
79
|
+
if ((0, fs_1.existsSync)(envExample)) {
|
|
80
|
+
return {
|
|
81
|
+
passed: true,
|
|
82
|
+
details: 'Environment configuration suggests encryption practices',
|
|
83
|
+
evidence: { file: '.env.example' }
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
passed: false,
|
|
88
|
+
details: 'No evidence of encryption configuration'
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'ART25-002',
|
|
94
|
+
description: 'Check for data anonymization/pseudonymization',
|
|
95
|
+
check: async (_projectPath) => {
|
|
96
|
+
// This would check for anonymization libraries or patterns
|
|
97
|
+
return {
|
|
98
|
+
passed: false,
|
|
99
|
+
details: 'Manual review required for anonymization practices'
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'ART32',
|
|
107
|
+
title: 'Security of Processing',
|
|
108
|
+
description: 'Implement appropriate technical and organisational measures to ensure a level of security',
|
|
109
|
+
category: 'security',
|
|
110
|
+
requirements: [
|
|
111
|
+
'Pseudonymisation and encryption',
|
|
112
|
+
'Ongoing confidentiality, integrity, availability',
|
|
113
|
+
'Regular testing and evaluation',
|
|
114
|
+
'Process for restoring availability'
|
|
115
|
+
],
|
|
116
|
+
automatedChecks: [
|
|
117
|
+
{
|
|
118
|
+
id: 'ART32-001',
|
|
119
|
+
description: 'Verify HTTPS enforcement',
|
|
120
|
+
check: async (_projectPath) => {
|
|
121
|
+
// Check for HTTPS/TLS configuration
|
|
122
|
+
// In production would check actual configuration
|
|
123
|
+
return {
|
|
124
|
+
passed: false,
|
|
125
|
+
details: 'Manual verification required for HTTPS enforcement'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: 'ART32-002',
|
|
131
|
+
description: 'Check for security testing',
|
|
132
|
+
check: async (projectPath) => {
|
|
133
|
+
const securityTestDirs = [
|
|
134
|
+
'test/security',
|
|
135
|
+
'tests/security',
|
|
136
|
+
'__tests__/security'
|
|
137
|
+
];
|
|
138
|
+
for (const dir of securityTestDirs) {
|
|
139
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, dir))) {
|
|
140
|
+
return {
|
|
141
|
+
passed: true,
|
|
142
|
+
details: 'Security tests found',
|
|
143
|
+
evidence: { directory: dir }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
passed: false,
|
|
149
|
+
details: 'No security tests found'
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'ART33',
|
|
157
|
+
title: 'Breach Notification',
|
|
158
|
+
description: 'Notify supervisory authority of a personal data breach within 72 hours',
|
|
159
|
+
category: 'incident-response',
|
|
160
|
+
requirements: [
|
|
161
|
+
'Breach detection capability',
|
|
162
|
+
'Breach notification procedures',
|
|
163
|
+
'Documentation of breaches'
|
|
164
|
+
],
|
|
165
|
+
automatedChecks: [
|
|
166
|
+
{
|
|
167
|
+
id: 'ART33-001',
|
|
168
|
+
description: 'Check for incident response procedures',
|
|
169
|
+
check: async (projectPath) => {
|
|
170
|
+
const irDocs = [
|
|
171
|
+
'SECURITY.md',
|
|
172
|
+
'docs/incident-response',
|
|
173
|
+
'docs/security/incident-response.md'
|
|
174
|
+
];
|
|
175
|
+
for (const doc of irDocs) {
|
|
176
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(projectPath, doc))) {
|
|
177
|
+
return {
|
|
178
|
+
passed: true,
|
|
179
|
+
details: 'Incident response documentation found',
|
|
180
|
+
evidence: { document: doc }
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
passed: false,
|
|
186
|
+
details: 'No incident response documentation found'
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
manualSteps: [
|
|
192
|
+
'Define breach notification workflow',
|
|
193
|
+
'Establish contact with supervisory authority',
|
|
194
|
+
'Create breach documentation templates'
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hipaa.d.ts","sourceRoot":"","sources":["../../src/frameworks/hipaa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAe,MAAM,UAAU,CAAC;AAI5D;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,mBAyM7B,CAAC"}
|