@aimarket/warden 0.8.2 → 0.13.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 +55 -1
- package/README-es.md +45 -10
- package/README-fr.md +45 -10
- package/README-ru.md +47 -10
- package/README-zh.md +45 -10
- package/README.md +47 -10
- package/dist/classifier.d.ts +79 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +360 -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/encoded-text.d.ts +7 -0
- package/dist/encoded-text.d.ts.map +1 -0
- package/dist/encoded-text.js +63 -0
- package/dist/encoded-text.js.map +1 -0
- package/dist/fold.d.ts +1 -2
- package/dist/fold.d.ts.map +1 -1
- package/dist/fold.js +3 -2
- package/dist/fold.js.map +1 -1
- package/dist/histor.d.ts +104 -0
- package/dist/histor.d.ts.map +1 -0
- package/dist/histor.js +86 -0
- package/dist/histor.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.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 +29 -4
- 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.d.ts.map +1 -1
- package/dist/pin-store.js +1 -0
- package/dist/pin-store.js.map +1 -1
- package/dist/pinning.d.ts +1 -1
- package/dist/pinning.d.ts.map +1 -1
- package/dist/pinning.js +12 -4
- package/dist/pinning.js.map +1 -1
- package/dist/result-screen.d.ts +19 -0
- package/dist/result-screen.d.ts.map +1 -0
- package/dist/result-screen.js +86 -0
- package/dist/result-screen.js.map +1 -0
- 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 +113 -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 +288 -0
- package/dist/scan-report.js.map +1 -0
- package/dist/scan.d.ts +177 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +754 -0
- package/dist/scan.js.map +1 -0
- package/dist/static-scan.d.ts +4 -3
- package/dist/static-scan.d.ts.map +1 -1
- package/dist/static-scan.js +227 -11
- 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/toxic-flow.d.ts +33 -0
- package/dist/toxic-flow.d.ts.map +1 -0
- package/dist/toxic-flow.js +117 -0
- package/dist/toxic-flow.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wrap-cli.d.ts +3 -0
- package/dist/wrap-cli.d.ts.map +1 -1
- package/dist/wrap-cli.js +17 -6
- package/dist/wrap-cli.js.map +1 -1
- package/dist/wrap-state.js +2 -2
- package/dist/wrap-state.js.map +1 -1
- package/dist/wrap.d.ts.map +1 -1
- package/dist/wrap.js +22 -35
- package/dist/wrap.js.map +1 -1
- package/docs/gates.es.md +40 -7
- package/docs/gates.fr.md +39 -6
- package/docs/gates.md +38 -7
- package/docs/gates.ru.md +40 -7
- package/docs/gates.zh.md +10 -5
- package/docs/scan.es.md +199 -0
- package/docs/scan.fr.md +199 -0
- package/docs/scan.md +199 -0
- package/docs/scan.ru.md +199 -0
- package/docs/scan.zh.md +199 -0
- package/docs/scanner-comparison.es.md +209 -0
- package/docs/scanner-comparison.fr.md +213 -0
- package/docs/scanner-comparison.md +200 -0
- package/docs/scanner-comparison.ru.md +205 -0
- package/docs/scanner-comparison.zh.md +131 -0
- package/docs/security-hardening-language-boundary.md +306 -0
- package/package.json +10 -5
- package/scripts/check-quality-gate.mjs +64 -0
- package/scripts/quality-public-key.pem +3 -0
|
@@ -0,0 +1,113 @@
|
|
|
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.approvalMode === undefined || ['operator', 'automatic'].includes(p.approvalMode)) &&
|
|
34
|
+
(p.identityHash === undefined || /^[a-f0-9]{64}$/.test(p.identityHash)) &&
|
|
35
|
+
(p.tools === undefined || Array.isArray(p.tools));
|
|
36
|
+
}
|
|
37
|
+
/** Read a lock. A missing file is an empty lock; a malformed one is an error, never "empty". */
|
|
38
|
+
export async function readLock(path) {
|
|
39
|
+
if (!existsSync(path))
|
|
40
|
+
return undefined;
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = JSON.parse(await readFile(path, 'utf8'));
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
throw new Error(`${path}: not JSON (${err instanceof Error ? err.message : String(err)})`);
|
|
47
|
+
}
|
|
48
|
+
const lock = raw;
|
|
49
|
+
if (!lock || typeof lock !== 'object' || lock.lockfileVersion !== LOCK_VERSION || !lock.servers || typeof lock.servers !== 'object' || Array.isArray(lock.servers)) {
|
|
50
|
+
throw new Error(`${path}: not a WARDEN lock file (lockfileVersion ${LOCK_VERSION})`);
|
|
51
|
+
}
|
|
52
|
+
for (const [id, entry] of Object.entries(lock.servers)) {
|
|
53
|
+
if (!validEntry(id, entry))
|
|
54
|
+
throw new Error(`${path}: entry ${displaySafe(JSON.stringify(id), 140)} is malformed; refusing to read the lock as partly empty`);
|
|
55
|
+
}
|
|
56
|
+
return lock;
|
|
57
|
+
}
|
|
58
|
+
/** Recursively sort object keys so the committed file diffs line by line, not reorder by reorder. */
|
|
59
|
+
export function sortKeys(value) {
|
|
60
|
+
if (Array.isArray(value))
|
|
61
|
+
return value.map(sortKeys);
|
|
62
|
+
if (value && typeof value === 'object') {
|
|
63
|
+
const out = {};
|
|
64
|
+
for (const key of Object.keys(value).sort())
|
|
65
|
+
out[key] = sortKeys(value[key]);
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
export function lockEntryFor(server, tools, mtlDigest, previous, now) {
|
|
71
|
+
const toolsHash = pinToolsHash(tools), identityHash = serverIdentityHash(server);
|
|
72
|
+
const unchanged = previous && previous.toolsHash === toolsHash && previous.identityHash === identityHash;
|
|
73
|
+
const sorted = [...tools].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
74
|
+
return {
|
|
75
|
+
serverId: server.id,
|
|
76
|
+
toolsHash, toolsHashVersion: 2, identityHash, approvalMode: "operator",
|
|
77
|
+
// An unchanged entry keeps its date, so re-running --update-lock produces no diff.
|
|
78
|
+
approvedAt: unchanged ? previous.approvedAt : now,
|
|
79
|
+
toolNames: sorted.map(t => t.name),
|
|
80
|
+
tools: structuredClone(sorted),
|
|
81
|
+
...(mtlDigest ? { mtlDigest } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export async function writeLock(path, lock) {
|
|
85
|
+
const text = JSON.stringify(sortKeys(lock), null, 2) + '\n';
|
|
86
|
+
// Pretty, sorted and atomic: the lock is read in a diff, and a failed write keeps the old one.
|
|
87
|
+
await mkdir(dirname(path), { recursive: true });
|
|
88
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
89
|
+
try {
|
|
90
|
+
await writeFile(temp, text, { mode: 0o644 });
|
|
91
|
+
await rename(temp, path);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await unlink(temp).catch(() => { });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** What changed between the reviewed tools and the ones served now, tool by tool. */
|
|
98
|
+
export function diffTools(before, after) {
|
|
99
|
+
const old = new Map((before ?? []).map(t => [t.name, t])), now = new Map(after.map(t => [t.name, t]));
|
|
100
|
+
const names = [...new Set([...old.keys(), ...now.keys()])].sort();
|
|
101
|
+
const changes = [];
|
|
102
|
+
for (const name of names) {
|
|
103
|
+
const a = old.get(name), b = now.get(name);
|
|
104
|
+
if (!a && b)
|
|
105
|
+
changes.push({ tool: name, kind: 'added', after: b });
|
|
106
|
+
else if (a && !b)
|
|
107
|
+
changes.push({ tool: name, kind: 'removed', before: a });
|
|
108
|
+
else if (a && b && pinToolsHash([a]) !== pinToolsHash([b]))
|
|
109
|
+
changes.push({ tool: name, kind: 'changed', before: a, after: b });
|
|
110
|
+
}
|
|
111
|
+
return changes;
|
|
112
|
+
}
|
|
113
|
+
//# 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":"AAOA,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,CAgD/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,CAwDlE"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { flowSentence } from './toxic-flow.js';
|
|
3
|
+
import { relative, isAbsolute, sep } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { displaySafe } from './sanitize.js';
|
|
8
|
+
const SEVERITY_ORDER = ['info', 'low', 'medium', 'high', 'critical'];
|
|
9
|
+
/** Short, fixed descriptions; the finding message carries the specifics. */
|
|
10
|
+
export const CODE_TEXT = {
|
|
11
|
+
TOOL_DEF_INJECTION: 'Tool definition carries prompt-injection phrasing',
|
|
12
|
+
TOOL_DEF_SECRET_REQUEST: 'Tool definition asks for a private key, seed phrase or SSH key',
|
|
13
|
+
TOOL_DEF_SECRET_HARVEST: 'Tool whose stated job is to read or reveal secrets',
|
|
14
|
+
TOOL_DEF_EXFIL: 'Tool definition instructs sending data to an outside destination',
|
|
15
|
+
TOOL_DEF_HIDDEN_UNICODE: 'Invisible or bidirectional characters in a tool definition',
|
|
16
|
+
TOOL_DEF_BASE64_BLOB: 'Long base64 run in a tool definition',
|
|
17
|
+
TOOL_DEF_DATA_URL: 'data: or javascript: URL in a tool definition',
|
|
18
|
+
TOOL_DEF_CREDENTIAL_PARAM: 'Tool asks for a credential as a parameter',
|
|
19
|
+
TOOL_DEF_ENV_REFERENCE: 'Tool definition refers to environment files or variables',
|
|
20
|
+
TOOL_DEF_SECRET_EXFIL: 'A secret store and a destination named close together',
|
|
21
|
+
TOOL_DEF_IMPERATIVE: 'Prompt-shaped imperative phrasing',
|
|
22
|
+
TOOL_DEF_DRIFT: 'Tool definitions changed since they were approved',
|
|
23
|
+
TOOL_DEF_UNPINNED: 'No approved snapshot of the tool definitions yet',
|
|
24
|
+
TOOL_DEF_UNCANONICAL: 'Tool definitions have no canonical form to pin',
|
|
25
|
+
SERVER_IDENTITY_DRIFT: 'The command or URL behind an approved server changed',
|
|
26
|
+
PIN_FORMAT_UPGRADE_REQUIRED: 'Approval predates extended tool fields; re-approve',
|
|
27
|
+
SERVER_UNDECLARED: 'Server came from a catalog, not from the operator',
|
|
28
|
+
LOCK_MISSING: 'Server is not in the reviewed lock file',
|
|
29
|
+
HISTOR_UNSEEN_TOOLSET: 'HISTOR never observed the tool set this server served',
|
|
30
|
+
HISTOR_CLASSIFIER: "HISTOR's classifier reads a tool as directing the model",
|
|
31
|
+
TOOL_DEF_CLASSIFIER: 'A model reads the tool as directing the model (opt-in classifier)',
|
|
32
|
+
TOOL_DEF_CROSS_TOOL: "A tool's description directs how another tool is called",
|
|
33
|
+
HISTOR_OLDER_TOOLSET: 'This server served a tool set HISTOR saw earlier, not the current one',
|
|
34
|
+
GATE_ERROR: 'A WARDEN gate failed to complete',
|
|
35
|
+
};
|
|
36
|
+
function codeText(code) {
|
|
37
|
+
return CODE_TEXT[code] ?? (code.startsWith('THREAT_') ? 'Matches a known-bad record in the threat feed' : code);
|
|
38
|
+
}
|
|
39
|
+
/** JSON report without the raw tool definitions (they are in the lock when they matter). */
|
|
40
|
+
export function toJson(report) {
|
|
41
|
+
return JSON.stringify({ ...report, servers: report.servers.map(({ tools: _tools, ...rest }) => rest) }, null, 2);
|
|
42
|
+
}
|
|
43
|
+
function displayPath(path, cwd) {
|
|
44
|
+
const rel = relative(cwd, path);
|
|
45
|
+
if (rel && !rel.startsWith('..') && !isAbsolute(rel))
|
|
46
|
+
return rel;
|
|
47
|
+
const home = homedir();
|
|
48
|
+
return path.startsWith(home + sep) ? '~' + path.slice(home.length) : path;
|
|
49
|
+
}
|
|
50
|
+
function findingLabel(f) {
|
|
51
|
+
return `${displaySafe(f.code, 60)}${f.tool ? `(${displaySafe(f.tool, 60)})` : ''}`;
|
|
52
|
+
}
|
|
53
|
+
/** The terminal table. Every untrusted string goes through displaySafe. */
|
|
54
|
+
export function toTable(report, cwd, color) {
|
|
55
|
+
const c = (code, text) => color ? `\x1b[${code}m${text}\x1b[0m` : text;
|
|
56
|
+
const lines = [];
|
|
57
|
+
const r = report.ruleset;
|
|
58
|
+
lines.push(`WARDEN scan ${report.version} · ruleset ${r.version} ${r.digest.slice(0, 19)}… · block at ${report.policy.blockAtSeverity}`);
|
|
59
|
+
if (!report.sources.length)
|
|
60
|
+
lines.push('No MCP client config found. Pass a file, or run where .mcp.json lives.');
|
|
61
|
+
for (const s of report.sources)
|
|
62
|
+
lines.push(` ${s.error ? c('31', 'unreadable') : 'read'} ${displayPath(s.path, cwd)} (${s.client}, ${s.servers} server${s.servers === 1 ? '' : 's'})${s.error ? ': ' + displaySafe(s.error, 200) : ''}`);
|
|
63
|
+
lines.push('');
|
|
64
|
+
const width = Math.min(28, Math.max(6, ...report.servers.map(s => displaySafe(s.key, 28).length)));
|
|
65
|
+
for (const s of report.servers) {
|
|
66
|
+
const mark = s.allow === false ? c('31;1', '✗ BLOCK ') : s.status === 'error' ? c('33', '! error ') : s.status === 'skipped' ? c('2', '- skip ')
|
|
67
|
+
: s.status === 'launch-only' ? c('36', '~ launch') : c('32', '✓ allow ');
|
|
68
|
+
const name = displaySafe(s.key, 28).padEnd(width);
|
|
69
|
+
let detail;
|
|
70
|
+
if (s.status === 'skipped')
|
|
71
|
+
detail = displaySafe(s.skipped ?? '', 120);
|
|
72
|
+
else if (s.status === 'error')
|
|
73
|
+
detail = displaySafe(s.error ?? '', 200);
|
|
74
|
+
else {
|
|
75
|
+
const blockingFindings = s.findings.filter(f => !f.advisory && SEVERITY_ORDER.indexOf(f.severity) >= SEVERITY_ORDER.indexOf(report.policy.blockAtSeverity));
|
|
76
|
+
const labels = [...new Set((s.allow === false ? blockingFindings : s.findings.filter(f => !f.advisory)).map(findingLabel))];
|
|
77
|
+
const shown = labels.slice(0, 4);
|
|
78
|
+
const parts = [];
|
|
79
|
+
if (s.status === 'launch-only')
|
|
80
|
+
parts.push('not started (--no-launch): launch line vetted only');
|
|
81
|
+
if (s.toolCount !== undefined)
|
|
82
|
+
parts.push(`${s.toolCount} tool${s.toolCount === 1 ? '' : 's'}`);
|
|
83
|
+
if (s.score !== undefined && s.status === 'scanned')
|
|
84
|
+
parts.push(`score ${s.score.toFixed(2)}`);
|
|
85
|
+
if (shown.length)
|
|
86
|
+
parts.push(shown.join(' '));
|
|
87
|
+
const more = labels.length - shown.length;
|
|
88
|
+
if (more > 0)
|
|
89
|
+
parts.push(`+${more} more`);
|
|
90
|
+
if (s.lock)
|
|
91
|
+
parts.push(`lock: ${s.lock.state}`);
|
|
92
|
+
if (s.histor)
|
|
93
|
+
parts.push(`histor: ${displaySafe(s.histor.match ?? (s.histor.notSent ? 'not sent' : 'unavailable'), 40)}`);
|
|
94
|
+
if (s.classifier)
|
|
95
|
+
parts.push(s.classifier.error ? 'classifier: no answer' : `classifier: ${s.classifier.flagged} flagged`);
|
|
96
|
+
detail = parts.join(' · ');
|
|
97
|
+
}
|
|
98
|
+
lines.push(` ${mark} ${name} ${c('2', s.client.padEnd(14))} ${detail}`);
|
|
99
|
+
}
|
|
100
|
+
for (const f of report.flows ?? []) {
|
|
101
|
+
lines.push('');
|
|
102
|
+
lines.push(` ${c('33;1', '⚠ toxic flow')} ${flowSentence(f, t => `${displaySafe(t.server, 28)}.${displaySafe(t.tool, 40)}`)}`);
|
|
103
|
+
}
|
|
104
|
+
const m = report.summary;
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push(`${m.servers} server${m.servers === 1 ? '' : 's'}: ${m.allowed} allowed, ${m.blocked} blocked, ${m.errors} not checked, ${m.skipped} skipped${m.launchOnly ? `, ${m.launchOnly} not started` : ''}.`);
|
|
107
|
+
if (report.lock) {
|
|
108
|
+
if (report.lock.written)
|
|
109
|
+
lines.push(`Lock written: ${displayPath(report.lock.path, cwd)}. Commit it; the diff is the review.`);
|
|
110
|
+
if (report.lock.stale.length)
|
|
111
|
+
lines.push(`In the lock but not in any config: ${report.lock.stale.map(id => displaySafe(id, 60)).join(', ')}`);
|
|
112
|
+
}
|
|
113
|
+
if (m.blocked)
|
|
114
|
+
lines.push(`Details: warden-mcp scan --json, or --markdown FILE. To review a changed server: warden-mcp scan --lock warden.lock.json --update-lock.`);
|
|
115
|
+
if (report.historWatch)
|
|
116
|
+
lines.push(`Follow changes to these servers in any feed reader: ${displaySafe(report.historWatch, 2000)}`);
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
}
|
|
119
|
+
// ── SARIF 2.1.0 ──────────────────────────────────────────────────────────────
|
|
120
|
+
const SECURITY_SEVERITY = { critical: '9.5', high: '8.0', medium: '5.5', low: '3.0', info: '1.0' };
|
|
121
|
+
const LEVEL = { critical: 'error', high: 'error', medium: 'warning', low: 'note', info: 'note' };
|
|
122
|
+
function lineOf(path, key) {
|
|
123
|
+
try {
|
|
124
|
+
const text = readFileSync(path, 'utf8');
|
|
125
|
+
const needle = JSON.stringify(key);
|
|
126
|
+
const at = text.indexOf(needle + ':') >= 0 ? text.indexOf(needle + ':') : text.indexOf(needle);
|
|
127
|
+
return at < 0 ? 1 : text.slice(0, at).split('\n').length;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function artifactUri(path, cwd) {
|
|
134
|
+
const rel = relative(cwd, path);
|
|
135
|
+
if (rel && !rel.startsWith('..') && !isAbsolute(rel))
|
|
136
|
+
return { uri: rel.split(sep).join('/'), uriBaseId: '%SRCROOT%' };
|
|
137
|
+
return { uri: pathToFileURL(path).href };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* SARIF for GitHub code scanning. Advisory findings are left out on purpose: the
|
|
141
|
+
* Security tab is for things that block, and TOOL_DEF_UNPINNED alone would put a
|
|
142
|
+
* result on every server in every repository.
|
|
143
|
+
*/
|
|
144
|
+
export function toSarif(report, cwd) {
|
|
145
|
+
const rules = new Map();
|
|
146
|
+
const results = [];
|
|
147
|
+
for (const s of report.servers) {
|
|
148
|
+
for (const f of s.findings) {
|
|
149
|
+
if (f.advisory)
|
|
150
|
+
continue;
|
|
151
|
+
const known = rules.get(f.code);
|
|
152
|
+
if (!known || SEVERITY_ORDER.indexOf(f.severity) > SEVERITY_ORDER.indexOf(known.severity))
|
|
153
|
+
rules.set(f.code, { severity: f.severity });
|
|
154
|
+
const fingerprint = createHash('sha256').update([s.client, s.key, f.code, f.tool ?? '', f.message].join('\u0000')).digest('hex');
|
|
155
|
+
results.push({
|
|
156
|
+
ruleId: f.code,
|
|
157
|
+
level: LEVEL[f.severity],
|
|
158
|
+
message: { text: `${displaySafe(s.key, 120)}: ${displaySafe(f.message, 1500)}` },
|
|
159
|
+
locations: [{ physicalLocation: { artifactLocation: artifactUri(s.source, cwd), region: { startLine: lineOf(s.source, s.key) } } }],
|
|
160
|
+
partialFingerprints: { 'wardenFinding/v1': fingerprint },
|
|
161
|
+
properties: { server: displaySafe(s.key, 200), client: s.client, gate: f.gate, severity: f.severity, ...(f.tool ? { tool: displaySafe(f.tool, 200) } : {}) },
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
$schema: 'https://json.schemastore.org/sarif-2.1.0.json',
|
|
167
|
+
version: '2.1.0',
|
|
168
|
+
runs: [{
|
|
169
|
+
tool: { driver: {
|
|
170
|
+
name: 'WARDEN', semanticVersion: report.version, informationUri: 'https://warden.modelmarket.dev/',
|
|
171
|
+
rules: [...rules.entries()].sort(([a], [b]) => a < b ? -1 : 1).map(([id, r]) => ({
|
|
172
|
+
id, name: id, shortDescription: { text: codeText(id) },
|
|
173
|
+
helpUri: 'https://github.com/alexar76/warden/blob/main/docs/gates.md',
|
|
174
|
+
defaultConfiguration: { level: LEVEL[r.severity] },
|
|
175
|
+
properties: { tags: ['security', 'mcp', 'prompt-injection'], 'security-severity': SECURITY_SEVERITY[r.severity] },
|
|
176
|
+
})),
|
|
177
|
+
} },
|
|
178
|
+
results,
|
|
179
|
+
properties: { ruleset: report.ruleset, blockAtSeverity: report.policy.blockAtSeverity },
|
|
180
|
+
}],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// ── Markdown (GitHub step summary, PR comment) ───────────────────────────────
|
|
184
|
+
/** Inline code that untrusted text cannot break out of. */
|
|
185
|
+
export function mdCode(text, max = 80) {
|
|
186
|
+
const t = displaySafe(text, max).replace(/[\r\n]+/g, ' ').replace(/\|/g, '¦');
|
|
187
|
+
const run = Math.max(0, ...[...t.matchAll(/`+/g)].map(m => m[0].length));
|
|
188
|
+
const fence = '`'.repeat(run + 1);
|
|
189
|
+
return `${fence}${run ? ' ' : ''}${t}${run ? ' ' : ''}${fence}`;
|
|
190
|
+
}
|
|
191
|
+
/** A fenced block that untrusted text cannot close. */
|
|
192
|
+
export function mdBlock(text, lang = '') {
|
|
193
|
+
const run = Math.max(2, ...[...text.matchAll(/`+/g)].map(m => m[0].length));
|
|
194
|
+
const fence = '`'.repeat(run + 1);
|
|
195
|
+
return `${fence}${lang}\n${text}\n${fence}`;
|
|
196
|
+
}
|
|
197
|
+
function toolText(t) {
|
|
198
|
+
if (!t)
|
|
199
|
+
return [];
|
|
200
|
+
const lines = [`name: ${t.name}`];
|
|
201
|
+
if (t.title)
|
|
202
|
+
lines.push(`title: ${t.title}`);
|
|
203
|
+
for (const l of String(t.description ?? '').split(/\r?\n/))
|
|
204
|
+
lines.push(`description: ${l}`);
|
|
205
|
+
lines.push(`inputSchema: ${JSON.stringify(t.inputSchema ?? {})}`);
|
|
206
|
+
for (const k of Object.keys(t).filter(k => !['name', 'title', 'description', 'inputSchema'].includes(k)).sort())
|
|
207
|
+
lines.push(`${k}: ${JSON.stringify(t[k])}`);
|
|
208
|
+
return lines.map(l => displaySafe(l, 4000));
|
|
209
|
+
}
|
|
210
|
+
/** Line diff, small and dependency-free: common prefix/suffix, then the middle as -/+. */
|
|
211
|
+
export function lineDiff(before, after) {
|
|
212
|
+
let start = 0;
|
|
213
|
+
while (start < before.length && start < after.length && before[start] === after[start])
|
|
214
|
+
start++;
|
|
215
|
+
let endA = before.length, endB = after.length;
|
|
216
|
+
while (endA > start && endB > start && before[endA - 1] === after[endB - 1]) {
|
|
217
|
+
endA--;
|
|
218
|
+
endB--;
|
|
219
|
+
}
|
|
220
|
+
return [
|
|
221
|
+
...before.slice(Math.max(0, start - 1), start).map(l => ' ' + l),
|
|
222
|
+
...before.slice(start, endA).map(l => '- ' + l),
|
|
223
|
+
...after.slice(start, endB).map(l => '+ ' + l),
|
|
224
|
+
...after.slice(endB, endB + 1).map(l => ' ' + l),
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
export function toMarkdown(report, cwd) {
|
|
228
|
+
const m = report.summary;
|
|
229
|
+
const out = [];
|
|
230
|
+
out.push(`## WARDEN · MCP server scan`);
|
|
231
|
+
out.push('');
|
|
232
|
+
out.push(`${m.blocked ? '❌' : '✅'} **${m.blocked} blocked**, ${m.allowed} allowed, ${m.errors} not checked, ${m.skipped} skipped${m.launchOnly ? `, ${m.launchOnly} not started` : ''} · ruleset ${mdCode(report.ruleset.version)} · block at ${mdCode(report.policy.blockAtSeverity)}`);
|
|
233
|
+
out.push('');
|
|
234
|
+
if (!report.servers.length) {
|
|
235
|
+
out.push('No MCP servers found in the scanned config files.');
|
|
236
|
+
return out.join('\n') + '\n';
|
|
237
|
+
}
|
|
238
|
+
out.push('| | Server | Config | Tools | Findings | Lock |');
|
|
239
|
+
out.push('|---|---|---|---|---|---|');
|
|
240
|
+
for (const s of report.servers) {
|
|
241
|
+
const mark = s.allow === false ? '❌' : s.status === 'error' ? '⚠️' : s.status === 'skipped' ? '➖' : s.status === 'launch-only' ? '🔸' : '✅';
|
|
242
|
+
const findings = s.status === 'error' ? `not checked: ${mdCode(s.error ?? '', 100)}`
|
|
243
|
+
: s.status === 'skipped' ? mdCode(s.skipped ?? '', 80)
|
|
244
|
+
: [...new Set(s.findings.filter(f => !f.advisory).map(f => f.code + (f.tool ? `(${f.tool})` : '')))].slice(0, 5).map(l => mdCode(l, 70)).join(' ') || (s.status === 'launch-only' ? 'launch line only (not started)' : '—');
|
|
245
|
+
out.push(`| ${mark} | ${mdCode(s.key, 50)} | ${mdCode(displayPath(s.source, cwd), 60)} | ${s.toolCount ?? '—'} | ${findings} | ${s.lock ? mdCode(s.lock.state) : '—'} |`);
|
|
246
|
+
}
|
|
247
|
+
const blocked = report.servers.filter(s => s.allow === false);
|
|
248
|
+
for (const s of blocked) {
|
|
249
|
+
out.push('');
|
|
250
|
+
out.push(`<details><summary>❌ ${mdCode(s.key, 60)} — why it was blocked</summary>`);
|
|
251
|
+
out.push('');
|
|
252
|
+
out.push(mdBlock(s.findings.filter(f => !f.advisory).map(f => `[${f.severity}] ${f.code}${f.tool ? ` (${f.tool})` : ''}: ${f.message}`).map(l => displaySafe(l, 1500)).join('\n')));
|
|
253
|
+
out.push('');
|
|
254
|
+
out.push('</details>');
|
|
255
|
+
}
|
|
256
|
+
const changed = report.servers.filter(s => s.lock?.changes?.length);
|
|
257
|
+
for (const s of changed) {
|
|
258
|
+
out.push('');
|
|
259
|
+
out.push(`<details${s.lock.state === 'drift' || s.lock.state === 'missing' ? ' open' : ''}><summary>${s.lock.state === 'missing' ? 'New server' : 'Changed tool definitions'}: ${mdCode(s.key, 60)} (${s.lock.changes.length} tool${s.lock.changes.length === 1 ? '' : 's'})</summary>`);
|
|
260
|
+
out.push('');
|
|
261
|
+
const diff = [];
|
|
262
|
+
for (const ch of s.lock.changes.slice(0, 40)) {
|
|
263
|
+
diff.push(`@@ ${ch.kind} ${displaySafe(ch.tool, 120)} @@`);
|
|
264
|
+
diff.push(...lineDiff(toolText(ch.before), toolText(ch.after)));
|
|
265
|
+
}
|
|
266
|
+
if (s.lock.changes.length > 40)
|
|
267
|
+
diff.push(`… ${s.lock.changes.length - 40} more tools`);
|
|
268
|
+
out.push(mdBlock(diff.join('\n').slice(0, 60_000), 'diff'));
|
|
269
|
+
out.push('');
|
|
270
|
+
out.push('</details>');
|
|
271
|
+
}
|
|
272
|
+
if (report.lock?.stale.length) {
|
|
273
|
+
out.push('');
|
|
274
|
+
out.push(`In the lock but no longer in any config: ${report.lock.stale.map(id => mdCode(id, 60)).join(', ')}`);
|
|
275
|
+
}
|
|
276
|
+
for (const f of report.flows ?? []) {
|
|
277
|
+
out.push('');
|
|
278
|
+
out.push(`⚠️ **Toxic flow** (advisory): ${flowSentence(f, t => mdCode(`${t.server}.${t.tool}`, 70))}`);
|
|
279
|
+
}
|
|
280
|
+
if (report.historWatch) {
|
|
281
|
+
out.push('');
|
|
282
|
+
out.push(`[Follow changes to these servers](${report.historWatch}) (HISTOR feed)`);
|
|
283
|
+
}
|
|
284
|
+
out.push('');
|
|
285
|
+
out.push(`<sub>@aimarket/warden ${displaySafe(report.version, 20)} · ${mdCode(report.ruleset.digest, 60)} · tool descriptions are shown as code; they are untrusted text from the servers.</sub>`);
|
|
286
|
+
return out.join('\n') + '\n';
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=scan-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-report.js","sourceRoot":"","sources":["../src/scan-report.ts"],"names":[],"mappings":"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"}
|