guardrail-compliance 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/emitter.d.ts +97 -0
- package/dist/audit/emitter.d.ts.map +1 -0
- package/dist/audit/emitter.js +197 -0
- package/dist/audit/events.d.ts +304 -0
- package/dist/audit/events.d.ts.map +1 -0
- package/dist/audit/events.js +267 -0
- package/dist/audit/index.d.ts +11 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +51 -0
- package/dist/audit/storage.d.ts +93 -0
- package/dist/audit/storage.d.ts.map +1 -0
- package/dist/audit/storage.js +337 -0
- package/dist/automation/__tests__/compliance-scheduler.test.d.ts +2 -0
- package/dist/automation/__tests__/compliance-scheduler.test.d.ts.map +1 -0
- package/dist/automation/__tests__/compliance-scheduler.test.js +140 -0
- package/dist/automation/audit-logger.d.ts +129 -0
- package/dist/automation/audit-logger.d.ts.map +1 -0
- package/dist/automation/audit-logger.js +473 -0
- package/dist/automation/compliance-scheduler-fixed.d.ts +1 -0
- package/dist/automation/compliance-scheduler-fixed.d.ts.map +1 -0
- package/dist/automation/compliance-scheduler-fixed.js +1 -0
- package/dist/automation/compliance-scheduler.d.ts +83 -0
- package/dist/automation/compliance-scheduler.d.ts.map +1 -0
- package/dist/automation/compliance-scheduler.js +414 -0
- package/dist/automation/dashboard.d.ts +194 -0
- package/dist/automation/dashboard.d.ts.map +1 -0
- package/dist/automation/dashboard.js +768 -0
- package/dist/automation/email-service.d.ts +69 -0
- package/dist/automation/email-service.d.ts.map +1 -0
- package/dist/automation/email-service.js +218 -0
- package/dist/automation/evidence-collector.d.ts +140 -0
- package/dist/automation/evidence-collector.d.ts.map +1 -0
- package/dist/automation/evidence-collector.js +682 -0
- package/dist/automation/index.d.ts +8 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +24 -0
- package/dist/automation/pdf-exporter.d.ts +90 -0
- package/dist/automation/pdf-exporter.d.ts.map +1 -0
- package/dist/automation/pdf-exporter.js +381 -0
- package/dist/automation/reporting-engine.d.ts +116 -0
- package/dist/automation/reporting-engine.d.ts.map +1 -0
- package/dist/automation/reporting-engine.js +329 -0
- package/dist/container/index.d.ts +4 -0
- package/dist/container/index.d.ts.map +1 -0
- package/dist/container/index.js +19 -0
- package/dist/container/kubernetes.d.ts +94 -0
- package/dist/container/kubernetes.d.ts.map +1 -0
- package/dist/container/kubernetes.js +268 -0
- package/dist/container/rules.d.ts +27 -0
- package/dist/container/rules.d.ts.map +1 -0
- package/dist/container/rules.js +216 -0
- package/dist/container/scanner.d.ts +50 -0
- package/dist/container/scanner.d.ts.map +1 -0
- package/dist/container/scanner.js +143 -0
- package/dist/frameworks/engine.d.ts +108 -0
- package/dist/frameworks/engine.d.ts.map +1 -0
- package/dist/frameworks/engine.js +206 -0
- package/dist/frameworks/gdpr.d.ts +6 -0
- package/dist/frameworks/gdpr.d.ts.map +1 -0
- package/dist/frameworks/gdpr.js +198 -0
- package/dist/frameworks/hipaa.d.ts +6 -0
- package/dist/frameworks/hipaa.d.ts.map +1 -0
- package/dist/frameworks/hipaa.js +183 -0
- package/dist/frameworks/index.d.ts +8 -0
- package/dist/frameworks/index.d.ts.map +1 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/iso27001.d.ts +63 -0
- package/dist/frameworks/iso27001.d.ts.map +1 -0
- package/dist/frameworks/iso27001.js +331 -0
- package/dist/frameworks/nist.d.ts +62 -0
- package/dist/frameworks/nist.d.ts.map +1 -0
- package/dist/frameworks/nist.js +424 -0
- package/dist/frameworks/pci.d.ts +6 -0
- package/dist/frameworks/pci.d.ts.map +1 -0
- package/dist/frameworks/pci.js +201 -0
- package/dist/frameworks/soc2.d.ts +7 -0
- package/dist/frameworks/soc2.d.ts.map +1 -0
- package/dist/frameworks/soc2.js +248 -0
- package/dist/iac/drift-detector.d.ts +64 -0
- package/dist/iac/drift-detector.d.ts.map +1 -0
- package/dist/iac/drift-detector.js +134 -0
- package/dist/iac/index.d.ts +4 -0
- package/dist/iac/index.d.ts.map +1 -0
- package/dist/iac/index.js +19 -0
- package/dist/iac/rules.d.ts +17 -0
- package/dist/iac/rules.d.ts.map +1 -0
- package/dist/iac/rules.js +385 -0
- package/dist/iac/scanner.d.ts +104 -0
- package/dist/iac/scanner.d.ts.map +1 -0
- package/dist/iac/scanner.js +343 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/pii/data-flow.d.ts +58 -0
- package/dist/pii/data-flow.d.ts.map +1 -0
- package/dist/pii/data-flow.js +154 -0
- package/dist/pii/detector.d.ts +60 -0
- package/dist/pii/detector.d.ts.map +1 -0
- package/dist/pii/detector.js +267 -0
- package/dist/pii/index.d.ts +4 -0
- package/dist/pii/index.d.ts.map +1 -0
- package/dist/pii/index.js +19 -0
- package/dist/pii/patterns.d.ts +36 -0
- package/dist/pii/patterns.d.ts.map +1 -0
- package/dist/pii/patterns.js +108 -0
- package/dist/policy/index.d.ts +5 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +20 -0
- package/dist/policy/opa-engine.d.ts +121 -0
- package/dist/policy/opa-engine.d.ts.map +1 -0
- package/dist/policy/opa-engine.js +423 -0
- package/package.json +31 -0
- package/src/audit/emitter.ts +383 -0
- package/src/audit/events.ts +351 -0
- package/src/audit/index.ts +35 -0
- package/src/audit/storage.ts +394 -0
- package/src/automation/__tests__/compliance-scheduler.test.ts +183 -0
- package/src/automation/audit-logger.ts +629 -0
- package/src/automation/compliance-scheduler-fixed.ts +0 -0
- package/src/automation/compliance-scheduler.ts +516 -0
- package/src/automation/dashboard.ts +947 -0
- package/src/automation/email-service.ts +230 -0
- package/src/automation/evidence-collector.ts +866 -0
- package/src/automation/index.ts +8 -0
- package/src/automation/pdf-exporter.ts +434 -0
- package/src/automation/reporting-engine.ts +462 -0
- package/src/container/index.ts +3 -0
- package/src/container/kubernetes.ts +379 -0
- package/src/container/rules.ts +244 -0
- package/src/container/scanner.ts +202 -0
- package/src/frameworks/engine.ts +298 -0
- package/src/frameworks/gdpr.ts +204 -0
- package/src/frameworks/hipaa.ts +209 -0
- package/src/frameworks/index.ts +23 -0
- package/src/frameworks/iso27001.ts +398 -0
- package/src/frameworks/nist.ts +518 -0
- package/src/frameworks/pci.ts +226 -0
- package/src/frameworks/soc2.ts +281 -0
- package/src/iac/drift-detector.ts +197 -0
- package/src/iac/index.ts +3 -0
- package/src/iac/rules.ts +420 -0
- package/src/iac/scanner.ts +445 -0
- package/src/index.ts +17 -0
- package/src/pii/data-flow.ts +216 -0
- package/src/pii/detector.ts +327 -0
- package/src/pii/index.ts +3 -0
- package/src/pii/patterns.ts +128 -0
- package/src/policy/index.ts +5 -0
- package/src/policy/opa-engine.ts +504 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audit Trail Storage
|
|
4
|
+
*
|
|
5
|
+
* Hash-chained JSONL storage with adapter interface for future extensibility.
|
|
6
|
+
* Default: Local file storage at .guardrail/audit/audit.log.jsonl
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.ServerStorageAdapter = exports.LocalJSONLStorage = void 0;
|
|
43
|
+
exports.createStorageAdapter = createStorageAdapter;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const readline = __importStar(require("readline"));
|
|
47
|
+
const events_1 = require("./events");
|
|
48
|
+
// Genesis hash (used as prevHash for first event)
|
|
49
|
+
const GENESIS_HASH = '0'.repeat(64);
|
|
50
|
+
/**
|
|
51
|
+
* Local JSONL file storage adapter
|
|
52
|
+
*/
|
|
53
|
+
class LocalJSONLStorage {
|
|
54
|
+
filePath;
|
|
55
|
+
lastHash = GENESIS_HASH;
|
|
56
|
+
initialized = false;
|
|
57
|
+
constructor(basePath = process.cwd()) {
|
|
58
|
+
const auditDir = path.join(basePath, '.guardrail', 'audit');
|
|
59
|
+
this.filePath = path.join(auditDir, 'audit.log.jsonl');
|
|
60
|
+
}
|
|
61
|
+
async ensureDir() {
|
|
62
|
+
const dir = path.dirname(this.filePath);
|
|
63
|
+
if (!fs.existsSync(dir)) {
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async initialize() {
|
|
68
|
+
if (this.initialized)
|
|
69
|
+
return;
|
|
70
|
+
await this.ensureDir();
|
|
71
|
+
// Read last hash from existing log
|
|
72
|
+
if (fs.existsSync(this.filePath)) {
|
|
73
|
+
const events = await this.tail(1);
|
|
74
|
+
if (events.length > 0 && events[0]) {
|
|
75
|
+
this.lastHash = events[0].hash;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.initialized = true;
|
|
79
|
+
}
|
|
80
|
+
async append(event) {
|
|
81
|
+
await this.initialize();
|
|
82
|
+
const line = JSON.stringify(event) + '\n';
|
|
83
|
+
fs.appendFileSync(this.filePath, line, 'utf8');
|
|
84
|
+
this.lastHash = event.hash;
|
|
85
|
+
}
|
|
86
|
+
async getLastHash() {
|
|
87
|
+
await this.initialize();
|
|
88
|
+
return this.lastHash;
|
|
89
|
+
}
|
|
90
|
+
async read(options = {}) {
|
|
91
|
+
await this.initialize();
|
|
92
|
+
if (!fs.existsSync(this.filePath)) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const events = [];
|
|
96
|
+
const fileStream = fs.createReadStream(this.filePath);
|
|
97
|
+
const rl = readline.createInterface({
|
|
98
|
+
input: fileStream,
|
|
99
|
+
crlfDelay: Infinity,
|
|
100
|
+
});
|
|
101
|
+
let index = 0;
|
|
102
|
+
const offset = options.offset ?? 0;
|
|
103
|
+
const limit = options.limit ?? Infinity;
|
|
104
|
+
for await (const line of rl) {
|
|
105
|
+
if (!line.trim())
|
|
106
|
+
continue;
|
|
107
|
+
try {
|
|
108
|
+
const event = JSON.parse(line);
|
|
109
|
+
// Apply filters
|
|
110
|
+
if (options.startDate && new Date(event.timestamp) < options.startDate)
|
|
111
|
+
continue;
|
|
112
|
+
if (options.endDate && new Date(event.timestamp) > options.endDate)
|
|
113
|
+
continue;
|
|
114
|
+
if (options.surface && event.surface !== options.surface)
|
|
115
|
+
continue;
|
|
116
|
+
if (options.category && event.category !== options.category)
|
|
117
|
+
continue;
|
|
118
|
+
if (options.action && event.action !== options.action)
|
|
119
|
+
continue;
|
|
120
|
+
if (options.actorId && event.actor.id !== options.actorId)
|
|
121
|
+
continue;
|
|
122
|
+
if (options.result && event.result !== options.result)
|
|
123
|
+
continue;
|
|
124
|
+
// Apply pagination
|
|
125
|
+
if (index >= offset && events.length < limit) {
|
|
126
|
+
events.push(event);
|
|
127
|
+
}
|
|
128
|
+
index++;
|
|
129
|
+
if (events.length >= limit)
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
// Skip malformed lines
|
|
134
|
+
console.error(`Skipping malformed audit event: ${e}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return events;
|
|
138
|
+
}
|
|
139
|
+
async tail(count) {
|
|
140
|
+
await this.initialize();
|
|
141
|
+
if (!fs.existsSync(this.filePath)) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
// Read all events and return last N
|
|
145
|
+
const allEvents = [];
|
|
146
|
+
const fileStream = fs.createReadStream(this.filePath);
|
|
147
|
+
const rl = readline.createInterface({
|
|
148
|
+
input: fileStream,
|
|
149
|
+
crlfDelay: Infinity,
|
|
150
|
+
});
|
|
151
|
+
for await (const line of rl) {
|
|
152
|
+
if (!line.trim())
|
|
153
|
+
continue;
|
|
154
|
+
try {
|
|
155
|
+
const event = JSON.parse(line);
|
|
156
|
+
allEvents.push(event);
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
// Skip malformed lines
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return allEvents.slice(-count);
|
|
163
|
+
}
|
|
164
|
+
async validateChain() {
|
|
165
|
+
await this.initialize();
|
|
166
|
+
const result = {
|
|
167
|
+
valid: true,
|
|
168
|
+
totalEvents: 0,
|
|
169
|
+
validEvents: 0,
|
|
170
|
+
invalidEvents: 0,
|
|
171
|
+
brokenLinks: [],
|
|
172
|
+
tamperedEvents: [],
|
|
173
|
+
};
|
|
174
|
+
if (!fs.existsSync(this.filePath)) {
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
const fileStream = fs.createReadStream(this.filePath);
|
|
178
|
+
const rl = readline.createInterface({
|
|
179
|
+
input: fileStream,
|
|
180
|
+
crlfDelay: Infinity,
|
|
181
|
+
});
|
|
182
|
+
let expectedPrevHash = GENESIS_HASH;
|
|
183
|
+
let index = 0;
|
|
184
|
+
for await (const line of rl) {
|
|
185
|
+
if (!line.trim())
|
|
186
|
+
continue;
|
|
187
|
+
try {
|
|
188
|
+
const event = JSON.parse(line);
|
|
189
|
+
result.totalEvents++;
|
|
190
|
+
// Validate hash chain
|
|
191
|
+
if (event.prevHash !== expectedPrevHash) {
|
|
192
|
+
result.valid = false;
|
|
193
|
+
result.invalidEvents++;
|
|
194
|
+
result.brokenLinks.push({
|
|
195
|
+
index,
|
|
196
|
+
eventId: event.id,
|
|
197
|
+
expectedPrevHash,
|
|
198
|
+
actualPrevHash: event.prevHash,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
else if (!(0, events_1.verifyEventHash)(event)) {
|
|
202
|
+
// Validate event hash
|
|
203
|
+
result.valid = false;
|
|
204
|
+
result.invalidEvents++;
|
|
205
|
+
result.tamperedEvents.push({
|
|
206
|
+
index,
|
|
207
|
+
eventId: event.id,
|
|
208
|
+
reason: 'Event hash does not match content',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
result.validEvents++;
|
|
213
|
+
}
|
|
214
|
+
expectedPrevHash = event.hash;
|
|
215
|
+
index++;
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
result.totalEvents++;
|
|
219
|
+
result.invalidEvents++;
|
|
220
|
+
result.tamperedEvents.push({
|
|
221
|
+
index,
|
|
222
|
+
eventId: 'unknown',
|
|
223
|
+
reason: `Malformed JSON: ${e}`,
|
|
224
|
+
});
|
|
225
|
+
index++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
async export(format, options = {}) {
|
|
231
|
+
const events = await this.read({
|
|
232
|
+
startDate: options.startDate,
|
|
233
|
+
endDate: options.endDate,
|
|
234
|
+
});
|
|
235
|
+
if (format === 'json') {
|
|
236
|
+
return JSON.stringify(events, null, 2);
|
|
237
|
+
}
|
|
238
|
+
// CSV export
|
|
239
|
+
const headers = [
|
|
240
|
+
'id',
|
|
241
|
+
'timestamp',
|
|
242
|
+
'actor_id',
|
|
243
|
+
'actor_type',
|
|
244
|
+
'actor_name',
|
|
245
|
+
'surface',
|
|
246
|
+
'category',
|
|
247
|
+
'action',
|
|
248
|
+
'target_type',
|
|
249
|
+
'target_path',
|
|
250
|
+
'tier',
|
|
251
|
+
'result',
|
|
252
|
+
'hash',
|
|
253
|
+
];
|
|
254
|
+
if (options.includeMetadata) {
|
|
255
|
+
headers.push('metadata');
|
|
256
|
+
}
|
|
257
|
+
const rows = events.map(event => {
|
|
258
|
+
const row = [
|
|
259
|
+
event.id,
|
|
260
|
+
event.timestamp,
|
|
261
|
+
event.actor.id,
|
|
262
|
+
event.actor.type,
|
|
263
|
+
event.actor.name ?? '',
|
|
264
|
+
event.surface,
|
|
265
|
+
event.category,
|
|
266
|
+
event.action,
|
|
267
|
+
event.target.type,
|
|
268
|
+
event.target.path ?? '',
|
|
269
|
+
event.tier,
|
|
270
|
+
event.result,
|
|
271
|
+
event.hash,
|
|
272
|
+
];
|
|
273
|
+
if (options.includeMetadata) {
|
|
274
|
+
row.push(JSON.stringify(event.metadata ?? {}));
|
|
275
|
+
}
|
|
276
|
+
return row.map(v => `"${String(v).replace(/"/g, '""')}"`).join(',');
|
|
277
|
+
});
|
|
278
|
+
return [headers.join(','), ...rows].join('\n');
|
|
279
|
+
}
|
|
280
|
+
async clear() {
|
|
281
|
+
if (fs.existsSync(this.filePath)) {
|
|
282
|
+
fs.unlinkSync(this.filePath);
|
|
283
|
+
}
|
|
284
|
+
this.lastHash = GENESIS_HASH;
|
|
285
|
+
this.initialized = false;
|
|
286
|
+
}
|
|
287
|
+
getFilePath() {
|
|
288
|
+
return this.filePath;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
exports.LocalJSONLStorage = LocalJSONLStorage;
|
|
292
|
+
/**
|
|
293
|
+
* Server storage adapter (placeholder for future implementation)
|
|
294
|
+
*/
|
|
295
|
+
class ServerStorageAdapter {
|
|
296
|
+
apiUrl;
|
|
297
|
+
apiKey;
|
|
298
|
+
constructor(apiUrl, apiKey) {
|
|
299
|
+
this.apiUrl = apiUrl;
|
|
300
|
+
this.apiKey = apiKey;
|
|
301
|
+
}
|
|
302
|
+
async append(_event) {
|
|
303
|
+
// TODO: Implement server storage
|
|
304
|
+
void this.apiUrl;
|
|
305
|
+
void this.apiKey;
|
|
306
|
+
throw new Error('Server storage not yet implemented');
|
|
307
|
+
}
|
|
308
|
+
async getLastHash() {
|
|
309
|
+
throw new Error('Server storage not yet implemented');
|
|
310
|
+
}
|
|
311
|
+
async read(_options) {
|
|
312
|
+
throw new Error('Server storage not yet implemented');
|
|
313
|
+
}
|
|
314
|
+
async tail(_count) {
|
|
315
|
+
throw new Error('Server storage not yet implemented');
|
|
316
|
+
}
|
|
317
|
+
async validateChain() {
|
|
318
|
+
throw new Error('Server storage not yet implemented');
|
|
319
|
+
}
|
|
320
|
+
async export(_format, _options) {
|
|
321
|
+
throw new Error('Server storage not yet implemented');
|
|
322
|
+
}
|
|
323
|
+
async clear() {
|
|
324
|
+
throw new Error('Server storage not yet implemented');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
exports.ServerStorageAdapter = ServerStorageAdapter;
|
|
328
|
+
/**
|
|
329
|
+
* Factory function to create storage adapter based on configuration
|
|
330
|
+
*/
|
|
331
|
+
function createStorageAdapter(config) {
|
|
332
|
+
const type = config?.type ?? 'local';
|
|
333
|
+
if (type === 'server' && config?.apiUrl && config?.apiKey) {
|
|
334
|
+
return new ServerStorageAdapter(config.apiUrl, config.apiKey);
|
|
335
|
+
}
|
|
336
|
+
return new LocalJSONLStorage(config?.basePath);
|
|
337
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance-scheduler.test.d.ts","sourceRoot":"","sources":["../../../src/automation/__tests__/compliance-scheduler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const compliance_scheduler_1 = require("../compliance-scheduler");
|
|
4
|
+
const globals_1 = require("@jest/globals");
|
|
5
|
+
// Create mocks for the dependencies
|
|
6
|
+
globals_1.jest.mock("@guardrail/database", () => ({
|
|
7
|
+
prisma: {
|
|
8
|
+
complianceSchedule: {
|
|
9
|
+
findMany: globals_1.jest.fn().mockResolvedValue([]),
|
|
10
|
+
upsert: globals_1.jest.fn(),
|
|
11
|
+
deleteMany: globals_1.jest.fn(),
|
|
12
|
+
update: globals_1.jest.fn(),
|
|
13
|
+
findFirst: globals_1.jest
|
|
14
|
+
.fn()
|
|
15
|
+
.mockImplementation(async ({ where }) => {
|
|
16
|
+
if (where.projectId === "test-project" &&
|
|
17
|
+
where.frameworkId === "test-framework") {
|
|
18
|
+
return {
|
|
19
|
+
id: "test-id",
|
|
20
|
+
projectId: "test-project",
|
|
21
|
+
frameworkId: "test-framework",
|
|
22
|
+
enabled: true,
|
|
23
|
+
schedule: "0 0 * * *",
|
|
24
|
+
notifications: {
|
|
25
|
+
slack: "https://hooks.slack.com/services/test/webhook",
|
|
26
|
+
email: ["test@example.com"],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}),
|
|
32
|
+
},
|
|
33
|
+
project: {
|
|
34
|
+
findUnique: globals_1.jest
|
|
35
|
+
.fn()
|
|
36
|
+
.mockResolvedValue({ id: "test-project", path: "/tmp" }),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
globals_1.jest.mock("../../frameworks/engine", () => ({
|
|
41
|
+
complianceAutomationEngine: {
|
|
42
|
+
// Return structure matching result.result.assessment.summary.score
|
|
43
|
+
assess: globals_1.jest.fn().mockResolvedValue({
|
|
44
|
+
summary: { score: 85 },
|
|
45
|
+
details: {},
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
globals_1.jest.mock("../reporting-engine", () => ({
|
|
50
|
+
reportingEngine: {
|
|
51
|
+
generateReport: globals_1.jest
|
|
52
|
+
.fn()
|
|
53
|
+
.mockResolvedValue({ id: "report-1" }),
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
globals_1.jest.mock("../email-service", () => ({
|
|
57
|
+
emailService: {
|
|
58
|
+
sendComplianceNotification: globals_1.jest
|
|
59
|
+
.fn()
|
|
60
|
+
.mockResolvedValue({
|
|
61
|
+
success: true,
|
|
62
|
+
messageId: "test-message-id",
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
(0, globals_1.describe)("ComplianceScheduler Slack Integration", () => {
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
globals_1.jest.useFakeTimers();
|
|
69
|
+
});
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
globals_1.jest.useRealTimers();
|
|
72
|
+
});
|
|
73
|
+
(0, globals_1.it)("should send Slack notification", async () => {
|
|
74
|
+
// Mock fetch
|
|
75
|
+
const fetchMock = globals_1.jest.fn().mockResolvedValue({
|
|
76
|
+
ok: true,
|
|
77
|
+
json: () => Promise.resolve({}),
|
|
78
|
+
});
|
|
79
|
+
global.fetch = fetchMock;
|
|
80
|
+
// Spy on console.log to check current behavior
|
|
81
|
+
const consoleSpy = globals_1.jest.spyOn(console, "log");
|
|
82
|
+
const scheduler = new compliance_scheduler_1.ComplianceScheduler();
|
|
83
|
+
// Create a mock result
|
|
84
|
+
const mockResult = {
|
|
85
|
+
scheduleId: "test-schedule",
|
|
86
|
+
executionId: "test-execution",
|
|
87
|
+
startTime: new Date(),
|
|
88
|
+
endTime: new Date(),
|
|
89
|
+
status: "completed",
|
|
90
|
+
result: {
|
|
91
|
+
assessment: {
|
|
92
|
+
summary: { score: 85 },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
// Call sendNotifications directly
|
|
97
|
+
await scheduler.sendNotifications("test-project", "test-framework", mockResult);
|
|
98
|
+
(0, globals_1.expect)(fetchMock).toHaveBeenCalledWith("https://hooks.slack.com/services/test/webhook", globals_1.expect.objectContaining({
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: { "Content-Type": "application/json" },
|
|
101
|
+
body: globals_1.expect.stringContaining("Compliance Check WARNING"), // Score is 85, so warning
|
|
102
|
+
}));
|
|
103
|
+
// Verify block structure in body
|
|
104
|
+
const callArgs = fetchMock.mock.calls[0];
|
|
105
|
+
if (callArgs && callArgs.length > 1) {
|
|
106
|
+
const body = JSON.parse(callArgs[1].body);
|
|
107
|
+
(0, globals_1.expect)(body.blocks).toBeDefined();
|
|
108
|
+
// Check for score in fields instead of text
|
|
109
|
+
(0, globals_1.expect)(body.blocks.some((b) => b.fields &&
|
|
110
|
+
b.fields.some((f) => f.text && f.text.includes("85%")))).toBe(true);
|
|
111
|
+
}
|
|
112
|
+
// Check if console log was called
|
|
113
|
+
(0, globals_1.expect)(consoleSpy).toHaveBeenCalledWith(globals_1.expect.stringContaining("Sending Slack notification to https://hooks.slack.com/services/test/webhook"));
|
|
114
|
+
});
|
|
115
|
+
(0, globals_1.it)("should handle Slack errors gracefully", async () => {
|
|
116
|
+
// Mock fetch error
|
|
117
|
+
const fetchMock = globals_1.jest
|
|
118
|
+
.fn()
|
|
119
|
+
.mockRejectedValue(new Error("Network error"));
|
|
120
|
+
global.fetch = fetchMock;
|
|
121
|
+
const consoleErrorSpy = globals_1.jest.spyOn(console, "error");
|
|
122
|
+
const scheduler = new compliance_scheduler_1.ComplianceScheduler();
|
|
123
|
+
// Create a mock result
|
|
124
|
+
const mockResult = {
|
|
125
|
+
scheduleId: "test-schedule",
|
|
126
|
+
executionId: "test-execution",
|
|
127
|
+
startTime: new Date(),
|
|
128
|
+
endTime: new Date(),
|
|
129
|
+
status: "completed",
|
|
130
|
+
result: {
|
|
131
|
+
assessment: {
|
|
132
|
+
summary: { score: 85 },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
// Call sendNotifications directly
|
|
137
|
+
await scheduler.sendNotifications("test-project", "test-framework", mockResult);
|
|
138
|
+
(0, globals_1.expect)(consoleErrorSpy).toHaveBeenCalledWith("Failed to send Slack notification:", globals_1.expect.any(Error));
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
interface AuditEvent {
|
|
2
|
+
id?: string;
|
|
3
|
+
type: string;
|
|
4
|
+
category: 'compliance' | 'security' | 'access' | 'data' | 'system';
|
|
5
|
+
projectId?: string;
|
|
6
|
+
frameworkId?: string;
|
|
7
|
+
userId?: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
metadata?: any;
|
|
11
|
+
details?: any;
|
|
12
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
13
|
+
source: string;
|
|
14
|
+
correlationId?: string;
|
|
15
|
+
ipAddress?: string;
|
|
16
|
+
userAgent?: string;
|
|
17
|
+
}
|
|
18
|
+
interface AuditQuery {
|
|
19
|
+
projectId?: string;
|
|
20
|
+
frameworkId?: string;
|
|
21
|
+
userId?: string;
|
|
22
|
+
type?: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
severity?: string;
|
|
25
|
+
startDate?: Date;
|
|
26
|
+
endDate?: Date;
|
|
27
|
+
limit?: number;
|
|
28
|
+
offset?: number;
|
|
29
|
+
orderBy?: 'timestamp' | 'severity' | 'type';
|
|
30
|
+
orderDirection?: 'asc' | 'desc';
|
|
31
|
+
}
|
|
32
|
+
interface AuditTrail {
|
|
33
|
+
events: AuditEvent[];
|
|
34
|
+
summary: {
|
|
35
|
+
totalEvents: number;
|
|
36
|
+
byType: Record<string, number>;
|
|
37
|
+
byCategory: Record<string, number>;
|
|
38
|
+
bySeverity: Record<string, number>;
|
|
39
|
+
timeRange: {
|
|
40
|
+
start: Date;
|
|
41
|
+
end: Date;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
metadata: {
|
|
45
|
+
hasMore: boolean;
|
|
46
|
+
totalCount: number;
|
|
47
|
+
query: AuditQuery;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Comprehensive Audit Trail Logger
|
|
52
|
+
*
|
|
53
|
+
* Provides tamper-proof logging of all compliance-related activities
|
|
54
|
+
* with chain of custody verification and evidence preservation
|
|
55
|
+
*/
|
|
56
|
+
export declare class AuditLogger {
|
|
57
|
+
private readonly sequenceCounters;
|
|
58
|
+
/**
|
|
59
|
+
* Log an audit event
|
|
60
|
+
*/
|
|
61
|
+
logEvent(event: AuditEvent): Promise<string>;
|
|
62
|
+
/**
|
|
63
|
+
* Log compliance check start
|
|
64
|
+
*/
|
|
65
|
+
logComplianceCheckStart(projectId: string, frameworkId: string, executionId: string, metadata?: any): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Log compliance check completion
|
|
68
|
+
*/
|
|
69
|
+
logComplianceCheckComplete(projectId: string, frameworkId: string, executionId: string, result: any, metadata?: any): Promise<string>;
|
|
70
|
+
/**
|
|
71
|
+
* Log evidence collection
|
|
72
|
+
*/
|
|
73
|
+
logEvidenceCollection(projectId: string, frameworkId: string, collectionId: string, artifactCount: number, metadata?: any): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Log compliance violation
|
|
76
|
+
*/
|
|
77
|
+
logViolation(projectId: string, frameworkId: string, controlId: string, violation: any, severity?: 'medium' | 'high' | 'critical'): Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Log remediation action
|
|
80
|
+
*/
|
|
81
|
+
logRemediation(projectId: string, frameworkId: string, controlId: string, action: string, userId?: string): Promise<string>;
|
|
82
|
+
/**
|
|
83
|
+
* Log access to compliance data
|
|
84
|
+
*/
|
|
85
|
+
logAccess(projectId: string, userId: string, action: string, resource: string, metadata?: any): Promise<string>;
|
|
86
|
+
/**
|
|
87
|
+
* Query audit trail
|
|
88
|
+
*/
|
|
89
|
+
query(query: AuditQuery): Promise<AuditTrail>;
|
|
90
|
+
/**
|
|
91
|
+
* Get audit trail for a specific time period
|
|
92
|
+
*/
|
|
93
|
+
getAuditTrail(projectId: string, startDate: Date, endDate: Date): Promise<AuditTrail>;
|
|
94
|
+
/**
|
|
95
|
+
* Verify audit trail integrity
|
|
96
|
+
*/
|
|
97
|
+
verifyIntegrity(projectId?: string): Promise<{
|
|
98
|
+
valid: boolean;
|
|
99
|
+
totalEvents: number;
|
|
100
|
+
violations: Array<{
|
|
101
|
+
eventId: string;
|
|
102
|
+
sequenceNumber: number;
|
|
103
|
+
issue: string;
|
|
104
|
+
}>;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Store audit event in database
|
|
108
|
+
*/
|
|
109
|
+
private storeEvent;
|
|
110
|
+
/**
|
|
111
|
+
* Calculate hash for event
|
|
112
|
+
*/
|
|
113
|
+
private calculateHash;
|
|
114
|
+
/**
|
|
115
|
+
* Determine severity based on compliance result
|
|
116
|
+
*/
|
|
117
|
+
private determineSeverity;
|
|
118
|
+
/**
|
|
119
|
+
* Log to external systems for redundancy
|
|
120
|
+
*/
|
|
121
|
+
private logToExternalSystems;
|
|
122
|
+
/**
|
|
123
|
+
* Generate summary statistics
|
|
124
|
+
*/
|
|
125
|
+
private generateSummary;
|
|
126
|
+
}
|
|
127
|
+
export declare const auditLogger: AuditLogger;
|
|
128
|
+
export {};
|
|
129
|
+
//# sourceMappingURL=audit-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.d.ts","sourceRoot":"","sources":["../../src/automation/audit-logger.ts"],"names":[],"mappings":"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"}
|