@aimarket/warden 0.8.1 → 0.9.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/CHANGELOG.md +41 -5
- package/README-es.md +27 -9
- package/README-fr.md +28 -9
- package/README-ru.md +28 -9
- package/README-zh.md +23 -9
- package/README.md +27 -9
- package/dist/classifier.d.ts +50 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +164 -0
- package/dist/classifier.js.map +1 -0
- package/dist/claude-hook.d.ts +53 -0
- package/dist/claude-hook.d.ts.map +1 -0
- package/dist/claude-hook.js +192 -0
- package/dist/claude-hook.js.map +1 -0
- package/dist/histor.d.ts +69 -0
- package/dist/histor.d.ts.map +1 -0
- package/dist/histor.js +82 -0
- package/dist/histor.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/jcs.d.ts +8 -0
- package/dist/jcs.d.ts.map +1 -1
- package/dist/jcs.js +25 -5
- package/dist/jcs.js.map +1 -1
- package/dist/mcp-client.d.ts +58 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +451 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp-rpc.js +1 -1
- package/dist/mcp-server.js +8 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +7 -6
- package/dist/mcp-tools.js.map +1 -1
- package/dist/mtl.d.ts +28 -0
- package/dist/mtl.d.ts.map +1 -0
- package/dist/mtl.js +77 -0
- package/dist/mtl.js.map +1 -0
- package/dist/pin-store.js +3 -3
- package/dist/pin-store.js.map +1 -1
- package/dist/pinning.d.ts +18 -2
- package/dist/pinning.d.ts.map +1 -1
- package/dist/pinning.js +34 -7
- package/dist/pinning.js.map +1 -1
- package/dist/scan-cli.d.ts +3 -0
- package/dist/scan-cli.d.ts.map +1 -0
- package/dist/scan-cli.js +36 -0
- package/dist/scan-cli.js.map +1 -0
- package/dist/scan-config.d.ts +72 -0
- package/dist/scan-config.d.ts.map +1 -0
- package/dist/scan-config.js +239 -0
- package/dist/scan-config.js.map +1 -0
- package/dist/scan-lock.d.ts +46 -0
- package/dist/scan-lock.d.ts.map +1 -0
- package/dist/scan-lock.js +112 -0
- package/dist/scan-lock.js.map +1 -0
- package/dist/scan-report.d.ts +21 -0
- package/dist/scan-report.d.ts.map +1 -0
- package/dist/scan-report.js +273 -0
- package/dist/scan-report.js.map +1 -0
- package/dist/scan.d.ts +137 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +534 -0
- package/dist/scan.js.map +1 -0
- package/dist/static-scan.d.ts +1 -1
- package/dist/static-scan.d.ts.map +1 -1
- package/dist/static-scan.js +262 -12
- package/dist/static-scan.js.map +1 -1
- package/dist/tool-list.d.ts +34 -0
- package/dist/tool-list.d.ts.map +1 -0
- package/dist/tool-list.js +57 -0
- package/dist/tool-list.js.map +1 -0
- package/dist/wrap-cli.d.ts.map +1 -1
- package/dist/wrap-cli.js +6 -4
- package/dist/wrap-cli.js.map +1 -1
- package/dist/wrap-state.d.ts +3 -0
- package/dist/wrap-state.d.ts.map +1 -1
- package/dist/wrap-state.js +7 -4
- package/dist/wrap-state.js.map +1 -1
- package/dist/wrap.js +50 -42
- package/dist/wrap.js.map +1 -1
- package/docs/gates.es.md +59 -10
- package/docs/gates.fr.md +59 -10
- package/docs/gates.md +55 -10
- package/docs/gates.ru.md +59 -11
- package/docs/gates.zh.md +13 -7
- package/docs/scan.es.md +184 -0
- package/docs/scan.fr.md +184 -0
- package/docs/scan.md +184 -0
- package/docs/scan.ru.md +184 -0
- package/docs/scan.zh.md +184 -0
- package/docs/scanner-comparison.es.md +218 -0
- package/docs/scanner-comparison.fr.md +223 -0
- package/docs/scanner-comparison.md +209 -0
- package/docs/scanner-comparison.ru.md +214 -0
- package/docs/scanner-comparison.zh.md +135 -0
- package/package.json +5 -3
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { basename, join, resolve } from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
export const CLIENT_KINDS = ['claude-code', 'claude-desktop', 'cursor', 'vscode', 'windsurf'];
|
|
6
|
+
/** Every file a known client reads, whether or not it exists. */
|
|
7
|
+
export function knownConfigSources(d) {
|
|
8
|
+
const appData = d.env.APPDATA ?? join(d.home, 'AppData', 'Roaming');
|
|
9
|
+
const xdg = d.env.XDG_CONFIG_HOME ?? join(d.home, '.config');
|
|
10
|
+
const appSupport = (app) => d.platform === 'darwin' ? join(d.home, 'Library', 'Application Support', app)
|
|
11
|
+
: d.platform === 'win32' ? join(appData, app) : join(xdg, app);
|
|
12
|
+
return [
|
|
13
|
+
{ client: 'claude-code', scope: 'project', path: join(d.cwd, '.mcp.json') },
|
|
14
|
+
{ client: 'claude-code', scope: 'user', path: join(d.home, '.claude.json') },
|
|
15
|
+
{ client: 'claude-desktop', scope: 'user', path: join(appSupport('Claude'), 'claude_desktop_config.json') },
|
|
16
|
+
{ client: 'cursor', scope: 'project', path: join(d.cwd, '.cursor', 'mcp.json') },
|
|
17
|
+
{ client: 'cursor', scope: 'user', path: join(d.home, '.cursor', 'mcp.json') },
|
|
18
|
+
{ client: 'vscode', scope: 'project', path: join(d.cwd, '.vscode', 'mcp.json') },
|
|
19
|
+
{ client: 'vscode', scope: 'user', path: join(appSupport('Code'), 'User', 'mcp.json') },
|
|
20
|
+
{ client: 'windsurf', scope: 'user', path: join(d.home, '.codeium', 'windsurf', 'mcp_config.json') },
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
/** Which client a file given on the command line belongs to, from its name and path. */
|
|
24
|
+
export function guessClient(path) {
|
|
25
|
+
const name = basename(path), norm = path.replace(/\\/g, '/');
|
|
26
|
+
if (name === '.mcp.json' || name === '.claude.json')
|
|
27
|
+
return 'claude-code';
|
|
28
|
+
if (name === 'claude_desktop_config.json')
|
|
29
|
+
return 'claude-desktop';
|
|
30
|
+
if (name === 'mcp_config.json' || norm.includes('/windsurf/'))
|
|
31
|
+
return 'windsurf';
|
|
32
|
+
if (norm.includes('/.cursor/'))
|
|
33
|
+
return 'cursor';
|
|
34
|
+
if (norm.includes('/.vscode/') || norm.includes('/Code/User/'))
|
|
35
|
+
return 'vscode';
|
|
36
|
+
return 'file';
|
|
37
|
+
}
|
|
38
|
+
const SLUG = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
|
|
39
|
+
/** A pin id from a config key: the key itself when it is a slug, else a slug made from it. */
|
|
40
|
+
export function pinIdFor(key) {
|
|
41
|
+
if (SLUG.test(key))
|
|
42
|
+
return key;
|
|
43
|
+
const slug = key.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^[^a-zA-Z0-9]+/, '').slice(0, 128);
|
|
44
|
+
return SLUG.test(slug) ? slug : 'server-' + createHash('sha256').update(key).digest('hex').slice(0, 16);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Strip `//` and `/* *\/` comments and trailing commas, outside strings. VS Code's
|
|
48
|
+
* `mcp.json` is JSONC; the others are plain JSON, for which this is a no-op.
|
|
49
|
+
*/
|
|
50
|
+
export function stripJsonc(text) {
|
|
51
|
+
// Two string-aware passes: comments first, so a trailing comma before a comment is still seen.
|
|
52
|
+
const scan = (input, onChar) => {
|
|
53
|
+
const out = [];
|
|
54
|
+
let i = 0;
|
|
55
|
+
while (i < input.length) {
|
|
56
|
+
if (input[i] === '"') {
|
|
57
|
+
let j = i + 1;
|
|
58
|
+
while (j < input.length && input[j] !== '"') {
|
|
59
|
+
if (input[j] === '\\')
|
|
60
|
+
j++;
|
|
61
|
+
j++;
|
|
62
|
+
}
|
|
63
|
+
out.push(input.slice(i, j + 1));
|
|
64
|
+
i = j + 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
i = onChar(input[i], i, out);
|
|
68
|
+
}
|
|
69
|
+
return out.join('');
|
|
70
|
+
};
|
|
71
|
+
const noComments = scan(text, (c, i, out) => {
|
|
72
|
+
if (c === '/' && text[i + 1] === '/') {
|
|
73
|
+
let j = i;
|
|
74
|
+
while (j < text.length && text[j] !== '\n')
|
|
75
|
+
j++;
|
|
76
|
+
return j;
|
|
77
|
+
}
|
|
78
|
+
if (c === '/' && text[i + 1] === '*') {
|
|
79
|
+
const end = text.indexOf('*/', i + 2);
|
|
80
|
+
return end < 0 ? text.length : end + 2;
|
|
81
|
+
}
|
|
82
|
+
out.push(c);
|
|
83
|
+
return i + 1;
|
|
84
|
+
});
|
|
85
|
+
return scan(noComments, (c, i, out) => {
|
|
86
|
+
if (c === ',') {
|
|
87
|
+
let j = i + 1;
|
|
88
|
+
while (j < noComments.length && /\s/.test(noComments[j]))
|
|
89
|
+
j++;
|
|
90
|
+
if (noComments[j] === '}' || noComments[j] === ']')
|
|
91
|
+
return i + 1;
|
|
92
|
+
}
|
|
93
|
+
out.push(c);
|
|
94
|
+
return i + 1;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* If a config entry starts a server through `warden-mcp wrap`, return the server
|
|
99
|
+
* behind it, so `scan` vets the real program and the same pin the proxy uses.
|
|
100
|
+
*/
|
|
101
|
+
export function unwrapWarden(command, args) {
|
|
102
|
+
const base = basename(command).toLowerCase();
|
|
103
|
+
let rest;
|
|
104
|
+
if (base === 'warden-mcp' || base === 'warden-mcp.cmd')
|
|
105
|
+
rest = args;
|
|
106
|
+
else if ((base === 'node' || base === 'nodejs' || base === 'node.exe') && args[0] && /mcp-server\.js$/.test(args[0]))
|
|
107
|
+
rest = args.slice(1);
|
|
108
|
+
else if (['npx', 'npx.cmd', 'bunx', 'pnpx', 'pnpm', 'npm'].includes(base)) {
|
|
109
|
+
const at = args.findIndex(a => /^@aimarket\/warden(@[^\s]*)?$/.test(a));
|
|
110
|
+
if (at >= 0)
|
|
111
|
+
rest = args.slice(at + 1);
|
|
112
|
+
}
|
|
113
|
+
if (!rest || rest[0] !== 'wrap')
|
|
114
|
+
return undefined;
|
|
115
|
+
const dash = rest.indexOf('--');
|
|
116
|
+
if (dash < 0 || !rest[dash + 1])
|
|
117
|
+
return undefined;
|
|
118
|
+
const idAt = rest.indexOf('--id');
|
|
119
|
+
const id = idAt > 0 && idAt < dash ? rest[idAt + 1] : undefined;
|
|
120
|
+
return { id, command: rest[dash + 1], args: [...rest.slice(dash + 2)] };
|
|
121
|
+
}
|
|
122
|
+
function substitute(value, d) {
|
|
123
|
+
return value
|
|
124
|
+
.replace(/\$\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, name) => d.env[name] ?? '')
|
|
125
|
+
.replace(/\$\{workspaceFolder\}/g, d.cwd)
|
|
126
|
+
.replace(/\$\{userHome\}/g, d.home);
|
|
127
|
+
}
|
|
128
|
+
function stringMap(value, d) {
|
|
129
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
130
|
+
return undefined;
|
|
131
|
+
const out = {};
|
|
132
|
+
for (const [k, v] of Object.entries(value))
|
|
133
|
+
if (v !== undefined && v !== null)
|
|
134
|
+
out[k] = substitute(String(v), d);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
/** Parse one client file into the servers it starts. Throws on a file that is not JSON. */
|
|
138
|
+
export function parseConfigText(text, source, d) {
|
|
139
|
+
let root;
|
|
140
|
+
try {
|
|
141
|
+
root = JSON.parse(stripJsonc(text));
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
throw new Error(`${source.path}: not JSON (${err instanceof Error ? err.message : String(err)})`);
|
|
145
|
+
}
|
|
146
|
+
if (!root || typeof root !== 'object' || Array.isArray(root))
|
|
147
|
+
throw new Error(`${source.path}: top level is not an object`);
|
|
148
|
+
const r = root;
|
|
149
|
+
const maps = [];
|
|
150
|
+
const pick = (v) => { if (v && typeof v === 'object' && !Array.isArray(v))
|
|
151
|
+
maps.push(v); };
|
|
152
|
+
if (source.client === 'vscode') {
|
|
153
|
+
pick(r.servers);
|
|
154
|
+
pick(r.mcpServers);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
pick(r.mcpServers);
|
|
158
|
+
if (source.client === 'file')
|
|
159
|
+
pick(r.servers);
|
|
160
|
+
if (source.client === 'claude-code' && source.scope === 'user' && r.projects && typeof r.projects === 'object') {
|
|
161
|
+
// ~/.claude.json keeps every project's local-scope servers; only this project's start here.
|
|
162
|
+
const projects = r.projects;
|
|
163
|
+
for (const key of new Set([d.cwd, resolve(d.cwd)])) {
|
|
164
|
+
const p = projects[key];
|
|
165
|
+
if (p && typeof p === 'object')
|
|
166
|
+
pick(p.mcpServers);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const servers = [];
|
|
171
|
+
for (const map of maps) {
|
|
172
|
+
for (const [key, raw] of Object.entries(map)) {
|
|
173
|
+
const skip = (reason) => ({ id: pinIdFor(key), key, client: source.client, source: source.path, scope: source.scope,
|
|
174
|
+
ref: { id: pinIdFor(key), name: key, transport: 'stdio' }, wrapped: false, skipped: reason });
|
|
175
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
176
|
+
servers.push(skip('entry is not an object'));
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const e = raw;
|
|
180
|
+
if (e.disabled === true) {
|
|
181
|
+
servers.push(skip('disabled in the client config'));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const texts = JSON.stringify([e.command, e.args, e.url, e.serverUrl, e.headers, e.env]);
|
|
185
|
+
if (texts.includes('${input:')) {
|
|
186
|
+
servers.push(skip('needs an input value the client prompts for'));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const type = typeof e.type === 'string' ? e.type.toLowerCase() : undefined;
|
|
190
|
+
const url = typeof e.url === 'string' ? e.url : typeof e.serverUrl === 'string' ? e.serverUrl : undefined;
|
|
191
|
+
if (url) {
|
|
192
|
+
const transport = type === 'sse' ? 'sse' : 'http';
|
|
193
|
+
const id = pinIdFor(key);
|
|
194
|
+
servers.push({ id, key, client: source.client, source: source.path, scope: source.scope, wrapped: false,
|
|
195
|
+
ref: { id, name: key, transport, url: substitute(url, d) }, headers: stringMap(e.headers, d) });
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (typeof e.command !== 'string' || !e.command) {
|
|
199
|
+
servers.push(skip('no command or url'));
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
let command = substitute(e.command, d);
|
|
203
|
+
let args = Array.isArray(e.args) ? e.args.map(a => substitute(String(a), d)) : [];
|
|
204
|
+
const env = stringMap(e.env, d);
|
|
205
|
+
const inner = unwrapWarden(command, args);
|
|
206
|
+
let id = pinIdFor(key);
|
|
207
|
+
if (inner) {
|
|
208
|
+
command = inner.command;
|
|
209
|
+
args = inner.args;
|
|
210
|
+
// The id `wrap` itself uses, so its pins apply: --id when given, else its hash of the launch.
|
|
211
|
+
id = inner.id ?? createHash('sha256').update(JSON.stringify([command, args])).digest('hex');
|
|
212
|
+
}
|
|
213
|
+
servers.push({ id, key, client: source.client, source: source.path, scope: source.scope, wrapped: !!inner,
|
|
214
|
+
ref: { id, name: inner ? id : key, transport: 'stdio', command, args, ...(env ? { env } : {}) } });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return servers;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Read the given files, or every known client file that exists. A file that
|
|
221
|
+
* cannot be parsed is reported, not skipped: a config the client cannot read is
|
|
222
|
+
* not a config the client starts servers from, but the scan should say so.
|
|
223
|
+
*/
|
|
224
|
+
export async function discoverServers(paths, d, clients) {
|
|
225
|
+
const sources = paths?.length
|
|
226
|
+
? paths.map(p => ({ client: guessClient(p), scope: 'project', path: resolve(d.cwd, p) }))
|
|
227
|
+
: knownConfigSources(d).filter(s => existsSync(s.path) && (!clients || clients.includes(s.client)));
|
|
228
|
+
const results = [];
|
|
229
|
+
for (const source of sources) {
|
|
230
|
+
try {
|
|
231
|
+
results.push({ source, servers: parseConfigText(await readFile(source.path, 'utf8'), source, d) });
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
results.push({ source, servers: [], error: err instanceof Error ? err.message : String(err) });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return results;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=scan-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-config.js","sourceRoot":"","sources":["../src/scan-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { McpServerRef, PinStore, PinnedServer, RulesetRef, ToolDef } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `warden.lock.json` — reviewed tool definitions committed next to the MCP config.
|
|
4
|
+
*
|
|
5
|
+
* The lock is the pull-request form of a pin. Whoever adds or changes a server
|
|
6
|
+
* runs `scan --update-lock`; the diff of this file is what reviewers read — the
|
|
7
|
+
* tool descriptions that will reach the model, not just the command line. CI then
|
|
8
|
+
* runs `scan --lock` and fails when the config starts a server the lock does not
|
|
9
|
+
* know, starts it differently, or the server now advertises different tools.
|
|
10
|
+
*
|
|
11
|
+
* Stored entries are ordinary {@link PinnedServer} records (plus the MTL/1 digest
|
|
12
|
+
* HISTOR keys tool sets by), so the same {@link PinningGate} decides drift for
|
|
13
|
+
* `wrap` and for `scan`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const LOCK_VERSION = 1;
|
|
16
|
+
export interface LockEntry extends PinnedServer {
|
|
17
|
+
/** MTL/1 digest (HISTOR's key); absent when the set has no MTL/1 form. */
|
|
18
|
+
mtlDigest?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface LockFile {
|
|
21
|
+
lockfileVersion: number;
|
|
22
|
+
generatedBy: string;
|
|
23
|
+
ruleset: RulesetRef;
|
|
24
|
+
servers: Record<string, LockEntry>;
|
|
25
|
+
}
|
|
26
|
+
export declare class LockStore implements PinStore {
|
|
27
|
+
readonly entries: Map<string, LockEntry>;
|
|
28
|
+
constructor(entries?: Record<string, LockEntry>);
|
|
29
|
+
getPin(id: string): Promise<PinnedServer | undefined>;
|
|
30
|
+
putPin(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** Read a lock. A missing file is an empty lock; a malformed one is an error, never "empty". */
|
|
33
|
+
export declare function readLock(path: string): Promise<LockFile | undefined>;
|
|
34
|
+
/** Recursively sort object keys so the committed file diffs line by line, not reorder by reorder. */
|
|
35
|
+
export declare function sortKeys(value: unknown): unknown;
|
|
36
|
+
export declare function lockEntryFor(server: McpServerRef, tools: ToolDef[], mtlDigest: string | undefined, previous: LockEntry | undefined, now: string): LockEntry;
|
|
37
|
+
export declare function writeLock(path: string, lock: LockFile): Promise<void>;
|
|
38
|
+
export interface ToolChange {
|
|
39
|
+
tool: string;
|
|
40
|
+
kind: 'added' | 'removed' | 'changed';
|
|
41
|
+
before?: ToolDef;
|
|
42
|
+
after?: ToolDef;
|
|
43
|
+
}
|
|
44
|
+
/** What changed between the reviewed tools and the ones served now, tool by tool. */
|
|
45
|
+
export declare function diffTools(before: readonly ToolDef[] | undefined, after: readonly ToolDef[]): ToolChange[];
|
|
46
|
+
//# sourceMappingURL=scan-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-lock.d.ts","sourceRoot":"","sources":["../src/scan-lock.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC;AAED,qBAAa,SAAU,YAAW,QAAQ;IACxC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBAC7B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAM;IAC7C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IACrD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAC9B;AAWD,gGAAgG;AAChG,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAa1E;AAED,qGAAqG;AACrG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQhD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAa3J;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3E;AAED,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE;AAEtH,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,EAAE,CAWzG"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { mkdir, rename, unlink, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
import { pinToolsHash, serverIdentityHash } from './pinning.js';
|
|
6
|
+
import { displaySafe } from './sanitize.js';
|
|
7
|
+
/**
|
|
8
|
+
* `warden.lock.json` — reviewed tool definitions committed next to the MCP config.
|
|
9
|
+
*
|
|
10
|
+
* The lock is the pull-request form of a pin. Whoever adds or changes a server
|
|
11
|
+
* runs `scan --update-lock`; the diff of this file is what reviewers read — the
|
|
12
|
+
* tool descriptions that will reach the model, not just the command line. CI then
|
|
13
|
+
* runs `scan --lock` and fails when the config starts a server the lock does not
|
|
14
|
+
* know, starts it differently, or the server now advertises different tools.
|
|
15
|
+
*
|
|
16
|
+
* Stored entries are ordinary {@link PinnedServer} records (plus the MTL/1 digest
|
|
17
|
+
* HISTOR keys tool sets by), so the same {@link PinningGate} decides drift for
|
|
18
|
+
* `wrap` and for `scan`.
|
|
19
|
+
*/
|
|
20
|
+
export const LOCK_VERSION = 1;
|
|
21
|
+
export class LockStore {
|
|
22
|
+
entries;
|
|
23
|
+
constructor(entries = {}) { this.entries = new Map(Object.entries(entries)); }
|
|
24
|
+
async getPin(id) { return this.entries.get(id); }
|
|
25
|
+
async putPin() { }
|
|
26
|
+
}
|
|
27
|
+
function validEntry(id, e) {
|
|
28
|
+
if (!e || typeof e !== 'object' || Array.isArray(e))
|
|
29
|
+
return false;
|
|
30
|
+
const p = e;
|
|
31
|
+
return p.serverId === id && typeof p.toolsHash === 'string' && /^(?:rfc8785:)?[a-f0-9]{64}$/.test(p.toolsHash) &&
|
|
32
|
+
typeof p.approvedAt === 'string' && Array.isArray(p.toolNames) && p.toolNames.every(n => typeof n === 'string') &&
|
|
33
|
+
(p.identityHash === undefined || /^[a-f0-9]{64}$/.test(p.identityHash)) &&
|
|
34
|
+
(p.tools === undefined || Array.isArray(p.tools));
|
|
35
|
+
}
|
|
36
|
+
/** Read a lock. A missing file is an empty lock; a malformed one is an error, never "empty". */
|
|
37
|
+
export async function readLock(path) {
|
|
38
|
+
if (!existsSync(path))
|
|
39
|
+
return undefined;
|
|
40
|
+
let raw;
|
|
41
|
+
try {
|
|
42
|
+
raw = JSON.parse(await readFile(path, 'utf8'));
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
throw new Error(`${path}: not JSON (${err instanceof Error ? err.message : String(err)})`);
|
|
46
|
+
}
|
|
47
|
+
const lock = raw;
|
|
48
|
+
if (!lock || typeof lock !== 'object' || lock.lockfileVersion !== LOCK_VERSION || !lock.servers || typeof lock.servers !== 'object' || Array.isArray(lock.servers)) {
|
|
49
|
+
throw new Error(`${path}: not a WARDEN lock file (lockfileVersion ${LOCK_VERSION})`);
|
|
50
|
+
}
|
|
51
|
+
for (const [id, entry] of Object.entries(lock.servers)) {
|
|
52
|
+
if (!validEntry(id, entry))
|
|
53
|
+
throw new Error(`${path}: entry ${displaySafe(JSON.stringify(id), 140)} is malformed; refusing to read the lock as partly empty`);
|
|
54
|
+
}
|
|
55
|
+
return lock;
|
|
56
|
+
}
|
|
57
|
+
/** Recursively sort object keys so the committed file diffs line by line, not reorder by reorder. */
|
|
58
|
+
export function sortKeys(value) {
|
|
59
|
+
if (Array.isArray(value))
|
|
60
|
+
return value.map(sortKeys);
|
|
61
|
+
if (value && typeof value === 'object') {
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const key of Object.keys(value).sort())
|
|
64
|
+
out[key] = sortKeys(value[key]);
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
export function lockEntryFor(server, tools, mtlDigest, previous, now) {
|
|
70
|
+
const toolsHash = pinToolsHash(tools), identityHash = serverIdentityHash(server);
|
|
71
|
+
const unchanged = previous && previous.toolsHash === toolsHash && previous.identityHash === identityHash;
|
|
72
|
+
const sorted = [...tools].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
73
|
+
return {
|
|
74
|
+
serverId: server.id,
|
|
75
|
+
toolsHash, toolsHashVersion: 2, identityHash,
|
|
76
|
+
// An unchanged entry keeps its date, so re-running --update-lock produces no diff.
|
|
77
|
+
approvedAt: unchanged ? previous.approvedAt : now,
|
|
78
|
+
toolNames: sorted.map(t => t.name),
|
|
79
|
+
tools: structuredClone(sorted),
|
|
80
|
+
...(mtlDigest ? { mtlDigest } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function writeLock(path, lock) {
|
|
84
|
+
const text = JSON.stringify(sortKeys(lock), null, 2) + '\n';
|
|
85
|
+
// Pretty, sorted and atomic: the lock is read in a diff, and a failed write keeps the old one.
|
|
86
|
+
await mkdir(dirname(path), { recursive: true });
|
|
87
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
88
|
+
try {
|
|
89
|
+
await writeFile(temp, text, { mode: 0o644 });
|
|
90
|
+
await rename(temp, path);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await unlink(temp).catch(() => { });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** What changed between the reviewed tools and the ones served now, tool by tool. */
|
|
97
|
+
export function diffTools(before, after) {
|
|
98
|
+
const old = new Map((before ?? []).map(t => [t.name, t])), now = new Map(after.map(t => [t.name, t]));
|
|
99
|
+
const names = [...new Set([...old.keys(), ...now.keys()])].sort();
|
|
100
|
+
const changes = [];
|
|
101
|
+
for (const name of names) {
|
|
102
|
+
const a = old.get(name), b = now.get(name);
|
|
103
|
+
if (!a && b)
|
|
104
|
+
changes.push({ tool: name, kind: 'added', after: b });
|
|
105
|
+
else if (a && !b)
|
|
106
|
+
changes.push({ tool: name, kind: 'removed', before: a });
|
|
107
|
+
else if (a && b && pinToolsHash([a]) !== pinToolsHash([b]))
|
|
108
|
+
changes.push({ tool: name, kind: 'changed', before: a, after: b });
|
|
109
|
+
}
|
|
110
|
+
return changes;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=scan-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-lock.js","sourceRoot":"","sources":["../src/scan-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ScanReport } from './scan.js';
|
|
2
|
+
/** Short, fixed descriptions; the finding message carries the specifics. */
|
|
3
|
+
export declare const CODE_TEXT: Record<string, string>;
|
|
4
|
+
/** JSON report without the raw tool definitions (they are in the lock when they matter). */
|
|
5
|
+
export declare function toJson(report: ScanReport): string;
|
|
6
|
+
/** The terminal table. Every untrusted string goes through displaySafe. */
|
|
7
|
+
export declare function toTable(report: ScanReport, cwd: string, color: boolean): string;
|
|
8
|
+
/**
|
|
9
|
+
* SARIF for GitHub code scanning. Advisory findings are left out on purpose: the
|
|
10
|
+
* Security tab is for things that block, and TOOL_DEF_UNPINNED alone would put a
|
|
11
|
+
* result on every server in every repository.
|
|
12
|
+
*/
|
|
13
|
+
export declare function toSarif(report: ScanReport, cwd: string): object;
|
|
14
|
+
/** Inline code that untrusted text cannot break out of. */
|
|
15
|
+
export declare function mdCode(text: string, max?: number): string;
|
|
16
|
+
/** A fenced block that untrusted text cannot close. */
|
|
17
|
+
export declare function mdBlock(text: string, lang?: string): string;
|
|
18
|
+
/** Line diff, small and dependency-free: common prefix/suffix, then the middle as -/+. */
|
|
19
|
+
export declare function lineDiff(before: string[], after: string[]): string[];
|
|
20
|
+
export declare function toMarkdown(report: ScanReport, cwd: string): string;
|
|
21
|
+
//# sourceMappingURL=scan-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-report.d.ts","sourceRoot":"","sources":["../src/scan-report.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAC;AAK9D,4EAA4E;AAC5E,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyB5C,CAAC;AAMF,4FAA4F;AAC5F,wBAAgB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEjD;AAaD,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CA2C/E;AAsBD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAoC/D;AAID,2DAA2D;AAC3D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAKrD;AAED,uDAAuD;AACvD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAIvD;AAYD,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAWpE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgDlE"}
|