aura-security 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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +446 -0
  3. package/deploy/AWS-DEPLOYMENT.md +358 -0
  4. package/deploy/terraform/main.tf +362 -0
  5. package/deploy/terraform/terraform.tfvars.example +6 -0
  6. package/dist/agents/base.d.ts +44 -0
  7. package/dist/agents/base.js +96 -0
  8. package/dist/agents/index.d.ts +14 -0
  9. package/dist/agents/index.js +17 -0
  10. package/dist/agents/policy/evaluator.d.ts +15 -0
  11. package/dist/agents/policy/evaluator.js +183 -0
  12. package/dist/agents/policy/index.d.ts +12 -0
  13. package/dist/agents/policy/index.js +15 -0
  14. package/dist/agents/policy/validator.d.ts +15 -0
  15. package/dist/agents/policy/validator.js +182 -0
  16. package/dist/agents/scanners/gitleaks.d.ts +14 -0
  17. package/dist/agents/scanners/gitleaks.js +155 -0
  18. package/dist/agents/scanners/grype.d.ts +14 -0
  19. package/dist/agents/scanners/grype.js +109 -0
  20. package/dist/agents/scanners/index.d.ts +15 -0
  21. package/dist/agents/scanners/index.js +27 -0
  22. package/dist/agents/scanners/npm-audit.d.ts +13 -0
  23. package/dist/agents/scanners/npm-audit.js +129 -0
  24. package/dist/agents/scanners/semgrep.d.ts +14 -0
  25. package/dist/agents/scanners/semgrep.js +131 -0
  26. package/dist/agents/scanners/trivy.d.ts +14 -0
  27. package/dist/agents/scanners/trivy.js +122 -0
  28. package/dist/agents/types.d.ts +137 -0
  29. package/dist/agents/types.js +91 -0
  30. package/dist/auditor/index.d.ts +3 -0
  31. package/dist/auditor/index.js +2 -0
  32. package/dist/auditor/pipeline.d.ts +19 -0
  33. package/dist/auditor/pipeline.js +240 -0
  34. package/dist/auditor/validator.d.ts +17 -0
  35. package/dist/auditor/validator.js +58 -0
  36. package/dist/aura/client.d.ts +29 -0
  37. package/dist/aura/client.js +125 -0
  38. package/dist/aura/index.d.ts +4 -0
  39. package/dist/aura/index.js +2 -0
  40. package/dist/aura/server.d.ts +45 -0
  41. package/dist/aura/server.js +343 -0
  42. package/dist/cli.d.ts +17 -0
  43. package/dist/cli.js +1433 -0
  44. package/dist/client/index.d.ts +41 -0
  45. package/dist/client/index.js +170 -0
  46. package/dist/compliance/index.d.ts +40 -0
  47. package/dist/compliance/index.js +292 -0
  48. package/dist/database/index.d.ts +77 -0
  49. package/dist/database/index.js +395 -0
  50. package/dist/index.d.ts +25 -0
  51. package/dist/index.js +762 -0
  52. package/dist/integrations/aura-scanner.d.ts +69 -0
  53. package/dist/integrations/aura-scanner.js +155 -0
  54. package/dist/integrations/aws-scanner.d.ts +63 -0
  55. package/dist/integrations/aws-scanner.js +624 -0
  56. package/dist/integrations/config.d.ts +69 -0
  57. package/dist/integrations/config.js +212 -0
  58. package/dist/integrations/github.d.ts +45 -0
  59. package/dist/integrations/github.js +201 -0
  60. package/dist/integrations/gitlab.d.ts +36 -0
  61. package/dist/integrations/gitlab.js +110 -0
  62. package/dist/integrations/index.d.ts +11 -0
  63. package/dist/integrations/index.js +11 -0
  64. package/dist/integrations/local-scanner.d.ts +146 -0
  65. package/dist/integrations/local-scanner.js +1654 -0
  66. package/dist/integrations/notifications.d.ts +99 -0
  67. package/dist/integrations/notifications.js +305 -0
  68. package/dist/integrations/scanners.d.ts +57 -0
  69. package/dist/integrations/scanners.js +217 -0
  70. package/dist/integrations/slop-scanner.d.ts +69 -0
  71. package/dist/integrations/slop-scanner.js +155 -0
  72. package/dist/integrations/webhook.d.ts +37 -0
  73. package/dist/integrations/webhook.js +256 -0
  74. package/dist/orchestrator/index.d.ts +72 -0
  75. package/dist/orchestrator/index.js +187 -0
  76. package/dist/output/index.d.ts +152 -0
  77. package/dist/output/index.js +399 -0
  78. package/dist/pipeline/index.d.ts +72 -0
  79. package/dist/pipeline/index.js +313 -0
  80. package/dist/sbom/index.d.ts +94 -0
  81. package/dist/sbom/index.js +298 -0
  82. package/dist/schemas/index.d.ts +2 -0
  83. package/dist/schemas/index.js +2 -0
  84. package/dist/schemas/input.schema.d.ts +87 -0
  85. package/dist/schemas/input.schema.js +44 -0
  86. package/dist/schemas/output.schema.d.ts +115 -0
  87. package/dist/schemas/output.schema.js +64 -0
  88. package/dist/serve-visualizer.d.ts +2 -0
  89. package/dist/serve-visualizer.js +78 -0
  90. package/dist/slop/client.d.ts +29 -0
  91. package/dist/slop/client.js +125 -0
  92. package/dist/slop/index.d.ts +4 -0
  93. package/dist/slop/index.js +2 -0
  94. package/dist/slop/server.d.ts +45 -0
  95. package/dist/slop/server.js +343 -0
  96. package/dist/types/events.d.ts +62 -0
  97. package/dist/types/events.js +2 -0
  98. package/dist/types/index.d.ts +1 -0
  99. package/dist/types/index.js +1 -0
  100. package/dist/visualizer/index.d.ts +4 -0
  101. package/dist/visualizer/index.js +181 -0
  102. package/dist/websocket/index.d.ts +88 -0
  103. package/dist/websocket/index.js +195 -0
  104. package/dist/zones/index.d.ts +7 -0
  105. package/dist/zones/index.js +7 -0
  106. package/dist/zones/manager.d.ts +101 -0
  107. package/dist/zones/manager.js +304 -0
  108. package/dist/zones/types.d.ts +78 -0
  109. package/dist/zones/types.js +33 -0
  110. package/package.json +84 -0
  111. package/visualizer/app.js +0 -0
  112. package/visualizer/index-minimal.html +1771 -0
  113. package/visualizer/index.html +2933 -0
  114. package/visualizer/landing.html +1328 -0
  115. package/visualizer/styles.css +0 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Aura Protocol - Trivy Agent
3
+ *
4
+ * Scans for vulnerabilities in dependencies and containers.
5
+ */
6
+ import { BaseAgent } from '../base.js';
7
+ const CONFIG = {
8
+ id: 'trivy',
9
+ name: 'Trivy',
10
+ role: 'scanner',
11
+ description: 'Scan for vulnerabilities in dependencies and containers',
12
+ enabled: true,
13
+ externalTool: 'trivy',
14
+ };
15
+ const CAPABILITIES = {
16
+ fileTypes: ['package.json', 'package-lock.json', 'requirements.txt', 'Gemfile', 'go.mod', 'Cargo.toml'],
17
+ languages: ['javascript', 'typescript', 'python', 'ruby', 'go', 'rust'],
18
+ requiresExternalTool: true,
19
+ supportsParallel: true,
20
+ };
21
+ export class TrivyAgent extends BaseAgent {
22
+ constructor() {
23
+ super(CONFIG, CAPABILITIES);
24
+ }
25
+ async execute(context) {
26
+ const startTime = Date.now();
27
+ this.status = 'running';
28
+ const findings = [];
29
+ try {
30
+ context.log('info', `Trivy scanning: ${context.targetPath}`);
31
+ // Run trivy filesystem scan
32
+ const { stdout, stderr, exitCode } = await this.executeCommand('trivy', [
33
+ 'fs',
34
+ '--format',
35
+ 'json',
36
+ '--scanners',
37
+ 'vuln',
38
+ '--skip-dirs',
39
+ 'node_modules,.git,dist,build',
40
+ context.targetPath,
41
+ ], { cwd: context.targetPath, timeout: 300000 });
42
+ if (stdout.trim()) {
43
+ try {
44
+ const output = JSON.parse(stdout);
45
+ if (output.Results) {
46
+ for (const result of output.Results) {
47
+ if (result.Vulnerabilities) {
48
+ for (const vuln of result.Vulnerabilities) {
49
+ const finding = this.createFinding('trivy', {
50
+ type: 'vulnerability',
51
+ severity: this.mapSeverity(vuln.Severity),
52
+ title: `${vuln.PkgName}: ${vuln.VulnerabilityID}`,
53
+ description: vuln.Title || vuln.Description || `Vulnerability in ${vuln.PkgName}`,
54
+ file: result.Target,
55
+ metadata: {
56
+ vulnerabilityId: vuln.VulnerabilityID,
57
+ package: vuln.PkgName,
58
+ installedVersion: vuln.InstalledVersion,
59
+ fixedVersion: vuln.FixedVersion,
60
+ references: vuln.References?.slice(0, 3),
61
+ cvssScore: this.getCvssScore(vuln),
62
+ },
63
+ });
64
+ findings.push(finding);
65
+ context.addFinding(finding);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ catch (parseError) {
72
+ context.log('warn', `Failed to parse trivy output: ${parseError}`);
73
+ }
74
+ }
75
+ this.status = 'complete';
76
+ context.log('info', `Trivy found ${findings.length} vulnerabilities`);
77
+ return {
78
+ agentId: this.config.id,
79
+ agentName: this.config.name,
80
+ status: 'success',
81
+ findings,
82
+ duration: Date.now() - startTime,
83
+ };
84
+ }
85
+ catch (error) {
86
+ this.status = 'error';
87
+ const errorMsg = error instanceof Error ? error.message : String(error);
88
+ context.log('error', `Trivy error: ${errorMsg}`);
89
+ return {
90
+ agentId: this.config.id,
91
+ agentName: this.config.name,
92
+ status: 'error',
93
+ findings,
94
+ duration: Date.now() - startTime,
95
+ error: errorMsg,
96
+ };
97
+ }
98
+ }
99
+ mapSeverity(trivySeverity) {
100
+ switch (trivySeverity.toUpperCase()) {
101
+ case 'CRITICAL':
102
+ return 'critical';
103
+ case 'HIGH':
104
+ return 'high';
105
+ case 'MEDIUM':
106
+ return 'medium';
107
+ case 'LOW':
108
+ return 'low';
109
+ default:
110
+ return 'info';
111
+ }
112
+ }
113
+ getCvssScore(vuln) {
114
+ if (!vuln.CVSS)
115
+ return undefined;
116
+ for (const source of Object.values(vuln.CVSS)) {
117
+ if (source.V3Score)
118
+ return source.V3Score;
119
+ }
120
+ return undefined;
121
+ }
122
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Aura Protocol - Agent Types
3
+ *
4
+ * Agents are specialized workers that execute within zones.
5
+ * Each agent has a specific role and can only operate within its assigned zone.
6
+ */
7
+ import { ZoneContext, ZoneFinding, AgentResult } from '../zones/types.js';
8
+ export { AgentResult } from '../zones/types.js';
9
+ export type AgentRole = 'scanner' | 'policy' | 'validator' | 'reporter' | 'notifier';
10
+ export type AgentStatus = 'idle' | 'running' | 'complete' | 'error' | 'disabled';
11
+ export interface AgentConfig {
12
+ id: string;
13
+ name: string;
14
+ role: AgentRole;
15
+ description: string;
16
+ enabled: boolean;
17
+ externalTool?: string;
18
+ config?: Record<string, unknown>;
19
+ }
20
+ export interface AgentCapabilities {
21
+ fileTypes?: string[];
22
+ languages?: string[];
23
+ requiresExternalTool: boolean;
24
+ supportsParallel: boolean;
25
+ }
26
+ /**
27
+ * Base Agent Interface
28
+ *
29
+ * All agents must implement this interface.
30
+ */
31
+ export interface Agent {
32
+ readonly config: AgentConfig;
33
+ readonly capabilities: AgentCapabilities;
34
+ /**
35
+ * Check if the agent is available (external tools installed, etc.)
36
+ */
37
+ isAvailable(): Promise<boolean>;
38
+ /**
39
+ * Execute the agent within a zone context
40
+ */
41
+ execute(context: ZoneContext): Promise<AgentResult>;
42
+ /**
43
+ * Get agent status
44
+ */
45
+ getStatus(): AgentStatus;
46
+ }
47
+ /**
48
+ * Scanner Agent Interface
49
+ *
50
+ * Agents that scan for secrets, vulnerabilities, etc.
51
+ */
52
+ export interface ScannerAgent extends Agent {
53
+ readonly config: AgentConfig & {
54
+ role: 'scanner';
55
+ };
56
+ /**
57
+ * Run the scan and return findings
58
+ */
59
+ scan(targetPath: string, context: ZoneContext): Promise<ZoneFinding[]>;
60
+ }
61
+ /**
62
+ * Policy Agent Interface
63
+ *
64
+ * Agents that evaluate policies and context
65
+ */
66
+ export interface PolicyAgent extends Agent {
67
+ readonly config: AgentConfig & {
68
+ role: 'policy';
69
+ };
70
+ /**
71
+ * Evaluate findings against policies
72
+ */
73
+ evaluate(findings: ZoneFinding[], context: ZoneContext): Promise<{
74
+ filtered: ZoneFinding[];
75
+ falsePositives: ZoneFinding[];
76
+ escalated: ZoneFinding[];
77
+ }>;
78
+ }
79
+ /**
80
+ * Validator Agent Interface
81
+ *
82
+ * Agents that validate and deduplicate findings
83
+ */
84
+ export interface IValidatorAgent extends Agent {
85
+ readonly config: AgentConfig & {
86
+ role: 'validator';
87
+ };
88
+ /**
89
+ * Validate findings and remove false positives
90
+ */
91
+ validate(findings: ZoneFinding[], context: ZoneContext): Promise<ZoneFinding[]>;
92
+ }
93
+ /**
94
+ * Reporter Agent Interface
95
+ *
96
+ * Agents that generate reports
97
+ */
98
+ export interface ReporterAgent extends Agent {
99
+ readonly config: AgentConfig & {
100
+ role: 'reporter';
101
+ };
102
+ /**
103
+ * Generate a report from findings
104
+ */
105
+ generateReport(findings: ZoneFinding[], format: 'sarif' | 'json' | 'html' | 'markdown', context: ZoneContext): Promise<string>;
106
+ }
107
+ /**
108
+ * Notifier Agent Interface
109
+ *
110
+ * Agents that send notifications
111
+ */
112
+ export interface NotifierAgent extends Agent {
113
+ readonly config: AgentConfig & {
114
+ role: 'notifier';
115
+ };
116
+ /**
117
+ * Send notification about findings
118
+ */
119
+ notify(findings: ZoneFinding[], channel: string, context: ZoneContext): Promise<boolean>;
120
+ }
121
+ /**
122
+ * Agent Registry
123
+ *
124
+ * Stores all available agents
125
+ */
126
+ export interface AgentRegistry {
127
+ register(agent: Agent): void;
128
+ unregister(agentId: string): void;
129
+ get(agentId: string): Agent | undefined;
130
+ getAll(): Agent[];
131
+ getByRole(role: AgentRole): Agent[];
132
+ getAvailable(): Promise<Agent[]>;
133
+ }
134
+ /**
135
+ * Default agent configurations
136
+ */
137
+ export declare const DEFAULT_AGENTS: AgentConfig[];
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Aura Protocol - Agent Types
3
+ *
4
+ * Agents are specialized workers that execute within zones.
5
+ * Each agent has a specific role and can only operate within its assigned zone.
6
+ */
7
+ /**
8
+ * Default agent configurations
9
+ */
10
+ export const DEFAULT_AGENTS = [
11
+ // Scanner agents
12
+ {
13
+ id: 'gitleaks',
14
+ name: 'Gitleaks',
15
+ role: 'scanner',
16
+ description: 'Detect secrets and API keys in code',
17
+ enabled: true,
18
+ externalTool: 'gitleaks',
19
+ },
20
+ {
21
+ id: 'trivy',
22
+ name: 'Trivy',
23
+ role: 'scanner',
24
+ description: 'Scan for vulnerabilities in dependencies and containers',
25
+ enabled: true,
26
+ externalTool: 'trivy',
27
+ },
28
+ {
29
+ id: 'semgrep',
30
+ name: 'Semgrep',
31
+ role: 'scanner',
32
+ description: 'Static analysis for security patterns',
33
+ enabled: true,
34
+ externalTool: 'semgrep',
35
+ },
36
+ {
37
+ id: 'grype',
38
+ name: 'Grype',
39
+ role: 'scanner',
40
+ description: 'Vulnerability scanner for container images and filesystems',
41
+ enabled: true,
42
+ externalTool: 'grype',
43
+ },
44
+ {
45
+ id: 'npm-audit',
46
+ name: 'NPM Audit',
47
+ role: 'scanner',
48
+ description: 'Audit npm packages for vulnerabilities',
49
+ enabled: true,
50
+ externalTool: 'npm',
51
+ },
52
+ // Policy agents
53
+ {
54
+ id: 'policy-evaluator',
55
+ name: 'Policy Evaluator',
56
+ role: 'policy',
57
+ description: 'Evaluate findings against security policies',
58
+ enabled: true,
59
+ },
60
+ // Validator agents
61
+ {
62
+ id: 'validator',
63
+ name: 'Finding Validator',
64
+ role: 'validator',
65
+ description: 'Validate and deduplicate findings, remove false positives',
66
+ enabled: true,
67
+ },
68
+ // Reporter agents
69
+ {
70
+ id: 'sarif-reporter',
71
+ name: 'SARIF Reporter',
72
+ role: 'reporter',
73
+ description: 'Generate SARIF format reports',
74
+ enabled: true,
75
+ },
76
+ // Notifier agents
77
+ {
78
+ id: 'slack-notifier',
79
+ name: 'Slack Notifier',
80
+ role: 'notifier',
81
+ description: 'Send notifications to Slack',
82
+ enabled: true,
83
+ },
84
+ {
85
+ id: 'discord-notifier',
86
+ name: 'Discord Notifier',
87
+ role: 'notifier',
88
+ description: 'Send notifications to Discord',
89
+ enabled: true,
90
+ },
91
+ ];
@@ -0,0 +1,3 @@
1
+ export { AuditorPipeline } from './pipeline.js';
2
+ export type { PipelineConfig } from './pipeline.js';
3
+ export { SchemaValidator, ValidationError } from './validator.js';
@@ -0,0 +1,2 @@
1
+ export { AuditorPipeline } from './pipeline.js';
2
+ export { SchemaValidator, ValidationError } from './validator.js';
@@ -0,0 +1,19 @@
1
+ import type { AuditorOutput } from '../types/events.js';
2
+ import { AuraClient } from '../aura/client.js';
3
+ export interface PipelineConfig {
4
+ auraClient: AuraClient;
5
+ strictMode?: boolean;
6
+ }
7
+ export declare class AuditorPipeline {
8
+ private validator;
9
+ private client;
10
+ private strictMode;
11
+ constructor(config: PipelineConfig);
12
+ analyze(rawInput: unknown): Promise<AuditorOutput>;
13
+ private runAnalysisRules;
14
+ private findCriticalAssetChanges;
15
+ private detectSecretPatterns;
16
+ private parseVulnScan;
17
+ private getSeverityForRisk;
18
+ private createEvent;
19
+ }
@@ -0,0 +1,240 @@
1
+ // Auditor Pipeline - Rule-based security analysis with fail-closed behavior
2
+ import { SchemaValidator } from './validator.js';
3
+ import { AuraConnectionError } from '../aura/client.js';
4
+ const AGENT_ID = 'exploit-reviewer';
5
+ export class AuditorPipeline {
6
+ validator;
7
+ client;
8
+ strictMode;
9
+ constructor(config) {
10
+ this.validator = new SchemaValidator();
11
+ this.client = config.auraClient;
12
+ this.strictMode = config.strictMode ?? true;
13
+ }
14
+ // Main entry point - fail-closed on any error
15
+ async analyze(rawInput) {
16
+ // Fail-closed: must be connected to Aura
17
+ if (!this.client.connected) {
18
+ throw new AuraConnectionError('No Aura connection - blocking execution');
19
+ }
20
+ // Fail-closed: validate input
21
+ this.validator.assertValidInput(rawInput);
22
+ const input = rawInput;
23
+ // Start analysis
24
+ const events = [];
25
+ const assumptions = [];
26
+ const uncertainties = [];
27
+ // Emit analysis_started
28
+ events.push(this.createEvent('analysis_started', 'self', {
29
+ severity: 'low',
30
+ claim: `Analyzing ${input.change_event.type} in ${input.change_event.environment}`,
31
+ attack_path: ['Initiated audit pipeline'],
32
+ affected_assets: [],
33
+ evidence_refs: [{ type: 'diff', pointer: input.change_event.id }],
34
+ assurance_break: [],
35
+ confidence: 1.0
36
+ }));
37
+ // Run analysis rules
38
+ const findings = this.runAnalysisRules(input, assumptions, uncertainties);
39
+ events.push(...findings);
40
+ // Determine final state
41
+ const hasCritical = findings.some(e => e.payload.severity === 'critical');
42
+ const hasHigh = findings.some(e => e.payload.severity === 'high');
43
+ const hasConflict = findings.some(e => e.event_type === 'conflict_detected');
44
+ let agentState = 'idle';
45
+ if (hasCritical) {
46
+ agentState = 'blocked';
47
+ }
48
+ else if (hasConflict) {
49
+ agentState = 'conflict';
50
+ }
51
+ else if (hasHigh) {
52
+ agentState = 'escalated';
53
+ }
54
+ else if (findings.length > 0) {
55
+ agentState = 'analyzing';
56
+ }
57
+ const output = {
58
+ agent_id: AGENT_ID,
59
+ agent_state: agentState,
60
+ events,
61
+ meta: { assumptions, uncertainties }
62
+ };
63
+ // Fail-closed: validate output
64
+ this.validator.assertValidOutput(output);
65
+ // Publish to Aura memory (audit log)
66
+ await this.client.publishToMemory({
67
+ key: `audit:${input.change_event.id}:${Date.now()}`,
68
+ value: output,
69
+ metadata: {
70
+ commit: input.change_event.commit,
71
+ repo: input.change_event.repo,
72
+ environment: input.change_event.environment
73
+ }
74
+ });
75
+ return output;
76
+ }
77
+ runAnalysisRules(input, assumptions, uncertainties) {
78
+ const findings = [];
79
+ const { change_event, evidence_bundle, policy_context } = input;
80
+ // Rule: Critical asset modification
81
+ const criticalFiles = this.findCriticalAssetChanges(change_event.files_changed, policy_context.critical_assets);
82
+ if (criticalFiles.length > 0) {
83
+ findings.push(this.createEvent('finding_raised', 'self', {
84
+ severity: this.getSeverityForRisk(policy_context.risk_tolerance, 'high'),
85
+ claim: 'Critical asset files modified without explicit approval chain',
86
+ attack_path: [
87
+ 'Attacker gains commit access',
88
+ 'Modifies critical asset configuration',
89
+ 'Changes bypass standard review due to file location'
90
+ ],
91
+ affected_assets: criticalFiles,
92
+ evidence_refs: criticalFiles.map(f => ({ type: 'diff', pointer: f })),
93
+ assurance_break: ['integrity', 'access_control'],
94
+ confidence: 0.85
95
+ }));
96
+ }
97
+ // Rule: Production deployment without staging
98
+ if (change_event.environment === 'prod' && change_event.type === 'deploy') {
99
+ assumptions.push('Assumes staging validation is required before prod');
100
+ findings.push(this.createEvent('finding_raised', 'self', {
101
+ severity: this.getSeverityForRisk(policy_context.risk_tolerance, 'medium'),
102
+ claim: 'Direct production deployment detected',
103
+ attack_path: [
104
+ 'Change bypasses staging environment',
105
+ 'Untested code reaches production',
106
+ 'Runtime errors expose attack surface'
107
+ ],
108
+ affected_assets: ['production-environment'],
109
+ evidence_refs: [{ type: 'diff', pointer: change_event.commit }],
110
+ assurance_break: ['isolation'],
111
+ confidence: 0.7
112
+ }));
113
+ }
114
+ // Rule: Check for secrets in diff
115
+ const secretPatterns = this.detectSecretPatterns(change_event.diff);
116
+ if (secretPatterns.length > 0) {
117
+ findings.push(this.createEvent('escalation_triggered', 'self', {
118
+ severity: 'critical',
119
+ claim: 'Potential secrets or credentials detected in diff',
120
+ attack_path: [
121
+ 'Credentials committed to repository',
122
+ 'Secrets exposed in version history',
123
+ 'Attacker extracts credentials from git history'
124
+ ],
125
+ affected_assets: secretPatterns.map(p => p.file),
126
+ evidence_refs: secretPatterns.map(p => ({ type: 'diff', pointer: p.line })),
127
+ assurance_break: ['integrity', 'access_control'],
128
+ confidence: 0.95
129
+ }));
130
+ }
131
+ // Rule: Vulnerability scan findings
132
+ if (evidence_bundle.vuln_scan) {
133
+ const vulnFindings = this.parseVulnScan(evidence_bundle.vuln_scan);
134
+ if (vulnFindings.critical > 0 || vulnFindings.high > 0) {
135
+ findings.push(this.createEvent('finding_raised', 'self', {
136
+ severity: vulnFindings.critical > 0 ? 'critical' : 'high',
137
+ claim: `Vulnerability scan detected ${vulnFindings.critical} critical and ${vulnFindings.high} high severity issues`,
138
+ attack_path: [
139
+ 'Known vulnerability present in dependencies',
140
+ 'Attacker identifies CVE in deployed version',
141
+ 'Exploit executed against vulnerable component'
142
+ ],
143
+ affected_assets: ['dependencies'],
144
+ evidence_refs: [{ type: 'scan', pointer: 'vuln_scan' }],
145
+ assurance_break: ['integrity'],
146
+ confidence: 0.9
147
+ }));
148
+ }
149
+ }
150
+ // Rule: Infrastructure changes
151
+ if (change_event.type === 'infra_change') {
152
+ uncertainties.push('Infrastructure change impact depends on cloud provider specifics');
153
+ findings.push(this.createEvent('finding_raised', 'self', {
154
+ severity: this.getSeverityForRisk(policy_context.risk_tolerance, 'medium'),
155
+ claim: 'Infrastructure modification requires manual review',
156
+ attack_path: [
157
+ 'IaC change modifies security boundaries',
158
+ 'Misconfiguration exposes internal services',
159
+ 'Attacker gains network access to protected resources'
160
+ ],
161
+ affected_assets: ['infrastructure'],
162
+ evidence_refs: change_event.files_changed.map(f => ({ type: 'diff', pointer: f })),
163
+ assurance_break: ['isolation', 'access_control'],
164
+ confidence: 0.6
165
+ }));
166
+ }
167
+ return findings;
168
+ }
169
+ findCriticalAssetChanges(files, criticalAssets) {
170
+ const matches = [];
171
+ for (const file of files) {
172
+ const fileLower = file.toLowerCase();
173
+ for (const asset of criticalAssets) {
174
+ if (fileLower.includes(asset.toLowerCase())) {
175
+ matches.push(file);
176
+ break;
177
+ }
178
+ }
179
+ }
180
+ return matches;
181
+ }
182
+ detectSecretPatterns(diff) {
183
+ const patterns = [
184
+ /api[_-]?key\s*[=:]\s*['"][^'"]+['"]/gi,
185
+ /secret\s*[=:]\s*['"][^'"]+['"]/gi,
186
+ /password\s*[=:]\s*['"][^'"]+['"]/gi,
187
+ /bearer\s+[a-z0-9_-]+/gi,
188
+ /-----BEGIN\s+(RSA|EC|OPENSSH)\s+PRIVATE\s+KEY-----/g,
189
+ /aws[_-]?secret[_-]?access[_-]?key/gi
190
+ ];
191
+ const findings = [];
192
+ const lines = diff.split('\n');
193
+ for (let i = 0; i < lines.length; i++) {
194
+ const line = lines[i];
195
+ if (line.startsWith('+')) {
196
+ for (const pattern of patterns) {
197
+ if (pattern.test(line)) {
198
+ findings.push({ file: 'diff', line: `line:${i + 1}` });
199
+ break;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ return findings;
205
+ }
206
+ parseVulnScan(scan) {
207
+ // Simple parser - in production would parse actual scanner output
208
+ const criticalMatch = scan.match(/critical[:\s]+(\d+)/i);
209
+ const highMatch = scan.match(/high[:\s]+(\d+)/i);
210
+ return {
211
+ critical: criticalMatch ? parseInt(criticalMatch[1], 10) : 0,
212
+ high: highMatch ? parseInt(highMatch[1], 10) : 0
213
+ };
214
+ }
215
+ getSeverityForRisk(tolerance, baseSeverity) {
216
+ if (tolerance === 'low') {
217
+ if (baseSeverity === 'low')
218
+ return 'medium';
219
+ if (baseSeverity === 'medium')
220
+ return 'high';
221
+ return 'critical';
222
+ }
223
+ if (tolerance === 'high') {
224
+ if (baseSeverity === 'high')
225
+ return 'medium';
226
+ if (baseSeverity === 'medium')
227
+ return 'low';
228
+ return 'low';
229
+ }
230
+ return baseSeverity;
231
+ }
232
+ createEvent(eventType, target, payload) {
233
+ return {
234
+ event_type: eventType,
235
+ target,
236
+ payload,
237
+ timestamp: new Date().toISOString()
238
+ };
239
+ }
240
+ }
@@ -0,0 +1,17 @@
1
+ import type { AuditorInput, AuditorOutput } from '../types/events.js';
2
+ export declare class ValidationError extends Error {
3
+ readonly errors: unknown[];
4
+ constructor(message: string, errors: unknown[]);
5
+ }
6
+ export declare class SchemaValidator {
7
+ private ajv;
8
+ private validateInput;
9
+ private validateOutput;
10
+ constructor();
11
+ assertValidInput(data: unknown): asserts data is AuditorInput;
12
+ assertValidOutput(data: unknown): asserts data is AuditorOutput;
13
+ isValidInput(data: unknown): data is AuditorInput;
14
+ isValidOutput(data: unknown): data is AuditorOutput;
15
+ getInputErrors(data: unknown): unknown[];
16
+ getOutputErrors(data: unknown): unknown[];
17
+ }