@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.
- package/README.md +43 -18
- package/dist/config/colour.d.ts +38 -0
- package/dist/config/colour.js +36 -0
- package/dist/config/colour.js.map +1 -0
- package/dist/config/defaults.d.ts +6 -7
- package/dist/config/defaults.js +4 -8
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +50 -3
- package/dist/config/loader.js +345 -29
- package/dist/config/loader.js.map +1 -1
- package/dist/config/mouse.d.ts +50 -0
- package/dist/config/mouse.js +44 -0
- package/dist/config/mouse.js.map +1 -0
- package/dist/config/profiles.d.ts +68 -0
- package/dist/config/profiles.js +93 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/schema.d.ts +2441 -116
- package/dist/config/schema.js +930 -19
- package/dist/config/schema.js.map +1 -1
- package/dist/config/shell-policy.d.ts +466 -116
- package/dist/config/shell-policy.js +273 -62
- package/dist/config/shell-policy.js.map +1 -1
- package/dist/config/tool-descriptions.d.ts +165 -0
- package/dist/config/tool-descriptions.js +229 -0
- package/dist/config/tool-descriptions.js.map +1 -0
- package/dist/config/types.d.ts +139 -6
- package/dist/config/types.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +85 -2
- package/dist/core/GthAbstractAgent.js +194 -1
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +341 -58
- package/dist/core/GthAgentRunner.js +857 -149
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.d.ts +99 -0
- package/dist/core/GthLangChainAgent.js +388 -3
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/approvals/annotations.d.ts +122 -0
- package/dist/core/approvals/annotations.js +137 -0
- package/dist/core/approvals/annotations.js.map +1 -0
- package/dist/core/approvals/grants.d.ts +216 -0
- package/dist/core/approvals/grants.js +469 -0
- package/dist/core/approvals/grants.js.map +1 -0
- package/dist/core/approvals/matcher.d.ts +202 -0
- package/dist/core/approvals/matcher.js +267 -0
- package/dist/core/approvals/matcher.js.map +1 -0
- package/dist/core/approvals/mcpSubjects.d.ts +40 -0
- package/dist/core/approvals/mcpSubjects.js +99 -0
- package/dist/core/approvals/mcpSubjects.js.map +1 -0
- package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
- package/dist/core/approvals/toolAnnotationSources.js +277 -0
- package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
- package/dist/core/approvals/toolHost.d.ts +46 -0
- package/dist/core/approvals/toolHost.js +108 -0
- package/dist/core/approvals/toolHost.js.map +1 -0
- package/dist/core/debugCapture.d.ts +16 -0
- package/dist/core/debugCapture.js.map +1 -1
- package/dist/core/launchBanner.d.ts +120 -0
- package/dist/core/launchBanner.js +399 -0
- package/dist/core/launchBanner.js.map +1 -0
- package/dist/core/plainToolIndication.js +61 -35
- package/dist/core/plainToolIndication.js.map +1 -1
- package/dist/core/refusal.d.ts +53 -0
- package/dist/core/refusal.js +129 -0
- package/dist/core/refusal.js.map +1 -0
- package/dist/core/shell/approvalStop.d.ts +75 -0
- package/dist/core/shell/approvalStop.js +108 -0
- package/dist/core/shell/approvalStop.js.map +1 -0
- package/dist/core/shell/arity.d.ts +6 -0
- package/dist/core/shell/arity.js +20 -6
- package/dist/core/shell/arity.js.map +1 -1
- package/dist/core/shell/denylist.d.ts +11 -0
- package/dist/core/shell/denylist.js +37 -0
- package/dist/core/shell/denylist.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +41 -1
- package/dist/core/shell/normalize.js +58 -4
- package/dist/core/shell/normalize.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +138 -0
- package/dist/core/shell/openWorld.js +523 -0
- package/dist/core/shell/openWorld.js.map +1 -0
- package/dist/core/shell/rater.d.ts +560 -0
- package/dist/core/shell/rater.js +895 -0
- package/dist/core/shell/rater.js.map +1 -0
- package/dist/core/shell/raterModel.d.ts +41 -0
- package/dist/core/shell/raterModel.js +51 -0
- package/dist/core/shell/raterModel.js.map +1 -0
- package/dist/core/shell/rejection.d.ts +66 -0
- package/dist/core/shell/rejection.js +38 -0
- package/dist/core/shell/rejection.js.map +1 -0
- package/dist/core/toolCallRepair/grammar.d.ts +41 -0
- package/dist/core/toolCallRepair/grammar.js +116 -0
- package/dist/core/toolCallRepair/grammar.js.map +1 -0
- package/dist/core/toolCallRepair/index.d.ts +2 -0
- package/dist/core/toolCallRepair/index.js +7 -0
- package/dist/core/toolCallRepair/index.js.map +1 -0
- package/dist/core/toolCallRepair/payload.d.ts +36 -0
- package/dist/core/toolCallRepair/payload.js +341 -0
- package/dist/core/toolCallRepair/payload.js.map +1 -0
- package/dist/core/toolCallRepair/promote.d.ts +45 -0
- package/dist/core/toolCallRepair/promote.js +90 -0
- package/dist/core/toolCallRepair/promote.js.map +1 -0
- package/dist/core/toolDisplay.d.ts +14 -1
- package/dist/core/toolDisplay.js +69 -12
- package/dist/core/toolDisplay.js.map +1 -1
- package/dist/core/toolOutputChannel.d.ts +33 -6
- package/dist/core/toolOutputChannel.js +61 -8
- package/dist/core/toolOutputChannel.js.map +1 -1
- package/dist/core/types.d.ts +71 -9
- package/dist/core/types.js.map +1 -1
- package/dist/providers/geminiSchemaSanitizer.d.ts +6 -3
- package/dist/providers/geminiSchemaSanitizer.js +152 -6
- package/dist/providers/geminiSchemaSanitizer.js.map +1 -1
- package/dist/providers/modelDiscovery.d.ts +18 -4
- package/dist/providers/modelDiscovery.js +67 -17
- package/dist/providers/modelDiscovery.js.map +1 -1
- package/dist/providers/openai.js +34 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/runtime/askStructured.d.ts +8 -7
- package/dist/runtime/askStructured.js +8 -7
- package/dist/runtime/askStructured.js.map +1 -1
- package/dist/runtime/conversation.js +89 -76
- package/dist/runtime/conversation.js.map +1 -1
- package/dist/runtime/singleShot.js +71 -60
- package/dist/runtime/singleShot.js.map +1 -1
- package/dist/utils/ProgressIndicator.d.ts +21 -0
- package/dist/utils/ProgressIndicator.js +30 -3
- package/dist/utils/ProgressIndicator.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +30 -0
- package/dist/utils/consoleUtils.js +27 -2
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/crashHandler.d.ts +87 -0
- package/dist/utils/crashHandler.js +128 -0
- package/dist/utils/crashHandler.js.map +1 -0
- package/dist/utils/debugDump.d.ts +58 -0
- package/dist/utils/debugDump.js +149 -15
- package/dist/utils/debugDump.js.map +1 -1
- package/dist/utils/llmUtils.d.ts +22 -8
- package/dist/utils/llmUtils.js +48 -8
- package/dist/utils/llmUtils.js.map +1 -1
- package/dist/utils/redactSecrets.js +68 -20
- package/dist/utils/redactSecrets.js.map +1 -1
- package/dist/utils/systemUtils.d.ts +17 -0
- package/dist/utils/systemUtils.js +17 -0
- package/dist/utils/systemUtils.js.map +1 -1
- package/package.json +5 -2
- package/schema/gsloth-config.schema.json +1484 -466
- package/dist/core/shell/allowlist.d.ts +0 -75
- package/dist/core/shell/allowlist.js +0 -187
- package/dist/core/shell/allowlist.js.map +0 -1
- package/dist/core/shell/judge.d.ts +0 -161
- package/dist/core/shell/judge.js +0 -261
- package/dist/core/shell/judge.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LastModelRequest } from '#src/core/debugCapture.js';
|
|
1
2
|
/**
|
|
2
3
|
* GS2-46/GS2-47 — `/debug-dump`: a live-session diagnostic archive. GS2-46 shipped it raw; GS2-47
|
|
3
4
|
* adds a shared secret-redaction pass ({@link file://./redactSecrets.ts}) that is ON BY DEFAULT and
|
|
@@ -26,6 +27,17 @@ export interface WriteDebugDumpInput {
|
|
|
26
27
|
* depending on where the test runner happens to execute.
|
|
27
28
|
*/
|
|
28
29
|
cwd?: string;
|
|
30
|
+
/**
|
|
31
|
+
* GS2-56 — the always-on snapshot of the last model request (the composed system prompt, tool
|
|
32
|
+
* defs with schema, model params, tool-choice, and the AS-SENT post-summarization messages),
|
|
33
|
+
* threaded straight from `agent.lastModelRequest` by the caller (both the TUI and the readline
|
|
34
|
+
* `--no-tui` surface). ADDITIVE & optional: when present, `writeDebugDump` writes
|
|
35
|
+
* `model-request.json` (the extras) and `model-messages.json` (the as-sent messages, distinct
|
|
36
|
+
* from the conversation-view `transcript.json`), both routed through the same redaction pass as
|
|
37
|
+
* every other artifact. Absent (no model call yet / a surface with no agent handle) ⇒ those two
|
|
38
|
+
* files are simply omitted.
|
|
39
|
+
*/
|
|
40
|
+
modelRequest?: LastModelRequest;
|
|
29
41
|
}
|
|
30
42
|
export interface WriteDebugDumpResult {
|
|
31
43
|
/** The absolute path to the archive directory just written. */
|
|
@@ -55,3 +67,49 @@ export declare function debugDumpDirName(date?: Date): string;
|
|
|
55
67
|
* On opt-out the archive is raw and the caller surfaces the loud "may contain secrets" warning.
|
|
56
68
|
*/
|
|
57
69
|
export declare function writeDebugDump(input: WriteDebugDumpInput): WriteDebugDumpResult;
|
|
70
|
+
/** Input to {@link writeCrashSnapshot}. */
|
|
71
|
+
export interface WriteCrashSnapshotInput {
|
|
72
|
+
/** The thrown error / rejection reason. Need not be an `Error`. */
|
|
73
|
+
error: unknown;
|
|
74
|
+
/** Where the failure came from — e.g. `'uncaughtException'` / `'unhandledRejection'`. */
|
|
75
|
+
origin: string;
|
|
76
|
+
/** The effective resolved config, if the crashing process had one registered. Opaque. */
|
|
77
|
+
config?: unknown;
|
|
78
|
+
/** Model display name, if known. */
|
|
79
|
+
modelDisplayName?: string;
|
|
80
|
+
/** The in-flight turn's transcript tail, if a session registered one. Opaque. */
|
|
81
|
+
transcriptTail?: unknown;
|
|
82
|
+
}
|
|
83
|
+
export interface WriteCrashSnapshotResult {
|
|
84
|
+
/** The absolute path to the crash directory just written. */
|
|
85
|
+
crashDir: string;
|
|
86
|
+
/** The absolute path to the `crash.json` file inside it. */
|
|
87
|
+
crashFile: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* GS2-48 — write a MINIMAL, ALWAYS-REDACTED crash snapshot to
|
|
91
|
+
* `~/.gsloth/debug-dumps/crash-<timestamp>/crash.json` and return its paths.
|
|
92
|
+
*
|
|
93
|
+
* This is the unattended sibling of {@link writeDebugDump}: it fires from the process-level crash
|
|
94
|
+
* handler ({@link file://./crashHandler.ts}) with no human present, so — unlike `/debug-dump` — it
|
|
95
|
+
* exposes NO `redact` opt-out. Redaction (GS2-47, hard-dep) is MANDATORY and applied to the whole
|
|
96
|
+
* snapshot. It reuses this module's location convention (`ensureGlobalGslothDir()` + `debug-dumps/`)
|
|
97
|
+
* and rendering helpers, but deliberately stays minimal and crash-safe:
|
|
98
|
+
* - a SINGLE `crash.json` (not the multi-file interactive archive);
|
|
99
|
+
* - it does NOT shell out for git state (a subprocess is unsafe/slow while the process is dying);
|
|
100
|
+
* - it keeps only the last {@link CRASH_DEBUG_LOG_TAIL_LINES} debugLog lines and the transcript TAIL.
|
|
101
|
+
*
|
|
102
|
+
* Redaction shape (conscious choice): the entire normalized snapshot is passed through
|
|
103
|
+
* {@link redactValue} in one pass. That is stricter than {@link writeDebugDump}, which uses
|
|
104
|
+
* {@link redactText} (literal+pattern only) for its non-config artifacts to avoid field-masking a
|
|
105
|
+
* legitimately `token`/`secret`-named field in tool output. For an unattended crash file the
|
|
106
|
+
* over-masking is the SAFE direction and buys uniform circular-ref / depth / function handling in
|
|
107
|
+
* one place, so it is intended, not an oversight. The config subtree is stripped of live instances
|
|
108
|
+
* first (as `writeDebugDump` does) so a live LLM client's internals never serialize.
|
|
109
|
+
*
|
|
110
|
+
* Callers wrap this in their own try/catch (see {@link file://./crashHandler.ts}); it does its best
|
|
111
|
+
* to be fail-safe internally (`redactValue`/`safeStringify` never throw), but the ONE unavoidably
|
|
112
|
+
* throwing operation is the `mkdirSync`/`writeFileSync` to disk — an unwritable `~/.gsloth` is what
|
|
113
|
+
* the handler's degraded path is for.
|
|
114
|
+
*/
|
|
115
|
+
export declare function writeCrashSnapshot(input: WriteCrashSnapshotInput): WriteCrashSnapshotResult;
|
package/dist/utils/debugDump.js
CHANGED
|
@@ -134,21 +134,46 @@ function describeLiveModel(config, llm) {
|
|
|
134
134
|
return { type, model };
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
|
-
* GS2-54 (gap 3) — defense-in-depth for the CONFIG artifact: return a shallow
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
137
|
+
* GS2-54 (gap 3) + GS2-66 (residual 3) — defense-in-depth for the CONFIG artifact: return a shallow
|
|
138
|
+
* clone of `config` with the LIVE instances stripped to short descriptors so their large internal
|
|
139
|
+
* surface (client objects, cached kwargs, inline keys, and non-secret-NAMED opaque fields the
|
|
140
|
+
* `caCert` class that field-masking cannot catch) never reaches disk — rather than relying on
|
|
141
|
+
* {@link redactValue}'s field-masking alone. Mirrors `configCommand.ts`'s `redactConfigForPrint`:
|
|
142
|
+
* - a *live* `llm` (a `BaseChatModel`) → a `{ type, model }` descriptor;
|
|
143
|
+
* - a `tools` array → `[N tool instance(s)]`;
|
|
144
|
+
* - a `middleware` array → `[N middleware]`.
|
|
145
|
+
* PURE: never mutates the caller's config (a fresh clone is made only if something is stripped).
|
|
146
|
+
* FAIL-SAFE: on any error, or when a field is absent / not a live instance, that field is left as-is
|
|
147
|
+
* so {@link redactValue}'s existing GS2-47 masking still applies (never less-redacted). The `llm`,
|
|
148
|
+
* `tools` and `middleware` strips are independent — `tools`/`middleware` are stripped even when the
|
|
149
|
+
* config carries no live `llm`.
|
|
143
150
|
*/
|
|
144
|
-
function
|
|
151
|
+
function stripLiveInstancesForConfig(config) {
|
|
145
152
|
try {
|
|
146
153
|
if (config == null || typeof config !== 'object' || Array.isArray(config))
|
|
147
154
|
return config;
|
|
148
155
|
const record = config;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
// Clone lazily: only spread into a new object once we know a field is actually being replaced,
|
|
157
|
+
// so a config with no live instances is returned untouched (===).
|
|
158
|
+
let out = record;
|
|
159
|
+
const clone = () => {
|
|
160
|
+
if (out === record)
|
|
161
|
+
out = { ...record };
|
|
162
|
+
return out;
|
|
163
|
+
};
|
|
164
|
+
if ('llm' in record && isLiveChatModel(record.llm)) {
|
|
165
|
+
clone().llm = describeLiveModel(record, record.llm);
|
|
166
|
+
}
|
|
167
|
+
// Hoist before the mutating clone() call so TS keeps the `Array` narrowing on `.length`.
|
|
168
|
+
const tools = record.tools;
|
|
169
|
+
if (Array.isArray(tools)) {
|
|
170
|
+
clone().tools = `[${tools.length} tool instance(s)]`;
|
|
171
|
+
}
|
|
172
|
+
const middleware = record.middleware;
|
|
173
|
+
if (Array.isArray(middleware)) {
|
|
174
|
+
clone().middleware = `[${middleware.length} middleware]`;
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
152
177
|
}
|
|
153
178
|
catch {
|
|
154
179
|
return config; // fail safe: fall back to redactValue over the untouched config
|
|
@@ -160,16 +185,17 @@ function stripLiveModelForConfig(config) {
|
|
|
160
185
|
* any throw yields the fully-withheld marker rather than raw content ("redact more on error, never
|
|
161
186
|
* write a raw artifact because redaction hiccuped").
|
|
162
187
|
*
|
|
163
|
-
* GS2-54 (gap 3) — before redaction, {@link
|
|
164
|
-
* `{ type, model }` descriptor
|
|
165
|
-
*
|
|
166
|
-
*
|
|
188
|
+
* GS2-54 (gap 3) + GS2-66 (residual 3) — before redaction, {@link stripLiveInstancesForConfig} swaps
|
|
189
|
+
* a live `llm` for a `{ type, model }` descriptor and the `tools`/`middleware` arrays for count
|
|
190
|
+
* descriptors, so those live instances' internals never serialize. This runs on a fresh clone only;
|
|
191
|
+
* the caller's config (and the {@link collectSecretValues} harvest already taken from it) is
|
|
192
|
+
* untouched, so inline secrets inside those instances are still scrubbed from the OTHER artifacts.
|
|
167
193
|
*/
|
|
168
194
|
function renderConfig(config, redact, secrets) {
|
|
169
195
|
if (!redact)
|
|
170
196
|
return safeStringify(config);
|
|
171
197
|
try {
|
|
172
|
-
return safeStringify(redactValue(
|
|
198
|
+
return safeStringify(redactValue(stripLiveInstancesForConfig(config), secrets));
|
|
173
199
|
}
|
|
174
200
|
catch {
|
|
175
201
|
return REDACTED;
|
|
@@ -209,6 +235,21 @@ export function writeDebugDump(input) {
|
|
|
209
235
|
const secrets = redact ? collectSecretValues(input.config, env) : [];
|
|
210
236
|
writeFileSync(resolve(archiveDir, 'transcript.json'), renderStructured(input.transcript, redact, secrets), 'utf8');
|
|
211
237
|
writeFileSync(resolve(archiveDir, 'config.json'), renderConfig(input.config, redact, secrets), 'utf8');
|
|
238
|
+
// GS2-56 — the always-on model-request snapshot: WHAT was actually fed to the model (the thing a
|
|
239
|
+
// bug report needs, previously omitted whenever the TUI `/debug` panel wasn't open). Written only
|
|
240
|
+
// when the caller threaded `agent.lastModelRequest` (a model call has happened), so before the
|
|
241
|
+
// first turn these files are simply absent. Both go through `renderStructured` (literal+pattern
|
|
242
|
+
// redaction, like transcript.json/env.json) rather than `renderConfig`'s field-masking, so a
|
|
243
|
+
// legitimately `token`/`secret`-named field inside a tool result or a schema isn't blanket-masked.
|
|
244
|
+
if (input.modelRequest) {
|
|
245
|
+
// model-request.json — the composed system prompt + tool defs (with JSON schema) + model params
|
|
246
|
+
// + tool-choice. `?? {}` keeps the artifact present-but-empty rather than serializing `undefined`.
|
|
247
|
+
writeFileSync(resolve(archiveDir, 'model-request.json'), renderStructured(input.modelRequest.extras ?? {}, redact, secrets), 'utf8');
|
|
248
|
+
// model-messages.json — the EXACT messages sent to the model for the last call (post-
|
|
249
|
+
// summarization / middleware), i.e. what the model actually saw. Deliberately a separate
|
|
250
|
+
// artifact from transcript.json (the conversation view): the two are distinct arrays.
|
|
251
|
+
writeFileSync(resolve(archiveDir, 'model-messages.json'), renderStructured(input.modelRequest.messages ?? [], redact, secrets), 'utf8');
|
|
252
|
+
}
|
|
212
253
|
// getSlothVersion() reads the installed package.json via the install dir set at CLI startup
|
|
213
254
|
// (setEntryPoint); guarded so a dump can never fail just because that wasn't wired (e.g. an
|
|
214
255
|
// unusual embedding), falling back to 'unknown'.
|
|
@@ -233,4 +274,97 @@ export function writeDebugDump(input) {
|
|
|
233
274
|
}
|
|
234
275
|
return { archiveDir };
|
|
235
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* GS2-48 — how many trailing lines of the always-on in-memory debugLog ring buffer
|
|
279
|
+
* ({@link file://./debugUtils.ts}, cap {@link DEBUG_LOG_BUFFER_MAX} = 1000) the crash snapshot keeps.
|
|
280
|
+
* The buffer itself is the "always-on capture" the crash handler relies on (nothing is written to
|
|
281
|
+
* disk until a crash — O(N) memory, zero steady-state I/O); the snapshot copies only this TAIL to
|
|
282
|
+
* stay MINIMAL (a crash file is a triage artifact, not the full session). 200 is enough to show what
|
|
283
|
+
* the agent was doing in the moments before death without bloating the file.
|
|
284
|
+
*/
|
|
285
|
+
const CRASH_DEBUG_LOG_TAIL_LINES = 200;
|
|
286
|
+
/**
|
|
287
|
+
* GS2-48 — flatten a thrown value (or a rejection reason, which need not be an `Error`) into a plain
|
|
288
|
+
* object BEFORE redaction. `Error.message`/`Error.stack` are NON-ENUMERABLE, so `Object.entries`
|
|
289
|
+
* (which {@link redactValue} walks with) would silently drop them — the crash file would carry no
|
|
290
|
+
* error and no stack. Explicitly copying them here is what makes the error survive the redaction pass.
|
|
291
|
+
* Tolerates a non-Error reason (string / number / object / undefined) without throwing.
|
|
292
|
+
*/
|
|
293
|
+
function normalizeError(error) {
|
|
294
|
+
if (error instanceof Error) {
|
|
295
|
+
return { name: error.name, message: error.message, stack: error.stack };
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
return {
|
|
299
|
+
name: 'NonError',
|
|
300
|
+
message: typeof error === 'string' ? error : safeStringify(error),
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
return { name: 'NonError', message: String(error) };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* GS2-48 — write a MINIMAL, ALWAYS-REDACTED crash snapshot to
|
|
309
|
+
* `~/.gsloth/debug-dumps/crash-<timestamp>/crash.json` and return its paths.
|
|
310
|
+
*
|
|
311
|
+
* This is the unattended sibling of {@link writeDebugDump}: it fires from the process-level crash
|
|
312
|
+
* handler ({@link file://./crashHandler.ts}) with no human present, so — unlike `/debug-dump` — it
|
|
313
|
+
* exposes NO `redact` opt-out. Redaction (GS2-47, hard-dep) is MANDATORY and applied to the whole
|
|
314
|
+
* snapshot. It reuses this module's location convention (`ensureGlobalGslothDir()` + `debug-dumps/`)
|
|
315
|
+
* and rendering helpers, but deliberately stays minimal and crash-safe:
|
|
316
|
+
* - a SINGLE `crash.json` (not the multi-file interactive archive);
|
|
317
|
+
* - it does NOT shell out for git state (a subprocess is unsafe/slow while the process is dying);
|
|
318
|
+
* - it keeps only the last {@link CRASH_DEBUG_LOG_TAIL_LINES} debugLog lines and the transcript TAIL.
|
|
319
|
+
*
|
|
320
|
+
* Redaction shape (conscious choice): the entire normalized snapshot is passed through
|
|
321
|
+
* {@link redactValue} in one pass. That is stricter than {@link writeDebugDump}, which uses
|
|
322
|
+
* {@link redactText} (literal+pattern only) for its non-config artifacts to avoid field-masking a
|
|
323
|
+
* legitimately `token`/`secret`-named field in tool output. For an unattended crash file the
|
|
324
|
+
* over-masking is the SAFE direction and buys uniform circular-ref / depth / function handling in
|
|
325
|
+
* one place, so it is intended, not an oversight. The config subtree is stripped of live instances
|
|
326
|
+
* first (as `writeDebugDump` does) so a live LLM client's internals never serialize.
|
|
327
|
+
*
|
|
328
|
+
* Callers wrap this in their own try/catch (see {@link file://./crashHandler.ts}); it does its best
|
|
329
|
+
* to be fail-safe internally (`redactValue`/`safeStringify` never throw), but the ONE unavoidably
|
|
330
|
+
* throwing operation is the `mkdirSync`/`writeFileSync` to disk — an unwritable `~/.gsloth` is what
|
|
331
|
+
* the handler's degraded path is for.
|
|
332
|
+
*/
|
|
333
|
+
export function writeCrashSnapshot(input) {
|
|
334
|
+
const crashDir = resolve(ensureGlobalGslothDir(), 'debug-dumps', `crash-${debugDumpDirName()}`);
|
|
335
|
+
mkdirSync(crashDir, { recursive: true });
|
|
336
|
+
// Redaction is unconditional here (no opt-out) — gather the literal secret values to scrub from
|
|
337
|
+
// env + config, exactly as writeDebugDump does. `env` is the systemUtils accessor (process.env).
|
|
338
|
+
const secrets = collectSecretValues(input.config, env);
|
|
339
|
+
let gthVersion;
|
|
340
|
+
try {
|
|
341
|
+
gthVersion = getSlothVersion();
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
gthVersion = 'unknown';
|
|
345
|
+
}
|
|
346
|
+
const snapshot = {
|
|
347
|
+
kind: 'crash',
|
|
348
|
+
origin: input.origin,
|
|
349
|
+
timestamp: new Date().toISOString(),
|
|
350
|
+
// Flattened to plain enumerable fields so message/stack survive the redaction walk.
|
|
351
|
+
error: normalizeError(input.error),
|
|
352
|
+
env: {
|
|
353
|
+
gthVersion,
|
|
354
|
+
nodeVersion: process.version,
|
|
355
|
+
platform: process.platform,
|
|
356
|
+
model: input.modelDisplayName ?? 'unknown',
|
|
357
|
+
},
|
|
358
|
+
// Strip live LLM/tool/middleware instances to short descriptors before redaction (as the
|
|
359
|
+
// interactive config artifact does), so their internals never reach disk. `?? null` so an
|
|
360
|
+
// absent config serializes as an explicit `null` (JSON drops an `undefined`-valued key).
|
|
361
|
+
config: stripLiveInstancesForConfig(input.config) ?? null,
|
|
362
|
+
debugLogTail: getDebugLogBuffer().slice(-CRASH_DEBUG_LOG_TAIL_LINES),
|
|
363
|
+
transcriptTail: input.transcriptTail ?? null,
|
|
364
|
+
};
|
|
365
|
+
// Single fail-safe redaction pass over the whole normalized snapshot (see doc above).
|
|
366
|
+
const crashFile = resolve(crashDir, 'crash.json');
|
|
367
|
+
writeFileSync(crashFile, safeStringify(redactValue(snapshot, secrets)), 'utf8');
|
|
368
|
+
return { crashDir, crashFile };
|
|
369
|
+
}
|
|
236
370
|
//# sourceMappingURL=debugDump.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debugDump.js","sourceRoot":"","sources":["../../src/utils/debugDump.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,UAAU,EACV,WAAW,GACZ,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"debugDump.js","sourceRoot":"","sources":["../../src/utils/debugDump.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/llmUtils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RunnableConfig } from '@langchain/core/runnables';
|
|
2
|
-
import { GthConfig } from '#src/config.js';
|
|
2
|
+
import { GthConfig, PromptSegmentName } from '#src/config.js';
|
|
3
3
|
import { SystemMessage } from '@langchain/core/messages';
|
|
4
4
|
/**
|
|
5
5
|
* Creates new runnable config.
|
|
@@ -8,14 +8,27 @@ import { SystemMessage } from '@langchain/core/messages';
|
|
|
8
8
|
* and in another prototype project where I was importing Gaunt Sloth.
|
|
9
9
|
*/
|
|
10
10
|
export declare function getNewRunnableConfig(recursionLimit?: number): RunnableConfig;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
/** The config slice every prompt-segment read needs. */
|
|
12
|
+
type PromptReadConfig = Pick<GthConfig, 'prompts' | 'identityProfile' | 'noDefaultPrompts'>;
|
|
13
|
+
/**
|
|
14
|
+
* GS2-43 — the single composition point for one prompt segment, honouring the segment's
|
|
15
|
+
* `prompts.<segment>` config:
|
|
16
|
+
* - no setting → the segment's default-named file ({@link PROMPT_SEGMENT_FILES}), falling back
|
|
17
|
+
* to the bundled default unless `noDefaultPrompts` — exactly the pre-GS2-43 behaviour;
|
|
18
|
+
* - a `string` → shorthand for `{ path }`;
|
|
19
|
+
* - `enabled: false` → the segment is dropped entirely (returns `''`), even its bundled default;
|
|
20
|
+
* - `path` + `mode: 'replace'` (default) → the file replaces the built-in segment content;
|
|
21
|
+
* - `path` + `mode: 'append'` → the file content is appended after the built-in content.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readPromptSegment(segment: PromptSegmentName, config: PromptReadConfig): string;
|
|
24
|
+
export declare function readBackstory(config: PromptReadConfig): string;
|
|
25
|
+
export declare function readGuidelines(config: Pick<GthConfig, 'prompts' | 'includeCurrentDateAfterGuidelines' | 'organization' | 'identityProfile' | 'noDefaultPrompts'> | string): string;
|
|
26
|
+
export declare function readReviewInstructions(config: PromptReadConfig | string): string;
|
|
27
|
+
export declare function readSystemPrompt(config: PromptReadConfig): string;
|
|
28
|
+
export declare function readChatPrompt(config: PromptReadConfig): string;
|
|
16
29
|
export declare function buildSystemMessages(config: GthConfig, modePrompt?: string | null): SystemMessage[];
|
|
17
|
-
export declare function readCodePrompt(config:
|
|
18
|
-
export declare function readExecPrompt(config:
|
|
30
|
+
export declare function readCodePrompt(config: PromptReadConfig): string;
|
|
31
|
+
export declare function readExecPrompt(config: PromptReadConfig): string;
|
|
19
32
|
/**
|
|
20
33
|
* Read a prompt file from the project config dir (honouring identity profiles), falling back
|
|
21
34
|
* to a packaged default unless `noDefaultPrompts` is set. Downstream packages owning their own
|
|
@@ -45,3 +58,4 @@ export declare function formatToolCalls(toolCalls: Array<{
|
|
|
45
58
|
name: string;
|
|
46
59
|
args?: Record<string, unknown>;
|
|
47
60
|
}>, maxLength?: number): string;
|
|
61
|
+
export {};
|
package/dist/utils/llmUtils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { GSLOTH_BACKSTORY, GSLOTH_CHAT_PROMPT, GSLOTH_CODE_PROMPT, GSLOTH_EXEC_PROMPT, GSLOTH_SYSTEM_PROMPT, } from '#src/constants.js';
|
|
2
|
+
import { GSLOTH_BACKSTORY, GSLOTH_CHAT_PROMPT, GSLOTH_CODE_PROMPT, GSLOTH_EXEC_PROMPT, GSLOTH_SYSTEM_PROMPT, PROJECT_GUIDELINES, PROJECT_REVIEW_INSTRUCTIONS, } from '#src/constants.js';
|
|
3
3
|
import { getGslothConfigReadPath, readFileFromInstallDir } from '#src/utils/fileUtils.js';
|
|
4
4
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
5
|
import { debugLog } from '#src/utils/debugUtils.js';
|
|
@@ -17,14 +17,54 @@ export function getNewRunnableConfig(recursionLimit = 1000) {
|
|
|
17
17
|
configurable: { thread_id: randomUUID() },
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* GS2-43 — each prompt segment's default-named file. The `prompts.<segment>` config retargets,
|
|
22
|
+
* disables, or composes against these; with no config the segment resolves exactly as before
|
|
23
|
+
* (config-dir/project file of this name, else the bundled default).
|
|
24
|
+
*/
|
|
25
|
+
const PROMPT_SEGMENT_FILES = {
|
|
26
|
+
backstory: GSLOTH_BACKSTORY,
|
|
27
|
+
guidelines: PROJECT_GUIDELINES,
|
|
28
|
+
system: GSLOTH_SYSTEM_PROMPT,
|
|
29
|
+
chat: GSLOTH_CHAT_PROMPT,
|
|
30
|
+
code: GSLOTH_CODE_PROMPT,
|
|
31
|
+
exec: GSLOTH_EXEC_PROMPT,
|
|
32
|
+
review: PROJECT_REVIEW_INSTRUCTIONS,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* GS2-43 — the single composition point for one prompt segment, honouring the segment's
|
|
36
|
+
* `prompts.<segment>` config:
|
|
37
|
+
* - no setting → the segment's default-named file ({@link PROMPT_SEGMENT_FILES}), falling back
|
|
38
|
+
* to the bundled default unless `noDefaultPrompts` — exactly the pre-GS2-43 behaviour;
|
|
39
|
+
* - a `string` → shorthand for `{ path }`;
|
|
40
|
+
* - `enabled: false` → the segment is dropped entirely (returns `''`), even its bundled default;
|
|
41
|
+
* - `path` + `mode: 'replace'` (default) → the file replaces the built-in segment content;
|
|
42
|
+
* - `path` + `mode: 'append'` → the file content is appended after the built-in content.
|
|
43
|
+
*/
|
|
44
|
+
export function readPromptSegment(segment, config) {
|
|
45
|
+
const setting = config.prompts?.[segment];
|
|
46
|
+
const segmentConfig = typeof setting === 'string' ? { path: setting } : (setting ?? {});
|
|
47
|
+
if (segmentConfig.enabled === false) {
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
const readBuiltIn = () => readPromptFile(PROMPT_SEGMENT_FILES[segment], config.identityProfile, config.noDefaultPrompts);
|
|
51
|
+
if (!segmentConfig.path) {
|
|
52
|
+
return readBuiltIn();
|
|
53
|
+
}
|
|
54
|
+
const fileContent = readPromptFile(segmentConfig.path, config.identityProfile, config.noDefaultPrompts);
|
|
55
|
+
if (segmentConfig.mode === 'append') {
|
|
56
|
+
return [readBuiltIn(), fileContent].filter(Boolean).join('\n');
|
|
57
|
+
}
|
|
58
|
+
return fileContent;
|
|
59
|
+
}
|
|
20
60
|
export function readBackstory(config) {
|
|
21
|
-
return
|
|
61
|
+
return readPromptSegment('backstory', config);
|
|
22
62
|
}
|
|
23
63
|
export function readGuidelines(config) {
|
|
24
64
|
if (typeof config === 'string') {
|
|
25
65
|
return readPromptFile(config, undefined);
|
|
26
66
|
}
|
|
27
|
-
const guidelines =
|
|
67
|
+
const guidelines = readPromptSegment('guidelines', config);
|
|
28
68
|
if (config.includeCurrentDateAfterGuidelines) {
|
|
29
69
|
const currentDate = new Date();
|
|
30
70
|
const orgName = config.organization?.name;
|
|
@@ -51,13 +91,13 @@ export function readReviewInstructions(config) {
|
|
|
51
91
|
if (typeof config === 'string') {
|
|
52
92
|
return readPromptFile(config, undefined);
|
|
53
93
|
}
|
|
54
|
-
return
|
|
94
|
+
return readPromptSegment('review', config);
|
|
55
95
|
}
|
|
56
96
|
export function readSystemPrompt(config) {
|
|
57
|
-
return
|
|
97
|
+
return readPromptSegment('system', config);
|
|
58
98
|
}
|
|
59
99
|
export function readChatPrompt(config) {
|
|
60
|
-
return
|
|
100
|
+
return readPromptSegment('chat', config);
|
|
61
101
|
}
|
|
62
102
|
export function buildSystemMessages(config, modePrompt) {
|
|
63
103
|
const parts = [readBackstory(config), readGuidelines(config)];
|
|
@@ -70,10 +110,10 @@ export function buildSystemMessages(config, modePrompt) {
|
|
|
70
110
|
return content.trim() ? [new SystemMessage(content)] : [];
|
|
71
111
|
}
|
|
72
112
|
export function readCodePrompt(config) {
|
|
73
|
-
return
|
|
113
|
+
return readPromptSegment('code', config);
|
|
74
114
|
}
|
|
75
115
|
export function readExecPrompt(config) {
|
|
76
|
-
return
|
|
116
|
+
return readPromptSegment('exec', config);
|
|
77
117
|
}
|
|
78
118
|
/**
|
|
79
119
|
* Read a prompt file from the project config dir (honouring identity profiles), falling back
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../../src/utils/llmUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../../src/utils/llmUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -54,6 +54,42 @@ const SECRET_ENV_NAME_RE = /(?:_API_KEY|_TOKEN|_SECRET|_KEY)$|PASSWORD/i;
|
|
|
54
54
|
const SECRET_KEY_RE = /(api[-_]?key|secret|token|password|passwd|authorization|bearer|credential)/i;
|
|
55
55
|
/** Field names that match {@link SECRET_KEY_RE} but must NOT be masked (they hold a var name). */
|
|
56
56
|
const NON_SECRET_KEY_NAMES = new Set(['apikeyenvironmentvariable']);
|
|
57
|
+
/**
|
|
58
|
+
* GS2-66 (residual 1) — building blocks for the `Authorization`-header VALUE grammar. GS2-54 bounded
|
|
59
|
+
* the value to `<scheme?> <one token>` where a token is {@link AUTH_TOKEN}; a credential with a char
|
|
60
|
+
* OUTSIDE that charset (`clientid:secret`, `token="…"`, `k=v,k=v`, Digest `response="…"`) left a raw
|
|
61
|
+
* tail beside the marker. These fragments extend the value across the STRUCTURED credential
|
|
62
|
+
* components (colon-joined `id:secret`, quoted `k="v"`, comma/semicolon-separated param lists) WITHOUT
|
|
63
|
+
* re-introducing the greedy prose-swallow GS2-47 removed: horizontal whitespace only (`[ \t]`, never
|
|
64
|
+
* a newline), a tight colon (no surrounding ws), and a param-continuation (`,` or `;`) whose atom must
|
|
65
|
+
* be *param-shaped* (contain `=` or be quoted) so `Authorization: … ; then we retried` keeps its prose.
|
|
66
|
+
*/
|
|
67
|
+
// A credential "word": the same token charset the SigV4 / standalone-`Bearer` rules already use.
|
|
68
|
+
const AUTH_TOKEN = String.raw `[A-Za-z0-9._~+/=-]+`;
|
|
69
|
+
// A quoted credential value (`"…"` / `'…'`) that never spans a newline — `k="v"` params + bare quotes.
|
|
70
|
+
const AUTH_QUOTED = String.raw `"[^"\n]*"|'[^'\n]*'`;
|
|
71
|
+
// One credential atom: a token optionally glued to a quoted value (`token="…"`), or a bare quote.
|
|
72
|
+
const AUTH_ATOM = `(?:${AUTH_TOKEN}(?:${AUTH_QUOTED})?|${AUTH_QUOTED})`;
|
|
73
|
+
// A colon-joined chain (`clientid:secret`); the colon is TIGHT (no surrounding whitespace) so a
|
|
74
|
+
// following `Header: value` pair or a prose colon on the same line is not chained in.
|
|
75
|
+
const AUTH_COLON_CHAIN = `${AUTH_ATOM}(?::${AUTH_ATOM})*`;
|
|
76
|
+
// A `,`- or `;`-separated PARAM continuation (`, key2=v2`; `;key2=v2`; Digest `, realm="…"`): the atom
|
|
77
|
+
// after the separator must be param-shaped — `key=…` or quoted — so a `,`/`;` followed by prose is NOT
|
|
78
|
+
// swallowed. (M1, GS2-71: `;` joined the accepted separators alongside `,`; the atom shape is unchanged,
|
|
79
|
+
// so `Authorization: … ; then we retried` still keeps its prose — same as the `,` case always has.)
|
|
80
|
+
const AUTH_PARAM = `(?:[A-Za-z0-9._~+/-]+=(?:${AUTH_QUOTED}|${AUTH_TOKEN})?|${AUTH_QUOTED})`;
|
|
81
|
+
// The full value: an optional scheme word (`Bearer` / `ApiKey` / `Digest` / …) + horizontal ws, then
|
|
82
|
+
// a colon-chain, then zero+ `,`- or `;`-separated params. The `(?!AWS4-HMAC-SHA256[ \t]+Credential=)`
|
|
83
|
+
// lookahead excludes ONLY a genuine SigV4 header (scheme immediately followed by `Credential=`) — its
|
|
84
|
+
// `SignedHeaders=…` is deliberately preserved, so it is owned solely by the Credential/Signature
|
|
85
|
+
// rule. The guard is narrow ON PURPOSE: a malformed/bare `AWS4-HMAC-SHA256 <token>` (no
|
|
86
|
+
// `Credential=`) still falls through here and IS redacted, so the "redact any scheme" contract holds.
|
|
87
|
+
const AUTH_VALUE = `(?!AWS4-HMAC-SHA256[ \\t]+Credential=)(?:${AUTH_TOKEN}[ \\t]+)?${AUTH_COLON_CHAIN}` +
|
|
88
|
+
`(?:[ \\t]*[,;][ \\t]*${AUTH_PARAM})*`;
|
|
89
|
+
// The header prefix (name + separator + optional opening quote), captured so `$1` is preserved. Its
|
|
90
|
+
// `\s*` gaps CAN include a newline (over-redacts a value on the next line — SAFE direction, never a
|
|
91
|
+
// leak); the VALUE above uses only horizontal ws and so never crosses a newline.
|
|
92
|
+
const AUTH_HEADER_PREFIX = String.raw `(\bAuthorization["']?\s*[:=]\s*["']?)`;
|
|
57
93
|
/**
|
|
58
94
|
* Provider key / auth-header PATTERNS (technique 2) — a tight, prefix-anchored set. Each entry is
|
|
59
95
|
* `[regex, replacement]`. Kept deliberately narrow (well-known key prefixes + explicit auth
|
|
@@ -78,26 +114,38 @@ const PROVIDER_PATTERNS = [
|
|
|
78
114
|
// GS2-54 (gap 2) — GitHub fine-grained PATs (`github_pat_…`); the value carries an inner `_`, so
|
|
79
115
|
// its charset includes `_`. Distinct prefix from the classic rule above (`github_` ≠ `gh[oprsu]_`).
|
|
80
116
|
[/\bgithub_pat_[A-Za-z0-9_]{16,}/g, REDACTED],
|
|
81
|
-
// GS2-54 (gap 2) — credentials embedded in a URL
|
|
82
|
-
// `user:password
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
// GS2-54 (gap 2) + GS2-66 (residual 2) — credentials embedded in a URL. Redact the whole userinfo
|
|
118
|
+
// (`user:password@` AND the colon-less bare-token form `opaquetoken@`, e.g. a PAT in a clone URL),
|
|
119
|
+
// KEEP the scheme + host so the artifact stays debuggable. GS2-54 required a `:` in the userinfo
|
|
120
|
+
// (`[^\s/@:]+:[^\s/@]+@`), so `https://opaquetoken@host` slipped through; the charset now allows the
|
|
121
|
+
// userinfo to include an internal `:` (or none) and simply stops at `@`. Bounded: userinfo can't
|
|
122
|
+
// contain `/` or whitespace, so it never swallows the rest of the URL/line. A URL WITHOUT userinfo
|
|
123
|
+
// (`https://host:port/path`) has no `@` after the authority and is left untouched.
|
|
124
|
+
[/(\b[a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, `$1${REDACTED}@`],
|
|
125
|
+
// GS2-54 (gap 1) + GS2-66 (residual 1 & 4) — an `Authorization` header value
|
|
126
|
+
// (`Authorization: <scheme?> <credential>` / `"Authorization":"…"`): keep the header name +
|
|
127
|
+
// separator ($1), redact the value REGARDLESS OF SCHEME. Generalized beyond the old fixed
|
|
128
|
+
// `Bearer|Basic|Token|Digest|Negotiate` list so a non-standard scheme (`ApiKey <secret>`, an
|
|
129
|
+
// unknown scheme) no longer leaks its token beside the marker.
|
|
130
|
+
//
|
|
131
|
+
// GS2-66 extends the value across STRUCTURED credential components (see {@link AUTH_VALUE}):
|
|
132
|
+
// `clientid:secret`, `token="…"`, `k=v,k=v` / `k=v;k=v` lists and a Digest `response="…"` no longer
|
|
133
|
+
// leave a raw tail past the token charset. It still cannot swallow following PROSE: the credential
|
|
134
|
+
// body is horizontal-whitespace-only and a `,`/`;` param-continuation must be param-shaped (GS2-47
|
|
135
|
+
// invariant, preserved by GS2-71's M1 widening of the separator to `[,;]`).
|
|
136
|
+
//
|
|
137
|
+
// NEWLINE precision (residual 4): the *credential body* uses only `[ \t]` and so never crosses a
|
|
138
|
+
// newline — but the header-PREFIX `\s*` gaps CAN span `\n` (`Authorization:\n<token>`), which
|
|
139
|
+
// over-redacts a next-line value in the SAFE direction (never a leak), not something this rule
|
|
140
|
+
// guards against. An optional value-quote is consumed so JSON `"Authorization":"…"` works too.
|
|
141
|
+
//
|
|
142
|
+
// A genuine SigV4 header is EXCLUDED here via `(?!AWS4-HMAC-SHA256[ \t]+Credential=)` (were it
|
|
143
|
+
// consumed, its intentionally-kept `SignedHeaders=…` would be eaten): SigV4 is owned entirely by
|
|
144
|
+
// the next rule, which redacts its `Credential=…`/`Signature=…` and leaves the scheme +
|
|
145
|
+
// `SignedHeaders` visible. The guard is scoped to a real SigV4 shape so a malformed bare-token
|
|
146
|
+
// `AWS4-HMAC-SHA256 <token>` is NOT let through unredacted. Runs before the standalone-`Bearer`
|
|
147
|
+
// rule so a normal header collapses to a single marker.
|
|
148
|
+
[new RegExp(AUTH_HEADER_PREFIX + AUTH_VALUE, 'gi'), `$1${REDACTED}`],
|
|
101
149
|
// GS2-54 (gap 1) — AWS SigV4 authorization components. The header is comma-separated `key=value`
|
|
102
150
|
// pairs; redact the SENSITIVE `Credential=…` (access-key id) and `Signature=…` values wherever they
|
|
103
151
|
// appear (header value OR a presigned-URL `X-Amz-Credential=…&X-Amz-Signature=…` query), keeping the
|