@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.
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/bin/cli.js +18 -0
- package/bin/sentryd.js +19 -0
- package/dist/api.d.ts +21 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +161 -0
- package/dist/api.js.map +1 -0
- package/dist/audit.d.ts +18 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +114 -0
- package/dist/audit.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +255 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +160 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +5 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +279 -0
- package/dist/discovery.js.map +1 -0
- package/dist/enforcement/enforcement-engine.d.ts +37 -0
- package/dist/enforcement/enforcement-engine.d.ts.map +1 -0
- package/dist/enforcement/enforcement-engine.js +325 -0
- package/dist/enforcement/enforcement-engine.js.map +1 -0
- package/dist/enforcement/file-monitor.d.ts +4 -0
- package/dist/enforcement/file-monitor.d.ts.map +1 -0
- package/dist/enforcement/file-monitor.js +114 -0
- package/dist/enforcement/file-monitor.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/sandbox/index.d.ts +14 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +91 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/linux-sandbox.d.ts +21 -0
- package/dist/sandbox/linux-sandbox.d.ts.map +1 -0
- package/dist/sandbox/linux-sandbox.js +186 -0
- package/dist/sandbox/linux-sandbox.js.map +1 -0
- package/dist/sandbox/macos-sandbox.d.ts +17 -0
- package/dist/sandbox/macos-sandbox.d.ts.map +1 -0
- package/dist/sandbox/macos-sandbox.js +145 -0
- package/dist/sandbox/macos-sandbox.js.map +1 -0
- package/dist/setup.d.ts +14 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +220 -0
- package/dist/setup.js.map +1 -0
- package/dist/skill-authz/skill-evaluator.d.ts +20 -0
- package/dist/skill-authz/skill-evaluator.d.ts.map +1 -0
- package/dist/skill-authz/skill-evaluator.js +159 -0
- package/dist/skill-authz/skill-evaluator.js.map +1 -0
- package/dist/skill-authz/skill-scanner.d.ts +18 -0
- package/dist/skill-authz/skill-scanner.d.ts.map +1 -0
- package/dist/skill-authz/skill-scanner.js +169 -0
- package/dist/skill-authz/skill-scanner.js.map +1 -0
- package/dist/telemetry.d.ts +18 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +106 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +209 -0
- package/dist/types.js.map +1 -0
- package/package.json +69 -0
- package/scripts/install-sentry-macos.sh +238 -0
- package/scripts/install-sentry.sh +253 -0
- package/scripts/postinstall.js +191 -0
- 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
|