verification-layer 0.4.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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +345 -0
  3. package/dist/audit/evidence.d.ts +25 -0
  4. package/dist/audit/evidence.d.ts.map +1 -0
  5. package/dist/audit/evidence.js +70 -0
  6. package/dist/audit/evidence.js.map +1 -0
  7. package/dist/audit/index.d.ts +54 -0
  8. package/dist/audit/index.d.ts.map +1 -0
  9. package/dist/audit/index.js +159 -0
  10. package/dist/audit/index.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +199 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/config.d.ts +7 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +77 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/fixer/index.d.ts +11 -0
  20. package/dist/fixer/index.d.ts.map +1 -0
  21. package/dist/fixer/index.js +171 -0
  22. package/dist/fixer/index.js.map +1 -0
  23. package/dist/fixer/strategies.d.ts +3 -0
  24. package/dist/fixer/strategies.d.ts.map +1 -0
  25. package/dist/fixer/strategies.js +199 -0
  26. package/dist/fixer/strategies.js.map +1 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +3 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/reporters/audit-report.d.ts +13 -0
  32. package/dist/reporters/audit-report.d.ts.map +1 -0
  33. package/dist/reporters/audit-report.js +526 -0
  34. package/dist/reporters/audit-report.js.map +1 -0
  35. package/dist/reporters/fix-report.d.ts +3 -0
  36. package/dist/reporters/fix-report.d.ts.map +1 -0
  37. package/dist/reporters/fix-report.js +70 -0
  38. package/dist/reporters/fix-report.js.map +1 -0
  39. package/dist/reporters/index.d.ts +3 -0
  40. package/dist/reporters/index.d.ts.map +1 -0
  41. package/dist/reporters/index.js +425 -0
  42. package/dist/reporters/index.js.map +1 -0
  43. package/dist/reporters/remediation-guides.d.ts +25 -0
  44. package/dist/reporters/remediation-guides.d.ts.map +1 -0
  45. package/dist/reporters/remediation-guides.js +636 -0
  46. package/dist/reporters/remediation-guides.js.map +1 -0
  47. package/dist/scan.d.ts +3 -0
  48. package/dist/scan.d.ts.map +1 -0
  49. package/dist/scan.js +96 -0
  50. package/dist/scan.js.map +1 -0
  51. package/dist/scanners/access/index.d.ts +3 -0
  52. package/dist/scanners/access/index.d.ts.map +1 -0
  53. package/dist/scanners/access/index.js +102 -0
  54. package/dist/scanners/access/index.js.map +1 -0
  55. package/dist/scanners/audit/index.d.ts +3 -0
  56. package/dist/scanners/audit/index.d.ts.map +1 -0
  57. package/dist/scanners/audit/index.js +94 -0
  58. package/dist/scanners/audit/index.js.map +1 -0
  59. package/dist/scanners/encryption/index.d.ts +3 -0
  60. package/dist/scanners/encryption/index.d.ts.map +1 -0
  61. package/dist/scanners/encryption/index.js +86 -0
  62. package/dist/scanners/encryption/index.js.map +1 -0
  63. package/dist/scanners/phi/index.d.ts +3 -0
  64. package/dist/scanners/phi/index.d.ts.map +1 -0
  65. package/dist/scanners/phi/index.js +47 -0
  66. package/dist/scanners/phi/index.js.map +1 -0
  67. package/dist/scanners/phi/patterns.d.ts +13 -0
  68. package/dist/scanners/phi/patterns.d.ts.map +1 -0
  69. package/dist/scanners/phi/patterns.js +242 -0
  70. package/dist/scanners/phi/patterns.js.map +1 -0
  71. package/dist/scanners/retention/index.d.ts +3 -0
  72. package/dist/scanners/retention/index.d.ts.map +1 -0
  73. package/dist/scanners/retention/index.js +102 -0
  74. package/dist/scanners/retention/index.js.map +1 -0
  75. package/dist/scanners/security/index.d.ts +3 -0
  76. package/dist/scanners/security/index.d.ts.map +1 -0
  77. package/dist/scanners/security/index.js +280 -0
  78. package/dist/scanners/security/index.js.map +1 -0
  79. package/dist/stack-detector/index.d.ts +26 -0
  80. package/dist/stack-detector/index.d.ts.map +1 -0
  81. package/dist/stack-detector/index.js +317 -0
  82. package/dist/stack-detector/index.js.map +1 -0
  83. package/dist/stack-detector/stack-guides.d.ts +16 -0
  84. package/dist/stack-detector/stack-guides.d.ts.map +1 -0
  85. package/dist/stack-detector/stack-guides.js +772 -0
  86. package/dist/stack-detector/stack-guides.js.map +1 -0
  87. package/dist/types.d.ts +143 -0
  88. package/dist/types.d.ts.map +1 -0
  89. package/dist/types.js +2 -0
  90. package/dist/types.js.map +1 -0
  91. package/dist/utils/context.d.ts +3 -0
  92. package/dist/utils/context.d.ts.map +1 -0
  93. package/dist/utils/context.js +14 -0
  94. package/dist/utils/context.js.map +1 -0
  95. package/package.json +76 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon Franco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # vlayer - HIPAA Compliance Scanner
2
+
3
+ **Automated security scanning for healthcare applications.** Detect PHI exposure, fix vulnerabilities, and generate audit-ready compliance reports.
4
+
5
+ [![CI](https://github.com/Francosimon53/verification-layer/actions/workflows/ci.yml/badge.svg)](https://github.com/Francosimon53/verification-layer/actions/workflows/ci.yml)
6
+ [![npm version](https://img.shields.io/npm/v/verification-layer)](https://www.npmjs.com/package/verification-layer)
7
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
+ [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen)](package.json)
9
+
10
+ ---
11
+
12
+ ## What is vlayer?
13
+
14
+ vlayer is a CLI tool that scans your codebase for HIPAA compliance issues. It's designed for healthcare startups and developers building applications that handle Protected Health Information (PHI).
15
+
16
+ **Key capabilities:**
17
+ - Scan for 50+ security vulnerabilities and PHI exposure patterns
18
+ - Auto-fix common issues with one command
19
+ - Generate professional audit reports (HTML, PDF, JSON)
20
+ - Detect your tech stack and provide tailored recommendations
21
+ - Create cryptographic audit trails for compliance documentation
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ```bash
28
+ # Install
29
+ npm install
30
+ npm run build
31
+
32
+ # Scan a project
33
+ node dist/cli.js scan /path/to/your/project
34
+
35
+ # Generate HTML report
36
+ node dist/cli.js scan /path/to/project -f html -o report.html
37
+
38
+ # Auto-fix issues
39
+ node dist/cli.js scan /path/to/project --fix
40
+
41
+ # Generate audit PDF
42
+ node dist/cli.js audit /path/to/project --generate-report
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Features
48
+
49
+ ### 1. Vulnerability Detection
50
+
51
+ Scans for **50+ security patterns** across 5 HIPAA compliance categories:
52
+
53
+ | Category | What it detects |
54
+ |----------|-----------------|
55
+ | **PHI Exposure** | SSN/MRN in code, PHI in logs, localStorage, URLs |
56
+ | **Encryption** | Weak crypto (MD5, DES), disabled SSL/TLS, HTTP URLs |
57
+ | **Access Control** | SQL injection, XSS, CORS wildcards, hardcoded credentials |
58
+ | **Audit Logging** | Missing logging framework, unlogged PHI operations |
59
+ | **Data Retention** | Bulk deletes without audit, missing retention policies |
60
+
61
+ <details>
62
+ <summary><strong>View all detection patterns</strong></summary>
63
+
64
+ **PHI Exposure (18 patterns)**
65
+ - Social Security Numbers (XXX-XX-XXXX)
66
+ - Medical Record Numbers (MRN patterns)
67
+ - Date of Birth handling
68
+ - Diagnosis codes (ICD-10)
69
+ - PHI in console.log statements
70
+ - PHI in localStorage/sessionStorage
71
+ - Patient data in URLs
72
+ - Unencrypted patient contact info
73
+
74
+ **Security Vulnerabilities (20+ patterns)**
75
+ - Hardcoded passwords and secrets
76
+ - API keys (generic, Stripe, AWS)
77
+ - Database URIs with credentials
78
+ - SQL injection (template literals & concatenation)
79
+ - innerHTML without sanitization
80
+ - eval() and Function constructor
81
+ - dangerouslySetInnerHTML in React
82
+
83
+ **Infrastructure Issues**
84
+ - HTTP URLs for PHI transmission
85
+ - Disabled SSL/TLS verification
86
+ - CORS wildcard origins
87
+ - Sessions without expiration
88
+ - Missing authentication checks
89
+
90
+ </details>
91
+
92
+ ---
93
+
94
+ ### 2. Auto-Fix (`--fix`)
95
+
96
+ Automatically remediate common vulnerabilities:
97
+
98
+ ```bash
99
+ node dist/cli.js scan ./my-app --fix
100
+ ```
101
+
102
+ | Issue | Auto-Fix Applied |
103
+ |-------|------------------|
104
+ | SQL injection | Convert to parameterized query `query('SELECT * FROM users WHERE id = ?', [id])` |
105
+ | Hardcoded password | Replace with `process.env.PASSWORD` |
106
+ | Hardcoded API key | Replace with `process.env.API_KEY` |
107
+ | HTTP URL | Upgrade to HTTPS |
108
+ | innerHTML | Replace with `textContent` |
109
+ | PHI in console.log | Comment out with review marker |
110
+
111
+ **Example output:**
112
+ ```
113
+ ✔ Scan complete. Found 29 issues.
114
+ ✔ Applied 8 automatic fixes.
115
+
116
+ Changes by file:
117
+ src/api/users.ts
118
+ Line 45: SQL injection → parameterized query
119
+ Line 89: Hardcoded password → process.env.DB_PASSWORD
120
+ src/utils/logger.ts
121
+ Line 12: PHI in console.log → commented out
122
+ ```
123
+
124
+ ---
125
+
126
+ ### 3. Stack Detection
127
+
128
+ vlayer automatically detects your tech stack and provides **personalized code examples**:
129
+
130
+ ```
131
+ Stack detected:
132
+ Framework: Next.js
133
+ Database: Supabase
134
+ Auth: Supabase Auth
135
+ ```
136
+
137
+ **Supported technologies:**
138
+
139
+ | Type | Detected |
140
+ |------|----------|
141
+ | Frameworks | Next.js, React, Vue, Nuxt, Angular, Express, Fastify, NestJS |
142
+ | Databases | Supabase, Firebase, PostgreSQL, MySQL, MongoDB, Prisma, Drizzle |
143
+ | Auth | NextAuth, Supabase Auth, Firebase Auth, Auth0, Clerk, Passport |
144
+
145
+ **Stack-specific recommendations include:**
146
+
147
+ - **Next.js + Supabase**: Server Components for PHI, Row Level Security (RLS), middleware protection
148
+ - **Express + PostgreSQL**: express-session with Redis, parameterized queries
149
+ - **React + Firebase**: Firestore Security Rules, Admin SDK for PHI
150
+
151
+ ---
152
+
153
+ ### 4. Remediation Guides
154
+
155
+ Each finding includes a detailed remediation guide with:
156
+
157
+ - **HIPAA Impact**: Why this matters for compliance
158
+ - **Multiple fix options**: Different approaches with trade-offs
159
+ - **Code examples**: Copy-paste ready solutions
160
+ - **Documentation links**: Official resources
161
+
162
+ The guides are **personalized to your stack** - if you're using Supabase, you'll see Supabase-specific code examples, not generic SQL.
163
+
164
+ ---
165
+
166
+ ### 5. Audit Trail & PDF Reports
167
+
168
+ Generate compliance documentation with cryptographic verification:
169
+
170
+ ```bash
171
+ # Run scan with fixes (creates audit trail)
172
+ node dist/cli.js scan ./my-app --fix
173
+
174
+ # Generate PDF report
175
+ node dist/cli.js audit ./my-app --generate-report --org "Healthcare Inc" --auditor "Jane Smith"
176
+ ```
177
+
178
+ **Audit trail includes:**
179
+
180
+ | For Auto-Fixed Issues | For Manual Review Items |
181
+ |-----------------------|-------------------------|
182
+ | Code before & after | Status: "Pending human review" |
183
+ | SHA256 file hashes | Assigned responsible party |
184
+ | Timestamp of change | Suggested deadline by severity |
185
+ | HIPAA reference resolved | Full finding details |
186
+
187
+ **PDF Report sections:**
188
+ 1. Cover Page - Project info, scan statistics
189
+ 2. Executive Summary - Remediation rate, risk breakdown
190
+ 3. Fix Evidence - Cryptographic proof of each change
191
+ 4. Manual Reviews - Pending items with deadlines
192
+ 5. Verification Page - Report hash, signature fields
193
+
194
+ ---
195
+
196
+ ## Report Examples
197
+
198
+ ### HTML Report
199
+
200
+ The HTML report includes:
201
+ - Summary cards with severity counts
202
+ - Stack detection section with tailored recommendations
203
+ - Each finding with code context and line highlighting
204
+ - Expandable remediation guides with code examples
205
+ - Auto-fixable badge on issues that can be fixed automatically
206
+
207
+ ### JSON Report
208
+
209
+ Machine-readable format for CI/CD integration:
210
+
211
+ ```json
212
+ {
213
+ "summary": {
214
+ "total": 29,
215
+ "critical": 8,
216
+ "high": 12,
217
+ "medium": 6,
218
+ "low": 3
219
+ },
220
+ "stack": {
221
+ "framework": "nextjs",
222
+ "database": "supabase",
223
+ "auth": "supabase-auth"
224
+ },
225
+ "findings": [...]
226
+ }
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Configuration
232
+
233
+ Create `.vlayerrc.json` in your project root:
234
+
235
+ ```json
236
+ {
237
+ "exclude": ["**/*.test.ts", "**/__mocks__/**"],
238
+ "ignorePaths": ["sample-data", "fixtures"],
239
+ "safeHttpDomains": ["my-internal-cdn.com"],
240
+ "contextLines": 3,
241
+ "categories": ["phi-exposure", "encryption", "access-control"]
242
+ }
243
+ ```
244
+
245
+ | Option | Description | Default |
246
+ |--------|-------------|---------|
247
+ | `exclude` | Glob patterns to skip | `[]` |
248
+ | `ignorePaths` | Path substrings to ignore | `[]` |
249
+ | `safeHttpDomains` | HTTP domains to allow (CDNs) | Built-in list |
250
+ | `contextLines` | Lines of context in reports | `2` |
251
+ | `categories` | Categories to scan | All |
252
+
253
+ ---
254
+
255
+ ## CLI Reference
256
+
257
+ ```bash
258
+ # Basic scan
259
+ vlayer scan <path>
260
+
261
+ # Scan options
262
+ vlayer scan <path> -f html -o report.html # HTML report
263
+ vlayer scan <path> -f markdown -o report.md # Markdown report
264
+ vlayer scan <path> -c phi-exposure encryption # Specific categories
265
+ vlayer scan <path> --fix # Auto-fix issues
266
+
267
+ # Audit commands
268
+ vlayer audit <path> --summary # View audit summary
269
+ vlayer audit <path> --generate-report # Generate PDF
270
+ vlayer audit <path> --generate-report --text # Generate text instead
271
+ vlayer audit <path> --generate-report --org "Company" --auditor "Name"
272
+ ```
273
+
274
+ **Exit codes:**
275
+ - `0` - No critical issues
276
+ - `1` - Critical issues found (useful for CI/CD)
277
+
278
+ ---
279
+
280
+ ## HIPAA References
281
+
282
+ Each finding maps to specific HIPAA regulations:
283
+
284
+ | Reference | Requirement |
285
+ |-----------|-------------|
286
+ | §164.502, §164.514 | PHI disclosure and de-identification |
287
+ | §164.312(a)(1) | Access control mechanisms |
288
+ | §164.312(a)(2)(iv) | Encryption and decryption |
289
+ | §164.312(b) | Audit controls |
290
+ | §164.312(d) | Person or entity authentication |
291
+ | §164.312(e)(1) | Transmission security |
292
+ | §164.530(j) | Documentation retention (6 years) |
293
+
294
+ ---
295
+
296
+ ## Roadmap
297
+
298
+ ### Coming Soon
299
+ - [x] GitHub Action for CI/CD integration
300
+ - [ ] VS Code extension with inline warnings
301
+ - [ ] Slack/Teams notifications for new findings
302
+ - [ ] Custom rule definitions (YAML)
303
+
304
+ ### Planned
305
+ - [ ] HITRUST CSF mapping
306
+ - [ ] SOC 2 compliance checks
307
+ - [ ] AWS/GCP/Azure infrastructure scanning
308
+ - [ ] Team dashboard with trend tracking
309
+ - [ ] Jira/Linear integration for issue tracking
310
+
311
+ ### Future
312
+ - [ ] AI-powered fix suggestions
313
+ - [ ] Dependency vulnerability scanning
314
+ - [ ] Runtime PHI detection agent
315
+ - [ ] Compliance certification workflows
316
+
317
+ ---
318
+
319
+ ## Contributing
320
+
321
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
322
+
323
+ ```bash
324
+ # Development
325
+ npm install
326
+ npm run dev # Watch mode
327
+ npm run test # Run tests
328
+ npm run lint # Lint code
329
+ ```
330
+
331
+ ---
332
+
333
+ ## License
334
+
335
+ MIT License - see [LICENSE](LICENSE) for details.
336
+
337
+ ---
338
+
339
+ <p align="center">
340
+ Built for healthcare developers who take compliance seriously.
341
+ <br>
342
+ <a href="https://github.com/Francosimon53/verification-layer/issues">Report Bug</a>
343
+ ·
344
+ <a href="https://github.com/Francosimon53/verification-layer/issues">Request Feature</a>
345
+ </p>
@@ -0,0 +1,25 @@
1
+ import type { AuditEvidence, CodeSnapshot, Finding, FixType } from '../types.js';
2
+ /**
3
+ * Generate SHA256 hash of file content
4
+ */
5
+ export declare function hashContent(content: string): string;
6
+ /**
7
+ * Extract code snapshot with context lines
8
+ */
9
+ export declare function extractCodeSnapshot(lines: string[], lineNumber: number, contextSize?: number): CodeSnapshot;
10
+ /**
11
+ * Create audit evidence for a fix
12
+ */
13
+ export declare function createEvidence(finding: Finding, filePath: string, contentBefore: string, contentAfter: string, lineNumber: number, fixType: FixType): Promise<AuditEvidence>;
14
+ /**
15
+ * Generate a hash for the entire audit trail (for verification)
16
+ */
17
+ export declare function generateAuditTrailHash(evidence: AuditEvidence[]): string;
18
+ /**
19
+ * Read file and compute hash
20
+ */
21
+ export declare function getFileWithHash(filePath: string): Promise<{
22
+ content: string;
23
+ hash: string;
24
+ }>;
25
+ //# sourceMappingURL=evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/audit/evidence.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAe,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE9F;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,GAAE,MAAU,GACtB,YAAY,CAkBd;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CAKxE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAMlG"}
@@ -0,0 +1,70 @@
1
+ import { createHash, randomUUID } from 'crypto';
2
+ import { readFile } from 'fs/promises';
3
+ /**
4
+ * Generate SHA256 hash of file content
5
+ */
6
+ export function hashContent(content) {
7
+ return createHash('sha256').update(content, 'utf8').digest('hex');
8
+ }
9
+ /**
10
+ * Extract code snapshot with context lines
11
+ */
12
+ export function extractCodeSnapshot(lines, lineNumber, contextSize = 3) {
13
+ const context = [];
14
+ const start = Math.max(0, lineNumber - contextSize);
15
+ const end = Math.min(lines.length - 1, lineNumber + contextSize);
16
+ for (let i = start; i <= end; i++) {
17
+ context.push({
18
+ lineNumber: i + 1,
19
+ content: lines[i] || '',
20
+ isMatch: i === lineNumber,
21
+ });
22
+ }
23
+ return {
24
+ content: lines[lineNumber] || '',
25
+ context,
26
+ lineNumber: lineNumber + 1,
27
+ };
28
+ }
29
+ /**
30
+ * Create audit evidence for a fix
31
+ */
32
+ export async function createEvidence(finding, filePath, contentBefore, contentAfter, lineNumber, fixType) {
33
+ const linesBefore = contentBefore.split('\n');
34
+ const linesAfter = contentAfter.split('\n');
35
+ const before = extractCodeSnapshot(linesBefore, lineNumber);
36
+ const after = extractCodeSnapshot(linesAfter, lineNumber);
37
+ return {
38
+ id: randomUUID(),
39
+ findingId: finding.id,
40
+ timestamp: new Date().toISOString(),
41
+ filePath,
42
+ before,
43
+ after,
44
+ fileHashBefore: hashContent(contentBefore),
45
+ fileHashAfter: hashContent(contentAfter),
46
+ hipaaReference: finding.hipaaReference || 'General HIPAA Security Rule',
47
+ fixType,
48
+ description: `Auto-fixed: ${finding.title}`,
49
+ };
50
+ }
51
+ /**
52
+ * Generate a hash for the entire audit trail (for verification)
53
+ */
54
+ export function generateAuditTrailHash(evidence) {
55
+ const evidenceStr = evidence
56
+ .map(e => `${e.id}|${e.fileHashBefore}|${e.fileHashAfter}|${e.timestamp}`)
57
+ .join('\n');
58
+ return hashContent(evidenceStr);
59
+ }
60
+ /**
61
+ * Read file and compute hash
62
+ */
63
+ export async function getFileWithHash(filePath) {
64
+ const content = await readFile(filePath, 'utf-8');
65
+ return {
66
+ content,
67
+ hash: hashContent(content),
68
+ };
69
+ }
70
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/audit/evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { AuditTrail, AuditEvidence, ManualReviewItem, Finding, ManualReviewStatus } from '../types.js';
2
+ /**
3
+ * Create a new audit trail
4
+ */
5
+ export declare function createAuditTrail(projectPath: string): AuditTrail;
6
+ /**
7
+ * Add evidence to audit trail
8
+ */
9
+ export declare function addEvidence(trail: AuditTrail, evidence: AuditEvidence): void;
10
+ /**
11
+ * Create a manual review item for findings that cannot be auto-fixed
12
+ */
13
+ export declare function createManualReview(finding: Finding): ManualReviewItem;
14
+ /**
15
+ * Add manual review items for non-fixable findings
16
+ */
17
+ export declare function addManualReviews(trail: AuditTrail, findings: Finding[]): void;
18
+ /**
19
+ * Update scan statistics
20
+ */
21
+ export declare function updateScanStats(trail: AuditTrail, totalFindings: number, scannedFiles: number, scanDuration: number): void;
22
+ /**
23
+ * Finalize audit trail with hash
24
+ */
25
+ export declare function finalizeAuditTrail(trail: AuditTrail): void;
26
+ /**
27
+ * Save audit trail to file
28
+ */
29
+ export declare function saveAuditTrail(trail: AuditTrail, projectPath: string): Promise<string>;
30
+ /**
31
+ * Load existing audit trail
32
+ */
33
+ export declare function loadAuditTrail(projectPath: string): Promise<AuditTrail | null>;
34
+ /**
35
+ * Get audit trail file path
36
+ */
37
+ export declare function getAuditTrailPath(projectPath: string): string;
38
+ /**
39
+ * Update manual review status
40
+ */
41
+ export declare function updateManualReviewStatus(trail: AuditTrail, reviewId: string, status: ManualReviewStatus, assignedTo?: string, notes?: string): boolean;
42
+ /**
43
+ * Get summary statistics from audit trail
44
+ */
45
+ export declare function getAuditSummary(trail: AuditTrail): {
46
+ totalFindings: number;
47
+ autoFixed: number;
48
+ pendingManualReview: number;
49
+ reviewsByStatus: Record<string, number>;
50
+ reviewsBySeverity: Record<string, number>;
51
+ overdueCount: number;
52
+ reportHash: string | undefined;
53
+ };
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAMrB;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAchE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAG5E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CA4BrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAO7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EACjB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,IAAI,CAIN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAE1D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5F;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CASpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAUT;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU;;;;;;;;EAwBhD"}
@@ -0,0 +1,159 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { readFile, writeFile, mkdir } from 'fs/promises';
3
+ import { basename, join } from 'path';
4
+ import { generateAuditTrailHash } from './evidence.js';
5
+ const AUDIT_DIR = '.vlayer';
6
+ const AUDIT_FILE = 'audit-trail.json';
7
+ /**
8
+ * Create a new audit trail
9
+ */
10
+ export function createAuditTrail(projectPath) {
11
+ return {
12
+ id: randomUUID(),
13
+ createdAt: new Date().toISOString(),
14
+ projectPath,
15
+ projectName: basename(projectPath),
16
+ scanDuration: 0,
17
+ scannedFiles: 0,
18
+ totalFindings: 0,
19
+ autoFixedCount: 0,
20
+ manualReviewCount: 0,
21
+ evidence: [],
22
+ manualReviews: [],
23
+ };
24
+ }
25
+ /**
26
+ * Add evidence to audit trail
27
+ */
28
+ export function addEvidence(trail, evidence) {
29
+ trail.evidence.push(evidence);
30
+ trail.autoFixedCount = trail.evidence.length;
31
+ }
32
+ /**
33
+ * Create a manual review item for findings that cannot be auto-fixed
34
+ */
35
+ export function createManualReview(finding) {
36
+ const now = new Date();
37
+ const suggestedDeadline = new Date(now);
38
+ // Set deadline based on severity
39
+ switch (finding.severity) {
40
+ case 'critical':
41
+ suggestedDeadline.setDate(now.getDate() + 7); // 1 week
42
+ break;
43
+ case 'high':
44
+ suggestedDeadline.setDate(now.getDate() + 14); // 2 weeks
45
+ break;
46
+ case 'medium':
47
+ suggestedDeadline.setDate(now.getDate() + 30); // 1 month
48
+ break;
49
+ default:
50
+ suggestedDeadline.setDate(now.getDate() + 60); // 2 months
51
+ }
52
+ return {
53
+ id: randomUUID(),
54
+ findingId: finding.id,
55
+ finding,
56
+ status: 'pending_review',
57
+ suggestedDeadline: suggestedDeadline.toISOString(),
58
+ createdAt: now.toISOString(),
59
+ updatedAt: now.toISOString(),
60
+ };
61
+ }
62
+ /**
63
+ * Add manual review items for non-fixable findings
64
+ */
65
+ export function addManualReviews(trail, findings) {
66
+ const nonFixableFindings = findings.filter(f => !f.fixType);
67
+ for (const finding of nonFixableFindings) {
68
+ const review = createManualReview(finding);
69
+ trail.manualReviews.push(review);
70
+ }
71
+ trail.manualReviewCount = trail.manualReviews.length;
72
+ }
73
+ /**
74
+ * Update scan statistics
75
+ */
76
+ export function updateScanStats(trail, totalFindings, scannedFiles, scanDuration) {
77
+ trail.totalFindings = totalFindings;
78
+ trail.scannedFiles = scannedFiles;
79
+ trail.scanDuration = scanDuration;
80
+ }
81
+ /**
82
+ * Finalize audit trail with hash
83
+ */
84
+ export function finalizeAuditTrail(trail) {
85
+ trail.reportHash = generateAuditTrailHash(trail.evidence);
86
+ }
87
+ /**
88
+ * Save audit trail to file
89
+ */
90
+ export async function saveAuditTrail(trail, projectPath) {
91
+ const auditDir = join(projectPath, AUDIT_DIR);
92
+ const auditPath = join(auditDir, AUDIT_FILE);
93
+ try {
94
+ await mkdir(auditDir, { recursive: true });
95
+ }
96
+ catch {
97
+ // Directory may already exist
98
+ }
99
+ await writeFile(auditPath, JSON.stringify(trail, null, 2), 'utf-8');
100
+ return auditPath;
101
+ }
102
+ /**
103
+ * Load existing audit trail
104
+ */
105
+ export async function loadAuditTrail(projectPath) {
106
+ const auditPath = join(projectPath, AUDIT_DIR, AUDIT_FILE);
107
+ try {
108
+ const content = await readFile(auditPath, 'utf-8');
109
+ return JSON.parse(content);
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ /**
116
+ * Get audit trail file path
117
+ */
118
+ export function getAuditTrailPath(projectPath) {
119
+ return join(projectPath, AUDIT_DIR, AUDIT_FILE);
120
+ }
121
+ /**
122
+ * Update manual review status
123
+ */
124
+ export function updateManualReviewStatus(trail, reviewId, status, assignedTo, notes) {
125
+ const review = trail.manualReviews.find(r => r.id === reviewId);
126
+ if (!review)
127
+ return false;
128
+ review.status = status;
129
+ review.updatedAt = new Date().toISOString();
130
+ if (assignedTo)
131
+ review.assignedTo = assignedTo;
132
+ if (notes)
133
+ review.notes = notes;
134
+ return true;
135
+ }
136
+ /**
137
+ * Get summary statistics from audit trail
138
+ */
139
+ export function getAuditSummary(trail) {
140
+ const reviewsByStatus = trail.manualReviews.reduce((acc, review) => {
141
+ acc[review.status] = (acc[review.status] || 0) + 1;
142
+ return acc;
143
+ }, {});
144
+ const reviewsBySeverity = trail.manualReviews.reduce((acc, review) => {
145
+ acc[review.finding.severity] = (acc[review.finding.severity] || 0) + 1;
146
+ return acc;
147
+ }, {});
148
+ const overdueReviews = trail.manualReviews.filter(r => new Date(r.suggestedDeadline) < new Date() && r.status === 'pending_review');
149
+ return {
150
+ totalFindings: trail.totalFindings,
151
+ autoFixed: trail.autoFixedCount,
152
+ pendingManualReview: trail.manualReviewCount,
153
+ reviewsByStatus,
154
+ reviewsBySeverity,
155
+ overdueCount: overdueReviews.length,
156
+ reportHash: trail.reportHash,
157
+ };
158
+ }
159
+ //# sourceMappingURL=index.js.map