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.
Files changed (180) hide show
  1. package/README.md +251 -615
  2. package/dist/cli.js +542 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/marketplace/index.d.ts +8 -0
  5. package/dist/marketplace/index.d.ts.map +1 -0
  6. package/dist/marketplace/index.js +7 -0
  7. package/dist/marketplace/index.js.map +1 -0
  8. package/dist/marketplace/installer.d.ts +62 -0
  9. package/dist/marketplace/installer.d.ts.map +1 -0
  10. package/dist/marketplace/installer.js +254 -0
  11. package/dist/marketplace/installer.js.map +1 -0
  12. package/dist/marketplace/registry.d.ts +52 -0
  13. package/dist/marketplace/registry.d.ts.map +1 -0
  14. package/dist/marketplace/registry.js +759 -0
  15. package/dist/marketplace/registry.js.map +1 -0
  16. package/dist/marketplace/types.d.ts +123 -0
  17. package/dist/marketplace/types.d.ts.map +1 -0
  18. package/dist/marketplace/types.js +6 -0
  19. package/dist/marketplace/types.js.map +1 -0
  20. package/dist/reporters/audit-report.d.ts.map +1 -1
  21. package/dist/reporters/audit-report.js +180 -0
  22. package/dist/reporters/audit-report.js.map +1 -1
  23. package/dist/reporters/index.d.ts.map +1 -1
  24. package/dist/reporters/index.js +2612 -5
  25. package/dist/reporters/index.js.map +1 -1
  26. package/dist/scan.d.ts.map +1 -1
  27. package/dist/scan.js +15 -1
  28. package/dist/scan.js.map +1 -1
  29. package/dist/scanners/api-security/index.d.ts +7 -0
  30. package/dist/scanners/api-security/index.d.ts.map +1 -0
  31. package/dist/scanners/api-security/index.js +139 -0
  32. package/dist/scanners/api-security/index.js.map +1 -0
  33. package/dist/scanners/api-security/index.test.d.ts +5 -0
  34. package/dist/scanners/api-security/index.test.d.ts.map +1 -0
  35. package/dist/scanners/api-security/index.test.js +360 -0
  36. package/dist/scanners/api-security/index.test.js.map +1 -0
  37. package/dist/scanners/api-security/patterns.d.ts +32 -0
  38. package/dist/scanners/api-security/patterns.d.ts.map +1 -0
  39. package/dist/scanners/api-security/patterns.js +159 -0
  40. package/dist/scanners/api-security/patterns.js.map +1 -0
  41. package/dist/scanners/authentication/index.d.ts +7 -0
  42. package/dist/scanners/authentication/index.d.ts.map +1 -0
  43. package/dist/scanners/authentication/index.js +107 -0
  44. package/dist/scanners/authentication/index.js.map +1 -0
  45. package/dist/scanners/authentication/index.test.d.ts +5 -0
  46. package/dist/scanners/authentication/index.test.d.ts.map +1 -0
  47. package/dist/scanners/authentication/index.test.js +379 -0
  48. package/dist/scanners/authentication/index.test.js.map +1 -0
  49. package/dist/scanners/authentication/patterns.d.ts +32 -0
  50. package/dist/scanners/authentication/patterns.d.ts.map +1 -0
  51. package/dist/scanners/authentication/patterns.js +133 -0
  52. package/dist/scanners/authentication/patterns.js.map +1 -0
  53. package/dist/scanners/configuration/index.d.ts +8 -0
  54. package/dist/scanners/configuration/index.d.ts.map +1 -0
  55. package/dist/scanners/configuration/index.js +87 -0
  56. package/dist/scanners/configuration/index.js.map +1 -0
  57. package/dist/scanners/configuration/index.test.d.ts +5 -0
  58. package/dist/scanners/configuration/index.test.d.ts.map +1 -0
  59. package/dist/scanners/configuration/index.test.js +344 -0
  60. package/dist/scanners/configuration/index.test.js.map +1 -0
  61. package/dist/scanners/configuration/patterns.d.ts +32 -0
  62. package/dist/scanners/configuration/patterns.d.ts.map +1 -0
  63. package/dist/scanners/configuration/patterns.js +146 -0
  64. package/dist/scanners/configuration/patterns.js.map +1 -0
  65. package/dist/scanners/credentials/index.d.ts +7 -0
  66. package/dist/scanners/credentials/index.d.ts.map +1 -0
  67. package/dist/scanners/credentials/index.js +129 -0
  68. package/dist/scanners/credentials/index.js.map +1 -0
  69. package/dist/scanners/credentials/index.test.d.ts +5 -0
  70. package/dist/scanners/credentials/index.test.d.ts.map +1 -0
  71. package/dist/scanners/credentials/index.test.js +395 -0
  72. package/dist/scanners/credentials/index.test.js.map +1 -0
  73. package/dist/scanners/credentials/patterns.d.ts +32 -0
  74. package/dist/scanners/credentials/patterns.d.ts.map +1 -0
  75. package/dist/scanners/credentials/patterns.js +140 -0
  76. package/dist/scanners/credentials/patterns.js.map +1 -0
  77. package/dist/scanners/errors/index.d.ts +8 -0
  78. package/dist/scanners/errors/index.d.ts.map +1 -0
  79. package/dist/scanners/errors/index.js +78 -0
  80. package/dist/scanners/errors/index.js.map +1 -0
  81. package/dist/scanners/errors/index.test.d.ts +5 -0
  82. package/dist/scanners/errors/index.test.d.ts.map +1 -0
  83. package/dist/scanners/errors/index.test.js +330 -0
  84. package/dist/scanners/errors/index.test.js.map +1 -0
  85. package/dist/scanners/errors/patterns.d.ts +27 -0
  86. package/dist/scanners/errors/patterns.d.ts.map +1 -0
  87. package/dist/scanners/errors/patterns.js +97 -0
  88. package/dist/scanners/errors/patterns.js.map +1 -0
  89. package/dist/scanners/hipaa2026/index.d.ts +8 -0
  90. package/dist/scanners/hipaa2026/index.d.ts.map +1 -0
  91. package/dist/scanners/hipaa2026/index.js +345 -0
  92. package/dist/scanners/hipaa2026/index.js.map +1 -0
  93. package/dist/scanners/hipaa2026/index.test.d.ts +5 -0
  94. package/dist/scanners/hipaa2026/index.test.d.ts.map +1 -0
  95. package/dist/scanners/hipaa2026/index.test.js +332 -0
  96. package/dist/scanners/hipaa2026/index.test.js.map +1 -0
  97. package/dist/scanners/hipaa2026/patterns.d.ts +57 -0
  98. package/dist/scanners/hipaa2026/patterns.d.ts.map +1 -0
  99. package/dist/scanners/hipaa2026/patterns.js +268 -0
  100. package/dist/scanners/hipaa2026/patterns.js.map +1 -0
  101. package/dist/scanners/operational/index.d.ts +7 -0
  102. package/dist/scanners/operational/index.d.ts.map +1 -0
  103. package/dist/scanners/operational/index.js +171 -0
  104. package/dist/scanners/operational/index.js.map +1 -0
  105. package/dist/scanners/operational/index.test.d.ts +5 -0
  106. package/dist/scanners/operational/index.test.d.ts.map +1 -0
  107. package/dist/scanners/operational/index.test.js +406 -0
  108. package/dist/scanners/operational/index.test.js.map +1 -0
  109. package/dist/scanners/operational/patterns.d.ts +33 -0
  110. package/dist/scanners/operational/patterns.d.ts.map +1 -0
  111. package/dist/scanners/operational/patterns.js +151 -0
  112. package/dist/scanners/operational/patterns.js.map +1 -0
  113. package/dist/scanners/rbac/index.d.ts +7 -0
  114. package/dist/scanners/rbac/index.d.ts.map +1 -0
  115. package/dist/scanners/rbac/index.js +145 -0
  116. package/dist/scanners/rbac/index.js.map +1 -0
  117. package/dist/scanners/rbac/index.test.d.ts +5 -0
  118. package/dist/scanners/rbac/index.test.d.ts.map +1 -0
  119. package/dist/scanners/rbac/index.test.js +422 -0
  120. package/dist/scanners/rbac/index.test.js.map +1 -0
  121. package/dist/scanners/rbac/patterns.d.ts +32 -0
  122. package/dist/scanners/rbac/patterns.d.ts.map +1 -0
  123. package/dist/scanners/rbac/patterns.js +124 -0
  124. package/dist/scanners/rbac/patterns.js.map +1 -0
  125. package/dist/scanners/revocation/index.d.ts +8 -0
  126. package/dist/scanners/revocation/index.d.ts.map +1 -0
  127. package/dist/scanners/revocation/index.js +83 -0
  128. package/dist/scanners/revocation/index.js.map +1 -0
  129. package/dist/scanners/revocation/index.test.d.ts +5 -0
  130. package/dist/scanners/revocation/index.test.d.ts.map +1 -0
  131. package/dist/scanners/revocation/index.test.js +332 -0
  132. package/dist/scanners/revocation/index.test.js.map +1 -0
  133. package/dist/scanners/revocation/patterns.d.ts +27 -0
  134. package/dist/scanners/revocation/patterns.d.ts.map +1 -0
  135. package/dist/scanners/revocation/patterns.js +109 -0
  136. package/dist/scanners/revocation/patterns.js.map +1 -0
  137. package/dist/scanners/sanitization/index.d.ts +8 -0
  138. package/dist/scanners/sanitization/index.d.ts.map +1 -0
  139. package/dist/scanners/sanitization/index.js +98 -0
  140. package/dist/scanners/sanitization/index.js.map +1 -0
  141. package/dist/scanners/sanitization/index.test.d.ts +5 -0
  142. package/dist/scanners/sanitization/index.test.d.ts.map +1 -0
  143. package/dist/scanners/sanitization/index.test.js +370 -0
  144. package/dist/scanners/sanitization/index.test.js.map +1 -0
  145. package/dist/scanners/sanitization/patterns.d.ts +27 -0
  146. package/dist/scanners/sanitization/patterns.d.ts.map +1 -0
  147. package/dist/scanners/sanitization/patterns.js +117 -0
  148. package/dist/scanners/sanitization/patterns.js.map +1 -0
  149. package/dist/training/certificate.d.ts +26 -0
  150. package/dist/training/certificate.d.ts.map +1 -0
  151. package/dist/training/certificate.js +92 -0
  152. package/dist/training/certificate.js.map +1 -0
  153. package/dist/training/index.d.ts +3 -0
  154. package/dist/training/index.d.ts.map +1 -0
  155. package/dist/training/index.js +243 -0
  156. package/dist/training/index.js.map +1 -0
  157. package/dist/training/modules.d.ts +13 -0
  158. package/dist/training/modules.d.ts.map +1 -0
  159. package/dist/training/modules.js +608 -0
  160. package/dist/training/modules.js.map +1 -0
  161. package/dist/training/questions.d.ts +9 -0
  162. package/dist/training/questions.d.ts.map +1 -0
  163. package/dist/training/questions.js +505 -0
  164. package/dist/training/questions.js.map +1 -0
  165. package/dist/types.d.ts +45 -0
  166. package/dist/types.d.ts.map +1 -1
  167. package/dist/utils/npm-audit.d.ts +6 -0
  168. package/dist/utils/npm-audit.d.ts.map +1 -0
  169. package/dist/utils/npm-audit.js +95 -0
  170. package/dist/utils/npm-audit.js.map +1 -0
  171. package/dist/utils/scan-history.d.ts +59 -0
  172. package/dist/utils/scan-history.d.ts.map +1 -0
  173. package/dist/utils/scan-history.js +170 -0
  174. package/dist/utils/scan-history.js.map +1 -0
  175. package/package.json +4 -1
  176. package/templates/baa-verification-letter.md +105 -0
  177. package/templates/irp.md +545 -0
  178. package/templates/notice-of-privacy-practices.md +491 -0
  179. package/templates/physical-safeguards-checklist.md +247 -0
  180. package/templates/security-officer-designation.md +237 -0
@@ -0,0 +1,406 @@
1
+ /**
2
+ * Operational Security Scanner Tests
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { operationalScanner } from './index.js';
6
+ import * as fs from 'fs/promises';
7
+ import * as path from 'path';
8
+ import * as os from 'os';
9
+ describe('Operational Security Scanner', () => {
10
+ let tempDir = '';
11
+ let testFiles = [];
12
+ beforeEach(async () => {
13
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'operational-test-'));
14
+ });
15
+ afterEach(async () => {
16
+ // Cleanup
17
+ for (const file of testFiles) {
18
+ try {
19
+ await fs.unlink(file);
20
+ }
21
+ catch {
22
+ // Ignore
23
+ }
24
+ }
25
+ try {
26
+ await fs.rm(tempDir, { recursive: true, force: true });
27
+ }
28
+ catch {
29
+ // Ignore
30
+ }
31
+ testFiles = [];
32
+ });
33
+ async function createTestFile(filename, content) {
34
+ const filePath = path.join(tempDir, filename);
35
+ await fs.writeFile(filePath, content, 'utf-8');
36
+ testFiles.push(filePath);
37
+ return filePath;
38
+ }
39
+ const scanOptions = {
40
+ path: tempDir,
41
+ };
42
+ describe('BACKUP-001: Database Without Backup Configuration', () => {
43
+ it('should detect Prisma usage without backup configuration', async () => {
44
+ await createTestFile('db.ts', `
45
+ import { PrismaClient } from '@prisma/client';
46
+
47
+ const prisma = new PrismaClient();
48
+ `);
49
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
50
+ const backupFindings = findings.filter((f) => f.id === 'BACKUP-001');
51
+ expect(backupFindings.length).toBeGreaterThan(0);
52
+ expect(backupFindings[0].severity).toBe('medium');
53
+ expect(backupFindings[0].confidence).toBe('low'); // Advisory
54
+ });
55
+ it('should detect Mongoose usage without backup configuration', async () => {
56
+ await createTestFile('mongoose.ts', `
57
+ import mongoose from 'mongoose';
58
+
59
+ mongoose.connect(process.env.MONGODB_URI);
60
+ `);
61
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
62
+ expect(findings.some((f) => f.id === 'BACKUP-001')).toBe(true);
63
+ });
64
+ it('should detect Supabase usage without backup configuration', async () => {
65
+ await createTestFile('supabase.ts', `
66
+ import { createClient } from '@supabase/supabase-js';
67
+
68
+ const supabase = createClient(url, key);
69
+ `);
70
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
71
+ expect(findings.some((f) => f.id === 'BACKUP-001')).toBe(true);
72
+ });
73
+ it('should detect Drizzle usage without backup configuration', async () => {
74
+ await createTestFile('drizzle.ts', `
75
+ import { drizzle } from 'drizzle-orm';
76
+ `);
77
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
78
+ expect(findings.some((f) => f.id === 'BACKUP-001')).toBe(true);
79
+ });
80
+ it('should detect TypeORM usage without backup configuration', async () => {
81
+ await createTestFile('typeorm.ts', `
82
+ import { createConnection } from 'typeorm';
83
+
84
+ await createConnection();
85
+ `);
86
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
87
+ expect(findings.some((f) => f.id === 'BACKUP-001')).toBe(true);
88
+ });
89
+ it('should NOT flag database with backup configuration', async () => {
90
+ await createTestFile('db.ts', `
91
+ import { PrismaClient } from '@prisma/client';
92
+
93
+ const prisma = new PrismaClient();
94
+ `);
95
+ await createTestFile('backup.ts', `
96
+ // Automated backup configuration
97
+ const backupSchedule = '0 2 * * *'; // Daily at 2 AM
98
+ const backupCommand = 'pg_dump -U postgres mydb > backup.sql';
99
+ `);
100
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
101
+ const backupFindings = findings.filter((f) => f.id === 'BACKUP-001');
102
+ expect(backupFindings.length).toBe(0);
103
+ });
104
+ it('should NOT flag database with pg_dump reference', async () => {
105
+ await createTestFile('db.ts', `
106
+ import mongoose from 'mongoose';
107
+ mongoose.connect(uri);
108
+ `);
109
+ await createTestFile('backup-script.ts', `
110
+ // Backup script
111
+ const backupCommand = 'mongodump --uri="mongodb://localhost:27017/mydb" --out=/backups';
112
+ `);
113
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
114
+ const backupFindings = findings.filter((f) => f.id === 'BACKUP-001');
115
+ expect(backupFindings.length).toBe(0);
116
+ });
117
+ it('should NOT flag database with snapshot reference', async () => {
118
+ await createTestFile('db.ts', `
119
+ import { createClient } from '@supabase/supabase-js';
120
+ const supabase = createClient(url, key);
121
+ `);
122
+ await createTestFile('config.yml', `
123
+ # Database Configuration
124
+ # We use Supabase automatic snapshots configured in the dashboard
125
+ # Snapshots are taken every 24 hours and retained for 30 days
126
+ database:
127
+ snapshot_enabled: true
128
+ snapshot_retention: 30d
129
+ `);
130
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
131
+ const backupFindings = findings.filter((f) => f.id === 'BACKUP-001');
132
+ expect(backupFindings.length).toBe(0);
133
+ });
134
+ it('should NOT flag database with replicate reference', async () => {
135
+ await createTestFile('db.ts', `
136
+ import { PrismaClient } from '@prisma/client';
137
+ const prisma = new PrismaClient();
138
+ `);
139
+ await createTestFile('config.yml', `
140
+ database:
141
+ primary: postgres://main
142
+ replicate: postgres://replica
143
+ replication_lag_check: true
144
+ `);
145
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
146
+ const backupFindings = findings.filter((f) => f.id === 'BACKUP-001');
147
+ expect(backupFindings.length).toBe(0);
148
+ });
149
+ });
150
+ describe('RETENTION-001: PHI Records Without Retention Fields', () => {
151
+ it('should detect Prisma patient create without retention fields', async () => {
152
+ const file = await createTestFile('patient.ts', `
153
+ const patient = await prisma.patient.create({
154
+ data: {
155
+ name: 'John Doe',
156
+ ssn: '123-45-6789',
157
+ dob: new Date('1990-01-01')
158
+ }
159
+ });
160
+ `);
161
+ const findings = await operationalScanner.scan([file], scanOptions);
162
+ const retentionFindings = findings.filter((f) => f.id === 'RETENTION-001');
163
+ expect(retentionFindings.length).toBeGreaterThan(0);
164
+ expect(retentionFindings[0].severity).toBe('medium');
165
+ });
166
+ it('should detect Mongoose Patient create without retention fields', async () => {
167
+ const file = await createTestFile('patient-model.ts', `
168
+ const newPatient = await Patient.create({
169
+ name: 'Jane Doe',
170
+ medicalRecordNumber: 'MRN-123456',
171
+ diagnosis: 'Hypertension'
172
+ });
173
+ `);
174
+ const findings = await operationalScanner.scan([file], scanOptions);
175
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
176
+ });
177
+ it('should detect health record insert without retention fields', async () => {
178
+ const file = await createTestFile('health.ts', `
179
+ await prisma.healthRecord.create({
180
+ data: {
181
+ patientId: patient.id,
182
+ diagnosis: 'Diabetes Type 2',
183
+ treatment: 'Metformin 500mg'
184
+ }
185
+ });
186
+ `);
187
+ const findings = await operationalScanner.scan([file], scanOptions);
188
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
189
+ });
190
+ it('should detect medical record upsert without retention fields', async () => {
191
+ const file = await createTestFile('medical.ts', `
192
+ const record = await prisma.medicalRecord.upsert({
193
+ where: { id: recordId },
194
+ update: { notes: 'Updated notes' },
195
+ create: { patientId: pid, notes: 'New record' }
196
+ });
197
+ `);
198
+ const findings = await operationalScanner.scan([file], scanOptions);
199
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
200
+ });
201
+ it('should detect Supabase patient insert without retention fields', async () => {
202
+ const file = await createTestFile('supabase-patient.ts', `
203
+ const { data, error } = await supabase.from('patients').insert({
204
+ name: 'John Smith',
205
+ ssn: '987-65-4321',
206
+ email: 'john@example.com'
207
+ });
208
+ `);
209
+ const findings = await operationalScanner.scan([file], scanOptions);
210
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
211
+ });
212
+ it('should detect clinical data insert without retention fields', async () => {
213
+ const file = await createTestFile('clinical.ts', `
214
+ await db.insert(clinicalNotes).values({
215
+ patientId: '123',
216
+ notes: 'Patient shows improvement',
217
+ provider: 'Dr. Smith'
218
+ });
219
+ `);
220
+ const findings = await operationalScanner.scan([file], scanOptions);
221
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
222
+ });
223
+ it('should NOT flag patient create with expiresAt field', async () => {
224
+ const file = await createTestFile('safe-patient.ts', `
225
+ const patient = await prisma.patient.create({
226
+ data: {
227
+ name: 'John Doe',
228
+ ssn: '123-45-6789',
229
+ expiresAt: new Date(Date.now() + 7 * 365 * 24 * 60 * 60 * 1000) // 7 years
230
+ }
231
+ });
232
+ `);
233
+ const findings = await operationalScanner.scan([file], scanOptions);
234
+ const retentionFindings = findings.filter((f) => f.id === 'RETENTION-001');
235
+ expect(retentionFindings.length).toBe(0);
236
+ });
237
+ it('should NOT flag health record with retentionPeriod field', async () => {
238
+ const file = await createTestFile('safe-health.ts', `
239
+ await prisma.healthRecord.create({
240
+ data: {
241
+ patientId: patient.id,
242
+ diagnosis: 'Diabetes',
243
+ retentionPeriod: '7years',
244
+ deleteAfter: calculateDeleteDate()
245
+ }
246
+ });
247
+ `);
248
+ const findings = await operationalScanner.scan([file], scanOptions);
249
+ const retentionFindings = findings.filter((f) => f.id === 'RETENTION-001');
250
+ expect(retentionFindings.length).toBe(0);
251
+ });
252
+ it('should NOT flag patient create with ttl field', async () => {
253
+ const file = await createTestFile('ttl-patient.ts', `
254
+ const patient = await Patient.create({
255
+ name: 'Jane Doe',
256
+ mrn: 'MRN-789',
257
+ ttl: 60 * 60 * 24 * 365 * 7 // 7 years in seconds
258
+ });
259
+ `);
260
+ const findings = await operationalScanner.scan([file], scanOptions);
261
+ const retentionFindings = findings.filter((f) => f.id === 'RETENTION-001');
262
+ expect(retentionFindings.length).toBe(0);
263
+ });
264
+ it('should NOT flag patient create in test files', async () => {
265
+ const file = await createTestFile('patient.test.ts', `
266
+ describe('Patient creation', () => {
267
+ it('should create patient', async () => {
268
+ const patient = await prisma.patient.create({
269
+ data: { name: 'Test Patient', ssn: '000-00-0000' }
270
+ });
271
+ });
272
+ });
273
+ `);
274
+ const findings = await operationalScanner.scan([file], scanOptions);
275
+ const retentionFindings = findings.filter((f) => f.id === 'RETENTION-001');
276
+ expect(retentionFindings.length).toBe(0);
277
+ });
278
+ });
279
+ describe('API-002: JSON Body Parser Without Size Limit', () => {
280
+ it('should detect express.json() without limit', async () => {
281
+ const file = await createTestFile('server.ts', `
282
+ import express from 'express';
283
+
284
+ const app = express();
285
+ app.use(express.json());
286
+ `);
287
+ const findings = await operationalScanner.scan([file], scanOptions);
288
+ const apiFindings = findings.filter((f) => f.id === 'API-002');
289
+ expect(apiFindings.length).toBeGreaterThan(0);
290
+ expect(apiFindings[0].severity).toBe('low');
291
+ });
292
+ it('should detect bodyParser.json() without limit', async () => {
293
+ const file = await createTestFile('body-parser.ts', `
294
+ import bodyParser from 'body-parser';
295
+
296
+ app.use(bodyParser.json());
297
+ `);
298
+ const findings = await operationalScanner.scan([file], scanOptions);
299
+ expect(findings.some((f) => f.id === 'API-002')).toBe(true);
300
+ });
301
+ it('should detect express.json() with empty options', async () => {
302
+ const file = await createTestFile('empty-options.ts', `
303
+ app.use(express.json({}));
304
+ `);
305
+ const findings = await operationalScanner.scan([file], scanOptions);
306
+ expect(findings.some((f) => f.id === 'API-002')).toBe(true);
307
+ });
308
+ it('should detect bodyParser.json() with empty options', async () => {
309
+ const file = await createTestFile('empty-body-parser.ts', `
310
+ const app = express();
311
+ app.use(bodyParser.json({}));
312
+ `);
313
+ const findings = await operationalScanner.scan([file], scanOptions);
314
+ expect(findings.some((f) => f.id === 'API-002')).toBe(true);
315
+ });
316
+ it('should NOT flag express.json() with limit configured', async () => {
317
+ const file = await createTestFile('safe-express.ts', `
318
+ import express from 'express';
319
+
320
+ const app = express();
321
+ app.use(express.json({ limit: '10mb' }));
322
+ `);
323
+ const findings = await operationalScanner.scan([file], scanOptions);
324
+ const apiFindings = findings.filter((f) => f.id === 'API-002');
325
+ expect(apiFindings.length).toBe(0);
326
+ });
327
+ it('should NOT flag bodyParser.json() with limit configured', async () => {
328
+ const file = await createTestFile('safe-body-parser.ts', `
329
+ app.use(bodyParser.json({
330
+ limit: '1mb',
331
+ strict: true
332
+ }));
333
+ `);
334
+ const findings = await operationalScanner.scan([file], scanOptions);
335
+ const apiFindings = findings.filter((f) => f.id === 'API-002');
336
+ expect(apiFindings.length).toBe(0);
337
+ });
338
+ it('should NOT flag express.json() with limit on separate line', async () => {
339
+ const file = await createTestFile('multiline-config.ts', `
340
+ app.use(express.json({
341
+ limit: '5mb',
342
+ type: 'application/json'
343
+ }));
344
+ `);
345
+ const findings = await operationalScanner.scan([file], scanOptions);
346
+ const apiFindings = findings.filter((f) => f.id === 'API-002');
347
+ expect(apiFindings.length).toBe(0);
348
+ });
349
+ });
350
+ describe('Combined violations', () => {
351
+ it('should detect multiple operational violations in same project', async () => {
352
+ await createTestFile('db.ts', `
353
+ import { PrismaClient } from '@prisma/client';
354
+ const prisma = new PrismaClient();
355
+ `);
356
+ await createTestFile('patient.ts', `
357
+ const patient = await prisma.patient.create({
358
+ data: { name: 'John', ssn: '123-45-6789' }
359
+ });
360
+ `);
361
+ await createTestFile('server.ts', `
362
+ import express from 'express';
363
+ const app = express();
364
+ app.use(express.json());
365
+ `);
366
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
367
+ expect(findings.some((f) => f.id === 'BACKUP-001')).toBe(true);
368
+ expect(findings.some((f) => f.id === 'RETENTION-001')).toBe(true);
369
+ expect(findings.some((f) => f.id === 'API-002')).toBe(true);
370
+ });
371
+ });
372
+ it('should provide correct HIPAA references', async () => {
373
+ await createTestFile('db.ts', `import { PrismaClient } from '@prisma/client';`);
374
+ await createTestFile('patient.ts', `await prisma.patient.create({ data: {} });`);
375
+ await createTestFile('server.ts', `app.use(express.json());`);
376
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
377
+ const backup = findings.find((f) => f.id === 'BACKUP-001');
378
+ const retention = findings.find((f) => f.id === 'RETENTION-001');
379
+ const api = findings.find((f) => f.id === 'API-002');
380
+ expect(backup?.hipaaReference).toContain('164.308(a)(7)(ii)(A)');
381
+ expect(retention?.hipaaReference).toContain('164.316(b)(2)(i)');
382
+ expect(api?.hipaaReference).toContain('164.308(a)(1)(ii)(D)');
383
+ });
384
+ it('should have correct severity levels', async () => {
385
+ await createTestFile('db.ts', `import mongoose from 'mongoose';`);
386
+ await createTestFile('patient.ts', `await Patient.create({});`);
387
+ await createTestFile('server.ts', `app.use(express.json());`);
388
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
389
+ const backup = findings.find((f) => f.id === 'BACKUP-001');
390
+ const retention = findings.find((f) => f.id === 'RETENTION-001');
391
+ const api = findings.find((f) => f.id === 'API-002');
392
+ expect(backup?.severity).toBe('medium');
393
+ expect(retention?.severity).toBe('medium');
394
+ expect(api?.severity).toBe('low');
395
+ });
396
+ it('should have correct confidence levels', async () => {
397
+ await createTestFile('db.ts', `import { PrismaClient } from '@prisma/client';`);
398
+ await createTestFile('patient.ts', `await prisma.patient.create({ data: {} });`);
399
+ const findings = await operationalScanner.scan(testFiles, scanOptions);
400
+ const backup = findings.find((f) => f.id === 'BACKUP-001');
401
+ const retention = findings.find((f) => f.id === 'RETENTION-001');
402
+ expect(backup?.confidence).toBe('low'); // Advisory finding
403
+ expect(retention?.confidence).toBe('medium');
404
+ });
405
+ });
406
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/scanners/operational/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Operational Security Detection Patterns
3
+ * Detects backup configuration, data retention, and API security issues
4
+ */
5
+ export interface OperationalPattern {
6
+ id: string;
7
+ name: string;
8
+ description: string;
9
+ severity: 'medium' | 'low';
10
+ hipaaReference: string;
11
+ patterns: RegExp[];
12
+ negativePatterns?: RegExp[];
13
+ recommendation: string;
14
+ category: string;
15
+ requiresProjectScan?: boolean;
16
+ }
17
+ /**
18
+ * BACKUP-001: Database Without Backup Configuration
19
+ * Detects database usage without backup/snapshot references in project
20
+ */
21
+ export declare const DATABASE_WITHOUT_BACKUP: OperationalPattern;
22
+ /**
23
+ * RETENTION-001: PHI Records Without Retention Fields
24
+ * Detects creation of PHI records without retention/expiration fields
25
+ */
26
+ export declare const PHI_RECORDS_WITHOUT_RETENTION: OperationalPattern;
27
+ /**
28
+ * API-002: JSON Body Parser Without Size Limit
29
+ * Detects express.json() or bodyParser.json() without limit configuration
30
+ */
31
+ export declare const BODY_PARSER_WITHOUT_LIMIT: OperationalPattern;
32
+ export declare const ALL_OPERATIONAL_PATTERNS: OperationalPattern[];
33
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/scanners/operational/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,kBAyCrC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,kBAmE3C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,kBAkCvC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,kBAAkB,EAIxD,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Operational Security Detection Patterns
3
+ * Detects backup configuration, data retention, and API security issues
4
+ */
5
+ /**
6
+ * BACKUP-001: Database Without Backup Configuration
7
+ * Detects database usage without backup/snapshot references in project
8
+ */
9
+ export const DATABASE_WITHOUT_BACKUP = {
10
+ id: 'BACKUP-001',
11
+ name: 'Database Without Backup Configuration',
12
+ description: 'Database usage detected (supabase, prisma, mongoose, drizzle, typeorm, sequelize, knex) without backup/snapshot/replicate configuration references in project. Advisory: Full verification requires infrastructure inspection.',
13
+ severity: 'medium',
14
+ hipaaReference: '45 CFR §164.308(a)(7)(ii)(A) - Data Backup Plan',
15
+ patterns: [
16
+ // Database library imports
17
+ /import.*from\s+['"]@supabase\/supabase-js['"]/i,
18
+ /import.*from\s+['"]@prisma\/client['"]/i,
19
+ /import.*from\s+['"]prisma['"]/i,
20
+ /import.*from\s+['"]mongoose['"]/i,
21
+ /import.*from\s+['"]drizzle-orm['"]/i,
22
+ /import.*from\s+['"]typeorm['"]/i,
23
+ /import.*from\s+['"]sequelize['"]/i,
24
+ /import.*from\s+['"]knex['"]/i,
25
+ // Database client initialization
26
+ /new\s+PrismaClient\s*\(/i,
27
+ /mongoose\.connect\s*\(/i,
28
+ /createClient\s*\(.*supabase/i,
29
+ /new\s+Sequelize\s*\(/i,
30
+ /createConnection\s*\(.*typeorm/i,
31
+ ],
32
+ negativePatterns: [
33
+ // Backup-related keywords (these are "good" - they prevent the finding)
34
+ /backup/i,
35
+ /snapshot/i,
36
+ /replicate/i,
37
+ /pg_dump/i,
38
+ /mongodump/i,
39
+ /restore/i,
40
+ /\.backup\(/i,
41
+ /backupSchedule/i,
42
+ /automaticBackup/i,
43
+ ],
44
+ recommendation: 'Configure automated database backups. Examples: Enable Supabase automatic backups, configure Prisma backup scripts, set up MongoDB Atlas continuous backups, or use pg_dump/mongodump in CI/CD. Document backup schedule and retention policy.',
45
+ category: 'data-retention',
46
+ requiresProjectScan: true, // This pattern needs to scan entire project
47
+ };
48
+ /**
49
+ * RETENTION-001: PHI Records Without Retention Fields
50
+ * Detects creation of PHI records without retention/expiration fields
51
+ */
52
+ export const PHI_RECORDS_WITHOUT_RETENTION = {
53
+ id: 'RETENTION-001',
54
+ name: 'PHI Records Created Without Retention Fields',
55
+ description: 'PHI record creation (insert/create/save/upsert on patient/health/medical/clinical tables) without retention fields (expiresAt, ttl, retainUntil, retentionPeriod, deleteAfter). HIPAA requires minimum necessary retention periods.',
56
+ severity: 'medium',
57
+ hipaaReference: '45 CFR §164.316(b)(2)(i) - Retention Period',
58
+ patterns: [
59
+ // Prisma operations
60
+ /prisma\.patient\.create\s*\(/i,
61
+ /prisma\.health.*\.create\s*\(/i,
62
+ /prisma\.medical.*\.create\s*\(/i,
63
+ /prisma\.clinical.*\.create\s*\(/i,
64
+ /prisma\.patient\.upsert\s*\(/i,
65
+ /prisma\.health.*\.upsert\s*\(/i,
66
+ // Mongoose operations
67
+ /Patient\.create\s*\(/i,
68
+ /Health.*\.create\s*\(/i,
69
+ /Medical.*\.create\s*\(/i,
70
+ /Clinical.*\.create\s*\(/i,
71
+ /new\s+Patient\s*\(.*\)\.save\s*\(/i,
72
+ // Generic ORM insert/create
73
+ /db\.insert\s*\(\s*patient/i,
74
+ /db\.insert\s*\(\s*health/i,
75
+ /db\.insert\s*\(\s*medical/i,
76
+ /db\.insert\s*\(\s*clinical/i,
77
+ /\.insert\s*\(.*\)\s*\.into\s*\(\s*['"`]patient/i,
78
+ /\.insert\s*\(.*\)\s*\.into\s*\(\s*['"`]health/i,
79
+ // Sequelize operations
80
+ /Patient\.create\s*\(\s*\{/i,
81
+ /Health.*Model\.create\s*\(/i,
82
+ /Medical.*\.upsert\s*\(/i,
83
+ // Drizzle operations
84
+ /db\.insert\s*\(.*patient.*\)/i,
85
+ /insertInto\s*\(\s*patient/i,
86
+ // Supabase operations
87
+ /supabase\.from\s*\(\s*['"`]patient.*['"]\s*\)\.insert/i,
88
+ /supabase\.from\s*\(\s*['"`]health.*['"]\s*\)\.insert/i,
89
+ /supabase\.from\s*\(\s*['"`]medical.*['"]\s*\)\.insert/i,
90
+ ],
91
+ negativePatterns: [
92
+ // Retention fields
93
+ /expiresAt/i,
94
+ /ttl/i,
95
+ /retainUntil/i,
96
+ /retentionPeriod/i,
97
+ /deleteAfter/i,
98
+ /retention_date/i,
99
+ /expiration/i,
100
+ /expires_at/i,
101
+ /retain_until/i,
102
+ /delete_after/i,
103
+ // Test files
104
+ /\.test\./i,
105
+ /\.spec\./i,
106
+ /describe\(/i,
107
+ /it\(/i,
108
+ ],
109
+ recommendation: 'Add retention fields to PHI record creation. Example: { ...patientData, expiresAt: new Date(Date.now() + 7 * 365 * 24 * 60 * 60 * 1000) } or { ...data, retentionPeriod: "7years", deleteAfter: calculateDeleteDate() }. Define retention policy based on record type and regulatory requirements.',
110
+ category: 'data-retention',
111
+ };
112
+ /**
113
+ * API-002: JSON Body Parser Without Size Limit
114
+ * Detects express.json() or bodyParser.json() without limit configuration
115
+ */
116
+ export const BODY_PARSER_WITHOUT_LIMIT = {
117
+ id: 'API-002',
118
+ name: 'JSON Body Parser Without Size Limit',
119
+ description: 'express.json() or bodyParser.json() configured without limit option. Unlimited body size can lead to DoS attacks via large payload submissions.',
120
+ severity: 'low',
121
+ hipaaReference: '45 CFR §164.308(a)(1)(ii)(D) - System Security',
122
+ patterns: [
123
+ // express.json()
124
+ /express\.json\s*\(\s*\)/i,
125
+ /app\.use\s*\(\s*express\.json\s*\(\s*\)\s*\)/i,
126
+ // bodyParser.json()
127
+ /bodyParser\.json\s*\(\s*\)/i,
128
+ /app\.use\s*\(\s*bodyParser\.json\s*\(\s*\)\s*\)/i,
129
+ // express.json() with empty object
130
+ /express\.json\s*\(\s*\{\s*\}\s*\)/i,
131
+ /bodyParser\.json\s*\(\s*\{\s*\}\s*\)/i,
132
+ ],
133
+ negativePatterns: [
134
+ // Has limit configured
135
+ /limit\s*:/i,
136
+ /\{\s*limit/i,
137
+ /"limit"/i,
138
+ /'limit'/i,
139
+ // Has size configuration
140
+ /size:/i,
141
+ /maxBodySize/i,
142
+ ],
143
+ recommendation: 'Configure body size limits. Example: app.use(express.json({ limit: "10mb" })) or bodyParser.json({ limit: "1mb" }). Set limit based on expected payload size. Typical values: 1mb for APIs, 10mb for file uploads.',
144
+ category: 'access-control',
145
+ };
146
+ export const ALL_OPERATIONAL_PATTERNS = [
147
+ DATABASE_WITHOUT_BACKUP,
148
+ PHI_RECORDS_WITHOUT_RETENTION,
149
+ BODY_PARSER_WITHOUT_LIMIT,
150
+ ];
151
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/scanners/operational/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAuB;IACzD,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,uCAAuC;IAC7C,WAAW,EACT,gOAAgO;IAClO,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,iDAAiD;IACjE,QAAQ,EAAE;QACR,2BAA2B;QAC3B,gDAAgD;QAChD,yCAAyC;QACzC,gCAAgC;QAChC,kCAAkC;QAClC,qCAAqC;QACrC,iCAAiC;QACjC,mCAAmC;QACnC,8BAA8B;QAE9B,iCAAiC;QACjC,0BAA0B;QAC1B,yBAAyB;QACzB,8BAA8B;QAC9B,uBAAuB;QACvB,iCAAiC;KAClC;IACD,gBAAgB,EAAE;QAChB,wEAAwE;QACxE,SAAS;QACT,WAAW;QACX,YAAY;QACZ,UAAU;QACV,YAAY;QACZ,UAAU;QACV,aAAa;QACb,iBAAiB;QACjB,kBAAkB;KACnB;IACD,cAAc,EACZ,gPAAgP;IAClP,QAAQ,EAAE,gBAAgB;IAC1B,mBAAmB,EAAE,IAAI,EAAE,4CAA4C;CACxE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAuB;IAC/D,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,8CAA8C;IACpD,WAAW,EACT,qOAAqO;IACvO,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,6CAA6C;IAC7D,QAAQ,EAAE;QACR,oBAAoB;QACpB,+BAA+B;QAC/B,gCAAgC;QAChC,iCAAiC;QACjC,kCAAkC;QAClC,+BAA+B;QAC/B,gCAAgC;QAEhC,sBAAsB;QACtB,uBAAuB;QACvB,wBAAwB;QACxB,yBAAyB;QACzB,0BAA0B;QAC1B,oCAAoC;QAEpC,4BAA4B;QAC5B,4BAA4B;QAC5B,2BAA2B;QAC3B,4BAA4B;QAC5B,6BAA6B;QAC7B,iDAAiD;QACjD,gDAAgD;QAEhD,uBAAuB;QACvB,4BAA4B;QAC5B,6BAA6B;QAC7B,yBAAyB;QAEzB,qBAAqB;QACrB,+BAA+B;QAC/B,4BAA4B;QAE5B,sBAAsB;QACtB,wDAAwD;QACxD,uDAAuD;QACvD,wDAAwD;KACzD;IACD,gBAAgB,EAAE;QAChB,mBAAmB;QACnB,YAAY;QACZ,MAAM;QACN,cAAc;QACd,kBAAkB;QAClB,cAAc;QACd,iBAAiB;QACjB,aAAa;QACb,aAAa;QACb,eAAe;QACf,eAAe;QAEf,aAAa;QACb,WAAW;QACX,WAAW;QACX,aAAa;QACb,OAAO;KACR;IACD,cAAc,EACZ,oSAAoS;IACtS,QAAQ,EAAE,gBAAgB;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAuB;IAC3D,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,qCAAqC;IAC3C,WAAW,EACT,iJAAiJ;IACnJ,QAAQ,EAAE,KAAK;IACf,cAAc,EAAE,gDAAgD;IAChE,QAAQ,EAAE;QACR,iBAAiB;QACjB,0BAA0B;QAC1B,+CAA+C;QAE/C,oBAAoB;QACpB,6BAA6B;QAC7B,kDAAkD;QAElD,mCAAmC;QACnC,oCAAoC;QACpC,uCAAuC;KACxC;IACD,gBAAgB,EAAE;QAChB,uBAAuB;QACvB,YAAY;QACZ,aAAa;QACb,UAAU;QACV,UAAU;QAEV,yBAAyB;QACzB,QAAQ;QACR,cAAc;KACf;IACD,cAAc,EACZ,oNAAoN;IACtN,QAAQ,EAAE,gBAAgB;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAyB;IAC5D,uBAAuB;IACvB,6BAA6B;IAC7B,yBAAyB;CAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Role-Based Access Control (RBAC) Scanner
3
+ * Detects missing authorization checks and HIPAA minimum necessary violations
4
+ */
5
+ import type { Scanner } from '../../types.js';
6
+ export declare const rbacScanner: Scanner;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/rbac/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAwB,MAAM,gBAAgB,CAAC;AAGpE,eAAO,MAAM,WAAW,EAAE,OAqFzB,CAAC"}