@tormentalabs/claude-code-wire-compat 0.6.0 → 0.7.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 +59 -0
- package/dist/build-request.d.ts.map +1 -1
- package/dist/build-request.js +49 -35
- package/dist/build-request.js.map +1 -1
- package/dist/limits.d.ts +3 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +4 -0
- package/dist/limits.js.map +1 -0
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +45 -2
- package/dist/redaction.js.map +1 -1
- package/dist/request-body.d.ts +3 -1
- package/dist/request-body.d.ts.map +1 -1
- package/dist/request-body.js +61 -43
- package/dist/request-body.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +23 -22
- package/dist/system-prompt.js.map +1 -1
- package/dist/unicode.d.ts +41 -0
- package/dist/unicode.d.ts.map +1 -1
- package/dist/unicode.js +37 -0
- package/dist/unicode.js.map +1 -1
- package/dist/violation.d.ts +23 -0
- package/dist/violation.d.ts.map +1 -0
- package/dist/violation.js +210 -0
- package/dist/violation.js.map +1 -0
- package/package.json +1 -1
- package/src/build-request.ts +66 -35
- package/src/limits.ts +4 -0
- package/src/redaction.ts +62 -2
- package/src/request-body.ts +82 -46
- package/src/system-prompt.ts +32 -24
- package/src/unicode.ts +71 -0
- package/src/violation.ts +226 -0
package/dist/system-prompt.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
import { MAX_INPUT_SIZE } from "./limits.js";
|
|
2
3
|
import { ClaudeCodeWireError } from "./contracts.js";
|
|
3
|
-
import {
|
|
4
|
+
import { inspectText, TEXT_POLICY_PROSE } from "./unicode.js";
|
|
5
|
+
import { violationDetails } from "./violation.js";
|
|
4
6
|
/**
|
|
5
7
|
* The pinned identity text, byte-exact.
|
|
6
8
|
*
|
|
@@ -18,26 +20,15 @@ import { classifySurrogateAt } from "./unicode.js";
|
|
|
18
20
|
*/
|
|
19
21
|
export const IDENTITY_TEXT = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
20
22
|
const MAX_INPUT_DEPTH = 64;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
throw new ClaudeCodeWireError(code);
|
|
23
|
+
function fail(code, safeDetails = {}) {
|
|
24
|
+
throw new ClaudeCodeWireError(code, safeDetails);
|
|
24
25
|
}
|
|
25
|
-
function validateText(text) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
codeUnit !== 0x0a &&
|
|
32
|
-
codeUnit !== 0x0d) ||
|
|
33
|
-
(codeUnit >= 0x7f && codeUnit <= 0x9f)) {
|
|
34
|
-
fail("INVALID_UNICODE");
|
|
35
|
-
}
|
|
36
|
-
const classification = classifySurrogateAt(text, index);
|
|
37
|
-
if (classification === "loneSurrogate")
|
|
38
|
-
fail("INVALID_UNICODE");
|
|
39
|
-
if (classification === "surrogatePair")
|
|
40
|
-
index += 1;
|
|
26
|
+
function validateText(text, path, inKey) {
|
|
27
|
+
// Body prose policy (P1.T1): the system field follows the same rule as
|
|
28
|
+
// every other body lane — only lone surrogates are rejected.
|
|
29
|
+
const violation = inspectText(text, TEXT_POLICY_PROSE);
|
|
30
|
+
if (violation !== null) {
|
|
31
|
+
fail("INVALID_UNICODE", violationDetails(violation, path, text.length, inKey));
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
34
|
function isUnknownRecord(value) {
|
|
@@ -46,6 +37,7 @@ function isUnknownRecord(value) {
|
|
|
46
37
|
function validateStructure(value) {
|
|
47
38
|
const ancestors = new WeakSet();
|
|
48
39
|
let size = 0;
|
|
40
|
+
const path = ["system"];
|
|
49
41
|
function visit(current, depth) {
|
|
50
42
|
if (depth > MAX_INPUT_DEPTH)
|
|
51
43
|
fail("INPUT_TOO_DEEP");
|
|
@@ -53,7 +45,7 @@ function validateStructure(value) {
|
|
|
53
45
|
size += current.length;
|
|
54
46
|
if (size > MAX_INPUT_SIZE)
|
|
55
47
|
fail("INPUT_TOO_LARGE");
|
|
56
|
-
validateText(current);
|
|
48
|
+
validateText(current, path, false);
|
|
57
49
|
return;
|
|
58
50
|
}
|
|
59
51
|
if (!isUnknownRecord(current))
|
|
@@ -62,13 +54,22 @@ function validateStructure(value) {
|
|
|
62
54
|
fail("CYCLIC_INPUT");
|
|
63
55
|
ancestors.add(current);
|
|
64
56
|
for (const key of Reflect.ownKeys(current)) {
|
|
57
|
+
// Only ARRAY indices become numeric segments (QA F1/F4); object keys
|
|
58
|
+
// stay strings and digits inside them render as `*`.
|
|
59
|
+
const segment = typeof key !== "string"
|
|
60
|
+
? "*"
|
|
61
|
+
: Array.isArray(current) && /^(?:0|[1-9]\d{0,5})$/u.test(key)
|
|
62
|
+
? Number(key)
|
|
63
|
+
: key;
|
|
64
|
+
path.push(segment);
|
|
65
65
|
if (typeof key === "string") {
|
|
66
66
|
size += key.length;
|
|
67
67
|
if (size > MAX_INPUT_SIZE)
|
|
68
68
|
fail("INPUT_TOO_LARGE");
|
|
69
|
-
validateText(key);
|
|
69
|
+
validateText(key, path, true);
|
|
70
70
|
}
|
|
71
71
|
visit(current[key], depth + 1);
|
|
72
|
+
path.pop();
|
|
72
73
|
}
|
|
73
74
|
ancestors.delete(current);
|
|
74
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,4CAA4C;
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/unicode.d.ts
CHANGED
|
@@ -7,4 +7,45 @@ export type SurrogateClassification = "notSurrogate" | "surrogatePair" | "loneSu
|
|
|
7
7
|
* a negated in-range test rather than an out-of-range test.
|
|
8
8
|
*/
|
|
9
9
|
export declare function classifySurrogateAt(value: string, index: number): SurrogateClassification;
|
|
10
|
+
export type TextViolationReason = "control-char" | "lone-surrogate";
|
|
11
|
+
/**
|
|
12
|
+
* One character-level policy violation found while screening a string.
|
|
13
|
+
*
|
|
14
|
+
* `offset` is the UTF-16 code-unit index of the offending unit and `codeUnit`
|
|
15
|
+
* is the unit itself. Both are safe diagnostics: offsets are numbers and the
|
|
16
|
+
* only code units ever reported are control characters or surrogate halves,
|
|
17
|
+
* never prose content.
|
|
18
|
+
*/
|
|
19
|
+
export interface TextViolation {
|
|
20
|
+
readonly reason: TextViolationReason;
|
|
21
|
+
readonly offset: number;
|
|
22
|
+
readonly codeUnit: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Character-level acceptance policy for one string lane.
|
|
26
|
+
*
|
|
27
|
+
* `rejectControls` rejects every C0 control except TAB (0x09), LF (0x0A) and
|
|
28
|
+
* CR (0x0D), plus DEL (0x7F). Lone surrogates are always rejected, rather than
|
|
29
|
+
* depending on whether a caller serializes or directly encodes the string.
|
|
30
|
+
*/
|
|
31
|
+
export interface TextPolicy {
|
|
32
|
+
readonly rejectControls: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Body prose: every well-formed UTF-16 string is accepted. */
|
|
35
|
+
export declare const TEXT_POLICY_PROSE: TextPolicy;
|
|
36
|
+
/**
|
|
37
|
+
* Identifier graph screening: C0 except TAB/LF/CR, plus DEL, plus lone
|
|
38
|
+
* surrogates. This is exactly the set the graph inspectors rejected before the
|
|
39
|
+
* shared validator existed.
|
|
40
|
+
*/
|
|
41
|
+
export declare const TEXT_POLICY_IDENTIFIER: TextPolicy;
|
|
42
|
+
/**
|
|
43
|
+
* Screens one string under `policy`, returning the first violation or null.
|
|
44
|
+
*
|
|
45
|
+
* The walk order matches the historical per-module inspectors: at each index
|
|
46
|
+
* the control check runs before the surrogate check, and a well-formed pair
|
|
47
|
+
* consumes two code units. `classifySurrogateAt` is the single surrogate
|
|
48
|
+
* authority; this function never re-implements it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function inspectText(value: string, policy: TextPolicy): TextViolation | null;
|
|
10
51
|
//# sourceMappingURL=unicode.d.ts.map
|
package/dist/unicode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unicode.d.ts","sourceRoot":"","sources":["../src/unicode.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GACjC,cAAc,GAAG,eAAe,GAAG,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,uBAAuB,CAQzB"}
|
|
1
|
+
{"version":3,"file":"unicode.d.ts","sourceRoot":"","sources":["../src/unicode.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GACjC,cAAc,GAAG,eAAe,GAAG,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,uBAAuB,CAQzB;AAED,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAEpE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,EAAE,UAE9B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,UAEnC,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,UAAU,GACjB,aAAa,GAAG,IAAI,CAiBtB"}
|
package/dist/unicode.js
CHANGED
|
@@ -16,4 +16,41 @@ export function classifySurrogateAt(value, index) {
|
|
|
16
16
|
return "loneSurrogate";
|
|
17
17
|
return "notSurrogate";
|
|
18
18
|
}
|
|
19
|
+
/** Body prose: every well-formed UTF-16 string is accepted. */
|
|
20
|
+
export const TEXT_POLICY_PROSE = Object.freeze({
|
|
21
|
+
rejectControls: false,
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Identifier graph screening: C0 except TAB/LF/CR, plus DEL, plus lone
|
|
25
|
+
* surrogates. This is exactly the set the graph inspectors rejected before the
|
|
26
|
+
* shared validator existed.
|
|
27
|
+
*/
|
|
28
|
+
export const TEXT_POLICY_IDENTIFIER = Object.freeze({
|
|
29
|
+
rejectControls: true,
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Screens one string under `policy`, returning the first violation or null.
|
|
33
|
+
*
|
|
34
|
+
* The walk order matches the historical per-module inspectors: at each index
|
|
35
|
+
* the control check runs before the surrogate check, and a well-formed pair
|
|
36
|
+
* consumes two code units. `classifySurrogateAt` is the single surrogate
|
|
37
|
+
* authority; this function never re-implements it.
|
|
38
|
+
*/
|
|
39
|
+
export function inspectText(value, policy) {
|
|
40
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
41
|
+
const unit = value.charCodeAt(index);
|
|
42
|
+
if (policy.rejectControls &&
|
|
43
|
+
((unit <= 0x1f && unit !== 0x09 && unit !== 0x0a && unit !== 0x0d) ||
|
|
44
|
+
unit === 0x7f)) {
|
|
45
|
+
return { reason: "control-char", offset: index, codeUnit: unit };
|
|
46
|
+
}
|
|
47
|
+
const classification = classifySurrogateAt(value, index);
|
|
48
|
+
if (classification === "loneSurrogate") {
|
|
49
|
+
return { reason: "lone-surrogate", offset: index, codeUnit: unit };
|
|
50
|
+
}
|
|
51
|
+
if (classification === "surrogatePair")
|
|
52
|
+
index += 1;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
19
56
|
//# sourceMappingURL=unicode.js.map
|
package/dist/unicode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unicode.js","sourceRoot":"","sources":["../src/unicode.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAK5C;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAa,EACb,KAAa;IAEb,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACzC,OAAO,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC;IAC9E,CAAC;IACD,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,OAAO,eAAe,CAAC;IAC7D,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
|
1
|
+
{"version":3,"file":"unicode.js","sourceRoot":"","sources":["../src/unicode.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAK5C;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAa,EACb,KAAa;IAEb,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACzC,OAAO,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC;IAC9E,CAAC;IACD,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,OAAO,eAAe,CAAC;IAC7D,OAAO,cAAc,CAAC;AACxB,CAAC;AA6BD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,iBAAiB,GAAe,MAAM,CAAC,MAAM,CAAC;IACzD,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAe,MAAM,CAAC,MAAM,CAAC;IAC9D,cAAc,EAAE,IAAI;CACrB,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,KAAa,EACb,MAAkB;IAElB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrC,IACE,MAAM,CAAC,cAAc;YACrB,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC;gBAChE,IAAI,KAAK,IAAI,CAAC,EAChB,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACnE,CAAC;QACD,MAAM,cAAc,GAAG,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACzD,IAAI,cAAc,KAAK,eAAe,EAAE,CAAC;YACvC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACrE,CAAC;QACD,IAAI,cAAc,KAAK,eAAe;YAAE,KAAK,IAAI,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TextViolation } from "./unicode.js";
|
|
2
|
+
export declare const VIOLATION_REASONS: ReadonlySet<string>;
|
|
3
|
+
export type ViolationPathSegment = string | number;
|
|
4
|
+
/**
|
|
5
|
+
* Renders a pointer-like path (`/messages/0/content`) from walk segments.
|
|
6
|
+
* At most 16 segments, then a trailing `/...`; at most 256 characters.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatViolationPath(segments: readonly ViolationPathSegment[]): string;
|
|
9
|
+
export declare function isValidViolationReason(value: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Revalidates a formatted violation path for the redaction allowlist. Every
|
|
12
|
+
* segment must be a vocabulary key, a decimal index of at most 6 digits, `*`,
|
|
13
|
+
* or the single trailing truncation marker; the whole string is capped.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isValidViolationPath(value: string): boolean;
|
|
16
|
+
/** Numeric range guard for `violationCodeUnit`: controls or surrogates only. */
|
|
17
|
+
export declare function isValidViolationCodeUnit(value: number): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Builds the safeDetails record for one text violation found at `path`.
|
|
20
|
+
* `inKey` distinguishes an offending object key from an offending value.
|
|
21
|
+
*/
|
|
22
|
+
export declare function violationDetails(violation: TextViolation, path: readonly ViolationPathSegment[], textLength: number, inKey: boolean): Readonly<Record<string, string | number | boolean>>;
|
|
23
|
+
//# sourceMappingURL=violation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violation.d.ts","sourceRoot":"","sources":["../src/violation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAYlD,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAGhD,CAAC;AA2GH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,CAAC;AAcnD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GACxC,MAAM,CAgBR;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7D;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAqB3D;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQ/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,SAAS,oBAAoB,EAAE,EACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,GACb,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CASrD"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
/*
|
|
3
|
+
* Safe validation-failure diagnostics (decision P1.T1, D4).
|
|
4
|
+
*
|
|
5
|
+
* Every value produced here is safe by construction: reasons come from a
|
|
6
|
+
* closed set, path segments from a closed vocabulary of schema-defined keys
|
|
7
|
+
* plus numeric indices and the `*` placeholder for user-controlled keys, and
|
|
8
|
+
* reported code units only ever come from control or surrogate ranges. No
|
|
9
|
+
* caller text, key name or excerpt can leak through these fields.
|
|
10
|
+
*/
|
|
11
|
+
export const VIOLATION_REASONS = new Set([
|
|
12
|
+
"lone-surrogate",
|
|
13
|
+
"control-char",
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* Schema-defined keys allowed verbatim in a violation path. Any other object
|
|
17
|
+
* key (tool input names, `input_schema` property names, arbitrary metadata
|
|
18
|
+
* members) is user-controlled text and is reported as `*`.
|
|
19
|
+
*/
|
|
20
|
+
const PATH_KEY_VOCABULARY = new Set([
|
|
21
|
+
"$schema",
|
|
22
|
+
"accept",
|
|
23
|
+
"additionalBetas",
|
|
24
|
+
"additionalProperties",
|
|
25
|
+
"anthropicAdditionalProtection",
|
|
26
|
+
"app",
|
|
27
|
+
"arch",
|
|
28
|
+
"accountUuid",
|
|
29
|
+
"body",
|
|
30
|
+
"cache_control",
|
|
31
|
+
"citations",
|
|
32
|
+
"clientApp",
|
|
33
|
+
"clientRequestId",
|
|
34
|
+
"claudeRemoteContainerId",
|
|
35
|
+
"claudeRemoteSessionId",
|
|
36
|
+
"content",
|
|
37
|
+
"context",
|
|
38
|
+
"crypto",
|
|
39
|
+
"data",
|
|
40
|
+
"default",
|
|
41
|
+
"defer_loading",
|
|
42
|
+
"description",
|
|
43
|
+
"deviceId",
|
|
44
|
+
"document",
|
|
45
|
+
"effort",
|
|
46
|
+
"enum",
|
|
47
|
+
"evidence",
|
|
48
|
+
"examples",
|
|
49
|
+
"extraHeaderPolicy",
|
|
50
|
+
"extraHeaders",
|
|
51
|
+
"headers",
|
|
52
|
+
"id",
|
|
53
|
+
"image",
|
|
54
|
+
"input",
|
|
55
|
+
"input_schema",
|
|
56
|
+
"input_examples",
|
|
57
|
+
"items",
|
|
58
|
+
"max_tokens",
|
|
59
|
+
"maxTokens",
|
|
60
|
+
"media_type",
|
|
61
|
+
"messages",
|
|
62
|
+
"metadata",
|
|
63
|
+
"metadataOverrides",
|
|
64
|
+
"method",
|
|
65
|
+
"model",
|
|
66
|
+
"name",
|
|
67
|
+
"os",
|
|
68
|
+
"output_config",
|
|
69
|
+
"profileOverride",
|
|
70
|
+
"properties",
|
|
71
|
+
"redacted_thinking",
|
|
72
|
+
"required",
|
|
73
|
+
"role",
|
|
74
|
+
"runtime",
|
|
75
|
+
"runtimeVersion",
|
|
76
|
+
"search_results",
|
|
77
|
+
"sessionId",
|
|
78
|
+
"signature",
|
|
79
|
+
"source",
|
|
80
|
+
"stainlessHelper",
|
|
81
|
+
"stainlessRetryCount",
|
|
82
|
+
"stop_sequences",
|
|
83
|
+
"stream",
|
|
84
|
+
"strict",
|
|
85
|
+
"system",
|
|
86
|
+
"text",
|
|
87
|
+
"thinking",
|
|
88
|
+
"timing",
|
|
89
|
+
"title",
|
|
90
|
+
"tool_name",
|
|
91
|
+
"tool_reference",
|
|
92
|
+
"tool_result",
|
|
93
|
+
"tool_use",
|
|
94
|
+
"tool_use_id",
|
|
95
|
+
"tools",
|
|
96
|
+
"type",
|
|
97
|
+
"url",
|
|
98
|
+
"user_id",
|
|
99
|
+
"userId",
|
|
100
|
+
"userIdFields",
|
|
101
|
+
]);
|
|
102
|
+
const MAX_PATH_SEGMENTS = 16;
|
|
103
|
+
const MAX_PATH_LENGTH = 256;
|
|
104
|
+
const TRUNCATION_MARKER = "...";
|
|
105
|
+
const OPAQUE_SUBTREES = new Set([
|
|
106
|
+
"headers",
|
|
107
|
+
"input",
|
|
108
|
+
"input_schema",
|
|
109
|
+
"input_examples",
|
|
110
|
+
"metadata",
|
|
111
|
+
"metadataOverrides",
|
|
112
|
+
"userIdFields",
|
|
113
|
+
"extraHeaders",
|
|
114
|
+
"data",
|
|
115
|
+
"default",
|
|
116
|
+
"examples",
|
|
117
|
+
]);
|
|
118
|
+
function mapSegment(segment, opaque) {
|
|
119
|
+
if (typeof segment === "number") {
|
|
120
|
+
return Number.isSafeInteger(segment) &&
|
|
121
|
+
!Object.is(segment, -0) &&
|
|
122
|
+
segment >= 0 &&
|
|
123
|
+
segment <= 999_999
|
|
124
|
+
? String(segment)
|
|
125
|
+
: "*";
|
|
126
|
+
}
|
|
127
|
+
return !opaque && PATH_KEY_VOCABULARY.has(segment) ? segment : "*";
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Renders a pointer-like path (`/messages/0/content`) from walk segments.
|
|
131
|
+
* At most 16 segments, then a trailing `/...`; at most 256 characters.
|
|
132
|
+
*/
|
|
133
|
+
export function formatViolationPath(segments) {
|
|
134
|
+
let path = "";
|
|
135
|
+
let opaque = false;
|
|
136
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
137
|
+
const segment = mapSegment(segments[index] ?? "*", opaque);
|
|
138
|
+
const tailLength = index < segments.length - 1 ? 4 : 0;
|
|
139
|
+
if (index >= MAX_PATH_SEGMENTS ||
|
|
140
|
+
path.length + 1 + segment.length + tailLength > MAX_PATH_LENGTH) {
|
|
141
|
+
return `${path}/${TRUNCATION_MARKER}`;
|
|
142
|
+
}
|
|
143
|
+
path += `/${segment}`;
|
|
144
|
+
opaque ||= segment === "*" || OPAQUE_SUBTREES.has(segment);
|
|
145
|
+
}
|
|
146
|
+
return path || "/";
|
|
147
|
+
}
|
|
148
|
+
export function isValidViolationReason(value) {
|
|
149
|
+
return VIOLATION_REASONS.has(value);
|
|
150
|
+
}
|
|
151
|
+
const PATH_INDEX_SEGMENT = /^(?:0|[1-9]\d{0,5})$/u;
|
|
152
|
+
/**
|
|
153
|
+
* Revalidates a formatted violation path for the redaction allowlist. Every
|
|
154
|
+
* segment must be a vocabulary key, a decimal index of at most 6 digits, `*`,
|
|
155
|
+
* or the single trailing truncation marker; the whole string is capped.
|
|
156
|
+
*/
|
|
157
|
+
export function isValidViolationPath(value) {
|
|
158
|
+
if (value.length === 0 || value.length > MAX_PATH_LENGTH)
|
|
159
|
+
return false;
|
|
160
|
+
if (!value.startsWith("/"))
|
|
161
|
+
return false;
|
|
162
|
+
if (value === "/")
|
|
163
|
+
return true;
|
|
164
|
+
const segments = value.slice(1).split("/");
|
|
165
|
+
if (segments.length > MAX_PATH_SEGMENTS + 1)
|
|
166
|
+
return false;
|
|
167
|
+
let opaque = false;
|
|
168
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
169
|
+
const segment = segments[index];
|
|
170
|
+
if (segment === undefined)
|
|
171
|
+
return false;
|
|
172
|
+
if (segment === TRUNCATION_MARKER)
|
|
173
|
+
return index === segments.length - 1;
|
|
174
|
+
if (index >= MAX_PATH_SEGMENTS)
|
|
175
|
+
return false;
|
|
176
|
+
if (segment === "*") {
|
|
177
|
+
opaque = true;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (PATH_INDEX_SEGMENT.test(segment))
|
|
181
|
+
continue;
|
|
182
|
+
if (opaque || !PATH_KEY_VOCABULARY.has(segment))
|
|
183
|
+
return false;
|
|
184
|
+
opaque ||= OPAQUE_SUBTREES.has(segment);
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
/** Numeric range guard for `violationCodeUnit`: controls or surrogates only. */
|
|
189
|
+
export function isValidViolationCodeUnit(value) {
|
|
190
|
+
if (!Number.isInteger(value) || Object.is(value, -0) || value < 0)
|
|
191
|
+
return false;
|
|
192
|
+
return (value <= 0x1f ||
|
|
193
|
+
(value >= 0x7f && value <= 0x9f) ||
|
|
194
|
+
(value >= 0xd800 && value <= 0xdfff));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Builds the safeDetails record for one text violation found at `path`.
|
|
198
|
+
* `inKey` distinguishes an offending object key from an offending value.
|
|
199
|
+
*/
|
|
200
|
+
export function violationDetails(violation, path, textLength, inKey) {
|
|
201
|
+
return {
|
|
202
|
+
violationReason: violation.reason,
|
|
203
|
+
violationPath: formatViolationPath(path),
|
|
204
|
+
violationOffset: violation.offset,
|
|
205
|
+
violationCodeUnit: violation.codeUnit,
|
|
206
|
+
violationTextLength: textLength,
|
|
207
|
+
violationInKey: inKey,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=violation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violation.js","sourceRoot":"","sources":["../src/violation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/build-request.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
2
|
|
|
3
|
+
import { MAX_INPUT_SIZE } from "./limits.js";
|
|
4
|
+
|
|
3
5
|
import { composeBetas, composeBetasWithAudit } from "./betas.js";
|
|
4
6
|
import type {
|
|
5
7
|
BuiltClaudeCodeCountTokensRequest,
|
|
@@ -40,11 +42,15 @@ import {
|
|
|
40
42
|
import { sha256Hex } from "./sha256.js";
|
|
41
43
|
import { buildCanonicalSystem, IDENTITY_TEXT } from "./system-prompt.js";
|
|
42
44
|
import { isThinkingActive, isThinkingDisplayActive } from "./thinking.js";
|
|
43
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
inspectText,
|
|
47
|
+
TEXT_POLICY_IDENTIFIER,
|
|
48
|
+
TEXT_POLICY_PROSE,
|
|
49
|
+
} from "./unicode.js";
|
|
50
|
+
import { violationDetails, type ViolationPathSegment } from "./violation.js";
|
|
44
51
|
|
|
45
52
|
const METHOD = "POST";
|
|
46
53
|
const MAX_INPUT_DEPTH = 100;
|
|
47
|
-
const MAX_INPUT_SIZE = 1_000_000;
|
|
48
54
|
const FORBIDDEN_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
49
55
|
const INPUT_KEYS = new Set([
|
|
50
56
|
"accessToken",
|
|
@@ -200,8 +206,9 @@ type UnknownRecord = Readonly<Record<string, unknown>>;
|
|
|
200
206
|
|
|
201
207
|
function fail(
|
|
202
208
|
code: ConstructorParameters<typeof ClaudeCodeWireError>[0] = "INVALID_INPUT",
|
|
209
|
+
safeDetails: Readonly<Record<string, string | number | boolean>> = {},
|
|
203
210
|
): never {
|
|
204
|
-
throw new ClaudeCodeWireError(code);
|
|
211
|
+
throw new ClaudeCodeWireError(code, safeDetails);
|
|
205
212
|
}
|
|
206
213
|
|
|
207
214
|
function isRecord(value: unknown): value is UnknownRecord {
|
|
@@ -231,39 +238,51 @@ function assertExactKeys(
|
|
|
231
238
|
/**
|
|
232
239
|
* Screens one string from the caller's input graph.
|
|
233
240
|
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* `
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* `src/metadata.ts` is likewise unchanged: `user_id` and metadata keys are
|
|
245
|
-
* identifiers that travel as JSON inside a header, not prose.
|
|
241
|
+
* BODY PROSE POLICY (decision P1.T1, 2026-09-25): every well-formed UTF-16
|
|
242
|
+
* string is accepted. Control characters are valid Unicode scalars;
|
|
243
|
+
* `JSON.stringify` escapes the C0 range and emits DEL/C1 raw, and
|
|
244
|
+
* `TextEncoder` encodes every scalar deterministically, so no control
|
|
245
|
+
* character can desync the body from its hash. Real tool output legitimately
|
|
246
|
+
* carries ESC (ANSI colour), NUL, FF and DEL; synthetic probes reproduced
|
|
247
|
+
* rejection before fetch, not the original incident's exact input. The old rule was a
|
|
248
|
+
* library-local defensive heuristic with no upstream provenance; whether the
|
|
249
|
+
* remote API rejects any scalar is a remote concern, surfaced as a remote
|
|
250
|
+
* error, not a local pre-flight abort.
|
|
246
251
|
*
|
|
247
|
-
*
|
|
248
|
-
* stay rejected: they have no meaning in prompt text and are a reliable signal
|
|
249
|
-
* of a corrupted or hostile input.
|
|
252
|
+
* What did NOT move:
|
|
250
253
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
+
* - HEADERS: `assertHeaderText` in `src/headers.ts` still rejects every
|
|
255
|
+
* control character, TAB/LF/CR included, because a bare LF in a header is
|
|
256
|
+
* request smuggling. `src/metadata.ts` is likewise unchanged: `user_id` and
|
|
257
|
+
* metadata keys are identifiers that travel as JSON inside a header, not
|
|
258
|
+
* prose, and keep their own strict rule.
|
|
259
|
+
* - LONE SURROGATES stay rejected in every context, deliberately.
|
|
260
|
+
* Raw `TextEncoder` replaces them, whereas JSON serialization escapes them.
|
|
261
|
+
* Rejecting them keeps the text contract independent of serialization order.
|
|
254
262
|
*/
|
|
255
|
-
function inspectString(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
function inspectString(
|
|
264
|
+
value: string,
|
|
265
|
+
path: readonly ViolationPathSegment[],
|
|
266
|
+
inKey: boolean,
|
|
267
|
+
): number {
|
|
268
|
+
const root = path[0];
|
|
269
|
+
const prose =
|
|
270
|
+
root === "messages" ||
|
|
271
|
+
root === "system" ||
|
|
272
|
+
root === "tools" ||
|
|
273
|
+
root === "stopSequences" ||
|
|
274
|
+
root === "stop_sequences" ||
|
|
275
|
+
root === "body";
|
|
276
|
+
const violation = inspectText(
|
|
277
|
+
value,
|
|
278
|
+
prose ? TEXT_POLICY_PROSE : TEXT_POLICY_IDENTIFIER,
|
|
279
|
+
);
|
|
280
|
+
if (violation !== null) {
|
|
281
|
+
if (violation.reason === "control-char") fail("INVALID_UNICODE");
|
|
282
|
+
fail(
|
|
283
|
+
"INVALID_UNICODE",
|
|
284
|
+
violationDetails(violation, path, value.length, inKey),
|
|
285
|
+
);
|
|
267
286
|
}
|
|
268
287
|
return new TextEncoder().encode(value).byteLength;
|
|
269
288
|
}
|
|
@@ -271,11 +290,14 @@ function inspectString(value: string): number {
|
|
|
271
290
|
function inspectGraph(value: unknown): void {
|
|
272
291
|
const active = new WeakSet();
|
|
273
292
|
let size = 0;
|
|
293
|
+
// Mutable walk stack: pushed/popped per node and only READ (synchronously)
|
|
294
|
+
// when a failure renders it, so successful requests pay no per-node copy.
|
|
295
|
+
const path: ViolationPathSegment[] = [];
|
|
274
296
|
|
|
275
297
|
function visit(current: unknown, depth: number): void {
|
|
276
298
|
if (depth > MAX_INPUT_DEPTH) fail("INPUT_TOO_DEEP");
|
|
277
299
|
if (typeof current === "string") {
|
|
278
|
-
size += inspectString(current);
|
|
300
|
+
size += inspectString(current, path, false);
|
|
279
301
|
} else if (
|
|
280
302
|
current === null ||
|
|
281
303
|
typeof current === "boolean" ||
|
|
@@ -300,8 +322,16 @@ function inspectGraph(value: unknown): void {
|
|
|
300
322
|
size += keys.length;
|
|
301
323
|
for (const key of keys) {
|
|
302
324
|
if (typeof key !== "string" || FORBIDDEN_KEYS.has(key)) fail();
|
|
303
|
-
|
|
325
|
+
// Only ARRAY indices become numeric segments; digits inside an object
|
|
326
|
+
// key are user-controlled text and must stay masked (QA F1).
|
|
327
|
+
const segment: ViolationPathSegment =
|
|
328
|
+
Array.isArray(current) && /^(?:0|[1-9]\d{0,5})$/u.test(key)
|
|
329
|
+
? Number(key)
|
|
330
|
+
: key;
|
|
331
|
+
path.push(segment);
|
|
332
|
+
size += inspectString(key, path, true);
|
|
304
333
|
visit(ownValue(current, key), depth + 1);
|
|
334
|
+
path.pop();
|
|
305
335
|
}
|
|
306
336
|
active.delete(current);
|
|
307
337
|
}
|
|
@@ -1763,6 +1793,7 @@ export function parseBuiltClaudeCodeRequest(
|
|
|
1763
1793
|
const body = ownValue(value, "body");
|
|
1764
1794
|
if (typeof body !== "string") fail();
|
|
1765
1795
|
const parsedBody = parseBody(body);
|
|
1796
|
+
inspectGraph(parsedBody);
|
|
1766
1797
|
const headers = parseHeaders(ownValue(value, "headers"));
|
|
1767
1798
|
const evidence = parseEvidence(ownValue(value, "evidence"), pinnedProfile);
|
|
1768
1799
|
// Reading evidence is not trusting evidence. A claim that the seam
|
package/src/limits.ts
ADDED