@neurosec/sentry 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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +118 -0
  3. package/bin/cli.js +18 -0
  4. package/bin/sentryd.js +19 -0
  5. package/dist/api.d.ts +21 -0
  6. package/dist/api.d.ts.map +1 -0
  7. package/dist/api.js +161 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/audit.d.ts +18 -0
  10. package/dist/audit.d.ts.map +1 -0
  11. package/dist/audit.js +114 -0
  12. package/dist/audit.js.map +1 -0
  13. package/dist/cli.d.ts +3 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +255 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/config.d.ts +54 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +160 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/discovery.d.ts +5 -0
  22. package/dist/discovery.d.ts.map +1 -0
  23. package/dist/discovery.js +279 -0
  24. package/dist/discovery.js.map +1 -0
  25. package/dist/enforcement/enforcement-engine.d.ts +37 -0
  26. package/dist/enforcement/enforcement-engine.d.ts.map +1 -0
  27. package/dist/enforcement/enforcement-engine.js +325 -0
  28. package/dist/enforcement/enforcement-engine.js.map +1 -0
  29. package/dist/enforcement/file-monitor.d.ts +4 -0
  30. package/dist/enforcement/file-monitor.d.ts.map +1 -0
  31. package/dist/enforcement/file-monitor.js +114 -0
  32. package/dist/enforcement/file-monitor.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +248 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/logger.d.ts +2 -0
  38. package/dist/logger.d.ts.map +1 -0
  39. package/dist/logger.js +17 -0
  40. package/dist/logger.js.map +1 -0
  41. package/dist/sandbox/index.d.ts +14 -0
  42. package/dist/sandbox/index.d.ts.map +1 -0
  43. package/dist/sandbox/index.js +91 -0
  44. package/dist/sandbox/index.js.map +1 -0
  45. package/dist/sandbox/linux-sandbox.d.ts +21 -0
  46. package/dist/sandbox/linux-sandbox.d.ts.map +1 -0
  47. package/dist/sandbox/linux-sandbox.js +186 -0
  48. package/dist/sandbox/linux-sandbox.js.map +1 -0
  49. package/dist/sandbox/macos-sandbox.d.ts +17 -0
  50. package/dist/sandbox/macos-sandbox.d.ts.map +1 -0
  51. package/dist/sandbox/macos-sandbox.js +145 -0
  52. package/dist/sandbox/macos-sandbox.js.map +1 -0
  53. package/dist/setup.d.ts +14 -0
  54. package/dist/setup.d.ts.map +1 -0
  55. package/dist/setup.js +220 -0
  56. package/dist/setup.js.map +1 -0
  57. package/dist/skill-authz/skill-evaluator.d.ts +20 -0
  58. package/dist/skill-authz/skill-evaluator.d.ts.map +1 -0
  59. package/dist/skill-authz/skill-evaluator.js +159 -0
  60. package/dist/skill-authz/skill-evaluator.js.map +1 -0
  61. package/dist/skill-authz/skill-scanner.d.ts +18 -0
  62. package/dist/skill-authz/skill-scanner.d.ts.map +1 -0
  63. package/dist/skill-authz/skill-scanner.js +169 -0
  64. package/dist/skill-authz/skill-scanner.js.map +1 -0
  65. package/dist/telemetry.d.ts +18 -0
  66. package/dist/telemetry.d.ts.map +1 -0
  67. package/dist/telemetry.js +106 -0
  68. package/dist/telemetry.js.map +1 -0
  69. package/dist/types.d.ts +127 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +209 -0
  72. package/dist/types.js.map +1 -0
  73. package/package.json +69 -0
  74. package/scripts/install-sentry-macos.sh +238 -0
  75. package/scripts/install-sentry.sh +253 -0
  76. package/scripts/postinstall.js +191 -0
  77. package/scripts/prepack.js +33 -0
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.discoverProcesses = discoverProcesses;
7
+ exports.detectHighRiskChildren = detectHighRiskChildren;
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const types_1 = require("./types");
10
+ const logger_1 = require("./logger");
11
+ const FRAMEWORK_SIGNATURES = [
12
+ {
13
+ id: 'langchain',
14
+ name: 'LangChain',
15
+ packagePatterns: ['langchain', '@langchain/'],
16
+ importRegexes: [/from\s+langchain\b/i, /import\s+langchain\b/i, /from\s+['"]@langchain\//i],
17
+ envKeys: ['LANGCHAIN_API_KEY', 'LANGCHAIN_TRACING_V2'],
18
+ manifestFiles: [],
19
+ processRegexes: [/langchain/i],
20
+ },
21
+ {
22
+ id: 'langgraph',
23
+ name: 'LangGraph',
24
+ packagePatterns: ['langgraph'],
25
+ importRegexes: [/from\s+langgraph\b/i, /import\s+langgraph\b/i],
26
+ envKeys: [],
27
+ manifestFiles: [],
28
+ processRegexes: [/langgraph\s+dev/i, /langgraph/i],
29
+ },
30
+ {
31
+ id: 'crewai',
32
+ name: 'CrewAI',
33
+ packagePatterns: ['crewai'],
34
+ importRegexes: [/from\s+crewai\b/i, /import\s+crewai\b/i],
35
+ envKeys: [],
36
+ manifestFiles: ['agents.yaml'],
37
+ processRegexes: [/python\s+-m\s+crewai/i, /crewai/i],
38
+ },
39
+ {
40
+ id: 'autogen',
41
+ name: 'AutoGen',
42
+ packagePatterns: ['autogen', 'pyautogen'],
43
+ importRegexes: [/from\s+autogen\b/i, /import\s+autogen\b/i],
44
+ envKeys: [],
45
+ manifestFiles: [],
46
+ processRegexes: [/autogen/i],
47
+ },
48
+ {
49
+ id: 'semantic-kernel',
50
+ name: 'Semantic Kernel',
51
+ packagePatterns: ['semantic-kernel', 'microsoft.semantickernel', '@microsoft/semantic-kernel'],
52
+ importRegexes: [/semantic_kernel/i, /@microsoft\/semantic-kernel/i, /Microsoft\.SemanticKernel/i],
53
+ envKeys: [],
54
+ manifestFiles: [],
55
+ processRegexes: [/semantic/i],
56
+ },
57
+ {
58
+ id: 'dspy',
59
+ name: 'DSPy',
60
+ packagePatterns: ['dspy', 'dspy-ai'],
61
+ importRegexes: [/import\s+dspy\b/i, /from\s+dspy\b/i],
62
+ envKeys: [],
63
+ manifestFiles: [],
64
+ processRegexes: [/dspy/i],
65
+ },
66
+ {
67
+ id: 'haystack',
68
+ name: 'Haystack',
69
+ packagePatterns: ['haystack-ai', 'farm-haystack'],
70
+ importRegexes: [/from\s+haystack\b/i, /import\s+haystack\b/i],
71
+ envKeys: [],
72
+ manifestFiles: [],
73
+ processRegexes: [/haystack/i],
74
+ },
75
+ {
76
+ id: 'mcp-server',
77
+ name: 'MCP Server',
78
+ packagePatterns: ['@modelcontextprotocol/sdk', 'modelcontextprotocol'],
79
+ importRegexes: [/modelcontextprotocol/i, /MCP_SERVER_/i],
80
+ envKeys: ['MCP_SERVER_NAME', 'MCP_SERVER_PORT', 'MCP_SERVER_TRANSPORT'],
81
+ manifestFiles: ['mcp.json', 'claude_desktop_config.json'],
82
+ processRegexes: [/mcp/i],
83
+ },
84
+ {
85
+ id: 'claude-code',
86
+ name: 'Claude Code',
87
+ packagePatterns: [],
88
+ importRegexes: [/claude_desktop_config\.json/i],
89
+ envKeys: [],
90
+ manifestFiles: ['claude_desktop_config.json'],
91
+ processRegexes: [/claude/i],
92
+ },
93
+ {
94
+ id: 'aider',
95
+ name: 'Aider',
96
+ packagePatterns: ['aider-chat', 'aider'],
97
+ importRegexes: [/aider/i],
98
+ envKeys: [],
99
+ manifestFiles: [],
100
+ processRegexes: [/aider/i],
101
+ },
102
+ {
103
+ id: 'openai-assistants',
104
+ name: 'OpenAI Assistants',
105
+ packagePatterns: [],
106
+ importRegexes: [/client\.beta\.assistants/i, /assistants\.create/i],
107
+ envKeys: [],
108
+ manifestFiles: [],
109
+ processRegexes: [],
110
+ },
111
+ ];
112
+ const HIGH_RISK_PROCESS_PATTERNS = [
113
+ /sudo/i, /pkexec/i, /su\s/, /doas/i,
114
+ /chmod\s+777/i, /chown/i,
115
+ /rm\s+-rf/i, /mkfs/i, /dd\s+if/i,
116
+ /nc\s/, /ncat/i, /netcat/i,
117
+ /bash\s+-c\s+.*curl/i, /bash\s+-c\s+.*wget/i,
118
+ /perl\s+-e/i, /python\s+-c\s+.*import/i,
119
+ /openssl\s+s_client/i,
120
+ /ssh\s+-R/i,
121
+ /iptables/i, /nft/i,
122
+ /tcpdump/i, /tshark/i,
123
+ /nmap/i, /masscan/i,
124
+ /gdb\s/, /lldb\s/, /strace/i, /dtrace/i,
125
+ ];
126
+ function matchByEnvKeys(env) {
127
+ const matched = [];
128
+ const keys = Object.keys(env);
129
+ for (const sig of FRAMEWORK_SIGNATURES) {
130
+ if (sig.envKeys.length > 0 && sig.envKeys.some(ek => keys.includes(ek))) {
131
+ matched.push(sig);
132
+ }
133
+ }
134
+ return matched;
135
+ }
136
+ function matchByProcessCommand(command) {
137
+ const matched = [];
138
+ for (const sig of FRAMEWORK_SIGNATURES) {
139
+ if (sig.processRegexes.length > 0 && sig.processRegexes.some(re => re.test(command))) {
140
+ matched.push(sig);
141
+ }
142
+ }
143
+ return matched;
144
+ }
145
+ async function getPidEnv(pid) {
146
+ const env = {};
147
+ try {
148
+ const content = await promises_1.default.readFile(`/proc/${pid}/environ`, 'utf8');
149
+ const parts = content.split('\u0000').filter(Boolean);
150
+ for (const part of parts) {
151
+ const eqIdx = part.indexOf('=');
152
+ if (eqIdx > 0) {
153
+ env[part.slice(0, eqIdx)] = part.slice(eqIdx + 1);
154
+ }
155
+ }
156
+ }
157
+ catch {
158
+ // no /proc or permission denied
159
+ }
160
+ return env;
161
+ }
162
+ async function getPidCmdline(pid) {
163
+ try {
164
+ const content = await promises_1.default.readFile(`/proc/${pid}/cmdline`, 'utf8');
165
+ return content.replace(/\u0000/g, ' ').trim();
166
+ }
167
+ catch {
168
+ return '';
169
+ }
170
+ }
171
+ async function getPidExe(pid) {
172
+ try {
173
+ return await promises_1.default.readlink(`/proc/${pid}/exe`);
174
+ }
175
+ catch {
176
+ return '';
177
+ }
178
+ }
179
+ async function getPidUid(pid) {
180
+ try {
181
+ const status = await promises_1.default.readFile(`/proc/${pid}/status`, 'utf8');
182
+ const match = status.match(/^Uid:\s+(\d+)/m);
183
+ return match ? parseInt(match[1], 10) : 0;
184
+ }
185
+ catch {
186
+ return 0;
187
+ }
188
+ }
189
+ function matchFrameworkSignatures(command, env) {
190
+ const byEnv = matchByEnvKeys(env);
191
+ const byCommand = matchByProcessCommand(command);
192
+ const all = [...new Set([...byEnv, ...byCommand])];
193
+ if (all.length === 0)
194
+ return null;
195
+ const best = all.reduce((a, b) => {
196
+ const aScore = (byEnv.includes(a) ? 0.3 : 0) + (byCommand.includes(a) ? 0.4 : 0);
197
+ const bScore = (byEnv.includes(b) ? 0.3 : 0) + (byCommand.includes(b) ? 0.4 : 0);
198
+ return bScore > aScore ? b : a;
199
+ });
200
+ let confidence = byEnv.includes(best) ? 0.6 : 0.4;
201
+ if (byCommand.includes(best))
202
+ confidence += 0.3;
203
+ confidence = Math.min(confidence, 0.95);
204
+ return { frameworkId: best.id, frameworkName: best.name, confidence };
205
+ }
206
+ function findSandboxProfile(frameworkId) {
207
+ for (const profile of types_1.AGENT_SANDBOX_PROFILES) {
208
+ if (profile.frameworkIds.includes(frameworkId)) {
209
+ return profile.name;
210
+ }
211
+ }
212
+ return null;
213
+ }
214
+ function isHighRiskCommand(command) {
215
+ return HIGH_RISK_PROCESS_PATTERNS.some(re => re.test(command));
216
+ }
217
+ async function discoverProcesses(config) {
218
+ const tagged = [];
219
+ try {
220
+ await promises_1.default.access('/proc');
221
+ }
222
+ catch {
223
+ logger_1.logger.warn('/proc not available — process discovery requires Linux with /proc mounted');
224
+ return tagged;
225
+ }
226
+ const entries = await promises_1.default.readdir('/proc');
227
+ const selfPid = process.pid;
228
+ for (const entry of entries) {
229
+ if (!/^\d+$/.test(entry))
230
+ continue;
231
+ const pid = parseInt(entry, 10);
232
+ if (pid === selfPid || pid === 1 || pid === 2)
233
+ continue;
234
+ const [command, exePath, env, uid] = await Promise.all([
235
+ getPidCmdline(pid),
236
+ getPidExe(pid),
237
+ getPidEnv(pid),
238
+ getPidUid(pid),
239
+ ]);
240
+ if (!command)
241
+ continue;
242
+ const ppidStr = await promises_1.default.readFile(`/proc/${pid}/status`, 'utf8')
243
+ .then(s => s.match(/^PPid:\s+(\d+)/m)?.[1])
244
+ .catch(() => undefined);
245
+ const match = matchFrameworkSignatures(command, env);
246
+ if (!match)
247
+ continue;
248
+ const isHighRisk = isHighRiskCommand(command);
249
+ tagged.push({
250
+ pid,
251
+ ppid: ppidStr ? parseInt(ppidStr, 10) : 0,
252
+ frameworkId: match.frameworkId,
253
+ frameworkName: match.frameworkName,
254
+ command: command.slice(0, 500),
255
+ exePath: exePath.slice(0, 255),
256
+ confidence: isHighRisk ? Math.min(match.confidence + 0.1, 0.99) : match.confidence,
257
+ envKeys: Object.keys(env).slice(0, 20),
258
+ discoveredAt: Date.now(),
259
+ sandboxed: false,
260
+ sandboxProfileName: findSandboxProfile(match.frameworkId),
261
+ uid,
262
+ gid: uid,
263
+ });
264
+ }
265
+ logger_1.logger.info('Process discovery complete', { tagged: tagged.length });
266
+ return tagged;
267
+ }
268
+ function detectHighRiskChildren(taggedProcesses) {
269
+ const pidSet = new Set(taggedProcesses.map(p => p.pid));
270
+ return taggedProcesses.filter(p => {
271
+ if (p.frameworkId === 'unknown')
272
+ return false;
273
+ if (pidSet.has(p.ppid) && taggedProcesses.some(parent => parent.pid === p.ppid)) {
274
+ return true;
275
+ }
276
+ return false;
277
+ });
278
+ }
279
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { SentryConfig } from '../config';
2
+ import { TaggedProcess, FileAccessEvent, NetworkEvent, SyscallEvent, EnforcementDecision } from '../types';
3
+ import { AuditLogger } from '../audit';
4
+ export declare class EnforcementEngine {
5
+ private config;
6
+ private decisions;
7
+ private decisionsDenied;
8
+ private taggedProcesses;
9
+ private auditLogger;
10
+ constructor(config: SentryConfig, auditLogger?: AuditLogger);
11
+ updateTaggedProcesses(processes: TaggedProcess[]): void;
12
+ getTaggedProcess(pid: number): TaggedProcess | null;
13
+ evaluateFileAccess(event: Omit<FileAccessEvent, 'decision' | 'timestamp'>): EnforcementDecision;
14
+ evaluateNetworkAccess(event: Omit<NetworkEvent, 'decision' | 'timestamp'>): EnforcementDecision;
15
+ evaluateSyscall(event: Omit<SyscallEvent, 'decision' | 'timestamp'>): EnforcementDecision;
16
+ evaluateSkillAuthz(frameworkId: string | null, skillName: string, pid: number, context: Record<string, unknown>): {
17
+ action: 'allow' | 'deny' | 'require_approval';
18
+ reason: string;
19
+ riskScore: number;
20
+ };
21
+ getStats(): {
22
+ total: number;
23
+ denied: number;
24
+ quarantined: number;
25
+ };
26
+ getRecentDecisions(limit?: number): EnforcementDecision[];
27
+ private recordDecision;
28
+ private decideFileAccess;
29
+ private decideNetworkAccess;
30
+ private isSyscallBlocked;
31
+ private findProfile;
32
+ private scoreSkillRisk;
33
+ private buildFileAccessReason;
34
+ private buildNetworkAccessReason;
35
+ private isPrivateIp;
36
+ }
37
+ //# sourceMappingURL=enforcement-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcement-engine.d.ts","sourceRoot":"","sources":["../../src/enforcement/enforcement-engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EACL,aAAa,EACb,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,mBAAmB,EAKpB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAsBvC,qBAAa,iBAAiB;IAO1B,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,eAAe,CAAyC;IAChE,OAAO,CAAC,WAAW,CAAc;gBAGvB,MAAM,EAAE,YAAY,EAC5B,WAAW,CAAC,EAAE,WAAW;IAK3B,qBAAqB,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI;IAOvD,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAInD,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG,mBAAmB;IAuB/F,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG,mBAAmB;IAwB/F,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,WAAW,CAAC,GAAG,mBAAmB;IA8BzF,kBAAkB,CAChB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B;QAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IA4BvF,QAAQ,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAQlE,kBAAkB,CAAC,KAAK,SAAM,GAAG,mBAAmB,EAAE;IAItD,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,gBAAgB;IA+BxB,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,cAAc;IAiCtB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,WAAW;CAUpB"}
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EnforcementEngine = void 0;
7
+ const uuid_1 = require("uuid");
8
+ const os_1 = __importDefault(require("os"));
9
+ const types_1 = require("../types");
10
+ const logger_1 = require("../logger");
11
+ const audit_1 = require("../audit");
12
+ function matchGlob(pattern, target) {
13
+ if (pattern.endsWith('/**')) {
14
+ const prefix = pattern.slice(0, -3);
15
+ return target.startsWith(prefix);
16
+ }
17
+ if (pattern.endsWith('*')) {
18
+ const prefix = pattern.slice(0, -1);
19
+ return target.startsWith(prefix);
20
+ }
21
+ return target === pattern;
22
+ }
23
+ function matchHostname(hostPattern, hostname) {
24
+ if (hostPattern.startsWith('*.')) {
25
+ const suffix = hostPattern.slice(1);
26
+ return hostname.endsWith(suffix);
27
+ }
28
+ return hostname === hostPattern;
29
+ }
30
+ class EnforcementEngine {
31
+ constructor(config, auditLogger) {
32
+ this.config = config;
33
+ this.decisions = [];
34
+ this.decisionsDenied = 0;
35
+ this.taggedProcesses = new Map();
36
+ this.auditLogger = auditLogger ?? new audit_1.AuditLogger(config);
37
+ }
38
+ updateTaggedProcesses(processes) {
39
+ this.taggedProcesses.clear();
40
+ for (const p of processes) {
41
+ this.taggedProcesses.set(p.pid, p);
42
+ }
43
+ }
44
+ getTaggedProcess(pid) {
45
+ return this.taggedProcesses.get(pid) ?? null;
46
+ }
47
+ evaluateFileAccess(event) {
48
+ const frameworkId = event.frameworkId;
49
+ const decision = this.decideFileAccess(event.pid, event.targetPath, event.operation, frameworkId);
50
+ const result = {
51
+ id: (0, uuid_1.v4)(),
52
+ type: 'file_access',
53
+ action: decision,
54
+ reason: this.buildFileAccessReason(event, decision),
55
+ frameworkId: event.frameworkId,
56
+ pid: event.pid,
57
+ detail: {
58
+ targetPath: event.targetPath,
59
+ operation: event.operation,
60
+ processPath: event.processPath,
61
+ },
62
+ timestamp: Date.now(),
63
+ };
64
+ this.recordDecision(result);
65
+ return result;
66
+ }
67
+ evaluateNetworkAccess(event) {
68
+ const frameworkId = event.frameworkId;
69
+ const decision = this.decideNetworkAccess(event.pid, event.destIp, event.destPort, event.hostname, frameworkId);
70
+ const result = {
71
+ id: (0, uuid_1.v4)(),
72
+ type: 'network',
73
+ action: decision,
74
+ reason: this.buildNetworkAccessReason(event, decision),
75
+ frameworkId: event.frameworkId,
76
+ pid: event.pid,
77
+ detail: {
78
+ destIp: event.destIp,
79
+ destPort: event.destPort,
80
+ hostname: event.hostname,
81
+ direction: event.direction,
82
+ },
83
+ timestamp: Date.now(),
84
+ };
85
+ this.recordDecision(result);
86
+ return result;
87
+ }
88
+ evaluateSyscall(event) {
89
+ const frameworkId = event.frameworkId;
90
+ const isBlocked = this.isSyscallBlocked(event.syscall, frameworkId);
91
+ let decision = 'allow';
92
+ if (isBlocked && this.config.enforcement.mode === 'enforce') {
93
+ decision = 'deny';
94
+ }
95
+ else if (isBlocked && this.config.enforcement.mode === 'quarantine') {
96
+ decision = 'quarantine';
97
+ }
98
+ else if (isBlocked) {
99
+ decision = 'allow';
100
+ }
101
+ const result = {
102
+ id: (0, uuid_1.v4)(),
103
+ type: 'syscall',
104
+ action: decision,
105
+ reason: isBlocked
106
+ ? `Blocked syscall '${event.syscall}' for ${frameworkId ?? 'unknown'} agent`
107
+ : `Allowed syscall '${event.syscall}'`,
108
+ frameworkId: event.frameworkId,
109
+ pid: event.pid,
110
+ detail: { syscall: event.syscall, ...event.details },
111
+ timestamp: Date.now(),
112
+ };
113
+ this.recordDecision(result);
114
+ return result;
115
+ }
116
+ evaluateSkillAuthz(frameworkId, skillName, pid, context) {
117
+ const riskScore = this.scoreSkillRisk(skillName, context);
118
+ let action;
119
+ let reason;
120
+ if (this.config.skillAuthz.requireApproval.some(s => skillName.toLowerCase().includes(s.toLowerCase()))) {
121
+ action = 'require_approval';
122
+ reason = `Skill '${skillName}' requires interactive approval`;
123
+ }
124
+ else if (riskScore >= 75 && this.config.enforcement.mode !== 'monitor') {
125
+ action = 'deny';
126
+ reason = `Skill '${skillName}' exceeds risk threshold (${riskScore}/100)`;
127
+ }
128
+ else if (riskScore >= 50 && this.config.enforcement.mode === 'enforce') {
129
+ action = 'require_approval';
130
+ reason = `Skill '${skillName}' has elevated risk (${riskScore}/100), requires approval`;
131
+ }
132
+ else {
133
+ action = 'allow';
134
+ reason = `Skill '${skillName}' passed authorization (risk: ${riskScore}/100)`;
135
+ }
136
+ if (this.config.enforcement.mode === 'monitor') {
137
+ action = 'allow';
138
+ reason = `[MONITOR] ${reason}`;
139
+ }
140
+ return { action, reason, riskScore };
141
+ }
142
+ getStats() {
143
+ return {
144
+ total: this.decisions.length,
145
+ denied: this.decisionsDenied,
146
+ quarantined: this.decisions.filter(d => d.action === 'quarantine').length,
147
+ };
148
+ }
149
+ getRecentDecisions(limit = 100) {
150
+ return this.decisions.slice(-limit);
151
+ }
152
+ recordDecision(decision) {
153
+ this.decisions.push(decision);
154
+ if (this.decisions.length > 10000) {
155
+ this.decisions = this.decisions.slice(-5000);
156
+ }
157
+ if (decision.action === 'deny' || decision.action === 'quarantine') {
158
+ this.decisionsDenied++;
159
+ logger_1.logger.warn('Enforcement decision', {
160
+ type: decision.type,
161
+ action: decision.action,
162
+ reason: decision.reason,
163
+ pid: decision.pid,
164
+ frameworkId: decision.frameworkId,
165
+ });
166
+ }
167
+ const auditEntry = {
168
+ id: decision.id,
169
+ timestamp: decision.timestamp,
170
+ type: decision.type,
171
+ action: decision.action,
172
+ frameworkId: decision.frameworkId,
173
+ frameworkName: this.taggedProcesses.get(decision.pid)?.frameworkName ?? null,
174
+ pid: decision.pid,
175
+ reason: decision.reason,
176
+ detail: decision.detail,
177
+ hostname: os_1.default.hostname(),
178
+ };
179
+ this.auditLogger.log(auditEntry).catch(err => {
180
+ logger_1.logger.error('Audit log write failed', { err: err.message });
181
+ });
182
+ }
183
+ decideFileAccess(pid, targetPath, operation, frameworkId) {
184
+ if (!frameworkId)
185
+ return 'allow';
186
+ const profile = this.findProfile(frameworkId);
187
+ if (!profile)
188
+ return 'allow';
189
+ if (this.config.enforcement.mode === 'monitor')
190
+ return 'allow';
191
+ if (this.config.enforcement.mode === 'quarantine')
192
+ return 'quarantine';
193
+ for (const rule of profile.fsRules) {
194
+ if (matchGlob(rule.path, targetPath)) {
195
+ if (rule.permissions === 'none')
196
+ return 'deny';
197
+ if (rule.permissions === 'r' && operation === 'write')
198
+ return 'deny';
199
+ if (rule.permissions === 'r' && operation === 'delete')
200
+ return 'deny';
201
+ if (rule.permissions === 'r' && operation === 'chmod')
202
+ return 'deny';
203
+ if (rule.permissions === 'rx' && operation === 'write')
204
+ return 'deny';
205
+ if (rule.permissions === 'rx' && operation === 'delete')
206
+ return 'deny';
207
+ if (rule.permissions === 'rx' && operation === 'chmod')
208
+ return 'deny';
209
+ return 'allow';
210
+ }
211
+ }
212
+ if (this.config.enforcement.mode === 'enforce')
213
+ return 'deny';
214
+ return 'allow';
215
+ }
216
+ decideNetworkAccess(pid, destIp, destPort, hostname, frameworkId) {
217
+ if (!frameworkId)
218
+ return 'allow';
219
+ if (this.config.enforcement.mode === 'monitor')
220
+ return 'allow';
221
+ if (this.config.enforcement.mode === 'quarantine')
222
+ return 'quarantine';
223
+ const profile = this.findProfile(frameworkId);
224
+ if (!profile)
225
+ return 'allow';
226
+ const hostToMatch = hostname ?? destIp;
227
+ for (const rule of profile.networkRules) {
228
+ if (rule.direction !== 'egress')
229
+ continue;
230
+ if (rule.host && !matchHostname(rule.host, hostToMatch))
231
+ continue;
232
+ if (rule.port && rule.port !== destPort)
233
+ continue;
234
+ if (rule.action === 'deny')
235
+ return 'deny';
236
+ if (rule.action === 'allow')
237
+ return 'allow';
238
+ }
239
+ if (this.config.network.allowPrivate && this.isPrivateIp(destIp)) {
240
+ return 'allow';
241
+ }
242
+ for (const blocked of this.config.network.blockHosts) {
243
+ if (matchHostname(blocked, hostToMatch))
244
+ return 'deny';
245
+ }
246
+ return 'deny';
247
+ }
248
+ isSyscallBlocked(syscall, frameworkId) {
249
+ if (!frameworkId)
250
+ return false;
251
+ const profile = this.findProfile(frameworkId);
252
+ if (!profile)
253
+ return false;
254
+ if (profile.blockedSyscalls.includes(syscall))
255
+ return true;
256
+ return false;
257
+ }
258
+ findProfile(frameworkId) {
259
+ for (const p of types_1.AGENT_SANDBOX_PROFILES) {
260
+ if (p.frameworkIds.includes(frameworkId))
261
+ return p;
262
+ }
263
+ return null;
264
+ }
265
+ scoreSkillRisk(skillName, args) {
266
+ let score = 0;
267
+ const highRiskPatterns = [
268
+ /exec/i, /shell/i, /bash/i, /terminal/i, /command/i,
269
+ /fs_|_fs_|filesystem|read_file|write_file|delete_file/i,
270
+ /db_|_db_|database|query|sql/i,
271
+ /network|http|fetch|curl|wget|request/i,
272
+ /ssh|scp|rsync/i,
273
+ /sudo|su|chmod|chown/i,
274
+ /rm\s/i, /mkfs/i,
275
+ ];
276
+ for (const pattern of highRiskPatterns) {
277
+ if (pattern.test(skillName))
278
+ score += 20;
279
+ }
280
+ const argString = JSON.stringify(args).toLowerCase();
281
+ const dangerousArgs = [
282
+ /rm\s+-rf/i, /mkfs/i, /dd\s+if/i,
283
+ /:\/\/[\w\.]+@/i,
284
+ /chmod\s+777/i,
285
+ /\/etc\/(passwd|shadow|sudoers)/i,
286
+ /\/\.ssh\//i, /\/\.aws\//i, /\/\.config\/gcloud/i,
287
+ /\/var\/log\/auth/i,
288
+ ];
289
+ for (const pattern of dangerousArgs) {
290
+ if (pattern.test(argString))
291
+ score += 15;
292
+ }
293
+ return Math.min(score, 100);
294
+ }
295
+ buildFileAccessReason(event, decision) {
296
+ if (decision === 'deny') {
297
+ return `Agent (pid ${event.pid}) ${event.operation} access to '${event.targetPath}' denied`;
298
+ }
299
+ if (decision === 'quarantine') {
300
+ return `Agent (pid ${event.pid}) ${event.operation} access to '${event.targetPath}' — host quarantined`;
301
+ }
302
+ return `Agent (pid ${event.pid}) ${event.operation} access to '${event.targetPath}' allowed`;
303
+ }
304
+ buildNetworkAccessReason(event, decision) {
305
+ const target = event.hostname ?? event.destIp;
306
+ if (decision === 'deny') {
307
+ return `Agent (pid ${event.pid}) egress to '${target}:${event.destPort}' denied`;
308
+ }
309
+ if (decision === 'quarantine') {
310
+ return `Agent (pid ${event.pid}) egress — host quarantined`;
311
+ }
312
+ return `Agent (pid ${event.pid}) egress to '${target}:${event.destPort}' allowed`;
313
+ }
314
+ isPrivateIp(ip) {
315
+ const parts = ip.split('.').map(Number);
316
+ if (parts.length !== 4)
317
+ return false;
318
+ return (parts[0] === 10 ||
319
+ (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) ||
320
+ (parts[0] === 192 && parts[1] === 168) ||
321
+ parts[0] === 127);
322
+ }
323
+ }
324
+ exports.EnforcementEngine = EnforcementEngine;
325
+ //# sourceMappingURL=enforcement-engine.js.map