@roxy-agent/agents 0.1.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 +306 -0
- package/dist/approvals.js +143 -0
- package/dist/approvals.js.map +1 -0
- package/dist/classifier.js +436 -0
- package/dist/classifier.js.map +1 -0
- package/dist/dashboard/client.js +2057 -0
- package/dist/dashboard/client.js.map +1 -0
- package/dist/dashboard/html.js +57 -0
- package/dist/dashboard/html.js.map +1 -0
- package/dist/dashboard/icons.js +18 -0
- package/dist/dashboard/icons.js.map +1 -0
- package/dist/dashboard/server.js +423 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/dashboard/styles.js +1685 -0
- package/dist/dashboard/styles.js.map +1 -0
- package/dist/dashboard.js +2 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/db.js +526 -0
- package/dist/db.js.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/license.js +257 -0
- package/dist/license.js.map +1 -0
- package/dist/logger.js +44 -0
- package/dist/logger.js.map +1 -0
- package/dist/ml/bash-classifier.js +121 -0
- package/dist/ml/bash-classifier.js.map +1 -0
- package/dist/ml/embedder.js +79 -0
- package/dist/ml/embedder.js.map +1 -0
- package/dist/ml/prototypes.js +707 -0
- package/dist/ml/prototypes.js.map +1 -0
- package/dist/policies.js +289 -0
- package/dist/policies.js.map +1 -0
- package/dist/slack.js +149 -0
- package/dist/slack.js.map +1 -0
- package/dist/tools/bash.js +134 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/conversation.js +36 -0
- package/dist/tools/conversation.js.map +1 -0
- package/dist/tools/filesystem.js +243 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/introspect.js +187 -0
- package/dist/tools/introspect.js.map +1 -0
- package/dist/tools/network.js +152 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/policies.js +107 -0
- package/dist/tools/policies.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototypes.js","sourceRoot":"","sources":["../../src/ml/prototypes.ts"],"names":[],"mappings":"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"}
|
package/dist/policies.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// Natural-language policies (allowlist + blocklist) configurable from the
|
|
2
|
+
// dashboard. Policies are embedded with the same sentence-transformer used by
|
|
3
|
+
// the bash classifier and matched against an "action description" for every
|
|
4
|
+
// tool call.
|
|
5
|
+
//
|
|
6
|
+
// Precedence inside the classifier:
|
|
7
|
+
// 1. Regex hard-deny (catastrophic, never overridable)
|
|
8
|
+
// 2. BLOCK policy (denies)
|
|
9
|
+
// 3. ALLOW policy (forces low/allowed, can de-escalate flagged actions)
|
|
10
|
+
// 4. Rules + ML (the existing combined classifier)
|
|
11
|
+
import { db } from "./db.js";
|
|
12
|
+
import { embed, cosineSimilarity, isEmbedderReady } from "./ml/embedder.js";
|
|
13
|
+
// In-memory cache. Refreshed on every CRUD operation, lazily on first match
|
|
14
|
+
// request, and on demand whenever the policies table changes (so a separate
|
|
15
|
+
// dashboard process can write a policy and the MCP process picks it up on
|
|
16
|
+
// the very next tool call).
|
|
17
|
+
let cache = [];
|
|
18
|
+
let cacheLoaded = false;
|
|
19
|
+
// Cheap version stamp computed from the policies table. If this is unchanged
|
|
20
|
+
// since the last cache load, we know nothing was added/removed/edited and
|
|
21
|
+
// can reuse the in-memory vectors.
|
|
22
|
+
let cacheStamp = "";
|
|
23
|
+
function readCacheStamp() {
|
|
24
|
+
const row = db
|
|
25
|
+
.prepare(`SELECT COUNT(*) AS n, COALESCE(MAX(id),0) AS mx, COALESCE(MAX(updated_at),'') AS up FROM policies`)
|
|
26
|
+
.get();
|
|
27
|
+
return row.n + ":" + row.mx + ":" + row.up;
|
|
28
|
+
}
|
|
29
|
+
// Similarity threshold for a policy to "match". Empirically (from
|
|
30
|
+
// scripts/policy-debug.mjs against all-MiniLM-L6-v2):
|
|
31
|
+
// - random short bash command vs unrelated policy: 0.05 – 0.30
|
|
32
|
+
// - terse CLI ("aws s3 ls") vs broad NL policy ("Block all AWS commands"):
|
|
33
|
+
// 0.35 – 0.45
|
|
34
|
+
// - well-aligned NL match: 0.50+
|
|
35
|
+
// 0.40 sits comfortably above the noise floor while still catching the
|
|
36
|
+
// terse-CLI-vs-broad-policy case. Tunable via env or the dashboard tester.
|
|
37
|
+
const DEFAULT_THRESHOLD = Number(process.env.AGENT_PROXY_POLICY_THRESHOLD ?? "0.40");
|
|
38
|
+
// Optional scope filter — only policies whose `scope` is in this set (or
|
|
39
|
+
// "global") are considered. Defaults to ["global"].
|
|
40
|
+
const ACTIVE_SCOPES = (process.env.AGENT_PROXY_SCOPES ?? "global")
|
|
41
|
+
.split(",")
|
|
42
|
+
.map((s) => s.trim())
|
|
43
|
+
.filter(Boolean);
|
|
44
|
+
export function initPoliciesTable() {
|
|
45
|
+
db.exec(`
|
|
46
|
+
CREATE TABLE IF NOT EXISTS policies (
|
|
47
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
48
|
+
kind TEXT NOT NULL CHECK(kind IN ('allow','block','approve')),
|
|
49
|
+
description TEXT NOT NULL,
|
|
50
|
+
scope TEXT NOT NULL DEFAULT 'global',
|
|
51
|
+
applies_to TEXT NOT NULL DEFAULT '*',
|
|
52
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
53
|
+
match_count INTEGER NOT NULL DEFAULT 0,
|
|
54
|
+
embedding BLOB,
|
|
55
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
56
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_policy_enabled ON policies(enabled);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_policy_scope ON policies(scope);
|
|
61
|
+
`);
|
|
62
|
+
// Soft-migration: expand the kind CHECK constraint on existing DBs.
|
|
63
|
+
const row = db
|
|
64
|
+
.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='policies'`)
|
|
65
|
+
.get();
|
|
66
|
+
if (row && !row.sql.includes("'approve'")) {
|
|
67
|
+
try {
|
|
68
|
+
db.unsafeMode(true);
|
|
69
|
+
db.pragma("writable_schema = ON");
|
|
70
|
+
db.prepare(`UPDATE sqlite_master SET sql = ? WHERE type='table' AND name='policies'`).run(row.sql.replace("kind IN ('allow','block')", "kind IN ('allow','block','approve')"));
|
|
71
|
+
const v = db.pragma("schema_version", { simple: true });
|
|
72
|
+
db.pragma(`schema_version = ${v + 1}`);
|
|
73
|
+
db.pragma("writable_schema = OFF");
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
db.unsafeMode(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Embedding storage helpers
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
function vecToBlob(v) {
|
|
84
|
+
return Buffer.from(v.buffer.slice(v.byteOffset, v.byteOffset + v.byteLength));
|
|
85
|
+
}
|
|
86
|
+
function blobToVec(b) {
|
|
87
|
+
// Copy to a fresh ArrayBuffer so it's safe to share with the embedder.
|
|
88
|
+
const copy = new Uint8Array(b.byteLength);
|
|
89
|
+
copy.set(b);
|
|
90
|
+
return new Float32Array(copy.buffer);
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// CRUD
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
export function listPolicies() {
|
|
96
|
+
const rows = db
|
|
97
|
+
.prepare(`SELECT id, kind, description, scope, applies_to, enabled, match_count, created_at, updated_at
|
|
98
|
+
FROM policies ORDER BY id ASC`)
|
|
99
|
+
.all();
|
|
100
|
+
return rows.map(rowToPolicy);
|
|
101
|
+
}
|
|
102
|
+
export function getPolicy(id) {
|
|
103
|
+
const row = db
|
|
104
|
+
.prepare(`SELECT id, kind, description, scope, applies_to, enabled, match_count, created_at, updated_at
|
|
105
|
+
FROM policies WHERE id = ?`)
|
|
106
|
+
.get(id);
|
|
107
|
+
return row ? rowToPolicy(row) : undefined;
|
|
108
|
+
}
|
|
109
|
+
function rowToPolicy(r) {
|
|
110
|
+
return { ...r, enabled: !!r.enabled };
|
|
111
|
+
}
|
|
112
|
+
export async function createPolicy(input) {
|
|
113
|
+
const description = input.description.trim();
|
|
114
|
+
if (!description)
|
|
115
|
+
throw new Error("description is required");
|
|
116
|
+
if (input.kind !== "allow" && input.kind !== "block" && input.kind !== "approve") {
|
|
117
|
+
throw new Error("kind must be 'allow', 'block', or 'approve'");
|
|
118
|
+
}
|
|
119
|
+
let blob = null;
|
|
120
|
+
if (isEmbedderReady()) {
|
|
121
|
+
const vec = await embed(description);
|
|
122
|
+
blob = vecToBlob(vec);
|
|
123
|
+
}
|
|
124
|
+
// If the embedder isn't ready yet, we insert without an embedding and
|
|
125
|
+
// backfill on next refresh.
|
|
126
|
+
const result = db
|
|
127
|
+
.prepare(`INSERT INTO policies (kind, description, scope, applies_to, enabled, embedding)
|
|
128
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
129
|
+
.run(input.kind, description, input.scope ?? "global", input.applies_to ?? "*", input.enabled === false ? 0 : 1, blob);
|
|
130
|
+
const id = Number(result.lastInsertRowid);
|
|
131
|
+
await refreshCache();
|
|
132
|
+
return getPolicy(id);
|
|
133
|
+
}
|
|
134
|
+
export async function updatePolicy(id, input) {
|
|
135
|
+
const existing = getPolicy(id);
|
|
136
|
+
if (!existing)
|
|
137
|
+
return undefined;
|
|
138
|
+
const description = input.description?.trim() ?? existing.description;
|
|
139
|
+
const kind = input.kind ?? existing.kind;
|
|
140
|
+
const scope = input.scope ?? existing.scope;
|
|
141
|
+
const applies_to = input.applies_to ?? existing.applies_to;
|
|
142
|
+
const enabled = input.enabled === undefined ? existing.enabled : input.enabled;
|
|
143
|
+
// Re-embed if description changed (or we never had an embedding).
|
|
144
|
+
let blob = undefined;
|
|
145
|
+
if (description !== existing.description && isEmbedderReady()) {
|
|
146
|
+
const vec = await embed(description);
|
|
147
|
+
blob = vecToBlob(vec);
|
|
148
|
+
}
|
|
149
|
+
if (blob !== undefined) {
|
|
150
|
+
db.prepare(`UPDATE policies SET kind=?, description=?, scope=?, applies_to=?, enabled=?, embedding=?, updated_at=datetime('now') WHERE id=?`).run(kind, description, scope, applies_to, enabled ? 1 : 0, blob, id);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
db.prepare(`UPDATE policies SET kind=?, description=?, scope=?, applies_to=?, enabled=?, updated_at=datetime('now') WHERE id=?`).run(kind, description, scope, applies_to, enabled ? 1 : 0, id);
|
|
154
|
+
}
|
|
155
|
+
await refreshCache();
|
|
156
|
+
return getPolicy(id);
|
|
157
|
+
}
|
|
158
|
+
export function deletePolicy(id) {
|
|
159
|
+
const r = db.prepare(`DELETE FROM policies WHERE id = ?`).run(id);
|
|
160
|
+
if (r.changes > 0) {
|
|
161
|
+
void refreshCache();
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
function bumpMatchCount(id) {
|
|
167
|
+
db.prepare(`UPDATE policies SET match_count = match_count + 1 WHERE id = ?`).run(id);
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Cache + matching
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// Refresh the in-memory cache from the DB, embedding any policies that
|
|
173
|
+
// don't yet have a stored embedding (e.g. created before the model loaded).
|
|
174
|
+
export async function refreshCache() {
|
|
175
|
+
const rows = db
|
|
176
|
+
.prepare(`SELECT id, kind, description, scope, applies_to, enabled, match_count, embedding, created_at, updated_at
|
|
177
|
+
FROM policies ORDER BY id ASC`)
|
|
178
|
+
.all();
|
|
179
|
+
const next = [];
|
|
180
|
+
for (const r of rows) {
|
|
181
|
+
let vec = r.embedding ? blobToVec(r.embedding) : null;
|
|
182
|
+
if (!vec && isEmbedderReady()) {
|
|
183
|
+
vec = await embed(r.description);
|
|
184
|
+
db.prepare(`UPDATE policies SET embedding = ? WHERE id = ?`).run(vecToBlob(vec), r.id);
|
|
185
|
+
}
|
|
186
|
+
next.push({ ...rowToPolicy(r), vec });
|
|
187
|
+
}
|
|
188
|
+
cache = next;
|
|
189
|
+
cacheLoaded = true;
|
|
190
|
+
cacheStamp = readCacheStamp();
|
|
191
|
+
}
|
|
192
|
+
// Refresh the cache only if the underlying policies table has changed.
|
|
193
|
+
async function refreshIfStale() {
|
|
194
|
+
if (!cacheLoaded) {
|
|
195
|
+
await refreshCache();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const stamp = readCacheStamp();
|
|
199
|
+
if (stamp !== cacheStamp)
|
|
200
|
+
await refreshCache();
|
|
201
|
+
}
|
|
202
|
+
// Backfill embeddings once the model becomes available. Safe to call multiple
|
|
203
|
+
// times; only re-embeds policies that don't already have a vector.
|
|
204
|
+
export async function ensureEmbeddings() {
|
|
205
|
+
if (!isEmbedderReady())
|
|
206
|
+
return;
|
|
207
|
+
await refreshCache();
|
|
208
|
+
}
|
|
209
|
+
export async function matchPolicy(text, tool, threshold = DEFAULT_THRESHOLD) {
|
|
210
|
+
await refreshIfStale();
|
|
211
|
+
if (!cache.length || !isEmbedderReady())
|
|
212
|
+
return {};
|
|
213
|
+
const enabled = cache.filter((p) => p.enabled &&
|
|
214
|
+
p.vec &&
|
|
215
|
+
ACTIVE_SCOPES.includes(p.scope) &&
|
|
216
|
+
(p.applies_to === "*" ||
|
|
217
|
+
p.applies_to.split(",").map((t) => t.trim()).includes(tool)));
|
|
218
|
+
if (!enabled.length)
|
|
219
|
+
return {};
|
|
220
|
+
const q = await embed(text);
|
|
221
|
+
let bestBlock;
|
|
222
|
+
let bestApprove;
|
|
223
|
+
let bestAllow;
|
|
224
|
+
for (const p of enabled) {
|
|
225
|
+
if (!p.vec)
|
|
226
|
+
continue;
|
|
227
|
+
const sim = cosineSimilarity(q, p.vec);
|
|
228
|
+
if (sim < threshold)
|
|
229
|
+
continue;
|
|
230
|
+
if (p.kind === "block") {
|
|
231
|
+
if (!bestBlock || sim > bestBlock.similarity)
|
|
232
|
+
bestBlock = { policy: stripVec(p), similarity: sim };
|
|
233
|
+
}
|
|
234
|
+
else if (p.kind === "approve") {
|
|
235
|
+
if (!bestApprove || sim > bestApprove.similarity)
|
|
236
|
+
bestApprove = { policy: stripVec(p), similarity: sim };
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
if (!bestAllow || sim > bestAllow.similarity)
|
|
240
|
+
bestAllow = { policy: stripVec(p), similarity: sim };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (bestBlock)
|
|
244
|
+
bumpMatchCount(bestBlock.policy.id);
|
|
245
|
+
else if (bestApprove)
|
|
246
|
+
bumpMatchCount(bestApprove.policy.id);
|
|
247
|
+
else if (bestAllow)
|
|
248
|
+
bumpMatchCount(bestAllow.policy.id);
|
|
249
|
+
return { block: bestBlock, approve: bestApprove, allow: bestAllow };
|
|
250
|
+
}
|
|
251
|
+
function stripVec(p) {
|
|
252
|
+
// Drop both the in-memory vector AND the raw embedding blob (if any) so
|
|
253
|
+
// we never leak large binary blobs through the JSON API.
|
|
254
|
+
const { vec: _vec, ...rest } = p;
|
|
255
|
+
const restAny = rest;
|
|
256
|
+
delete restAny.embedding;
|
|
257
|
+
return rest;
|
|
258
|
+
}
|
|
259
|
+
// "Test mode" — score `text` against all enabled policies and return all
|
|
260
|
+
// similarities sorted by best. Used by the dashboard's policy tester.
|
|
261
|
+
export async function scoreAllPolicies(text, tool = "bash") {
|
|
262
|
+
await refreshIfStale();
|
|
263
|
+
if (!isEmbedderReady() || !cache.length)
|
|
264
|
+
return [];
|
|
265
|
+
const enabled = cache.filter((p) => p.vec &&
|
|
266
|
+
(p.applies_to === "*" ||
|
|
267
|
+
p.applies_to.split(",").map((t) => t.trim()).includes(tool)));
|
|
268
|
+
if (!enabled.length)
|
|
269
|
+
return [];
|
|
270
|
+
const q = await embed(text);
|
|
271
|
+
return enabled
|
|
272
|
+
.map((p) => ({
|
|
273
|
+
policy: stripVec(p),
|
|
274
|
+
similarity: p.vec ? cosineSimilarity(q, p.vec) : 0,
|
|
275
|
+
}))
|
|
276
|
+
.sort((a, b) => b.similarity - a.similarity);
|
|
277
|
+
}
|
|
278
|
+
// Format a tool action into a natural-language string for matching.
|
|
279
|
+
export function describeAction(args) {
|
|
280
|
+
switch (args.tool) {
|
|
281
|
+
case "bash":
|
|
282
|
+
return args.bash_command ?? "";
|
|
283
|
+
case "filesystem":
|
|
284
|
+
return `${args.fs_op ?? "access"} file ${args.fs_path ?? ""}`.trim();
|
|
285
|
+
case "network":
|
|
286
|
+
return `${(args.net_method ?? "GET").toUpperCase()} ${args.net_url ?? ""}`.trim();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=policies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.js","sourceRoot":"","sources":["../src/policies.ts"],"names":[],"mappings":"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"}
|
package/dist/slack.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Slack notifier for HITL approvals.
|
|
2
|
+
//
|
|
3
|
+
// v1: incoming webhook. The user pastes their Slack incoming-webhook URL in
|
|
4
|
+
// settings. We POST a Block Kit message describing the action and linking
|
|
5
|
+
// back to the dashboard's Approvals tab. Approve / Deny is done in the
|
|
6
|
+
// dashboard for now.
|
|
7
|
+
//
|
|
8
|
+
// v2 (future): Slack Bolt + socket mode so users can click Approve/Deny
|
|
9
|
+
// directly inside Slack. Skipped for now to avoid the bolt SDK dependency.
|
|
10
|
+
import { getAppSetting } from "./db.js";
|
|
11
|
+
const DEFAULT_DASHBOARD_PORT = Number(process.env.AGENT_PROXY_PORT) || 4242;
|
|
12
|
+
function slackWebhookUrl() {
|
|
13
|
+
const env = process.env.AGENT_PROXY_SLACK_WEBHOOK;
|
|
14
|
+
if (env && env.trim())
|
|
15
|
+
return env.trim();
|
|
16
|
+
try {
|
|
17
|
+
return getAppSetting("slack_webhook_url");
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function dashboardUrl() {
|
|
24
|
+
const fromSetting = getAppSetting("dashboard_public_url");
|
|
25
|
+
if (fromSetting)
|
|
26
|
+
return fromSetting.replace(/\/$/, "");
|
|
27
|
+
return `http://localhost:${DEFAULT_DASHBOARD_PORT}`;
|
|
28
|
+
}
|
|
29
|
+
function fmt(s, max = 280) {
|
|
30
|
+
if (s.length <= max)
|
|
31
|
+
return s;
|
|
32
|
+
return s.slice(0, max) + "…";
|
|
33
|
+
}
|
|
34
|
+
export async function notifyApprovalRequest(row) {
|
|
35
|
+
const url = slackWebhookUrl();
|
|
36
|
+
if (!url)
|
|
37
|
+
return; // not configured; silently skip
|
|
38
|
+
const link = `${dashboardUrl()}/#/approvals?id=${row.id}`;
|
|
39
|
+
const text = `:eyes: agent-proxy: human approval requested for *${row.tool}* — ${fmt(row.reason, 140)}`;
|
|
40
|
+
const body = {
|
|
41
|
+
text,
|
|
42
|
+
blocks: [
|
|
43
|
+
{
|
|
44
|
+
type: "section",
|
|
45
|
+
text: {
|
|
46
|
+
type: "mrkdwn",
|
|
47
|
+
text: `:eyes: *agent-proxy* — human approval requested\n` +
|
|
48
|
+
`*Tool:* \`${row.tool}\`\n` +
|
|
49
|
+
`*Reason:* ${fmt(row.reason, 200)}\n` +
|
|
50
|
+
"*Action:*",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: "section",
|
|
55
|
+
text: { type: "mrkdwn", text: "```" + fmt(row.summary, 600) + "```" },
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: "actions",
|
|
59
|
+
elements: [
|
|
60
|
+
{
|
|
61
|
+
type: "button",
|
|
62
|
+
style: "primary",
|
|
63
|
+
text: { type: "plain_text", text: "Approve" },
|
|
64
|
+
url: `${link}&action=approve`,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: "button",
|
|
68
|
+
style: "danger",
|
|
69
|
+
text: { type: "plain_text", text: "Deny" },
|
|
70
|
+
url: `${link}&action=deny`,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: "button",
|
|
74
|
+
text: { type: "plain_text", text: "Open dashboard" },
|
|
75
|
+
url: link,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: "context",
|
|
81
|
+
elements: [
|
|
82
|
+
{
|
|
83
|
+
type: "mrkdwn",
|
|
84
|
+
text: `approval #${row.id} · requested ${row.requested_at} UTC`,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
try {
|
|
91
|
+
const res = await fetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: { "content-type": "application/json" },
|
|
94
|
+
body: JSON.stringify(body),
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const errText = await res.text().catch(() => "");
|
|
98
|
+
process.stderr.write(`[agent-proxy] slack notify failed: ${res.status} ${errText.slice(0, 200)}\n`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
process.stderr.write(`[agent-proxy] slack notify error: ${err.message}\n`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function notifyApprovalResolved(row) {
|
|
106
|
+
const url = slackWebhookUrl();
|
|
107
|
+
if (!url)
|
|
108
|
+
return;
|
|
109
|
+
const status = row.status;
|
|
110
|
+
const emoji = status === "approved" ? ":white_check_mark:" : status === "denied" ? ":no_entry_sign:" : ":hourglass:";
|
|
111
|
+
const text = `${emoji} agent-proxy: approval #${row.id} ${status} ${row.decided_by ? `by ${row.decided_by}` : ""} — ${fmt(row.summary, 140)}`;
|
|
112
|
+
try {
|
|
113
|
+
await fetch(url, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: { "content-type": "application/json" },
|
|
116
|
+
body: JSON.stringify({ text }),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch { }
|
|
120
|
+
}
|
|
121
|
+
export function isSlackConfigured() {
|
|
122
|
+
return !!slackWebhookUrl();
|
|
123
|
+
}
|
|
124
|
+
// Fire-and-forget test ping used by the Settings page to verify the webhook.
|
|
125
|
+
export async function sendSlackTestMessage() {
|
|
126
|
+
const url = slackWebhookUrl();
|
|
127
|
+
if (!url)
|
|
128
|
+
return { ok: false, error: "no webhook configured" };
|
|
129
|
+
try {
|
|
130
|
+
const res = await fetch(url, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: { "content-type": "application/json" },
|
|
133
|
+
body: JSON.stringify({
|
|
134
|
+
text: ":wave: agent-proxy test message — Slack webhook is wired up correctly.",
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
error: `${res.status} ${(await res.text().catch(() => "")).slice(0, 200)}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { ok: true };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
return { ok: false, error: err.message };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { exec } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { classifyBashCommandAsync } from "../classifier.js";
|
|
5
|
+
import { logEvent, updateEventResult } from "../logger.js";
|
|
6
|
+
import { awaitApproval } from "../approvals.js";
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
// Maximum bytes of stdout/stderr to retain in a single response. Anything
|
|
9
|
+
// beyond this is truncated so we don't blow up the MCP transport.
|
|
10
|
+
const MAX_OUTPUT_BYTES = 1_000_000;
|
|
11
|
+
export const bashToolDefinition = {
|
|
12
|
+
name: "bash",
|
|
13
|
+
description: "Execute a bash command. The command is risk-classified and logged to the audit DB before execution. High-risk commands matching known dangerous patterns are denied.",
|
|
14
|
+
schema: z.object({
|
|
15
|
+
command: z.string().min(1).describe("The bash command to execute."),
|
|
16
|
+
working_directory: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Directory in which to run the command. Defaults to the server's CWD."),
|
|
20
|
+
timeout_ms: z
|
|
21
|
+
.number()
|
|
22
|
+
.int()
|
|
23
|
+
.positive()
|
|
24
|
+
.max(10 * 60 * 1000)
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Timeout in milliseconds (default 30000, max 600000)."),
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
export async function executeBash(args, session_id) {
|
|
30
|
+
const classification = await classifyBashCommandAsync(args.command);
|
|
31
|
+
const timeout = args.timeout_ms ?? 30_000;
|
|
32
|
+
const event_id = logEvent({
|
|
33
|
+
session_id,
|
|
34
|
+
tool: "bash",
|
|
35
|
+
action_type: "exec",
|
|
36
|
+
payload: {
|
|
37
|
+
command: args.command,
|
|
38
|
+
working_directory: args.working_directory ?? process.cwd(),
|
|
39
|
+
timeout_ms: timeout,
|
|
40
|
+
},
|
|
41
|
+
risk_level: classification.risk_level,
|
|
42
|
+
decision: classification.decision,
|
|
43
|
+
reason: classification.reason,
|
|
44
|
+
});
|
|
45
|
+
if (classification.decision === "denied") {
|
|
46
|
+
updateEventResult(event_id, "blocked by classifier", 0);
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
blocked: true,
|
|
50
|
+
reason: classification.reason,
|
|
51
|
+
event_id,
|
|
52
|
+
risk_level: classification.risk_level,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (classification.decision === "pending_approval") {
|
|
56
|
+
const verdict = await awaitApproval({
|
|
57
|
+
event_id,
|
|
58
|
+
tool: "bash",
|
|
59
|
+
summary: args.command,
|
|
60
|
+
reason: classification.reason,
|
|
61
|
+
payload: { command: args.command, working_directory: args.working_directory },
|
|
62
|
+
session_id,
|
|
63
|
+
});
|
|
64
|
+
if (!verdict.approved) {
|
|
65
|
+
updateEventResult(event_id, verdict.reason, 0);
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
blocked: true,
|
|
69
|
+
reason: verdict.reason,
|
|
70
|
+
event_id,
|
|
71
|
+
risk_level: classification.risk_level,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
try {
|
|
77
|
+
const { stdout, stderr } = await execAsync(args.command, {
|
|
78
|
+
cwd: args.working_directory,
|
|
79
|
+
timeout,
|
|
80
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
81
|
+
env: process.env,
|
|
82
|
+
shell: "/bin/bash",
|
|
83
|
+
});
|
|
84
|
+
const duration_ms = Date.now() - start;
|
|
85
|
+
const trimmedStdout = truncate(stdout);
|
|
86
|
+
const trimmedStderr = truncate(stderr);
|
|
87
|
+
const summary = `exit=0 stdout=${stdout.length}B stderr=${stderr.length}B`;
|
|
88
|
+
updateEventResult(event_id, summary, duration_ms);
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
stdout: trimmedStdout,
|
|
92
|
+
stderr: trimmedStderr,
|
|
93
|
+
exit_code: 0,
|
|
94
|
+
duration_ms,
|
|
95
|
+
event_id,
|
|
96
|
+
risk_level: classification.risk_level,
|
|
97
|
+
flagged: classification.decision === "flagged",
|
|
98
|
+
flag_reason: classification.decision === "flagged"
|
|
99
|
+
? classification.reason
|
|
100
|
+
: undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const duration_ms = Date.now() - start;
|
|
105
|
+
const e = err;
|
|
106
|
+
const stdout = typeof e.stdout === "string" ? e.stdout : "";
|
|
107
|
+
const stderr = typeof e.stderr === "string" ? e.stderr : "";
|
|
108
|
+
const errorMsg = e.killed
|
|
109
|
+
? `killed (signal=${e.signal ?? "unknown"})`
|
|
110
|
+
: (e.message ?? "unknown error");
|
|
111
|
+
updateEventResult(event_id, `exit=${e.code ?? "?"} stdout=${stdout.length}B stderr=${stderr.length}B`, duration_ms, errorMsg);
|
|
112
|
+
return {
|
|
113
|
+
success: false,
|
|
114
|
+
stdout: truncate(stdout),
|
|
115
|
+
stderr: truncate(stderr),
|
|
116
|
+
exit_code: typeof e.code === "number" ? e.code : undefined,
|
|
117
|
+
duration_ms,
|
|
118
|
+
event_id,
|
|
119
|
+
risk_level: classification.risk_level,
|
|
120
|
+
flagged: classification.decision === "flagged",
|
|
121
|
+
flag_reason: classification.decision === "flagged"
|
|
122
|
+
? classification.reason
|
|
123
|
+
: undefined,
|
|
124
|
+
error: errorMsg,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function truncate(s) {
|
|
129
|
+
if (s.length <= MAX_OUTPUT_BYTES)
|
|
130
|
+
return s;
|
|
131
|
+
return (s.slice(0, MAX_OUTPUT_BYTES) +
|
|
132
|
+
`\n… [truncated, ${s.length - MAX_OUTPUT_BYTES} more bytes]`);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=bash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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"}
|