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.
Files changed (149) hide show
  1. package/dist/audit/emitter.d.ts +97 -0
  2. package/dist/audit/emitter.d.ts.map +1 -0
  3. package/dist/audit/emitter.js +197 -0
  4. package/dist/audit/events.d.ts +304 -0
  5. package/dist/audit/events.d.ts.map +1 -0
  6. package/dist/audit/events.js +267 -0
  7. package/dist/audit/index.d.ts +11 -0
  8. package/dist/audit/index.d.ts.map +1 -0
  9. package/dist/audit/index.js +51 -0
  10. package/dist/audit/storage.d.ts +93 -0
  11. package/dist/audit/storage.d.ts.map +1 -0
  12. package/dist/audit/storage.js +337 -0
  13. package/dist/automation/__tests__/compliance-scheduler.test.d.ts +2 -0
  14. package/dist/automation/__tests__/compliance-scheduler.test.d.ts.map +1 -0
  15. package/dist/automation/__tests__/compliance-scheduler.test.js +140 -0
  16. package/dist/automation/audit-logger.d.ts +129 -0
  17. package/dist/automation/audit-logger.d.ts.map +1 -0
  18. package/dist/automation/audit-logger.js +473 -0
  19. package/dist/automation/compliance-scheduler-fixed.d.ts +1 -0
  20. package/dist/automation/compliance-scheduler-fixed.d.ts.map +1 -0
  21. package/dist/automation/compliance-scheduler-fixed.js +1 -0
  22. package/dist/automation/compliance-scheduler.d.ts +83 -0
  23. package/dist/automation/compliance-scheduler.d.ts.map +1 -0
  24. package/dist/automation/compliance-scheduler.js +414 -0
  25. package/dist/automation/dashboard.d.ts +194 -0
  26. package/dist/automation/dashboard.d.ts.map +1 -0
  27. package/dist/automation/dashboard.js +768 -0
  28. package/dist/automation/email-service.d.ts +69 -0
  29. package/dist/automation/email-service.d.ts.map +1 -0
  30. package/dist/automation/email-service.js +218 -0
  31. package/dist/automation/evidence-collector.d.ts +140 -0
  32. package/dist/automation/evidence-collector.d.ts.map +1 -0
  33. package/dist/automation/evidence-collector.js +682 -0
  34. package/dist/automation/index.d.ts +8 -0
  35. package/dist/automation/index.d.ts.map +1 -0
  36. package/dist/automation/index.js +24 -0
  37. package/dist/automation/pdf-exporter.d.ts +90 -0
  38. package/dist/automation/pdf-exporter.d.ts.map +1 -0
  39. package/dist/automation/pdf-exporter.js +381 -0
  40. package/dist/automation/reporting-engine.d.ts +116 -0
  41. package/dist/automation/reporting-engine.d.ts.map +1 -0
  42. package/dist/automation/reporting-engine.js +329 -0
  43. package/dist/container/index.d.ts +4 -0
  44. package/dist/container/index.d.ts.map +1 -0
  45. package/dist/container/index.js +19 -0
  46. package/dist/container/kubernetes.d.ts +94 -0
  47. package/dist/container/kubernetes.d.ts.map +1 -0
  48. package/dist/container/kubernetes.js +268 -0
  49. package/dist/container/rules.d.ts +27 -0
  50. package/dist/container/rules.d.ts.map +1 -0
  51. package/dist/container/rules.js +216 -0
  52. package/dist/container/scanner.d.ts +50 -0
  53. package/dist/container/scanner.d.ts.map +1 -0
  54. package/dist/container/scanner.js +143 -0
  55. package/dist/frameworks/engine.d.ts +108 -0
  56. package/dist/frameworks/engine.d.ts.map +1 -0
  57. package/dist/frameworks/engine.js +206 -0
  58. package/dist/frameworks/gdpr.d.ts +6 -0
  59. package/dist/frameworks/gdpr.d.ts.map +1 -0
  60. package/dist/frameworks/gdpr.js +198 -0
  61. package/dist/frameworks/hipaa.d.ts +6 -0
  62. package/dist/frameworks/hipaa.d.ts.map +1 -0
  63. package/dist/frameworks/hipaa.js +183 -0
  64. package/dist/frameworks/index.d.ts +8 -0
  65. package/dist/frameworks/index.d.ts.map +1 -0
  66. package/dist/frameworks/index.js +30 -0
  67. package/dist/frameworks/iso27001.d.ts +63 -0
  68. package/dist/frameworks/iso27001.d.ts.map +1 -0
  69. package/dist/frameworks/iso27001.js +331 -0
  70. package/dist/frameworks/nist.d.ts +62 -0
  71. package/dist/frameworks/nist.d.ts.map +1 -0
  72. package/dist/frameworks/nist.js +424 -0
  73. package/dist/frameworks/pci.d.ts +6 -0
  74. package/dist/frameworks/pci.d.ts.map +1 -0
  75. package/dist/frameworks/pci.js +201 -0
  76. package/dist/frameworks/soc2.d.ts +7 -0
  77. package/dist/frameworks/soc2.d.ts.map +1 -0
  78. package/dist/frameworks/soc2.js +248 -0
  79. package/dist/iac/drift-detector.d.ts +64 -0
  80. package/dist/iac/drift-detector.d.ts.map +1 -0
  81. package/dist/iac/drift-detector.js +134 -0
  82. package/dist/iac/index.d.ts +4 -0
  83. package/dist/iac/index.d.ts.map +1 -0
  84. package/dist/iac/index.js +19 -0
  85. package/dist/iac/rules.d.ts +17 -0
  86. package/dist/iac/rules.d.ts.map +1 -0
  87. package/dist/iac/rules.js +385 -0
  88. package/dist/iac/scanner.d.ts +104 -0
  89. package/dist/iac/scanner.d.ts.map +1 -0
  90. package/dist/iac/scanner.js +343 -0
  91. package/dist/index.d.ts +7 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +28 -0
  94. package/dist/pii/data-flow.d.ts +58 -0
  95. package/dist/pii/data-flow.d.ts.map +1 -0
  96. package/dist/pii/data-flow.js +154 -0
  97. package/dist/pii/detector.d.ts +60 -0
  98. package/dist/pii/detector.d.ts.map +1 -0
  99. package/dist/pii/detector.js +267 -0
  100. package/dist/pii/index.d.ts +4 -0
  101. package/dist/pii/index.d.ts.map +1 -0
  102. package/dist/pii/index.js +19 -0
  103. package/dist/pii/patterns.d.ts +36 -0
  104. package/dist/pii/patterns.d.ts.map +1 -0
  105. package/dist/pii/patterns.js +108 -0
  106. package/dist/policy/index.d.ts +5 -0
  107. package/dist/policy/index.d.ts.map +1 -0
  108. package/dist/policy/index.js +20 -0
  109. package/dist/policy/opa-engine.d.ts +121 -0
  110. package/dist/policy/opa-engine.d.ts.map +1 -0
  111. package/dist/policy/opa-engine.js +423 -0
  112. package/package.json +31 -0
  113. package/src/audit/emitter.ts +383 -0
  114. package/src/audit/events.ts +351 -0
  115. package/src/audit/index.ts +35 -0
  116. package/src/audit/storage.ts +394 -0
  117. package/src/automation/__tests__/compliance-scheduler.test.ts +183 -0
  118. package/src/automation/audit-logger.ts +629 -0
  119. package/src/automation/compliance-scheduler-fixed.ts +0 -0
  120. package/src/automation/compliance-scheduler.ts +516 -0
  121. package/src/automation/dashboard.ts +947 -0
  122. package/src/automation/email-service.ts +230 -0
  123. package/src/automation/evidence-collector.ts +866 -0
  124. package/src/automation/index.ts +8 -0
  125. package/src/automation/pdf-exporter.ts +434 -0
  126. package/src/automation/reporting-engine.ts +462 -0
  127. package/src/container/index.ts +3 -0
  128. package/src/container/kubernetes.ts +379 -0
  129. package/src/container/rules.ts +244 -0
  130. package/src/container/scanner.ts +202 -0
  131. package/src/frameworks/engine.ts +298 -0
  132. package/src/frameworks/gdpr.ts +204 -0
  133. package/src/frameworks/hipaa.ts +209 -0
  134. package/src/frameworks/index.ts +23 -0
  135. package/src/frameworks/iso27001.ts +398 -0
  136. package/src/frameworks/nist.ts +518 -0
  137. package/src/frameworks/pci.ts +226 -0
  138. package/src/frameworks/soc2.ts +281 -0
  139. package/src/iac/drift-detector.ts +197 -0
  140. package/src/iac/index.ts +3 -0
  141. package/src/iac/rules.ts +420 -0
  142. package/src/iac/scanner.ts +445 -0
  143. package/src/index.ts +17 -0
  144. package/src/pii/data-flow.ts +216 -0
  145. package/src/pii/detector.ts +327 -0
  146. package/src/pii/index.ts +3 -0
  147. package/src/pii/patterns.ts +128 -0
  148. package/src/policy/index.ts +5 -0
  149. package/src/policy/opa-engine.ts +504 -0
@@ -0,0 +1,504 @@
1
+ /**
2
+ * Policy as Code Engine (OPA/Rego Integration)
3
+ *
4
+ * Enables custom security policies using Open Policy Agent and Rego language
5
+ * Supports:
6
+ * - Custom policy definitions
7
+ * - Policy evaluation against code/config
8
+ * - Policy bundles and versioning
9
+ * - Decision logging and auditing
10
+ */
11
+
12
+ export interface Policy {
13
+ id: string;
14
+ name: string;
15
+ description: string;
16
+ version: string;
17
+ rego: string;
18
+ category: 'security' | 'compliance' | 'quality' | 'access' | 'custom';
19
+ severity: 'low' | 'medium' | 'high' | 'critical';
20
+ enabled: boolean;
21
+ tags: string[];
22
+ }
23
+
24
+ export interface PolicyInput {
25
+ type: 'code' | 'config' | 'dependency' | 'request' | 'action';
26
+ data: Record<string, unknown>;
27
+ context?: {
28
+ user?: string;
29
+ project?: string;
30
+ environment?: string;
31
+ };
32
+ }
33
+
34
+ export interface PolicyDecision {
35
+ policyId: string;
36
+ allowed: boolean;
37
+ violations: PolicyViolation[];
38
+ warnings: string[];
39
+ metadata: Record<string, unknown>;
40
+ evaluatedAt: string;
41
+ durationMs: number;
42
+ }
43
+
44
+ export interface PolicyViolation {
45
+ rule: string;
46
+ message: string;
47
+ severity: 'low' | 'medium' | 'high' | 'critical';
48
+ remediation?: string;
49
+ location?: {
50
+ file?: string;
51
+ line?: number;
52
+ column?: number;
53
+ };
54
+ }
55
+
56
+ export interface PolicyBundle {
57
+ id: string;
58
+ name: string;
59
+ version: string;
60
+ policies: Policy[];
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ }
64
+
65
+ // Built-in policy templates
66
+ export const BUILTIN_POLICIES: Policy[] = [
67
+ {
68
+ id: 'no-hardcoded-secrets',
69
+ name: 'No Hardcoded Secrets',
70
+ description: 'Prevents hardcoded secrets in source code',
71
+ version: '1.0.0',
72
+ category: 'security',
73
+ severity: 'critical',
74
+ enabled: true,
75
+ tags: ['secrets', 'security', 'owasp'],
76
+ rego: `
77
+ package Guardrail.secrets
78
+
79
+ default allow = true
80
+ default violations = []
81
+
82
+ secret_patterns := [
83
+ "api[_-]?key\\\\s*[=:]\\\\s*['\\\"][^'\\\"]{10,}",
84
+ "password\\\\s*[=:]\\\\s*['\\\"][^'\\\"]{6,}",
85
+ "secret\\\\s*[=:]\\\\s*['\\\"][^'\\\"]{10,}",
86
+ "token\\\\s*[=:]\\\\s*['\\\"][^'\\\"]{10,}",
87
+ "aws_access_key_id",
88
+ "aws_secret_access_key"
89
+ ]
90
+
91
+ violations[v] {
92
+ pattern := secret_patterns[_]
93
+ regex.match(pattern, lower(input.content))
94
+ v := {
95
+ "rule": "no-hardcoded-secrets",
96
+ "message": sprintf("Potential secret detected matching pattern: %s", [pattern]),
97
+ "severity": "critical"
98
+ }
99
+ }
100
+
101
+ allow {
102
+ count(violations) == 0
103
+ }
104
+ `,
105
+ },
106
+ {
107
+ id: 'secure-dependencies',
108
+ name: 'Secure Dependencies',
109
+ description: 'Ensures dependencies meet security requirements',
110
+ version: '1.0.0',
111
+ category: 'security',
112
+ severity: 'high',
113
+ enabled: true,
114
+ tags: ['dependencies', 'supply-chain'],
115
+ rego: `
116
+ package Guardrail.dependencies
117
+
118
+ default allow = true
119
+ default violations = []
120
+
121
+ blocked_packages := [
122
+ "event-stream",
123
+ "flatmap-stream",
124
+ "ua-parser-js@0.7.29"
125
+ ]
126
+
127
+ violations[v] {
128
+ pkg := input.dependencies[_]
129
+ blocked := blocked_packages[_]
130
+ contains(sprintf("%s@%s", [pkg.name, pkg.version]), blocked)
131
+ v := {
132
+ "rule": "blocked-package",
133
+ "message": sprintf("Blocked package detected: %s@%s", [pkg.name, pkg.version]),
134
+ "severity": "critical"
135
+ }
136
+ }
137
+
138
+ violations[v] {
139
+ pkg := input.dependencies[_]
140
+ pkg.vulnerabilities[_].severity == "critical"
141
+ v := {
142
+ "rule": "critical-vulnerability",
143
+ "message": sprintf("Critical vulnerability in %s@%s", [pkg.name, pkg.version]),
144
+ "severity": "critical"
145
+ }
146
+ }
147
+
148
+ allow {
149
+ count(violations) == 0
150
+ }
151
+ `,
152
+ },
153
+ {
154
+ id: 'license-compliance',
155
+ name: 'License Compliance',
156
+ description: 'Ensures dependency licenses are compliant',
157
+ version: '1.0.0',
158
+ category: 'compliance',
159
+ severity: 'high',
160
+ enabled: true,
161
+ tags: ['license', 'compliance', 'legal'],
162
+ rego: `
163
+ package Guardrail.licenses
164
+
165
+ default allow = true
166
+ default violations = []
167
+
168
+ copyleft_licenses := ["GPL-2.0", "GPL-3.0", "AGPL-3.0"]
169
+
170
+ violations[v] {
171
+ input.project_license == "MIT"
172
+ pkg := input.dependencies[_]
173
+ copyleft := copyleft_licenses[_]
174
+ pkg.license == copyleft
175
+ v := {
176
+ "rule": "copyleft-contamination",
177
+ "message": sprintf("Copyleft license %s in %s incompatible with MIT project", [pkg.license, pkg.name]),
178
+ "severity": "high"
179
+ }
180
+ }
181
+
182
+ allow {
183
+ count(violations) == 0
184
+ }
185
+ `,
186
+ },
187
+ {
188
+ id: 'agent-permissions',
189
+ name: 'AI Agent Permission Control',
190
+ description: 'Controls what AI agents can do',
191
+ version: '1.0.0',
192
+ category: 'access',
193
+ severity: 'high',
194
+ enabled: true,
195
+ tags: ['ai', 'agent', 'permissions'],
196
+ rego: `
197
+ package Guardrail.agent
198
+
199
+ default allow = false
200
+
201
+ dangerous_paths := ["/etc", "/root", "/var/log", "C:\\\\Windows\\\\System32"]
202
+ dangerous_commands := ["rm -rf", "del /f", "format", "shutdown", "reboot"]
203
+
204
+ allow {
205
+ input.action.type == "read"
206
+ not path_is_dangerous(input.action.path)
207
+ }
208
+
209
+ allow {
210
+ input.action.type == "write"
211
+ input.agent.permissions.write == true
212
+ not path_is_dangerous(input.action.path)
213
+ }
214
+
215
+ path_is_dangerous(path) {
216
+ dangerous := dangerous_paths[_]
217
+ startswith(path, dangerous)
218
+ }
219
+
220
+ command_is_dangerous(cmd) {
221
+ dangerous := dangerous_commands[_]
222
+ contains(lower(cmd), dangerous)
223
+ }
224
+
225
+ violations[v] {
226
+ input.action.type == "execute"
227
+ command_is_dangerous(input.action.command)
228
+ v := {
229
+ "rule": "dangerous-command",
230
+ "message": sprintf("Dangerous command blocked: %s", [input.action.command]),
231
+ "severity": "critical"
232
+ }
233
+ }
234
+ `,
235
+ },
236
+ {
237
+ id: 'code-quality',
238
+ name: 'Code Quality Standards',
239
+ description: 'Enforces code quality standards',
240
+ version: '1.0.0',
241
+ category: 'quality',
242
+ severity: 'medium',
243
+ enabled: true,
244
+ tags: ['quality', 'standards'],
245
+ rego: `
246
+ package Guardrail.quality
247
+
248
+ default allow = true
249
+ default violations = []
250
+
251
+ violations[v] {
252
+ input.metrics.complexity > 20
253
+ v := {
254
+ "rule": "high-complexity",
255
+ "message": sprintf("Cyclomatic complexity %d exceeds threshold 20", [input.metrics.complexity]),
256
+ "severity": "medium"
257
+ }
258
+ }
259
+
260
+ violations[v] {
261
+ input.metrics.lines_of_code > 500
262
+ v := {
263
+ "rule": "large-file",
264
+ "message": sprintf("File has %d lines, exceeds threshold 500", [input.metrics.lines_of_code]),
265
+ "severity": "low"
266
+ }
267
+ }
268
+
269
+ violations[v] {
270
+ input.metrics.test_coverage < 60
271
+ v := {
272
+ "rule": "low-coverage",
273
+ "message": sprintf("Test coverage %d%% below threshold 60%%", [input.metrics.test_coverage]),
274
+ "severity": "medium"
275
+ }
276
+ }
277
+
278
+ allow {
279
+ count(violations) == 0
280
+ }
281
+ `,
282
+ },
283
+ ];
284
+
285
+ /**
286
+ * Policy Engine for evaluating Rego policies
287
+ */
288
+ export class PolicyEngine {
289
+ private policies: Map<string, Policy> = new Map();
290
+ private decisionLog: PolicyDecision[] = [];
291
+
292
+ constructor() {
293
+ // Load built-in policies
294
+ for (const policy of BUILTIN_POLICIES) {
295
+ this.policies.set(policy.id, policy);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Register a custom policy
301
+ */
302
+ registerPolicy(policy: Policy): void {
303
+ this.policies.set(policy.id, policy);
304
+ }
305
+
306
+ /**
307
+ * Remove a policy
308
+ */
309
+ removePolicy(policyId: string): boolean {
310
+ return this.policies.delete(policyId);
311
+ }
312
+
313
+ /**
314
+ * Get all registered policies
315
+ */
316
+ getPolicies(): Policy[] {
317
+ return Array.from(this.policies.values());
318
+ }
319
+
320
+ /**
321
+ * Get a specific policy
322
+ */
323
+ getPolicy(policyId: string): Policy | undefined {
324
+ return this.policies.get(policyId);
325
+ }
326
+
327
+ /**
328
+ * Evaluate input against all enabled policies
329
+ */
330
+ async evaluate(input: PolicyInput): Promise<PolicyDecision[]> {
331
+ const decisions: PolicyDecision[] = [];
332
+
333
+ for (const policy of this.policies.values()) {
334
+ if (!policy.enabled) continue;
335
+
336
+ const decision = await this.evaluatePolicy(policy, input);
337
+ decisions.push(decision);
338
+ this.decisionLog.push(decision);
339
+ }
340
+
341
+ return decisions;
342
+ }
343
+
344
+ /**
345
+ * Evaluate input against a specific policy
346
+ */
347
+ async evaluatePolicy(policy: Policy, input: PolicyInput): Promise<PolicyDecision> {
348
+ const startTime = Date.now();
349
+
350
+ try {
351
+ // In a real implementation, this would use an OPA client or WASM module
352
+ // For now, we use a simplified JavaScript-based evaluation
353
+ const result = await this.evaluateRego(policy.rego, input);
354
+
355
+ const violations: PolicyViolation[] = (result.violations || []).map((v: any) => ({
356
+ rule: v.rule || policy.id,
357
+ message: v.message || 'Policy violation',
358
+ severity: v.severity || policy.severity,
359
+ remediation: v.remediation,
360
+ location: v.location,
361
+ }));
362
+
363
+ return {
364
+ policyId: policy.id,
365
+ allowed: result.allow !== false && violations.length === 0,
366
+ violations,
367
+ warnings: result.warnings || [],
368
+ metadata: { policyVersion: policy.version },
369
+ evaluatedAt: new Date().toISOString(),
370
+ durationMs: Date.now() - startTime,
371
+ };
372
+ } catch (error) {
373
+ return {
374
+ policyId: policy.id,
375
+ allowed: false,
376
+ violations: [{
377
+ rule: 'policy-error',
378
+ message: `Policy evaluation failed: ${error}`,
379
+ severity: 'high',
380
+ }],
381
+ warnings: [],
382
+ metadata: { error: String(error) },
383
+ evaluatedAt: new Date().toISOString(),
384
+ durationMs: Date.now() - startTime,
385
+ };
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Simplified Rego evaluation (placeholder for OPA integration)
391
+ * In production, this would use @open-policy-agent/opa-wasm or call OPA server
392
+ */
393
+ private async evaluateRego(
394
+ _rego: string,
395
+ input: PolicyInput
396
+ ): Promise<{ allow: boolean; violations: any[]; warnings: string[] }> {
397
+ const violations: any[] = [];
398
+ const warnings: string[] = [];
399
+ let allow = true;
400
+
401
+ const data = input.data as any;
402
+
403
+ // Basic pattern matching for demonstration
404
+ // Real implementation would parse and evaluate Rego
405
+
406
+ // Check for secrets in content
407
+ if (data.content) {
408
+ const secretPatterns = [
409
+ /api[_-]?key\s*[=:]\s*['"][^'"]{10,}/i,
410
+ /password\s*[=:]\s*['"][^'"]{6,}/i,
411
+ /secret\s*[=:]\s*['"][^'"]{10,}/i,
412
+ ];
413
+
414
+ for (const pattern of secretPatterns) {
415
+ if (pattern.test(data.content)) {
416
+ violations.push({
417
+ rule: 'no-hardcoded-secrets',
418
+ message: 'Potential hardcoded secret detected',
419
+ severity: 'critical',
420
+ });
421
+ allow = false;
422
+ }
423
+ }
424
+ }
425
+
426
+ // Check for dangerous dependencies
427
+ if (data.dependencies) {
428
+ const blocked = ['event-stream', 'flatmap-stream'];
429
+ for (const dep of data.dependencies) {
430
+ if (blocked.includes(dep.name)) {
431
+ violations.push({
432
+ rule: 'blocked-package',
433
+ message: `Blocked package: ${dep.name}`,
434
+ severity: 'critical',
435
+ });
436
+ allow = false;
437
+ }
438
+ }
439
+ }
440
+
441
+ return { allow, violations, warnings };
442
+ }
443
+
444
+ /**
445
+ * Get decision log
446
+ */
447
+ getDecisionLog(): PolicyDecision[] {
448
+ return [...this.decisionLog];
449
+ }
450
+
451
+ /**
452
+ * Clear decision log
453
+ */
454
+ clearDecisionLog(): void {
455
+ this.decisionLog = [];
456
+ }
457
+
458
+ /**
459
+ * Export policies as a bundle
460
+ */
461
+ exportBundle(name: string): PolicyBundle {
462
+ return {
463
+ id: `bundle-${Date.now()}`,
464
+ name,
465
+ version: '1.0.0',
466
+ policies: this.getPolicies(),
467
+ createdAt: new Date().toISOString(),
468
+ updatedAt: new Date().toISOString(),
469
+ };
470
+ }
471
+
472
+ /**
473
+ * Import policies from a bundle
474
+ */
475
+ importBundle(bundle: PolicyBundle): void {
476
+ for (const policy of bundle.policies) {
477
+ this.registerPolicy(policy);
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Validate Rego syntax (placeholder)
483
+ */
484
+ validateRego(rego: string): { valid: boolean; errors: string[] } {
485
+ const errors: string[] = [];
486
+
487
+ // Basic syntax checks
488
+ if (!rego.includes('package ')) {
489
+ errors.push('Missing package declaration');
490
+ }
491
+
492
+ if (!rego.includes('default ') && !rego.includes('allow') && !rego.includes('deny')) {
493
+ errors.push('Policy should define allow or deny rules');
494
+ }
495
+
496
+ return {
497
+ valid: errors.length === 0,
498
+ errors,
499
+ };
500
+ }
501
+ }
502
+
503
+ // Export singleton
504
+ export const policyEngine = new PolicyEngine();