@aimarket/warden 0.17.0 → 0.19.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 +19 -1
- package/README-es.md +14 -15
- package/README-fr.md +14 -15
- package/README-ru.md +14 -15
- package/README-zh.md +14 -15
- package/README.md +15 -16
- package/dist/claude-hook.d.ts.map +1 -1
- package/dist/claude-hook.js +9 -3
- package/dist/claude-hook.js.map +1 -1
- package/dist/flow-guard.d.ts +60 -3
- package/dist/flow-guard.d.ts.map +1 -1
- package/dist/flow-guard.js +255 -16
- package/dist/flow-guard.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +4 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +25 -3
- package/dist/mcp-tools.js.map +1 -1
- package/dist/review-diff.d.ts +52 -0
- package/dist/review-diff.d.ts.map +1 -0
- package/dist/review-diff.js +237 -0
- package/dist/review-diff.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 +46 -3
- package/dist/static-scan.js.map +1 -1
- package/dist/wrap-state.d.ts.map +1 -1
- package/dist/wrap-state.js +5 -0
- package/dist/wrap-state.js.map +1 -1
- package/docs/flow-guard.es.md +57 -19
- package/docs/flow-guard.fr.md +58 -19
- package/docs/flow-guard.md +56 -20
- package/docs/flow-guard.ru.md +54 -18
- package/docs/flow-guard.zh.md +41 -16
- package/docs/gates.es.md +19 -5
- package/docs/gates.fr.md +19 -4
- package/docs/gates.md +19 -5
- package/docs/gates.ru.md +19 -5
- package/docs/gates.zh.md +6 -4
- package/docs/scanner-comparison.es.md +23 -1
- package/docs/scanner-comparison.fr.md +23 -1
- package/docs/scanner-comparison.md +22 -1
- package/docs/scanner-comparison.ru.md +23 -1
- package/docs/scanner-comparison.zh.md +18 -1
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What changed between the tool definitions a person approved and the ones a server serves now,
|
|
3
|
+
* field by field, for the re-approval review.
|
|
4
|
+
*
|
|
5
|
+
* A pin is a hash: it says THAT something changed. A reviewer needs WHAT changed. Over four weeks
|
|
6
|
+
* of HISTOR's log (snapshot 2026-10-20, 23,821 changes), 59.5% changed a tool's description
|
|
7
|
+
* (45.1% by more than digits) and 30.8% added or removed tools, while 13.4% touched nothing but
|
|
8
|
+
* digits, separators or whitespace (live counters, prices and limits written into definitions).
|
|
9
|
+
* A review that shows two full JSON blobs for each of those trains people to approve without
|
|
10
|
+
* reading. This module
|
|
11
|
+
* shows the path of every changed value, the words added and removed in text, and marks a change
|
|
12
|
+
* made only of numbers. It marks; it never approves: a changed limit is also a number.
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolDef } from "./types.js";
|
|
15
|
+
export type WordOp = ["=" | "+" | "-", string];
|
|
16
|
+
export interface FieldChange {
|
|
17
|
+
/** Dotted path inside the tool, e.g. `description` or `inputSchema.properties.days.maximum`. */
|
|
18
|
+
path: string;
|
|
19
|
+
/** Absent when the value did not exist on that side. */
|
|
20
|
+
before?: unknown;
|
|
21
|
+
after?: unknown;
|
|
22
|
+
/** For a string on both sides: the word diff. */
|
|
23
|
+
words?: WordOp[];
|
|
24
|
+
/** Only digits, separators or whitespace differ (a counter, a date, a limit). Still a change. */
|
|
25
|
+
numbersOnly: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ToolChange {
|
|
28
|
+
tool: string;
|
|
29
|
+
kind: "added" | "removed" | "changed";
|
|
30
|
+
/** For `changed`: every value that differs. */
|
|
31
|
+
fields: FieldChange[];
|
|
32
|
+
/** For `added` / `removed`: the whole definition. */
|
|
33
|
+
definition?: ToolDef;
|
|
34
|
+
/** A changed tool whose every field change is numbers only. */
|
|
35
|
+
numbersOnly: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface DefinitionDiff {
|
|
38
|
+
changes: ToolChange[];
|
|
39
|
+
added: number;
|
|
40
|
+
removed: number;
|
|
41
|
+
changed: number;
|
|
42
|
+
/** Changed tools whose changes are numbers only. */
|
|
43
|
+
numbersOnly: number;
|
|
44
|
+
}
|
|
45
|
+
/** Words and the spaces between them, so that joining the tokens gives the text back. */
|
|
46
|
+
export declare function tokenize(text: string): string[];
|
|
47
|
+
export declare function wordDiff(before: string, after: string): WordOp[];
|
|
48
|
+
/** Field-level changes from `before` (approved) to `after` (served now), tools matched by name. */
|
|
49
|
+
export declare function diffToolDefinitions(before: readonly ToolDef[], after: readonly ToolDef[]): DefinitionDiff;
|
|
50
|
+
/** The diff as review lines: `[-removed-]` and `{+added+}` inside text, `before → after` for values. */
|
|
51
|
+
export declare function formatDefinitionDiff(diff: DefinitionDiff): string[];
|
|
52
|
+
//# sourceMappingURL=review-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-diff.d.ts","sourceRoot":"","sources":["../src/review-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,iGAAiG;IACjG,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACtC,+CAA+C;IAC/C,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;CACrB;AAyBD,yFAAyF;AACzF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/C;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuChE;AAoED,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,cAAc,CAqBzG;AAOD,wGAAwG;AACxG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,EAAE,CA0BnE"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
const NUMERIC_TEXT = /^[\s\d.,:\-/+%]*$/;
|
|
2
|
+
/** Above this many token pairs the word diff falls back to "common start, common end, the middle replaced". */
|
|
3
|
+
const LCS_LIMIT = 4_000_000;
|
|
4
|
+
const MAX_FIELDS_PER_TOOL = 200;
|
|
5
|
+
function isPlainObject(v) {
|
|
6
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7
|
+
}
|
|
8
|
+
function isPrimitive(v) {
|
|
9
|
+
return v === null || (typeof v !== "object" && typeof v !== "function");
|
|
10
|
+
}
|
|
11
|
+
function same(a, b) {
|
|
12
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
13
|
+
}
|
|
14
|
+
function joinPath(base, key) {
|
|
15
|
+
if (typeof key === "number")
|
|
16
|
+
return `${base}[${key}]`;
|
|
17
|
+
const safe = /^[A-Za-z_$][\w$-]*$/.test(key) ? key : JSON.stringify(key);
|
|
18
|
+
return base ? `${base}.${safe}` : safe;
|
|
19
|
+
}
|
|
20
|
+
/** Words and the spaces between them, so that joining the tokens gives the text back. */
|
|
21
|
+
export function tokenize(text) {
|
|
22
|
+
// A number keeps its separators (6,426 · 1.5 · 2026-10-21), so a moved counter reads as one edit.
|
|
23
|
+
return text.match(/\s+|\d+(?:[.,:/-]\d+)*(?![\p{L}_])|[\p{L}\p{N}_]+|[^\s\p{L}\p{N}_]/gu) ?? [];
|
|
24
|
+
}
|
|
25
|
+
export function wordDiff(before, after) {
|
|
26
|
+
const a = tokenize(before), b = tokenize(after);
|
|
27
|
+
let start = 0;
|
|
28
|
+
while (start < a.length && start < b.length && a[start] === b[start])
|
|
29
|
+
start++;
|
|
30
|
+
let endA = a.length, endB = b.length;
|
|
31
|
+
while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {
|
|
32
|
+
endA--;
|
|
33
|
+
endB--;
|
|
34
|
+
}
|
|
35
|
+
const midA = a.slice(start, endA), midB = b.slice(start, endB);
|
|
36
|
+
const ops = [];
|
|
37
|
+
const push = (op, text) => {
|
|
38
|
+
if (!text)
|
|
39
|
+
return;
|
|
40
|
+
const last = ops[ops.length - 1];
|
|
41
|
+
if (last && last[0] === op)
|
|
42
|
+
last[1] += text;
|
|
43
|
+
else
|
|
44
|
+
ops.push([op, text]);
|
|
45
|
+
};
|
|
46
|
+
push("=", a.slice(0, start).join(""));
|
|
47
|
+
if (midA.length * midB.length > LCS_LIMIT) {
|
|
48
|
+
push("-", midA.join(""));
|
|
49
|
+
push("+", midB.join(""));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Longest common subsequence over the middle (after trimming the common start and end).
|
|
53
|
+
const n = midA.length, m = midB.length;
|
|
54
|
+
const table = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));
|
|
55
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
56
|
+
const row = table[i], next = table[i + 1];
|
|
57
|
+
for (let j = m - 1; j >= 0; j--) {
|
|
58
|
+
row[j] = midA[i] === midB[j] ? next[j + 1] + 1 : Math.max(next[j], row[j + 1]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let i = 0, j = 0;
|
|
62
|
+
while (i < n && j < m) {
|
|
63
|
+
if (midA[i] === midB[j]) {
|
|
64
|
+
push("=", midA[i]);
|
|
65
|
+
i++;
|
|
66
|
+
j++;
|
|
67
|
+
}
|
|
68
|
+
else if (table[i + 1][j] >= table[i][j + 1]) {
|
|
69
|
+
push("-", midA[i]);
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
push("+", midB[j]);
|
|
74
|
+
j++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
while (i < n)
|
|
78
|
+
push("-", midA[i++]);
|
|
79
|
+
while (j < m)
|
|
80
|
+
push("+", midB[j++]);
|
|
81
|
+
}
|
|
82
|
+
push("=", a.slice(endA).join(""));
|
|
83
|
+
return coalesce(ops);
|
|
84
|
+
}
|
|
85
|
+
/** Text so short and plain that splitting two edits around it only makes them harder to read. */
|
|
86
|
+
const GLUE = /^[\s\p{P}\p{S}]{1,3}$/u;
|
|
87
|
+
/**
|
|
88
|
+
* Join edits separated only by spaces or a stray punctuation mark into one removed and one added
|
|
89
|
+
* phrase: "[-Force a new-]{+Delete all previous+} login" reads; "[-Force-]{+Delete+} [-a-]{+all+}"
|
|
90
|
+
* does not. The glue appears on both sides, so the two sides still spell the old and new text.
|
|
91
|
+
*/
|
|
92
|
+
function coalesce(ops) {
|
|
93
|
+
const out = [];
|
|
94
|
+
let del = "", ins = "";
|
|
95
|
+
const flush = () => {
|
|
96
|
+
if (del)
|
|
97
|
+
out.push(["-", del]);
|
|
98
|
+
if (ins)
|
|
99
|
+
out.push(["+", ins]);
|
|
100
|
+
del = "";
|
|
101
|
+
ins = "";
|
|
102
|
+
};
|
|
103
|
+
for (let i = 0; i < ops.length; i++) {
|
|
104
|
+
const [op, text] = ops[i];
|
|
105
|
+
if (op === "-")
|
|
106
|
+
del += text;
|
|
107
|
+
else if (op === "+")
|
|
108
|
+
ins += text;
|
|
109
|
+
else if ((del || ins) && i + 1 < ops.length && GLUE.test(text)) {
|
|
110
|
+
del += text;
|
|
111
|
+
ins += text;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
flush();
|
|
115
|
+
out.push(["=", text]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
flush();
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
function textNumbersOnly(ops) {
|
|
122
|
+
const edits = ops.filter(op => op[0] !== "=").map(op => op[1]);
|
|
123
|
+
return edits.length > 0 && edits.every(e => NUMERIC_TEXT.test(e));
|
|
124
|
+
}
|
|
125
|
+
function walk(path, before, after, out) {
|
|
126
|
+
if (out.length >= MAX_FIELDS_PER_TOOL || same(before, after))
|
|
127
|
+
return;
|
|
128
|
+
if (isPlainObject(before) && isPlainObject(after)) {
|
|
129
|
+
const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])].sort();
|
|
130
|
+
for (const key of keys) {
|
|
131
|
+
const p = joinPath(path, key);
|
|
132
|
+
const hasB = Object.prototype.hasOwnProperty.call(before, key), hasA = Object.prototype.hasOwnProperty.call(after, key);
|
|
133
|
+
if (hasB && hasA)
|
|
134
|
+
walk(p, before[key], after[key], out);
|
|
135
|
+
else if (hasB)
|
|
136
|
+
out.push({ path: p, before: before[key], numbersOnly: false });
|
|
137
|
+
else
|
|
138
|
+
out.push({ path: p, after: after[key], numbersOnly: false });
|
|
139
|
+
if (out.length >= MAX_FIELDS_PER_TOOL)
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (Array.isArray(before) && Array.isArray(after) && !(before.every(isPrimitive) && after.every(isPrimitive))) {
|
|
145
|
+
const n = Math.max(before.length, after.length);
|
|
146
|
+
for (let i = 0; i < n; i++) {
|
|
147
|
+
const p = joinPath(path, i);
|
|
148
|
+
if (i >= before.length)
|
|
149
|
+
out.push({ path: p, after: after[i], numbersOnly: false });
|
|
150
|
+
else if (i >= after.length)
|
|
151
|
+
out.push({ path: p, before: before[i], numbersOnly: false });
|
|
152
|
+
else
|
|
153
|
+
walk(p, before[i], after[i], out);
|
|
154
|
+
if (out.length >= MAX_FIELDS_PER_TOOL)
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (typeof before === "string" && typeof after === "string") {
|
|
160
|
+
const words = wordDiff(before, after);
|
|
161
|
+
out.push({ path, before, after, words, numbersOnly: textNumbersOnly(words) });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const numbersOnly = typeof before === "number" && typeof after === "number";
|
|
165
|
+
out.push({ path, before, after, numbersOnly });
|
|
166
|
+
}
|
|
167
|
+
/** Field-level changes from `before` (approved) to `after` (served now), tools matched by name. */
|
|
168
|
+
export function diffToolDefinitions(before, after) {
|
|
169
|
+
const old = new Map(before.map(t => [t.name, t])), next = new Map(after.map(t => [t.name, t]));
|
|
170
|
+
const names = [...new Set([...old.keys(), ...next.keys()])].sort();
|
|
171
|
+
const changes = [];
|
|
172
|
+
for (const name of names) {
|
|
173
|
+
const b = old.get(name), a = next.get(name);
|
|
174
|
+
if (!b && a)
|
|
175
|
+
changes.push({ tool: name, kind: "added", fields: [], definition: a, numbersOnly: false });
|
|
176
|
+
else if (b && !a)
|
|
177
|
+
changes.push({ tool: name, kind: "removed", fields: [], definition: b, numbersOnly: false });
|
|
178
|
+
else if (b && a && !same(b, a)) {
|
|
179
|
+
const fields = [];
|
|
180
|
+
walk("", b, a, fields);
|
|
181
|
+
changes.push({ tool: name, kind: "changed", fields, numbersOnly: fields.length > 0 && fields.every(f => f.numbersOnly) });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
changes,
|
|
186
|
+
added: changes.filter(c => c.kind === "added").length,
|
|
187
|
+
removed: changes.filter(c => c.kind === "removed").length,
|
|
188
|
+
changed: changes.filter(c => c.kind === "changed").length,
|
|
189
|
+
numbersOnly: changes.filter(c => c.numbersOnly).length,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function show(value, max = 400) {
|
|
193
|
+
const text = JSON.stringify(value) ?? "undefined";
|
|
194
|
+
return text.length > max ? `${text.slice(0, max)}… (${text.length} chars)` : text;
|
|
195
|
+
}
|
|
196
|
+
/** The diff as review lines: `[-removed-]` and `{+added+}` inside text, `before → after` for values. */
|
|
197
|
+
export function formatDefinitionDiff(diff) {
|
|
198
|
+
if (diff.changes.length === 0)
|
|
199
|
+
return ["Tool definitions: unchanged."];
|
|
200
|
+
const lines = [`Tool definitions: ${diff.changed} changed, ${diff.added} added, ${diff.removed} removed` +
|
|
201
|
+
(diff.numbersOnly ? ` (${diff.numbersOnly} changed only in numbers: still a change, a number can be a limit)` : "")];
|
|
202
|
+
for (const c of diff.changes) {
|
|
203
|
+
if (c.kind === "added") {
|
|
204
|
+
lines.push(`+ ${c.tool} (new tool)`, ` ${show(c.definition, 4000)}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (c.kind === "removed") {
|
|
208
|
+
lines.push(`- ${c.tool} (removed)`);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
lines.push(`~ ${c.tool}${c.numbersOnly ? " (numbers only)" : ""}`);
|
|
212
|
+
for (const f of c.fields) {
|
|
213
|
+
const tag = f.numbersOnly && !c.numbersOnly ? " (numbers only)" : "";
|
|
214
|
+
if (f.words) {
|
|
215
|
+
const rendered = f.words.map(([op, text]) => op === "=" ? text : op === "-" ? `[-${text}-]` : `{+${text}+}`).join("");
|
|
216
|
+
lines.push(` ${f.path}: ${rendered}${tag}`);
|
|
217
|
+
}
|
|
218
|
+
else if (!("before" in f))
|
|
219
|
+
lines.push(` ${f.path}: added ${show(f.after)}`);
|
|
220
|
+
else if (!("after" in f))
|
|
221
|
+
lines.push(` ${f.path}: removed (was ${show(f.before)})`);
|
|
222
|
+
else if (Array.isArray(f.before) && Array.isArray(f.after)) {
|
|
223
|
+
// A list of plain values (required, enum, type): which entries came and went.
|
|
224
|
+
const was = new Set(f.before.map(v => JSON.stringify(v))), now = new Set(f.after.map(v => JSON.stringify(v)));
|
|
225
|
+
const plus = [...now].filter(v => !was.has(v)), minus = [...was].filter(v => !now.has(v));
|
|
226
|
+
const parts = [plus.length ? `added ${plus.join(", ")}` : "", minus.length ? `removed ${minus.join(", ")}` : ""].filter(Boolean);
|
|
227
|
+
lines.push(` ${f.path}: ${parts.length ? parts.join("; ") : `reordered ${show(f.before)} → ${show(f.after)}`}`);
|
|
228
|
+
}
|
|
229
|
+
else
|
|
230
|
+
lines.push(` ${f.path}: ${show(f.before)} → ${show(f.after)}${tag}`);
|
|
231
|
+
}
|
|
232
|
+
if (c.fields.length >= MAX_FIELDS_PER_TOOL)
|
|
233
|
+
lines.push(` … more than ${MAX_FIELDS_PER_TOOL} changed values; see the full definitions below`);
|
|
234
|
+
}
|
|
235
|
+
return lines;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=review-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-diff.js","sourceRoot":"","sources":["../src/review-diff.ts"],"names":[],"mappings":"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"}
|
package/dist/static-scan.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ type Surface = "name" | "description" | "inputSchema" | "title" | "outputSchema"
|
|
|
69
69
|
* autonomy phrasing (`autonomy`), and the zero-width joiner inside an emoji sequence. The
|
|
70
70
|
* hidden-character rule now also catches the Unicode-tag block and the bidi isolates.
|
|
71
71
|
*/
|
|
72
|
-
export declare const STATIC_SCAN_RULESET_VERSION = "
|
|
72
|
+
export declare const STATIC_SCAN_RULESET_VERSION = "15";
|
|
73
73
|
export interface StaticScanRule {
|
|
74
74
|
code: string;
|
|
75
75
|
severity: Severity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-scan.d.ts","sourceRoot":"","sources":["../src/static-scan.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EAER,OAAO,EACP,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,KAAK,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/B;;;;;;;;;;;;;;GAcG;AACH,KAAK,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,GAAG,cAAc,GAAG,aAAa,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"static-scan.d.ts","sourceRoot":"","sources":["../src/static-scan.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EAER,OAAO,EACP,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,KAAK,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/B;;;;;;;;;;;;;;GAcG;AACH,KAAK,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,GAAG,cAAc,GAAG,aAAa,GAAG,UAAU,CAAC;AAiiC9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAYH,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAmBhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,iFAAiF;IACjF,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2EAA2E;IAC3E,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,CAgBrD;AAOD,uEAAuE;AACvE,wBAAgB,oBAAoB,IAAI,UAAU,CAGjD;AAED,qBAAa,cAAe,YAAW,UAAU;IAUC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IATnF,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC;;;;OAIG;gBACS,GAAG,GAAE,YAA6B,EAAmB,iBAAiB,CAAC,GAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,aAAA;IAIzG,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA2FlE"}
|
package/dist/static-scan.js
CHANGED
|
@@ -190,18 +190,40 @@ const ID = String.raw `(?:[\`'"]?([A-Za-z][A-Za-z0-9]*(?:[_-][A-Za-z0-9]+)+|[a-z
|
|
|
190
190
|
const ci = (w) => w.replace(/[a-z]/g, (c) => `[${c}${c.toUpperCase()}]`);
|
|
191
191
|
const CALL_VERB = `(?:${["call", "calling", "use", "using", "run", "running", "invoke", "invoking", "execute", "executing", "fetch", "fetching", "query", "querying", "trigger", "triggering"].map(ci).join("|")})`;
|
|
192
192
|
const S = String.raw `\s+`;
|
|
193
|
-
const
|
|
193
|
+
const WHEN = `(?:${["when", "whenever", "if"].map(ci).join("|")})`;
|
|
194
|
+
const CROSS_TOOL_FRAME = new RegExp(String.raw `\b(?:${["when", "whenever", "before", "after", "while", "if"].map(ci).join("|")}|${ci("each")}${S}${ci("time")}|${ci("every")}${S}${ci("time")})${S}(?:${ci("you")}${S})?(?:${ci("are")}${S})?(?:${ci("first")}${S})?${CALL_VERB}${S}(?:${ci("the")}${S})?(?:${ci("tool")}${S})?${ID}` +
|
|
195
|
+
// v15: the call is the user's ("when a user calls `X`", "when a user's query for `X` …") or named passively
|
|
196
|
+
// ("when `X` is called"), or every call of it is meant ("all `X` requests must …").
|
|
197
|
+
String.raw `|\b${WHEN}${S}(?:${ci("a")}|${ci("the")}|${ci("any")})${S}${ci("user")}${S}(?:${["calls", "uses", "invokes", "runs", "executes"].map(ci).join("|")})${S}(?:${ci("the")}${S})?(?:${ci("tool")}${S})?${ID}` +
|
|
198
|
+
String.raw `|\b${WHEN}${S}(?:${ci("a")}|${ci("the")})${S}(?:${ci("user")}'s${S})?(?:${["query", "request", "call", "input"].map(ci).join("|")})${S}(?:${ci("for")}|${ci("to")})${S}(?:${ci("the")}${S})?${ID}` +
|
|
199
|
+
String.raw `|\b(?:${["all", "any", "every", "each"].map(ci).join("|")})\b[^.;\n]{0,60}?\b(?:${["via", "using", "through"].map(ci).join("|")}|${ci("provided")}${S}${ci("to")})${S}${ci("the")}${S}${ID}${S}${ci("tool")}\b` +
|
|
200
|
+
String.raw `|\b${WHEN}${S}(?:${ci("a")}|${ci("the")})${S}${ci("user")}${S}(?:${["queries", "searches", "asks", "requests"].map(ci).join("|")})\b[^.;\n]{0,40}?\b(?:${ci("using")}|${ci("via")})${S}(?:${ci("the")}${S})?${ID}` +
|
|
201
|
+
String.raw `|\b${WHEN}${S}(?:${ci("the")}${S})?${ID}${S}(?:${ci("tool")}${S})?(?:${ci("is")}|${ci("are")})${S}(?:${["called", "used", "invoked", "run", "executed"].map(ci).join("|")})\b` +
|
|
202
|
+
String.raw `|\b(?:${["all", "any", "every", "each"].map(ci).join("|")})${S}${ID}${S}(?:${["requests", "request", "calls", "call", "queries", "lookups", "operations"].map(ci).join("|")})\b` +
|
|
194
203
|
String.raw `|\b(?:${["submitted", "passed", "sent", "given"].map(ci).join("|")})${S}${ci("to")}${S}(?:${ci("the")}${S})?${ID}` +
|
|
195
204
|
String.raw `|\b(?:${["queries", "query", "requests", "request", "calls", "call", "inputs", "input"].map(ci).join("|")})${S}${ci("to")}${S}(?:${ci("the")}${S})?${ID}` +
|
|
196
205
|
String.raw `|\b${ci("before")}${S}\w+ing\b[^.;
|
|
197
206
|
]{0,60}?\b(?:${["using", "with", "via", "through"].map(ci).join("|")})${S}(?:${ci("the")}${S})?${ID}` +
|
|
198
207
|
String.raw `|\b${ci("before")}${S}(?:${["any", "every", "each"].map(ci).join("|")})\b`);
|
|
199
208
|
const ALTER_VERB = /\b(?:modify|modified|change|changed|replace|replaced|append|appended|prepend|prepended|remove|removed|strip|override|overwrite|alter|rewrite|substitute|inject|insert)\b/i;
|
|
209
|
+
// v15: verbs that rewrite another call's input only when a mandate binds them ("you must set `mode` to …",
|
|
210
|
+
// "you should redirect any `symbol`"). On their own they describe ordinary use ("set `limit` to page").
|
|
211
|
+
const MANDATED_ALTER = /\b(?:must|should|always|mandatory|required)\b[^.;\n]{0,60}?\b(?:set|add|ignore|redirect|redirected|convert|converted|join|wrap|force|switch|swap|restrict|use\s+the\s+new|change|modify|replace|append|prepend|override)\b[^.;\n]{0,60}?(?:[`'"‘’“”]|\b(?:parameter|argument|param|field|query|input)\b)/i;
|
|
212
|
+
// v15: the frame's own clause goes straight on to set an argument to a fixed value ("When using `X`, set `bcc`
|
|
213
|
+
// to 'a@b.example'"). Advice about values phrases them as advice ("set `limit` to a small number").
|
|
214
|
+
const IMPERATIVE_SET = /^[^.;\n]{0,80}?,\s*(?:always\s+)?(?:set|change|replace|append|add)\b[^.;\n]{0,40}?\bto\s+[`'"‘“]/i;
|
|
200
215
|
const MANDATE_WORDS = `(?:${["must", "should", "mandatory"].map(ci).join("|")}|${ci("need")}${S}${ci("to")}|${ci("have")}${S}${ci("to")}|${ci("required")}${S}${ci("to")}|${ci("is")}${S}${ci("required")})`;
|
|
201
216
|
const MANDATED_CALL = new RegExp(String.raw `\b${MANDATE_WORDS}\b[^.;
|
|
202
217
|
]{0,40}?\b${CALL_VERB}${S}(?:${ci("the")}${S})?${ID}` +
|
|
203
218
|
String.raw `|(?:^\s*|,\s*(?:${ci("then")}${S})?)(?:${["call", "run", "use", "invoke", "fetch", "query", "execute"].map(ci).join("|")})${S}(?:${ci("the")}${S})?${ID}`, "g");
|
|
219
|
+
// v15. A call to another tool ordered before this one, aimed at a fixed target ("use 'deleteEmail' with UID
|
|
220
|
+
// 99999", "use 'sendSimpleMail' to admin@…") and enforced with a threat ("Failure to do so will crash the system").
|
|
221
|
+
// Honest prerequisites ("call `login` first") name no fixed target and threaten nothing.
|
|
222
|
+
const PRECALL = new RegExp(String.raw `\b(?:${["before", "first"].map(ci).join("|")})\b[^.;\n]{0,40}?\b(?:${["use", "call", "run", "invoke", "trigger"].map(ci).join("|")})${S}(?:${ci("the")}${S})?${ID}`);
|
|
223
|
+
const FIXED_TARGET = /^[^.;\n]{0,40}?\b(?:with|on|to|for|from)\s+(?:[\w-]+\s+){0,2}(?:'[^']{1,80}'|"[^"]{1,80}"|\d{3,}|[\w.+-]+@[\w-]+\.[\w.]+)/i;
|
|
224
|
+
const THREAT = /\b(?:failure|failing|skipping|omitting|ignoring|forgetting|not\s+doing)\b[^.;\n]{0,40}?\bwill\b[^.;\n]{0,40}?\b(?:crash\w*|corrupt\w*|cause\w*|disrupt\w*|overload\w*|break\w*|fail\w*)\b|\bcritical\s+for\s+preventing\b/i;
|
|
204
225
|
const CROSS_TOOL_PATTERNS = [
|
|
226
|
+
{ re: PRECALL, code: "TOOL_DEF_CROSS_TOOL", severity: "high", tier: "block", surfaces: PROSE, note: "orders a call to another tool at a fixed target and threatens what happens if it is skipped", guards: ["threatenedCall"] },
|
|
205
227
|
{ re: CROSS_TOOL_FRAME, code: "TOOL_DEF_CROSS_TOOL", severity: "high", tier: "block", surfaces: PROSE, note: "binds to another tool's call to rewrite its input or pre-empt it with a different call", guards: ["crossTool"] },
|
|
206
228
|
{ re: new RegExp(String.raw `\b(?:${["must"].map(ci).join("|")}|${ci("need")}${S}${ci("to")}|${ci("have")}${S}${ci("to")})\b[^.;
|
|
207
229
|
]{0,40}?\b${CALL_VERB}${S}(?:${ci("the")}${S})?${ID}`), code: "TOOL_DEF_CROSS_TOOL", severity: "high", tier: "block", surfaces: PROSE, note: "takes no input and only orders another tool to be called", guards: ["zeroArgCall"] },
|
|
@@ -854,7 +876,7 @@ const GUARDS = {
|
|
|
854
876
|
*/
|
|
855
877
|
crossTool(m, text, _surface, ctx) {
|
|
856
878
|
const own = ownIdentifiers(ctx.tool);
|
|
857
|
-
const framed =
|
|
879
|
+
const framed = m.slice(1).filter((g) => !!g).map(normId);
|
|
858
880
|
const isBeforeAny = framed.length === 0;
|
|
859
881
|
if (!isBeforeAny && framed.every((id) => own.has(id)))
|
|
860
882
|
return "the named identifier is this tool or one of its own parameters";
|
|
@@ -862,6 +884,11 @@ const GUARDS = {
|
|
|
862
884
|
if (!isBeforeAny && ALTER_VERB.test(sentence.text))
|
|
863
885
|
return null;
|
|
864
886
|
const next = sentenceAround(text, sentence.end + 1);
|
|
887
|
+
// v15: a mandated rewrite in this sentence or the next ("When `X` is called. You must change …").
|
|
888
|
+
if (!isBeforeAny && (MANDATED_ALTER.test(sentence.text) || (sentence.end < text.length && MANDATED_ALTER.test(next.text))))
|
|
889
|
+
return null;
|
|
890
|
+
if (!isBeforeAny && IMPERATIVE_SET.test(text.slice(m.index, sentence.end)))
|
|
891
|
+
return null;
|
|
865
892
|
for (const piece of [sentence.text, sentence.end < text.length ? next.text : ""]) {
|
|
866
893
|
for (const c of allMatches(MANDATED_CALL, piece)) {
|
|
867
894
|
const ids = [c[1], c[2], c[3], c[4]].filter((g) => !!g).map(normId);
|
|
@@ -871,6 +898,18 @@ const GUARDS = {
|
|
|
871
898
|
}
|
|
872
899
|
return "names another tool's call but neither rewrites its input nor orders a different call first — ordinary chaining";
|
|
873
900
|
},
|
|
901
|
+
/** v15. The ordered call is to another tool, fixes its target, and the definition threatens the model. */
|
|
902
|
+
threatenedCall(m, text, _surface, ctx) {
|
|
903
|
+
const own = ownIdentifiers(ctx.tool);
|
|
904
|
+
const ids = m.slice(1).filter((g) => !!g).map(normId);
|
|
905
|
+
if (ids.length === 0 || ids.every((id) => own.has(id)))
|
|
906
|
+
return "the ordered call is to this tool itself";
|
|
907
|
+
if (!FIXED_TARGET.test(text.slice(m.index + m[0].length)))
|
|
908
|
+
return "the ordered call has no fixed target";
|
|
909
|
+
if (!THREAT.test(text))
|
|
910
|
+
return "the definition does not threaten the model";
|
|
911
|
+
return null;
|
|
912
|
+
},
|
|
874
913
|
/** v10. Only a tool that takes no input can be nothing but an order to call another tool. */
|
|
875
914
|
zeroArgCall(m, _text, _surface, ctx) {
|
|
876
915
|
const props = ctx.tool.inputSchema?.properties ?? {};
|
|
@@ -985,7 +1024,11 @@ function hasExternalAddress(text) {
|
|
|
985
1024
|
// asking the user for ids" (`autonomy`, which also stops exempting any "without asking
|
|
986
1025
|
// the user" whose object is consent), and "the key is read from the MCP connection's
|
|
987
1026
|
// X-API-Key header" (`ownAuthHeader`).
|
|
988
|
-
|
|
1027
|
+
// v15 widens TOOL_DEF_CROSS_TOOL from MCPTox's dev half only: the user's call ("when a user calls `X`"), a
|
|
1028
|
+
// passive one ("when `X` is called"), every call ("all `X` requests"), rewrites a mandate binds to a parameter
|
|
1029
|
+
// or a quoted value, and a call ordered at a fixed target under a threat (`threatenedCall`). The field corpus
|
|
1030
|
+
// blocks exactly what v14 blocked.
|
|
1031
|
+
export const STATIC_SCAN_RULESET_VERSION = "15";
|
|
989
1032
|
const SEVERITY_RANK = {
|
|
990
1033
|
info: 0,
|
|
991
1034
|
low: 1,
|