verification-layer 0.20.0 → 0.22.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/README.md +251 -615
- package/dist/cli.js +542 -0
- package/dist/cli.js.map +1 -1
- package/dist/marketplace/index.d.ts +8 -0
- package/dist/marketplace/index.d.ts.map +1 -0
- package/dist/marketplace/index.js +7 -0
- package/dist/marketplace/index.js.map +1 -0
- package/dist/marketplace/installer.d.ts +62 -0
- package/dist/marketplace/installer.d.ts.map +1 -0
- package/dist/marketplace/installer.js +254 -0
- package/dist/marketplace/installer.js.map +1 -0
- package/dist/marketplace/registry.d.ts +52 -0
- package/dist/marketplace/registry.d.ts.map +1 -0
- package/dist/marketplace/registry.js +759 -0
- package/dist/marketplace/registry.js.map +1 -0
- package/dist/marketplace/types.d.ts +123 -0
- package/dist/marketplace/types.d.ts.map +1 -0
- package/dist/marketplace/types.js +6 -0
- package/dist/marketplace/types.js.map +1 -0
- package/dist/reporters/audit-report.d.ts.map +1 -1
- package/dist/reporters/audit-report.js +180 -0
- package/dist/reporters/audit-report.js.map +1 -1
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js +2612 -5
- package/dist/reporters/index.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +15 -1
- package/dist/scan.js.map +1 -1
- package/dist/scanners/api-security/index.d.ts +7 -0
- package/dist/scanners/api-security/index.d.ts.map +1 -0
- package/dist/scanners/api-security/index.js +139 -0
- package/dist/scanners/api-security/index.js.map +1 -0
- package/dist/scanners/api-security/index.test.d.ts +5 -0
- package/dist/scanners/api-security/index.test.d.ts.map +1 -0
- package/dist/scanners/api-security/index.test.js +360 -0
- package/dist/scanners/api-security/index.test.js.map +1 -0
- package/dist/scanners/api-security/patterns.d.ts +32 -0
- package/dist/scanners/api-security/patterns.d.ts.map +1 -0
- package/dist/scanners/api-security/patterns.js +159 -0
- package/dist/scanners/api-security/patterns.js.map +1 -0
- package/dist/scanners/authentication/index.d.ts +7 -0
- package/dist/scanners/authentication/index.d.ts.map +1 -0
- package/dist/scanners/authentication/index.js +107 -0
- package/dist/scanners/authentication/index.js.map +1 -0
- package/dist/scanners/authentication/index.test.d.ts +5 -0
- package/dist/scanners/authentication/index.test.d.ts.map +1 -0
- package/dist/scanners/authentication/index.test.js +379 -0
- package/dist/scanners/authentication/index.test.js.map +1 -0
- package/dist/scanners/authentication/patterns.d.ts +32 -0
- package/dist/scanners/authentication/patterns.d.ts.map +1 -0
- package/dist/scanners/authentication/patterns.js +133 -0
- package/dist/scanners/authentication/patterns.js.map +1 -0
- package/dist/scanners/configuration/index.d.ts +8 -0
- package/dist/scanners/configuration/index.d.ts.map +1 -0
- package/dist/scanners/configuration/index.js +87 -0
- package/dist/scanners/configuration/index.js.map +1 -0
- package/dist/scanners/configuration/index.test.d.ts +5 -0
- package/dist/scanners/configuration/index.test.d.ts.map +1 -0
- package/dist/scanners/configuration/index.test.js +344 -0
- package/dist/scanners/configuration/index.test.js.map +1 -0
- package/dist/scanners/configuration/patterns.d.ts +32 -0
- package/dist/scanners/configuration/patterns.d.ts.map +1 -0
- package/dist/scanners/configuration/patterns.js +146 -0
- package/dist/scanners/configuration/patterns.js.map +1 -0
- package/dist/scanners/credentials/index.d.ts +7 -0
- package/dist/scanners/credentials/index.d.ts.map +1 -0
- package/dist/scanners/credentials/index.js +129 -0
- package/dist/scanners/credentials/index.js.map +1 -0
- package/dist/scanners/credentials/index.test.d.ts +5 -0
- package/dist/scanners/credentials/index.test.d.ts.map +1 -0
- package/dist/scanners/credentials/index.test.js +395 -0
- package/dist/scanners/credentials/index.test.js.map +1 -0
- package/dist/scanners/credentials/patterns.d.ts +32 -0
- package/dist/scanners/credentials/patterns.d.ts.map +1 -0
- package/dist/scanners/credentials/patterns.js +140 -0
- package/dist/scanners/credentials/patterns.js.map +1 -0
- package/dist/scanners/errors/index.d.ts +8 -0
- package/dist/scanners/errors/index.d.ts.map +1 -0
- package/dist/scanners/errors/index.js +78 -0
- package/dist/scanners/errors/index.js.map +1 -0
- package/dist/scanners/errors/index.test.d.ts +5 -0
- package/dist/scanners/errors/index.test.d.ts.map +1 -0
- package/dist/scanners/errors/index.test.js +330 -0
- package/dist/scanners/errors/index.test.js.map +1 -0
- package/dist/scanners/errors/patterns.d.ts +27 -0
- package/dist/scanners/errors/patterns.d.ts.map +1 -0
- package/dist/scanners/errors/patterns.js +97 -0
- package/dist/scanners/errors/patterns.js.map +1 -0
- package/dist/scanners/hipaa2026/index.d.ts +8 -0
- package/dist/scanners/hipaa2026/index.d.ts.map +1 -0
- package/dist/scanners/hipaa2026/index.js +345 -0
- package/dist/scanners/hipaa2026/index.js.map +1 -0
- package/dist/scanners/hipaa2026/index.test.d.ts +5 -0
- package/dist/scanners/hipaa2026/index.test.d.ts.map +1 -0
- package/dist/scanners/hipaa2026/index.test.js +332 -0
- package/dist/scanners/hipaa2026/index.test.js.map +1 -0
- package/dist/scanners/hipaa2026/patterns.d.ts +57 -0
- package/dist/scanners/hipaa2026/patterns.d.ts.map +1 -0
- package/dist/scanners/hipaa2026/patterns.js +268 -0
- package/dist/scanners/hipaa2026/patterns.js.map +1 -0
- package/dist/scanners/operational/index.d.ts +7 -0
- package/dist/scanners/operational/index.d.ts.map +1 -0
- package/dist/scanners/operational/index.js +171 -0
- package/dist/scanners/operational/index.js.map +1 -0
- package/dist/scanners/operational/index.test.d.ts +5 -0
- package/dist/scanners/operational/index.test.d.ts.map +1 -0
- package/dist/scanners/operational/index.test.js +406 -0
- package/dist/scanners/operational/index.test.js.map +1 -0
- package/dist/scanners/operational/patterns.d.ts +33 -0
- package/dist/scanners/operational/patterns.d.ts.map +1 -0
- package/dist/scanners/operational/patterns.js +151 -0
- package/dist/scanners/operational/patterns.js.map +1 -0
- package/dist/scanners/rbac/index.d.ts +7 -0
- package/dist/scanners/rbac/index.d.ts.map +1 -0
- package/dist/scanners/rbac/index.js +145 -0
- package/dist/scanners/rbac/index.js.map +1 -0
- package/dist/scanners/rbac/index.test.d.ts +5 -0
- package/dist/scanners/rbac/index.test.d.ts.map +1 -0
- package/dist/scanners/rbac/index.test.js +422 -0
- package/dist/scanners/rbac/index.test.js.map +1 -0
- package/dist/scanners/rbac/patterns.d.ts +32 -0
- package/dist/scanners/rbac/patterns.d.ts.map +1 -0
- package/dist/scanners/rbac/patterns.js +124 -0
- package/dist/scanners/rbac/patterns.js.map +1 -0
- package/dist/scanners/revocation/index.d.ts +8 -0
- package/dist/scanners/revocation/index.d.ts.map +1 -0
- package/dist/scanners/revocation/index.js +83 -0
- package/dist/scanners/revocation/index.js.map +1 -0
- package/dist/scanners/revocation/index.test.d.ts +5 -0
- package/dist/scanners/revocation/index.test.d.ts.map +1 -0
- package/dist/scanners/revocation/index.test.js +332 -0
- package/dist/scanners/revocation/index.test.js.map +1 -0
- package/dist/scanners/revocation/patterns.d.ts +27 -0
- package/dist/scanners/revocation/patterns.d.ts.map +1 -0
- package/dist/scanners/revocation/patterns.js +109 -0
- package/dist/scanners/revocation/patterns.js.map +1 -0
- package/dist/scanners/sanitization/index.d.ts +8 -0
- package/dist/scanners/sanitization/index.d.ts.map +1 -0
- package/dist/scanners/sanitization/index.js +98 -0
- package/dist/scanners/sanitization/index.js.map +1 -0
- package/dist/scanners/sanitization/index.test.d.ts +5 -0
- package/dist/scanners/sanitization/index.test.d.ts.map +1 -0
- package/dist/scanners/sanitization/index.test.js +370 -0
- package/dist/scanners/sanitization/index.test.js.map +1 -0
- package/dist/scanners/sanitization/patterns.d.ts +27 -0
- package/dist/scanners/sanitization/patterns.d.ts.map +1 -0
- package/dist/scanners/sanitization/patterns.js +117 -0
- package/dist/scanners/sanitization/patterns.js.map +1 -0
- package/dist/training/certificate.d.ts +26 -0
- package/dist/training/certificate.d.ts.map +1 -0
- package/dist/training/certificate.js +92 -0
- package/dist/training/certificate.js.map +1 -0
- package/dist/training/index.d.ts +3 -0
- package/dist/training/index.d.ts.map +1 -0
- package/dist/training/index.js +243 -0
- package/dist/training/index.js.map +1 -0
- package/dist/training/modules.d.ts +13 -0
- package/dist/training/modules.d.ts.map +1 -0
- package/dist/training/modules.js +608 -0
- package/dist/training/modules.js.map +1 -0
- package/dist/training/questions.d.ts +9 -0
- package/dist/training/questions.d.ts.map +1 -0
- package/dist/training/questions.js +505 -0
- package/dist/training/questions.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/npm-audit.d.ts +6 -0
- package/dist/utils/npm-audit.d.ts.map +1 -0
- package/dist/utils/npm-audit.js +95 -0
- package/dist/utils/npm-audit.js.map +1 -0
- package/dist/utils/scan-history.d.ts +59 -0
- package/dist/utils/scan-history.d.ts.map +1 -0
- package/dist/utils/scan-history.js +170 -0
- package/dist/utils/scan-history.js.map +1 -0
- package/package.json +4 -1
- package/templates/baa-verification-letter.md +105 -0
- package/templates/irp.md +545 -0
- package/templates/notice-of-privacy-practices.md +491 -0
- package/templates/physical-safeguards-checklist.md +247 -0
- package/templates/security-officer-designation.md +237 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
const execAsync = promisify(exec);
|
|
4
|
+
export async function runNpmAudit(projectPath) {
|
|
5
|
+
try {
|
|
6
|
+
// Execute npm audit --json in the project directory
|
|
7
|
+
const { stdout } = await execAsync('npm audit --json', {
|
|
8
|
+
cwd: projectPath,
|
|
9
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
10
|
+
timeout: 30000, // 30 second timeout
|
|
11
|
+
});
|
|
12
|
+
// Parse the JSON output
|
|
13
|
+
const auditResult = JSON.parse(stdout);
|
|
14
|
+
// Extract and transform vulnerabilities
|
|
15
|
+
const vulnerabilities = [];
|
|
16
|
+
for (const [packageName, vuln] of Object.entries(auditResult.vulnerabilities || {})) {
|
|
17
|
+
// Extract URL from via if it's an array
|
|
18
|
+
let url;
|
|
19
|
+
let via = '';
|
|
20
|
+
if (Array.isArray(vuln.via)) {
|
|
21
|
+
// via is an array of vulnerability details
|
|
22
|
+
const firstVia = vuln.via[0];
|
|
23
|
+
if (typeof firstVia === 'object' && 'url' in firstVia) {
|
|
24
|
+
url = firstVia.url;
|
|
25
|
+
via = firstVia.title || packageName;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
via = String(firstVia);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
via = String(vuln.via);
|
|
33
|
+
}
|
|
34
|
+
vulnerabilities.push({
|
|
35
|
+
name: packageName,
|
|
36
|
+
severity: vuln.severity,
|
|
37
|
+
via,
|
|
38
|
+
range: vuln.range,
|
|
39
|
+
fixAvailable: vuln.fixAvailable,
|
|
40
|
+
url,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return { vulnerabilities };
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// npm audit exits with non-zero if vulnerabilities are found
|
|
47
|
+
// Check if error contains JSON output
|
|
48
|
+
if (error.stdout) {
|
|
49
|
+
try {
|
|
50
|
+
const auditResult = JSON.parse(error.stdout);
|
|
51
|
+
const vulnerabilities = [];
|
|
52
|
+
for (const [packageName, vuln] of Object.entries(auditResult.vulnerabilities || {})) {
|
|
53
|
+
let url;
|
|
54
|
+
let via = '';
|
|
55
|
+
if (Array.isArray(vuln.via)) {
|
|
56
|
+
const firstVia = vuln.via[0];
|
|
57
|
+
if (typeof firstVia === 'object' && 'url' in firstVia) {
|
|
58
|
+
url = firstVia.url;
|
|
59
|
+
via = firstVia.title || packageName;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
via = String(firstVia);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
via = String(vuln.via);
|
|
67
|
+
}
|
|
68
|
+
vulnerabilities.push({
|
|
69
|
+
name: packageName,
|
|
70
|
+
severity: vuln.severity,
|
|
71
|
+
via,
|
|
72
|
+
range: vuln.range,
|
|
73
|
+
fixAvailable: vuln.fixAvailable,
|
|
74
|
+
url,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return { vulnerabilities };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Failed to parse JSON from error output
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Real error - npm audit failed or not available
|
|
84
|
+
const errorMessage = error.message || 'Unknown error';
|
|
85
|
+
// Common error scenarios
|
|
86
|
+
if (errorMessage.includes('ENOENT') || errorMessage.includes('not found')) {
|
|
87
|
+
return { vulnerabilities: [], error: 'npm command not found. Is Node.js/npm installed?' };
|
|
88
|
+
}
|
|
89
|
+
if (errorMessage.includes('package.json')) {
|
|
90
|
+
return { vulnerabilities: [], error: 'No package.json found in project directory' };
|
|
91
|
+
}
|
|
92
|
+
return { vulnerabilities: [], error: `npm audit failed: ${errorMessage}` };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=npm-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-audit.js","sourceRoot":"","sources":["../../src/utils/npm-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Finding } from '../types.js';
|
|
2
|
+
export interface ScanHistoryEntry {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
date: string;
|
|
5
|
+
complianceScore: number;
|
|
6
|
+
severity: {
|
|
7
|
+
critical: number;
|
|
8
|
+
high: number;
|
|
9
|
+
medium: number;
|
|
10
|
+
low: number;
|
|
11
|
+
};
|
|
12
|
+
failedRuleIds: string[];
|
|
13
|
+
totalFilesScanned: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ScanComparison {
|
|
16
|
+
previousScan?: ScanHistoryEntry;
|
|
17
|
+
scoreChange: number;
|
|
18
|
+
severityChanges: {
|
|
19
|
+
critical: number;
|
|
20
|
+
high: number;
|
|
21
|
+
medium: number;
|
|
22
|
+
low: number;
|
|
23
|
+
};
|
|
24
|
+
newIssues: string[];
|
|
25
|
+
resolvedIssues: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the history directory path for a project
|
|
29
|
+
*/
|
|
30
|
+
export declare function getHistoryDir(projectPath: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Ensure the history directory exists
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureHistoryDir(projectPath: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Generate filename for a scan history entry
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateHistoryFilename(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Save scan results to history
|
|
41
|
+
*/
|
|
42
|
+
export declare function saveScanHistory(projectPath: string, score: number, findings: Finding[], scannedFiles: number): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the most recent scan history entry
|
|
45
|
+
*/
|
|
46
|
+
export declare function getMostRecentScan(projectPath: string): Promise<ScanHistoryEntry | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Get all scan history entries
|
|
49
|
+
*/
|
|
50
|
+
export declare function getAllScans(projectPath: string): Promise<ScanHistoryEntry[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Compare current scan with previous scan
|
|
53
|
+
*/
|
|
54
|
+
export declare function compareScan(currentScore: number, currentFindings: Finding[], previousScan: ScanHistoryEntry | null): ScanComparison;
|
|
55
|
+
/**
|
|
56
|
+
* Format a date string from history filename format
|
|
57
|
+
*/
|
|
58
|
+
export declare function formatHistoryDate(dateStr: string): string;
|
|
59
|
+
//# sourceMappingURL=scan-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-history.d.ts","sourceRoot":"","sources":["../../src/utils/scan-history.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAUhD;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAwB7F;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4BlF;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,OAAO,EAAE,EAC1B,YAAY,EAAE,gBAAgB,GAAG,IAAI,GACpC,cAAc,CAgDhB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUzD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile, mkdir } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
/**
|
|
5
|
+
* Get the history directory path for a project
|
|
6
|
+
*/
|
|
7
|
+
export function getHistoryDir(projectPath) {
|
|
8
|
+
return join(projectPath, '.vlayer', 'history');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Ensure the history directory exists
|
|
12
|
+
*/
|
|
13
|
+
export async function ensureHistoryDir(projectPath) {
|
|
14
|
+
const historyDir = getHistoryDir(projectPath);
|
|
15
|
+
if (!existsSync(historyDir)) {
|
|
16
|
+
await mkdir(historyDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate filename for a scan history entry
|
|
21
|
+
*/
|
|
22
|
+
export function generateHistoryFilename() {
|
|
23
|
+
const now = new Date();
|
|
24
|
+
const yyyy = now.getFullYear();
|
|
25
|
+
const mm = String(now.getMonth() + 1).padStart(2, '0');
|
|
26
|
+
const dd = String(now.getDate()).padStart(2, '0');
|
|
27
|
+
const hh = String(now.getHours()).padStart(2, '0');
|
|
28
|
+
const min = String(now.getMinutes()).padStart(2, '0');
|
|
29
|
+
const ss = String(now.getSeconds()).padStart(2, '0');
|
|
30
|
+
return `scan-${yyyy}-${mm}-${dd}-${hh}${min}${ss}.json`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Save scan results to history
|
|
34
|
+
*/
|
|
35
|
+
export async function saveScanHistory(projectPath, score, findings, scannedFiles) {
|
|
36
|
+
await ensureHistoryDir(projectPath);
|
|
37
|
+
// Filter to active findings (not baseline, not suppressed, not acknowledged)
|
|
38
|
+
const activeFindings = findings.filter(f => !f.isBaseline && !f.suppressed && !f.acknowledged);
|
|
39
|
+
const entry = {
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
date: generateHistoryFilename().replace('scan-', '').replace('.json', ''),
|
|
42
|
+
complianceScore: score,
|
|
43
|
+
severity: {
|
|
44
|
+
critical: activeFindings.filter(f => f.severity === 'critical').length,
|
|
45
|
+
high: activeFindings.filter(f => f.severity === 'high').length,
|
|
46
|
+
medium: activeFindings.filter(f => f.severity === 'medium').length,
|
|
47
|
+
low: activeFindings.filter(f => f.severity === 'low').length,
|
|
48
|
+
},
|
|
49
|
+
failedRuleIds: [...new Set(activeFindings.map(f => f.id))],
|
|
50
|
+
totalFilesScanned: scannedFiles,
|
|
51
|
+
};
|
|
52
|
+
const historyDir = getHistoryDir(projectPath);
|
|
53
|
+
const filename = generateHistoryFilename();
|
|
54
|
+
const filePath = join(historyDir, filename);
|
|
55
|
+
await writeFile(filePath, JSON.stringify(entry, null, 2), 'utf-8');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the most recent scan history entry
|
|
59
|
+
*/
|
|
60
|
+
export async function getMostRecentScan(projectPath) {
|
|
61
|
+
const historyDir = getHistoryDir(projectPath);
|
|
62
|
+
if (!existsSync(historyDir)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const files = await readdir(historyDir);
|
|
67
|
+
const scanFiles = files
|
|
68
|
+
.filter(f => f.startsWith('scan-') && f.endsWith('.json'))
|
|
69
|
+
.sort()
|
|
70
|
+
.reverse(); // Most recent first
|
|
71
|
+
if (scanFiles.length === 0) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const mostRecentFile = scanFiles[0];
|
|
75
|
+
const content = await readFile(join(historyDir, mostRecentFile), 'utf-8');
|
|
76
|
+
return JSON.parse(content);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all scan history entries
|
|
84
|
+
*/
|
|
85
|
+
export async function getAllScans(projectPath) {
|
|
86
|
+
const historyDir = getHistoryDir(projectPath);
|
|
87
|
+
if (!existsSync(historyDir)) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const files = await readdir(historyDir);
|
|
92
|
+
const scanFiles = files
|
|
93
|
+
.filter(f => f.startsWith('scan-') && f.endsWith('.json'))
|
|
94
|
+
.sort()
|
|
95
|
+
.reverse(); // Most recent first
|
|
96
|
+
const scans = [];
|
|
97
|
+
for (const file of scanFiles) {
|
|
98
|
+
try {
|
|
99
|
+
const content = await readFile(join(historyDir, file), 'utf-8');
|
|
100
|
+
scans.push(JSON.parse(content));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Skip corrupted files
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return scans;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Compare current scan with previous scan
|
|
114
|
+
*/
|
|
115
|
+
export function compareScan(currentScore, currentFindings, previousScan) {
|
|
116
|
+
if (!previousScan) {
|
|
117
|
+
return {
|
|
118
|
+
previousScan: undefined,
|
|
119
|
+
scoreChange: 0,
|
|
120
|
+
severityChanges: {
|
|
121
|
+
critical: 0,
|
|
122
|
+
high: 0,
|
|
123
|
+
medium: 0,
|
|
124
|
+
low: 0,
|
|
125
|
+
},
|
|
126
|
+
newIssues: [],
|
|
127
|
+
resolvedIssues: [],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Filter to active findings
|
|
131
|
+
const activeFindings = currentFindings.filter(f => !f.isBaseline && !f.suppressed && !f.acknowledged);
|
|
132
|
+
const currentRuleIds = new Set(activeFindings.map(f => f.id));
|
|
133
|
+
const previousRuleIds = new Set(previousScan.failedRuleIds);
|
|
134
|
+
// Find new and resolved issues
|
|
135
|
+
const newIssues = [...currentRuleIds].filter(id => !previousRuleIds.has(id));
|
|
136
|
+
const resolvedIssues = [...previousRuleIds].filter(id => !currentRuleIds.has(id));
|
|
137
|
+
// Calculate severity changes
|
|
138
|
+
const currentSeverity = {
|
|
139
|
+
critical: activeFindings.filter(f => f.severity === 'critical').length,
|
|
140
|
+
high: activeFindings.filter(f => f.severity === 'high').length,
|
|
141
|
+
medium: activeFindings.filter(f => f.severity === 'medium').length,
|
|
142
|
+
low: activeFindings.filter(f => f.severity === 'low').length,
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
previousScan,
|
|
146
|
+
scoreChange: currentScore - previousScan.complianceScore,
|
|
147
|
+
severityChanges: {
|
|
148
|
+
critical: currentSeverity.critical - previousScan.severity.critical,
|
|
149
|
+
high: currentSeverity.high - previousScan.severity.high,
|
|
150
|
+
medium: currentSeverity.medium - previousScan.severity.medium,
|
|
151
|
+
low: currentSeverity.low - previousScan.severity.low,
|
|
152
|
+
},
|
|
153
|
+
newIssues,
|
|
154
|
+
resolvedIssues,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Format a date string from history filename format
|
|
159
|
+
*/
|
|
160
|
+
export function formatHistoryDate(dateStr) {
|
|
161
|
+
// dateStr format: YYYY-MM-DD-HHmmss
|
|
162
|
+
const year = dateStr.substring(0, 4);
|
|
163
|
+
const month = dateStr.substring(5, 7);
|
|
164
|
+
const day = dateStr.substring(8, 10);
|
|
165
|
+
const hour = dateStr.substring(11, 13);
|
|
166
|
+
const minute = dateStr.substring(13, 15);
|
|
167
|
+
const second = dateStr.substring(15, 17);
|
|
168
|
+
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=scan-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-history.js","sourceRoot":"","sources":["../../src/utils/scan-history.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verification-layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "CLI tool for HIPAA compliance scanning and reporting",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
+
"templates",
|
|
19
20
|
"README.md",
|
|
20
21
|
"LICENSE"
|
|
21
22
|
],
|
|
@@ -74,12 +75,14 @@
|
|
|
74
75
|
},
|
|
75
76
|
"dependencies": {
|
|
76
77
|
"@anthropic-ai/sdk": "^0.73.0",
|
|
78
|
+
"@types/inquirer": "^9.0.9",
|
|
77
79
|
"@types/pdfkit": "^0.17.4",
|
|
78
80
|
"@typescript-eslint/typescript-estree": "^8.54.0",
|
|
79
81
|
"chalk": "^5.3.0",
|
|
80
82
|
"chokidar": "^5.0.0",
|
|
81
83
|
"commander": "^12.0.0",
|
|
82
84
|
"glob": "^10.3.0",
|
|
85
|
+
"inquirer": "^9.3.8",
|
|
83
86
|
"minimatch": "^10.1.1",
|
|
84
87
|
"ora": "^8.0.0",
|
|
85
88
|
"pdfkit": "^0.17.2",
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Annual Business Associate Security Verification
|
|
2
|
+
|
|
3
|
+
**Date:** [DATE]
|
|
4
|
+
|
|
5
|
+
**To:** [COVERED ENTITY NAME]
|
|
6
|
+
**Attention:** [CE CONTACT NAME]
|
|
7
|
+
|
|
8
|
+
**From:** [BA COMPANY NAME]
|
|
9
|
+
**Contact:** [BA CONTACT NAME]
|
|
10
|
+
**Email:** [BA EMAIL]
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Certification Statement
|
|
15
|
+
|
|
16
|
+
This letter certifies that **[BA COMPANY NAME]** has reviewed and verified deployment of the following HIPAA Security Rule technical safeguards as required under our Business Associate Agreement with **[COVERED ENTITY NAME]**.
|
|
17
|
+
|
|
18
|
+
## Technical Safeguards Verification Checklist
|
|
19
|
+
|
|
20
|
+
As required by 45 CFR §164.312, the following technical safeguards have been implemented and verified:
|
|
21
|
+
|
|
22
|
+
### Required Safeguards (45 CFR §164.312)
|
|
23
|
+
|
|
24
|
+
- ☐ **Access Controls** (§164.312(a)(1))
|
|
25
|
+
- Unique user identification
|
|
26
|
+
- Emergency access procedures
|
|
27
|
+
- Automatic logoff
|
|
28
|
+
- Encryption and decryption
|
|
29
|
+
|
|
30
|
+
- ☐ **Audit Controls** (§164.312(b))
|
|
31
|
+
- Hardware, software, and/or procedural mechanisms to record and examine access and activity in systems containing ePHI
|
|
32
|
+
|
|
33
|
+
- ☐ **Integrity** (§164.312(c)(1))
|
|
34
|
+
- Mechanisms to authenticate ePHI and ensure it has not been altered or destroyed in an unauthorized manner
|
|
35
|
+
|
|
36
|
+
- ☐ **Person or Entity Authentication** (§164.312(d))
|
|
37
|
+
- Procedures to verify that a person or entity seeking access to ePHI is the one claimed
|
|
38
|
+
|
|
39
|
+
- ☐ **Transmission Security** (§164.312(e)(1))
|
|
40
|
+
- Technical security measures to guard against unauthorized access to ePHI transmitted over electronic networks
|
|
41
|
+
|
|
42
|
+
### Additional Security Measures Verified
|
|
43
|
+
|
|
44
|
+
- ☐ **Encryption at Rest**
|
|
45
|
+
- ePHI stored in encrypted format using industry-standard algorithms (AES-256 or equivalent)
|
|
46
|
+
|
|
47
|
+
- ☐ **Encryption in Transit**
|
|
48
|
+
- All ePHI transmissions protected with TLS 1.2 or higher
|
|
49
|
+
|
|
50
|
+
- ☐ **Multi-Factor Authentication (MFA)**
|
|
51
|
+
- MFA implemented for all accounts with access to ePHI
|
|
52
|
+
|
|
53
|
+
- ☐ **Role-Based Access Control (RBAC)**
|
|
54
|
+
- Access to ePHI restricted based on job function and minimum necessary principle
|
|
55
|
+
|
|
56
|
+
## Compliance Report Attachment
|
|
57
|
+
|
|
58
|
+
The vlayer HIPAA Compliance Report dated **[DATE]** is attached as **Exhibit A** to this verification letter.
|
|
59
|
+
|
|
60
|
+
**Compliance Score:** [SCORE]/100
|
|
61
|
+
|
|
62
|
+
This automated security assessment confirms the technical implementation of the above safeguards and identifies any gaps requiring remediation.
|
|
63
|
+
|
|
64
|
+
## Security Incident Reporting
|
|
65
|
+
|
|
66
|
+
[BA COMPANY NAME] confirms that:
|
|
67
|
+
- No security incidents affecting ePHI have occurred during this reporting period, OR
|
|
68
|
+
- All security incidents have been reported to [COVERED ENTITY NAME] in accordance with our BAA within the required timeframes
|
|
69
|
+
|
|
70
|
+
## Signatures
|
|
71
|
+
|
|
72
|
+
By signing below, both parties acknowledge receipt and review of this annual security verification.
|
|
73
|
+
|
|
74
|
+
### Business Associate
|
|
75
|
+
|
|
76
|
+
**Signature:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
77
|
+
|
|
78
|
+
**Name:** [BA CONTACT NAME]
|
|
79
|
+
|
|
80
|
+
**Title:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
81
|
+
|
|
82
|
+
**Date:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
83
|
+
|
|
84
|
+
### Covered Entity
|
|
85
|
+
|
|
86
|
+
**Signature:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
87
|
+
|
|
88
|
+
**Name:** [CE CONTACT NAME]
|
|
89
|
+
|
|
90
|
+
**Title:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
91
|
+
|
|
92
|
+
**Date:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Disclaimer
|
|
97
|
+
|
|
98
|
+
This verification does not guarantee absolute security but confirms that technical safeguards have been deployed and verified as of the date above. Security is an ongoing process requiring continuous monitoring, assessment, and improvement. [BA COMPANY NAME] commits to maintaining these safeguards and promptly notifying [COVERED ENTITY NAME] of any material changes or security incidents affecting ePHI.
|
|
99
|
+
|
|
100
|
+
**Retention:** This verification letter and attached compliance report must be retained for a minimum of six (6) years as required by 45 CFR §164.316(b)(2).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
*Generated using vlayer - HIPAA Compliance Scanner*
|
|
105
|
+
*https://github.com/Francosimon53/verification-layer*
|