opena2a-cli 0.1.1 → 0.1.2
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/README.md +2 -2
- package/dist/adapters/registry.js +1 -1
- package/dist/adapters/registry.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +78 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/protect.d.ts +2 -0
- package/dist/commands/protect.d.ts.map +1 -1
- package/dist/commands/protect.js +56 -10
- package/dist/commands/protect.js.map +1 -1
- package/dist/commands/runtime.d.ts +1 -1
- package/dist/commands/runtime.js +5 -5
- package/dist/commands/runtime.js.map +1 -1
- package/dist/commands/self-register.js +6 -6
- package/dist/commands/self-register.js.map +1 -1
- package/dist/commands/shield.d.ts +36 -0
- package/dist/commands/shield.d.ts.map +1 -0
- package/dist/commands/shield.js +834 -0
- package/dist/commands/shield.js.map +1 -0
- package/dist/commands/verify.js +1 -1
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -1
- package/dist/shield/detect.d.ts +18 -0
- package/dist/shield/detect.d.ts.map +1 -0
- package/dist/shield/detect.js +402 -0
- package/dist/shield/detect.js.map +1 -0
- package/dist/shield/events.d.ts +65 -0
- package/dist/shield/events.d.ts.map +1 -0
- package/dist/shield/events.js +342 -0
- package/dist/shield/events.js.map +1 -0
- package/dist/shield/init.d.ts +22 -0
- package/dist/shield/init.d.ts.map +1 -0
- package/dist/shield/init.js +290 -0
- package/dist/shield/init.js.map +1 -0
- package/dist/shield/integrity.d.ts +75 -0
- package/dist/shield/integrity.d.ts.map +1 -0
- package/dist/shield/integrity.js +435 -0
- package/dist/shield/integrity.js.map +1 -0
- package/dist/shield/llm-backend.d.ts +36 -0
- package/dist/shield/llm-backend.d.ts.map +1 -0
- package/dist/shield/llm-backend.js +145 -0
- package/dist/shield/llm-backend.js.map +1 -0
- package/dist/shield/llm.d.ts +116 -0
- package/dist/shield/llm.d.ts.map +1 -0
- package/dist/shield/llm.js +536 -0
- package/dist/shield/llm.js.map +1 -0
- package/dist/shield/policy.d.ts +70 -0
- package/dist/shield/policy.d.ts.map +1 -0
- package/dist/shield/policy.js +399 -0
- package/dist/shield/policy.js.map +1 -0
- package/dist/shield/session.d.ts +63 -0
- package/dist/shield/session.d.ts.map +1 -0
- package/dist/shield/session.js +242 -0
- package/dist/shield/session.js.map +1 -0
- package/dist/shield/signing.d.ts +41 -0
- package/dist/shield/signing.d.ts.map +1 -0
- package/dist/shield/signing.js +161 -0
- package/dist/shield/signing.js.map +1 -0
- package/dist/shield/status.d.ts +4 -0
- package/dist/shield/status.d.ts.map +1 -0
- package/dist/shield/status.js +241 -0
- package/dist/shield/status.js.map +1 -0
- package/dist/shield/types.d.ts +398 -0
- package/dist/shield/types.d.ts.map +1 -0
- package/dist/shield/types.js +31 -0
- package/dist/shield/types.js.map +1 -0
- package/dist/util/drift-liveness.d.ts +37 -0
- package/dist/util/drift-liveness.d.ts.map +1 -0
- package/dist/util/drift-liveness.js +114 -0
- package/dist/util/drift-liveness.js.map +1 -0
- package/dist/util/drift-verification.d.ts +60 -0
- package/dist/util/drift-verification.d.ts.map +1 -0
- package/dist/util/drift-verification.js +457 -0
- package/dist/util/drift-verification.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shield LLM Intelligence Layer
|
|
4
|
+
*
|
|
5
|
+
* Uses Claude Haiku for lightweight, cost-efficient security analysis:
|
|
6
|
+
* 1. Policy suggestions from observed agent behavior
|
|
7
|
+
* 2. Anomaly explanations for unusual actions
|
|
8
|
+
* 3. Weekly report narrative generation
|
|
9
|
+
* 4. Incident triage and severity classification
|
|
10
|
+
*
|
|
11
|
+
* Design principles:
|
|
12
|
+
* - Batch processing: aggregate events, analyze in bulk (not per-event)
|
|
13
|
+
* - Aggressive caching: file-based cache with TTLs per analysis type
|
|
14
|
+
* - Graceful degradation: returns null if no API key or no consent
|
|
15
|
+
* - Cost target: <$1/month at typical usage (~$0.40/month estimated)
|
|
16
|
+
* - Zero network by default: only calls API when LLM is explicitly enabled
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.loadCache = loadCache;
|
|
20
|
+
exports.saveCache = saveCache;
|
|
21
|
+
exports.cacheKey = cacheKey;
|
|
22
|
+
exports.getCached = getCached;
|
|
23
|
+
exports.callHaiku = callHaiku;
|
|
24
|
+
exports.checkLlmAvailable = checkLlmAvailable;
|
|
25
|
+
exports.suggestPolicy = suggestPolicy;
|
|
26
|
+
exports.explainAnomaly = explainAnomaly;
|
|
27
|
+
exports.generateNarrative = generateNarrative;
|
|
28
|
+
exports.triageIncident = triageIncident;
|
|
29
|
+
exports.getCacheStats = getCacheStats;
|
|
30
|
+
const node_crypto_1 = require("node:crypto");
|
|
31
|
+
const node_fs_1 = require("node:fs");
|
|
32
|
+
const node_path_1 = require("node:path");
|
|
33
|
+
const types_js_1 = require("./types.js");
|
|
34
|
+
const events_js_1 = require("./events.js");
|
|
35
|
+
const signing_js_1 = require("./signing.js");
|
|
36
|
+
const llm_backend_js_1 = require("./llm-backend.js");
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Constants
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
const MODEL = 'claude-haiku-4-5-20251001';
|
|
41
|
+
const API_URL = 'https://api.anthropic.com/v1/messages';
|
|
42
|
+
const API_VERSION = '2023-06-01';
|
|
43
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
44
|
+
// Max tokens per analysis type (minimize cost)
|
|
45
|
+
const MAX_TOKENS = {
|
|
46
|
+
'policy-suggestion': 500,
|
|
47
|
+
'anomaly-explanation': 200,
|
|
48
|
+
'report-narrative': 400,
|
|
49
|
+
'incident-triage': 300,
|
|
50
|
+
};
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Cache management
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
function getCachePath() {
|
|
55
|
+
return (0, node_path_1.join)((0, events_js_1.getShieldDir)(), types_js_1.SHIELD_LLM_CACHE_FILE);
|
|
56
|
+
}
|
|
57
|
+
/** Load the LLM response cache from disk. Verifies signature integrity first. */
|
|
58
|
+
function loadCache() {
|
|
59
|
+
const cachePath = getCachePath();
|
|
60
|
+
if (!(0, node_fs_1.existsSync)(cachePath)) {
|
|
61
|
+
return { version: 1, entries: [] };
|
|
62
|
+
}
|
|
63
|
+
// Verify cache file integrity before loading
|
|
64
|
+
const integrity = (0, signing_js_1.verifyArtifact)(cachePath);
|
|
65
|
+
if (!integrity.valid) {
|
|
66
|
+
// Cache has been tampered with -- return empty cache
|
|
67
|
+
return { version: 1, entries: [] };
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const raw = (0, node_fs_1.readFileSync)(cachePath, 'utf-8');
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
if (parsed.version !== 1)
|
|
73
|
+
return { version: 1, entries: [] };
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return { version: 1, entries: [] };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Save the cache to disk, pruning expired entries. Re-signs the cache file. */
|
|
81
|
+
function saveCache(cache) {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
// Prune expired entries before saving
|
|
84
|
+
cache.entries = cache.entries.filter(entry => {
|
|
85
|
+
const created = new Date(entry.createdAt).getTime();
|
|
86
|
+
return now - created < entry.ttlMs;
|
|
87
|
+
});
|
|
88
|
+
// Cap at 200 entries to prevent unbounded growth
|
|
89
|
+
if (cache.entries.length > 200) {
|
|
90
|
+
cache.entries = cache.entries.slice(-200);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
(0, node_fs_1.writeFileSync)(getCachePath(), JSON.stringify(cache, null, 2), { mode: 0o600 });
|
|
94
|
+
// Re-sign the cache file after writing
|
|
95
|
+
const sig = (0, signing_js_1.signArtifact)(getCachePath());
|
|
96
|
+
const store = (0, signing_js_1.loadSignatures)() ?? { version: 1, signatures: [], updatedAt: '' };
|
|
97
|
+
// Replace existing signature for this file or add new one
|
|
98
|
+
const idx = store.signatures.findIndex(s => s.filePath === sig.filePath);
|
|
99
|
+
if (idx >= 0) {
|
|
100
|
+
store.signatures[idx] = sig;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
store.signatures.push(sig);
|
|
104
|
+
}
|
|
105
|
+
store.updatedAt = new Date().toISOString();
|
|
106
|
+
(0, signing_js_1.saveSignatures)(store);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Best effort
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Compute a cache key from input data. */
|
|
113
|
+
function cacheKey(analysisType, input) {
|
|
114
|
+
return (0, node_crypto_1.createHash)('sha256').update(`${analysisType}:${input}`).digest('hex').slice(0, 32);
|
|
115
|
+
}
|
|
116
|
+
/** Look up a cached result. Returns null if not found or expired. */
|
|
117
|
+
function getCached(cache, key) {
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
const entry = cache.entries.find(e => e.key === key);
|
|
120
|
+
if (!entry)
|
|
121
|
+
return null;
|
|
122
|
+
const created = new Date(entry.createdAt).getTime();
|
|
123
|
+
if (now - created >= entry.ttlMs)
|
|
124
|
+
return null;
|
|
125
|
+
return entry;
|
|
126
|
+
}
|
|
127
|
+
function getTtl(analysisType) {
|
|
128
|
+
switch (analysisType) {
|
|
129
|
+
case 'policy-suggestion': return types_js_1.LLM_CACHE_TTL_POLICY;
|
|
130
|
+
case 'anomaly-explanation': return types_js_1.LLM_CACHE_TTL_ANOMALY;
|
|
131
|
+
case 'report-narrative': return types_js_1.LLM_CACHE_TTL_NARRATIVE;
|
|
132
|
+
case 'incident-triage': return types_js_1.LLM_CACHE_TTL_TRIAGE;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Make a single API call to Claude Haiku.
|
|
137
|
+
* Returns the text response and token usage, or null on failure.
|
|
138
|
+
*/
|
|
139
|
+
async function callHaiku(systemPrompt, userPrompt, maxTokens, apiKey) {
|
|
140
|
+
try {
|
|
141
|
+
const response = await fetch(API_URL, {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: {
|
|
144
|
+
'x-api-key': apiKey,
|
|
145
|
+
'anthropic-version': API_VERSION,
|
|
146
|
+
'content-type': 'application/json',
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
model: MODEL,
|
|
150
|
+
max_tokens: maxTokens,
|
|
151
|
+
system: systemPrompt,
|
|
152
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
153
|
+
}),
|
|
154
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
155
|
+
});
|
|
156
|
+
if (!response.ok)
|
|
157
|
+
return null;
|
|
158
|
+
const data = (await response.json());
|
|
159
|
+
const text = data.content?.[0]?.text;
|
|
160
|
+
if (!text)
|
|
161
|
+
return null;
|
|
162
|
+
return {
|
|
163
|
+
text,
|
|
164
|
+
inputTokens: data.usage?.input_tokens ?? 0,
|
|
165
|
+
outputTokens: data.usage?.output_tokens ?? 0,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// Consent & availability check
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
/**
|
|
176
|
+
* Check if LLM intelligence is available.
|
|
177
|
+
*
|
|
178
|
+
* Priority:
|
|
179
|
+
* 1. Claude Code CLI (zero-config, no API key needed)
|
|
180
|
+
* 2. Anthropic API (requires ANTHROPIC_API_KEY + consent)
|
|
181
|
+
* 3. None
|
|
182
|
+
*
|
|
183
|
+
* Returns the detected backend and optional API key.
|
|
184
|
+
*/
|
|
185
|
+
async function checkLlmAvailable() {
|
|
186
|
+
return (0, llm_backend_js_1.detectBackend)();
|
|
187
|
+
}
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// 1. Policy Suggestion
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
const POLICY_SYSTEM_PROMPT = `You are a security policy advisor for AI coding agents. Analyze the observed agent behavior and recommend a security policy.
|
|
192
|
+
|
|
193
|
+
Respond with ONLY a JSON object matching this schema:
|
|
194
|
+
{
|
|
195
|
+
"rules": {
|
|
196
|
+
"processes": { "allow": ["list of safe commands"], "deny": ["list of dangerous commands"] },
|
|
197
|
+
"credentials": { "allow": [], "deny": ["patterns that should be blocked"] },
|
|
198
|
+
"filesystem": { "allow": ["safe paths"], "deny": ["sensitive paths"] },
|
|
199
|
+
"network": { "allow": [], "deny": [] }
|
|
200
|
+
},
|
|
201
|
+
"reasoning": "1-2 sentence explanation",
|
|
202
|
+
"confidence": 0.85
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
Focus on the most impactful rules. Keep allow/deny lists concise (max 15 items each).
|
|
206
|
+
Only include rules where you have strong evidence from the observed behavior.`;
|
|
207
|
+
/**
|
|
208
|
+
* Analyze observed agent behavior and suggest a security policy.
|
|
209
|
+
*
|
|
210
|
+
* Input: summarized event data (not raw events -- pre-aggregated to save tokens).
|
|
211
|
+
*/
|
|
212
|
+
async function suggestPolicy(agent, behaviorSummary) {
|
|
213
|
+
const { backend } = await checkLlmAvailable();
|
|
214
|
+
if (backend === 'none')
|
|
215
|
+
return null;
|
|
216
|
+
// Build cache key from behavior summary
|
|
217
|
+
const summaryKey = JSON.stringify({
|
|
218
|
+
agent,
|
|
219
|
+
actions: behaviorSummary.totalActions,
|
|
220
|
+
sessions: behaviorSummary.totalSessions,
|
|
221
|
+
procs: behaviorSummary.topProcesses.map(p => p.name).sort(),
|
|
222
|
+
});
|
|
223
|
+
const key = cacheKey('policy-suggestion', summaryKey);
|
|
224
|
+
// Check cache
|
|
225
|
+
const cache = loadCache();
|
|
226
|
+
const cached = getCached(cache, key);
|
|
227
|
+
if (cached)
|
|
228
|
+
return cached.result;
|
|
229
|
+
// Build prompt
|
|
230
|
+
const userPrompt = `Agent: ${agent}
|
|
231
|
+
Observed over ${behaviorSummary.totalSessions} sessions, ${behaviorSummary.totalActions} total actions.
|
|
232
|
+
|
|
233
|
+
Top processes spawned:
|
|
234
|
+
${behaviorSummary.topProcesses.slice(0, 20).map(p => ` ${p.name} (${p.count}x)`).join('\n')}
|
|
235
|
+
|
|
236
|
+
Credential access patterns:
|
|
237
|
+
${behaviorSummary.topCredentials.slice(0, 10).map(c => ` ${c.name} (${c.count}x)`).join('\n') || ' (none observed)'}
|
|
238
|
+
|
|
239
|
+
Filesystem paths accessed:
|
|
240
|
+
${behaviorSummary.topFilePaths.slice(0, 15).map(f => ` ${f.path} (${f.count}x)`).join('\n') || ' (none observed)'}
|
|
241
|
+
|
|
242
|
+
Network connections:
|
|
243
|
+
${behaviorSummary.topNetworkHosts.slice(0, 10).map(n => ` ${n.host} (${n.count}x)`).join('\n') || ' (none observed)'}
|
|
244
|
+
|
|
245
|
+
Generate a security policy that allows the observed safe behavior and blocks potentially dangerous actions.`;
|
|
246
|
+
const result = await (0, llm_backend_js_1.callLlm)(POLICY_SYSTEM_PROMPT, userPrompt, MAX_TOKENS['policy-suggestion']);
|
|
247
|
+
if (!result)
|
|
248
|
+
return null;
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(result.text);
|
|
251
|
+
const suggestion = {
|
|
252
|
+
agent,
|
|
253
|
+
rules: parsed.rules ?? {},
|
|
254
|
+
reasoning: parsed.reasoning ?? '',
|
|
255
|
+
confidence: Math.max(0, Math.min(1, parsed.confidence ?? 0.5)),
|
|
256
|
+
basedOnActions: behaviorSummary.totalActions,
|
|
257
|
+
basedOnSessions: behaviorSummary.totalSessions,
|
|
258
|
+
};
|
|
259
|
+
// Cache the result
|
|
260
|
+
cache.entries.push({
|
|
261
|
+
key,
|
|
262
|
+
analysisType: 'policy-suggestion',
|
|
263
|
+
result: suggestion,
|
|
264
|
+
createdAt: new Date().toISOString(),
|
|
265
|
+
ttlMs: getTtl('policy-suggestion'),
|
|
266
|
+
inputTokens: result.inputTokens,
|
|
267
|
+
outputTokens: result.outputTokens,
|
|
268
|
+
});
|
|
269
|
+
saveCache(cache);
|
|
270
|
+
return suggestion;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// 2. Anomaly Explanation
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
const ANOMALY_SYSTEM_PROMPT = `You are a security analyst reviewing AI agent actions on a developer workstation. Explain why the flagged action is anomalous and assess its risk.
|
|
280
|
+
|
|
281
|
+
Respond with ONLY a JSON object:
|
|
282
|
+
{
|
|
283
|
+
"severity": "info|low|medium|high|critical",
|
|
284
|
+
"explanation": "1-2 sentence explanation of why this is anomalous",
|
|
285
|
+
"riskFactors": ["factor1", "factor2"],
|
|
286
|
+
"suggestedAction": "ignore|investigate|block"
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
Be concise. Focus on actual risk, not theoretical concerns.`;
|
|
290
|
+
/**
|
|
291
|
+
* Explain why a specific event or action is anomalous.
|
|
292
|
+
*
|
|
293
|
+
* Designed for batch use: call with a few flagged events, not every event.
|
|
294
|
+
*/
|
|
295
|
+
async function explainAnomaly(event, context) {
|
|
296
|
+
const { backend } = await checkLlmAvailable();
|
|
297
|
+
if (backend === 'none')
|
|
298
|
+
return null;
|
|
299
|
+
const key = cacheKey('anomaly-explanation', `${event.id}:${event.action}:${event.target}`);
|
|
300
|
+
const cache = loadCache();
|
|
301
|
+
const cached = getCached(cache, key);
|
|
302
|
+
if (cached)
|
|
303
|
+
return cached.result;
|
|
304
|
+
const userPrompt = `Agent "${context.agentName}" performed an action that may be anomalous.
|
|
305
|
+
|
|
306
|
+
Action: ${event.action}
|
|
307
|
+
Target: ${event.target}
|
|
308
|
+
Category: ${event.category}
|
|
309
|
+
Source: ${event.source}
|
|
310
|
+
First time: ${context.isFirstOccurrence ? 'yes' : 'no'}
|
|
311
|
+
|
|
312
|
+
Normal behavior for this agent:
|
|
313
|
+
${context.normalActions.slice(0, 10).map(a => ` - ${a}`).join('\n')}
|
|
314
|
+
|
|
315
|
+
Assess this action.`;
|
|
316
|
+
const result = await (0, llm_backend_js_1.callLlm)(ANOMALY_SYSTEM_PROMPT, userPrompt, MAX_TOKENS['anomaly-explanation']);
|
|
317
|
+
if (!result)
|
|
318
|
+
return null;
|
|
319
|
+
try {
|
|
320
|
+
const parsed = JSON.parse(result.text);
|
|
321
|
+
const explanation = {
|
|
322
|
+
eventId: event.id,
|
|
323
|
+
severity: parsed.severity ?? event.severity,
|
|
324
|
+
explanation: parsed.explanation ?? '',
|
|
325
|
+
riskFactors: parsed.riskFactors ?? [],
|
|
326
|
+
suggestedAction: parsed.suggestedAction ?? 'investigate',
|
|
327
|
+
};
|
|
328
|
+
cache.entries.push({
|
|
329
|
+
key,
|
|
330
|
+
analysisType: 'anomaly-explanation',
|
|
331
|
+
result: explanation,
|
|
332
|
+
createdAt: new Date().toISOString(),
|
|
333
|
+
ttlMs: getTtl('anomaly-explanation'),
|
|
334
|
+
inputTokens: result.inputTokens,
|
|
335
|
+
outputTokens: result.outputTokens,
|
|
336
|
+
});
|
|
337
|
+
saveCache(cache);
|
|
338
|
+
return explanation;
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
// 3. Report Narrative
|
|
346
|
+
// ---------------------------------------------------------------------------
|
|
347
|
+
const NARRATIVE_SYSTEM_PROMPT = `You are a security report writer for AI agent workstation security. Generate a concise, actionable narrative for a weekly security report.
|
|
348
|
+
|
|
349
|
+
Respond with ONLY a JSON object:
|
|
350
|
+
{
|
|
351
|
+
"summary": "2-3 sentence overall summary",
|
|
352
|
+
"highlights": ["positive finding 1", "positive finding 2"],
|
|
353
|
+
"concerns": ["concern 1", "concern 2"],
|
|
354
|
+
"recommendations": ["actionable recommendation 1", "actionable recommendation 2"]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
Use clear, non-alarmist language. Focus on actionable insights. Max 3 items per array.`;
|
|
358
|
+
/**
|
|
359
|
+
* Generate a human-readable narrative for a weekly report.
|
|
360
|
+
*
|
|
361
|
+
* Input: pre-computed report metrics (not raw events).
|
|
362
|
+
*/
|
|
363
|
+
async function generateNarrative(report) {
|
|
364
|
+
const { backend } = await checkLlmAvailable();
|
|
365
|
+
if (backend === 'none')
|
|
366
|
+
return null;
|
|
367
|
+
const key = cacheKey('report-narrative', `${report.periodStart}:${report.periodEnd}`);
|
|
368
|
+
const cache = loadCache();
|
|
369
|
+
const cached = getCached(cache, key);
|
|
370
|
+
if (cached)
|
|
371
|
+
return cached.result;
|
|
372
|
+
const userPrompt = `Weekly Security Report (${report.periodStart.slice(0, 10)} to ${report.periodEnd.slice(0, 10)})
|
|
373
|
+
|
|
374
|
+
Agent Activity:
|
|
375
|
+
Total sessions: ${report.agentActivity.totalSessions}
|
|
376
|
+
Total actions: ${report.agentActivity.totalActions}
|
|
377
|
+
Agents: ${Object.keys(report.agentActivity.byAgent).join(', ') || 'none'}
|
|
378
|
+
|
|
379
|
+
Policy Evaluation:
|
|
380
|
+
Monitored: ${report.policyEvaluation.monitored}
|
|
381
|
+
Would block: ${report.policyEvaluation.wouldBlock}
|
|
382
|
+
Blocked: ${report.policyEvaluation.blocked}
|
|
383
|
+
Top violations: ${report.policyEvaluation.topViolations.slice(0, 3).map(v => `${v.action} (${v.count}x, ${v.severity})`).join(', ') || 'none'}
|
|
384
|
+
|
|
385
|
+
Credential Exposure:
|
|
386
|
+
Access attempts: ${report.credentialExposure.accessAttempts}
|
|
387
|
+
Unique credentials: ${report.credentialExposure.uniqueCredentials}
|
|
388
|
+
Providers: ${Object.entries(report.credentialExposure.byProvider).map(([k, v]) => `${k}: ${v}`).join(', ') || 'none'}
|
|
389
|
+
|
|
390
|
+
Supply Chain:
|
|
391
|
+
Packages installed: ${report.supplyChain.packagesInstalled}
|
|
392
|
+
Advisories: ${report.supplyChain.advisoriesFound}
|
|
393
|
+
Blocked installs: ${report.supplyChain.blockedInstalls}
|
|
394
|
+
|
|
395
|
+
Config Integrity: ${report.configIntegrity.signatureStatus}
|
|
396
|
+
Tampered files: ${report.configIntegrity.tamperedFiles.length}
|
|
397
|
+
|
|
398
|
+
Posture Score: ${report.posture.score}/100 (${report.posture.grade})
|
|
399
|
+
Trend: ${report.posture.trend ?? 'first report'}
|
|
400
|
+
|
|
401
|
+
Generate a weekly narrative.`;
|
|
402
|
+
const result = await (0, llm_backend_js_1.callLlm)(NARRATIVE_SYSTEM_PROMPT, userPrompt, MAX_TOKENS['report-narrative']);
|
|
403
|
+
if (!result)
|
|
404
|
+
return null;
|
|
405
|
+
try {
|
|
406
|
+
const parsed = JSON.parse(result.text);
|
|
407
|
+
const narrative = {
|
|
408
|
+
summary: parsed.summary ?? '',
|
|
409
|
+
highlights: parsed.highlights ?? [],
|
|
410
|
+
concerns: parsed.concerns ?? [],
|
|
411
|
+
recommendations: parsed.recommendations ?? [],
|
|
412
|
+
};
|
|
413
|
+
cache.entries.push({
|
|
414
|
+
key,
|
|
415
|
+
analysisType: 'report-narrative',
|
|
416
|
+
result: narrative,
|
|
417
|
+
createdAt: new Date().toISOString(),
|
|
418
|
+
ttlMs: getTtl('report-narrative'),
|
|
419
|
+
inputTokens: result.inputTokens,
|
|
420
|
+
outputTokens: result.outputTokens,
|
|
421
|
+
});
|
|
422
|
+
saveCache(cache);
|
|
423
|
+
return narrative;
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// 4. Incident Triage
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
const TRIAGE_SYSTEM_PROMPT = `You are a security incident analyst for AI agent workstation security. Classify the incident severity and recommend response steps.
|
|
433
|
+
|
|
434
|
+
Respond with ONLY a JSON object:
|
|
435
|
+
{
|
|
436
|
+
"classification": "false-positive|suspicious|confirmed-threat",
|
|
437
|
+
"severity": "info|low|medium|high|critical",
|
|
438
|
+
"explanation": "1-2 sentence classification rationale",
|
|
439
|
+
"responseSteps": ["step 1", "step 2"]
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
Be precise. Only classify as "confirmed-threat" if there is clear evidence of malicious intent. Max 4 response steps.`;
|
|
443
|
+
/**
|
|
444
|
+
* Triage a batch of related events as a potential incident.
|
|
445
|
+
*
|
|
446
|
+
* Input: a small batch of related high-severity events.
|
|
447
|
+
*/
|
|
448
|
+
async function triageIncident(events, context) {
|
|
449
|
+
const { backend } = await checkLlmAvailable();
|
|
450
|
+
if (backend === 'none')
|
|
451
|
+
return null;
|
|
452
|
+
const eventIds = events.map(e => e.id);
|
|
453
|
+
const key = cacheKey('incident-triage', eventIds.sort().join(':'));
|
|
454
|
+
const cache = loadCache();
|
|
455
|
+
const cached = getCached(cache, key);
|
|
456
|
+
if (cached)
|
|
457
|
+
return cached.result;
|
|
458
|
+
const eventSummary = events.slice(0, 10).map(e => ` [${e.severity}] ${e.action} -> ${e.target} (${e.outcome})`).join('\n');
|
|
459
|
+
const userPrompt = `Incident triage for agent "${context.agentName}" (policy mode: ${context.policyMode})
|
|
460
|
+
|
|
461
|
+
Events (${events.length} total):
|
|
462
|
+
${eventSummary}
|
|
463
|
+
|
|
464
|
+
Known-safe baseline actions:
|
|
465
|
+
${context.recentBaseline.slice(0, 10).map(a => ` - ${a}`).join('\n') || ' (no baseline established)'}
|
|
466
|
+
|
|
467
|
+
Classify this incident.`;
|
|
468
|
+
const result = await (0, llm_backend_js_1.callLlm)(TRIAGE_SYSTEM_PROMPT, userPrompt, MAX_TOKENS['incident-triage']);
|
|
469
|
+
if (!result)
|
|
470
|
+
return null;
|
|
471
|
+
try {
|
|
472
|
+
const parsed = JSON.parse(result.text);
|
|
473
|
+
const triage = {
|
|
474
|
+
eventIds,
|
|
475
|
+
classification: parsed.classification ?? 'suspicious',
|
|
476
|
+
severity: parsed.severity ?? 'medium',
|
|
477
|
+
explanation: parsed.explanation ?? '',
|
|
478
|
+
responseSteps: parsed.responseSteps ?? [],
|
|
479
|
+
};
|
|
480
|
+
cache.entries.push({
|
|
481
|
+
key,
|
|
482
|
+
analysisType: 'incident-triage',
|
|
483
|
+
result: triage,
|
|
484
|
+
createdAt: new Date().toISOString(),
|
|
485
|
+
ttlMs: getTtl('incident-triage'),
|
|
486
|
+
inputTokens: result.inputTokens,
|
|
487
|
+
outputTokens: result.outputTokens,
|
|
488
|
+
});
|
|
489
|
+
saveCache(cache);
|
|
490
|
+
return triage;
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Compute cache statistics for diagnostics.
|
|
498
|
+
*
|
|
499
|
+
* Estimated cost uses Haiku pricing:
|
|
500
|
+
* Input: $0.80 per million tokens
|
|
501
|
+
* Output: $4.00 per million tokens
|
|
502
|
+
*/
|
|
503
|
+
function getCacheStats() {
|
|
504
|
+
const cache = loadCache();
|
|
505
|
+
const now = Date.now();
|
|
506
|
+
let totalInput = 0;
|
|
507
|
+
let totalOutput = 0;
|
|
508
|
+
let validCount = 0;
|
|
509
|
+
const byType = {
|
|
510
|
+
'policy-suggestion': 0,
|
|
511
|
+
'anomaly-explanation': 0,
|
|
512
|
+
'report-narrative': 0,
|
|
513
|
+
'incident-triage': 0,
|
|
514
|
+
};
|
|
515
|
+
for (const entry of cache.entries) {
|
|
516
|
+
const created = new Date(entry.createdAt).getTime();
|
|
517
|
+
const isValid = now - created < entry.ttlMs;
|
|
518
|
+
if (isValid)
|
|
519
|
+
validCount++;
|
|
520
|
+
totalInput += entry.inputTokens;
|
|
521
|
+
totalOutput += entry.outputTokens;
|
|
522
|
+
byType[entry.analysisType] = (byType[entry.analysisType] ?? 0) + 1;
|
|
523
|
+
}
|
|
524
|
+
// Haiku pricing: $0.80/M input, $4.00/M output
|
|
525
|
+
const costInput = (totalInput / 1_000_000) * 0.80;
|
|
526
|
+
const costOutput = (totalOutput / 1_000_000) * 4.00;
|
|
527
|
+
return {
|
|
528
|
+
totalEntries: cache.entries.length,
|
|
529
|
+
validEntries: validCount,
|
|
530
|
+
totalInputTokens: totalInput,
|
|
531
|
+
totalOutputTokens: totalOutput,
|
|
532
|
+
estimatedCostUsd: Math.round((costInput + costOutput) * 10000) / 10000,
|
|
533
|
+
byType,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
//# sourceMappingURL=llm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/shield/llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shield: Policy loading, evaluation, and default generation.
|
|
3
|
+
*
|
|
4
|
+
* Loads YAML-formatted policies (stored as JSON with .yaml extension),
|
|
5
|
+
* evaluates actions against allow/deny rules, and generates default
|
|
6
|
+
* policies from environment scans.
|
|
7
|
+
*/
|
|
8
|
+
import type { ShieldPolicy, PolicyRules, PolicyDecision, PolicyMode, EnvironmentScan } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Glob-like pattern matching.
|
|
11
|
+
*
|
|
12
|
+
* Supports:
|
|
13
|
+
* - `*` matches any sequence of characters
|
|
14
|
+
* - Exact string match
|
|
15
|
+
* - Path prefix matching: pattern ending with `/` matches anything under
|
|
16
|
+
* that path (e.g. `~/.ssh/` matches `~/.ssh/id_rsa`)
|
|
17
|
+
*/
|
|
18
|
+
export declare function matchesPattern(value: string, pattern: string): boolean;
|
|
19
|
+
/** Return sensible default policy rules for a developer workstation. */
|
|
20
|
+
export declare function getDefaultPolicyRules(): PolicyRules;
|
|
21
|
+
/** Create a default policy with standard rules and no agent-specific overrides. */
|
|
22
|
+
export declare function createDefaultPolicy(mode?: PolicyMode): ShieldPolicy;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a policy tailored to the scanned environment.
|
|
25
|
+
* Detected CLIs are added to the process deny list. Detected MCP servers
|
|
26
|
+
* are added to the mcpServers allow list. Project-type-appropriate tools
|
|
27
|
+
* are added to the process allow list. Mode is set to 'adaptive'.
|
|
28
|
+
*/
|
|
29
|
+
export declare function generatePolicyFromScan(scan: EnvironmentScan): ShieldPolicy;
|
|
30
|
+
/**
|
|
31
|
+
* Load a shield policy from disk.
|
|
32
|
+
*
|
|
33
|
+
* Checks the user-level policy file at `~/.opena2a/shield/policy.yaml`.
|
|
34
|
+
* The file is stored as JSON despite the .yaml extension (simplest approach
|
|
35
|
+
* since we control the format).
|
|
36
|
+
*
|
|
37
|
+
* Returns null if no policy file exists or it cannot be parsed.
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadPolicy(targetDir?: string): ShieldPolicy | null;
|
|
40
|
+
/**
|
|
41
|
+
* Write a policy to disk as JSON with restrictive permissions (0o600).
|
|
42
|
+
* Creates parent directories if they do not exist.
|
|
43
|
+
*/
|
|
44
|
+
export declare function savePolicy(policy: ShieldPolicy, path: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Load the cached policy. Returns null if the cache does not exist or
|
|
47
|
+
* if the policy file has been modified more recently than the cache.
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadPolicyCache(): ShieldPolicy | null;
|
|
50
|
+
/** Save a policy to the cache file with restrictive permissions. */
|
|
51
|
+
export declare function savePolicyCache(policy: ShieldPolicy): void;
|
|
52
|
+
/**
|
|
53
|
+
* Evaluate an action against the policy.
|
|
54
|
+
*
|
|
55
|
+
* Resolution order:
|
|
56
|
+
* 1. Agent-specific rules are merged over default rules if the agent
|
|
57
|
+
* has overrides defined.
|
|
58
|
+
* 2. Deny rules are checked first -- deny takes precedence over allow.
|
|
59
|
+
* 3. In adaptive/monitor mode, denied actions are logged but not blocked
|
|
60
|
+
* (outcome='monitored'). In enforce mode, they are blocked
|
|
61
|
+
* (outcome='blocked').
|
|
62
|
+
* 4. If no rule matches, the action is implicitly allowed.
|
|
63
|
+
*
|
|
64
|
+
* @param policy - The loaded shield policy.
|
|
65
|
+
* @param agent - Agent identifier (or null for unknown agents).
|
|
66
|
+
* @param category - The action or category string (e.g. 'process.spawn' or 'processes').
|
|
67
|
+
* @param target - The target of the action (e.g. binary name, file path, hostname).
|
|
68
|
+
*/
|
|
69
|
+
export declare function evaluatePolicy(policy: ShieldPolicy, agent: string | null, category: string, target: string): PolicyDecision;
|
|
70
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/shield/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,UAAU,EACV,eAAe,EAChB,MAAM,YAAY,CAAC;AA6BpB;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA4BtE;AAMD,wEAAwE;AACxE,wBAAgB,qBAAqB,IAAI,WAAW,CA8BnD;AAMD,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,UAAuB,GAAG,YAAY,CAO/E;AAaD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,eAAe,GAAG,YAAY,CAmC1E;AAMD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA0BlE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAMnE;AAgBD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CA0BrD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAO1D;AAgDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,cAAc,CAkFhB"}
|