@monoes/monomindcli 2.11.9 → 2.11.11
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/.claude/skills/mastermind/SKILL.md +13 -0
- package/README.md +1 -1
- package/bin/cli.js +17 -8
- package/dist/src/commands/crash-reporting.d.ts +3 -1
- package/dist/src/commands/crash-reporting.d.ts.map +1 -1
- package/dist/src/commands/crash-reporting.js +26 -10
- package/dist/src/commands/crash-reporting.js.map +1 -1
- package/dist/src/commands/doctor-env-checks.d.ts +9 -0
- package/dist/src/commands/doctor-env-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-env-checks.js +31 -0
- package/dist/src/commands/doctor-env-checks.js.map +1 -1
- package/dist/src/commands/doctor-monoes-checks.d.ts +12 -0
- package/dist/src/commands/doctor-monoes-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-monoes-checks.js +142 -1
- package/dist/src/commands/doctor-monoes-checks.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +11 -3
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/mcp.d.ts.map +1 -1
- package/dist/src/commands/mcp.js +16 -0
- package/dist/src/commands/mcp.js.map +1 -1
- package/dist/src/commands/org-observe.d.ts.map +1 -1
- package/dist/src/commands/org-observe.js +29 -4
- package/dist/src/commands/org-observe.js.map +1 -1
- package/dist/src/commands/org.d.ts.map +1 -1
- package/dist/src/commands/org.js +12 -3
- package/dist/src/commands/org.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +17 -0
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/mcp-generator.d.ts +2 -7
- package/dist/src/init/mcp-generator.d.ts.map +1 -1
- package/dist/src/init/mcp-generator.js +15 -17
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/write-claude.d.ts.map +1 -1
- package/dist/src/init/write-claude.js +9 -0
- package/dist/src/init/write-claude.js.map +1 -1
- package/dist/src/init/write-runtime-config.d.ts +8 -0
- package/dist/src/init/write-runtime-config.d.ts.map +1 -1
- package/dist/src/init/write-runtime-config.js +69 -14
- package/dist/src/init/write-runtime-config.js.map +1 -1
- package/dist/src/mcp/monoes-mcp-entry.mjs +152 -0
- package/dist/src/mcp/monoes-proxy.d.ts +48 -0
- package/dist/src/mcp/monoes-proxy.d.ts.map +1 -0
- package/dist/src/mcp/monoes-proxy.js +240 -0
- package/dist/src/mcp/monoes-proxy.js.map +1 -0
- package/dist/src/orgrt/completion-gate.d.ts +58 -0
- package/dist/src/orgrt/completion-gate.d.ts.map +1 -0
- package/dist/src/orgrt/completion-gate.js +86 -0
- package/dist/src/orgrt/completion-gate.js.map +1 -0
- package/dist/src/orgrt/daemon.d.ts +15 -0
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +194 -12
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/file-roots.d.ts +57 -0
- package/dist/src/orgrt/file-roots.d.ts.map +1 -0
- package/dist/src/orgrt/file-roots.js +100 -0
- package/dist/src/orgrt/file-roots.js.map +1 -0
- package/dist/src/orgrt/policy-git.d.ts.map +1 -1
- package/dist/src/orgrt/policy-git.js +122 -4
- package/dist/src/orgrt/policy-git.js.map +1 -1
- package/dist/src/orgrt/policy.d.ts +13 -1
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +60 -11
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/reporting.d.ts +56 -0
- package/dist/src/orgrt/reporting.d.ts.map +1 -1
- package/dist/src/orgrt/reporting.js +42 -3
- package/dist/src/orgrt/reporting.js.map +1 -1
- package/dist/src/orgrt/role-sandbox.d.ts.map +1 -1
- package/dist/src/orgrt/role-sandbox.js +19 -49
- package/dist/src/orgrt/role-sandbox.js.map +1 -1
- package/dist/src/orgrt/scheduler-integration.d.ts.map +1 -1
- package/dist/src/orgrt/scheduler-integration.js +4 -2
- package/dist/src/orgrt/scheduler-integration.js.map +1 -1
- package/dist/src/orgrt/session.d.ts +5 -2
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +51 -7
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +11 -0
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +19 -0
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +6 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +10 -0
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/prompt.d.ts.map +1 -1
- package/dist/src/prompt.js +14 -0
- package/dist/src/prompt.js.map +1 -1
- package/dist/src/services/crash-consent.d.ts +35 -0
- package/dist/src/services/crash-consent.d.ts.map +1 -0
- package/dist/src/services/crash-consent.js +100 -0
- package/dist/src/services/crash-consent.js.map +1 -0
- package/dist/src/services/crash-lock.d.ts +22 -0
- package/dist/src/services/crash-lock.d.ts.map +1 -0
- package/dist/src/services/crash-lock.js +86 -0
- package/dist/src/services/crash-lock.js.map +1 -0
- package/dist/src/services/crash-race-timeout.d.ts +13 -0
- package/dist/src/services/crash-race-timeout.d.ts.map +1 -0
- package/dist/src/services/crash-race-timeout.js +15 -0
- package/dist/src/services/crash-race-timeout.js.map +1 -0
- package/dist/src/services/crash-reporter.d.ts +12 -4
- package/dist/src/services/crash-reporter.d.ts.map +1 -1
- package/dist/src/services/crash-reporter.js +105 -129
- package/dist/src/services/crash-reporter.js.map +1 -1
- package/dist/src/ui/dashboard.html +122 -0
- package/dist/src/ui/mastermind-diagram-fallback.html +14 -0
- package/dist/src/ui/orgs.html +12 -0
- package/dist/src/ui/routes-monoes.mjs +105 -21
- package/dist/src/utils/redaction.d.ts +17 -0
- package/dist/src/utils/redaction.d.ts.map +1 -1
- package/dist/src/utils/redaction.js +52 -7
- package/dist/src/utils/redaction.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
import crypto from 'node:crypto';
|
|
12
12
|
import fs from 'node:fs';
|
|
13
13
|
import path from 'node:path';
|
|
14
|
+
import {
|
|
15
|
+
buildMonoesMcpEntry,
|
|
16
|
+
detectMonoesTokenLeak,
|
|
17
|
+
formatMonoesLeakWarning,
|
|
18
|
+
} from '../mcp/monoes-mcp-entry.mjs';
|
|
14
19
|
|
|
15
20
|
const MONOES_BASE_URL = process.env.MONOMIND_MONOES_URL || 'https://monoes.me';
|
|
16
21
|
const MONOES_SCOPE = 'community:read community:write offline_access';
|
|
@@ -22,6 +27,25 @@ const MONOES_SCOPE = 'community:read community:write offline_access';
|
|
|
22
27
|
const _pendingStates = new Map();
|
|
23
28
|
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
24
29
|
|
|
30
|
+
// i-066 reviewer finding 4: detectMonoesTokenLeak() shells out to git;
|
|
31
|
+
// throttle it to at most once per this interval per process instead of
|
|
32
|
+
// once per dashboard status poll (the leak condition changes on the order
|
|
33
|
+
// of "never", not per poll — see the /api/monoes/status handler below).
|
|
34
|
+
let _lastLeakCheckAt = 0;
|
|
35
|
+
const _leakCheckIntervalMs = 60_000;
|
|
36
|
+
|
|
37
|
+
// i-066 follow-up finding 10 [MINOR]: this module-level throttle is shared
|
|
38
|
+
// across every test in the same file (the module is imported once per test
|
|
39
|
+
// file, not reset between `it()` blocks) — an earlier test's status poll
|
|
40
|
+
// can silently suppress a later test's leak check for up to
|
|
41
|
+
// _leakCheckIntervalMs of real time, for a reason unrelated to what that
|
|
42
|
+
// later test is actually asserting. Test-only escape hatch so tests can
|
|
43
|
+
// reset it in beforeEach instead of reaching for fake timers to defeat a
|
|
44
|
+
// throttle they don't otherwise need to think about.
|
|
45
|
+
export function __resetMonoesLeakThrottle() {
|
|
46
|
+
_lastLeakCheckAt = 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
25
49
|
function _connectionFile(monomindHome) {
|
|
26
50
|
return path.join(monomindHome, '.monomind', 'monoes-connection.json');
|
|
27
51
|
}
|
|
@@ -90,19 +114,14 @@ async function _getOrRegisterClientId(monomindHome, redirectUri) {
|
|
|
90
114
|
return clientId;
|
|
91
115
|
}
|
|
92
116
|
|
|
93
|
-
function _buildMonoesMcpEntry(accessToken) {
|
|
94
|
-
return {
|
|
95
|
-
type: 'http',
|
|
96
|
-
url: `${MONOES_BASE_URL}/api/mcp`,
|
|
97
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
117
|
/** Merges (or removes) the `monoes` entry in the project's existing
|
|
102
118
|
* .mcp.json. Only touches that one key — never creates or rewrites the
|
|
103
119
|
* rest of the file, since .mcp.json is otherwise owned by `init`/the user.
|
|
104
|
-
* No-ops if .mcp.json doesn't exist yet (nothing to merge into).
|
|
105
|
-
|
|
120
|
+
* No-ops if .mcp.json doesn't exist yet (nothing to merge into).
|
|
121
|
+
* `hasConnection` is a boolean, not a token — the entry is a local stdio
|
|
122
|
+
* proxy (mcp/monoes-proxy.ts) that resolves the Authorization header itself
|
|
123
|
+
* at request time, so there is no token to embed here at all. */
|
|
124
|
+
function _syncMonoesMcpEntry(projectDir, hasConnection) {
|
|
106
125
|
const mcpPath = path.join(projectDir, '.mcp.json');
|
|
107
126
|
let config;
|
|
108
127
|
try {
|
|
@@ -111,8 +130,8 @@ function _syncMonoesMcpEntry(projectDir, accessToken) {
|
|
|
111
130
|
return;
|
|
112
131
|
}
|
|
113
132
|
config.mcpServers = config.mcpServers || {};
|
|
114
|
-
if (
|
|
115
|
-
config.mcpServers.monoes =
|
|
133
|
+
if (hasConnection) {
|
|
134
|
+
config.mcpServers.monoes = buildMonoesMcpEntry();
|
|
116
135
|
} else {
|
|
117
136
|
delete config.mcpServers.monoes;
|
|
118
137
|
}
|
|
@@ -244,7 +263,7 @@ export async function handleMonoesRoutes(req, res, url, corsOrigin, ctx) {
|
|
|
244
263
|
expiresAt: Date.now() + (tokenData.expires_in || 3600) * 1000,
|
|
245
264
|
connectedUsername: me.username || null,
|
|
246
265
|
});
|
|
247
|
-
_syncMonoesMcpEntry(path.resolve(projectDir || process.cwd()), tokenData.access_token);
|
|
266
|
+
_syncMonoesMcpEntry(path.resolve(projectDir || process.cwd()), !!tokenData.access_token);
|
|
248
267
|
|
|
249
268
|
closeTab('Connected to monoes.me — you can close this tab.');
|
|
250
269
|
} catch (err) {
|
|
@@ -255,21 +274,86 @@ export async function handleMonoesRoutes(req, res, url, corsOrigin, ctx) {
|
|
|
255
274
|
|
|
256
275
|
// ---------------------------------------------------- GET /api/monoes/status
|
|
257
276
|
// Polled on every dashboard load — piggybacks the silent-refresh check so
|
|
258
|
-
// .mcp.json's
|
|
259
|
-
//
|
|
260
|
-
//
|
|
277
|
+
// .mcp.json's entry self-heals (added/removed/migrated) roughly as often
|
|
278
|
+
// as the dashboard is opened, instead of only on the explicit
|
|
279
|
+
// connect/disconnect actions. Since the entry no longer embeds a token
|
|
280
|
+
// (it's a stdio proxy that resolves the header itself — see
|
|
281
|
+
// mcp/monoes-mcp-entry.mjs), a refresh that only changes the *value* of
|
|
282
|
+
// the token no longer requires a re-sync; only a change in *whether*
|
|
283
|
+
// .mcp.json's actual current entry matches the actual current connection
|
|
284
|
+
// state does (checked directly against the file, so this self-heals even
|
|
285
|
+
// if .mcp.json drifted from the connection for some other reason — a hand
|
|
286
|
+
// edit, a stale/missing file, etc). Reviewer i-066 finding 2: "matches"
|
|
287
|
+
// must be shape-aware, not presence-aware — a pre-fix entry that still
|
|
288
|
+
// carries a literal `headers`/`type: 'http'` bearer shape counts as
|
|
289
|
+
// needing a re-sync too, or a connected user whose .mcp.json already
|
|
290
|
+
// leaked the token is warned forever but never migrated.
|
|
261
291
|
if (req.method === 'GET' && url === '/api/monoes/status') {
|
|
262
292
|
const beforeConn = readMonoesConnection(MONOMIND_HOME);
|
|
263
293
|
const validToken = /* value */ beforeConn?.accessToken
|
|
264
294
|
? await getValidMonoesToken(MONOMIND_HOME)
|
|
265
295
|
: null;
|
|
266
296
|
const afterConn = readMonoesConnection(MONOMIND_HOME);
|
|
267
|
-
|
|
268
|
-
|
|
297
|
+
const isConnected = !!validToken;
|
|
298
|
+
|
|
299
|
+
const resolvedProjectDir = path.resolve(projectDir || process.cwd());
|
|
300
|
+
let entry;
|
|
301
|
+
try {
|
|
302
|
+
const currentMcp = JSON.parse(
|
|
303
|
+
fs.readFileSync(path.join(resolvedProjectDir, '.mcp.json'), 'utf8'),
|
|
304
|
+
);
|
|
305
|
+
entry = currentMcp?.mcpServers?.monoes;
|
|
306
|
+
} catch {
|
|
307
|
+
entry = undefined; // No .mcp.json, or unreadable — nothing to sync into; _syncMonoesMcpEntry no-ops too.
|
|
308
|
+
}
|
|
309
|
+
const hasEntry = !!entry;
|
|
310
|
+
// i-066 reviewer finding 8 [BLOCKER]: `'headers' in entry` throws a
|
|
311
|
+
// TypeError when entry isn't an object — a realistic shape for a file
|
|
312
|
+
// designed to be committed and merged (a typo, a hand edit, a bad merge
|
|
313
|
+
// resolution can leave mcpServers.monoes as a string/number/boolean/
|
|
314
|
+
// array). That throw would escape this handler uncaught, and
|
|
315
|
+
// ui/server.mjs's http.createServer callback has no enclosing
|
|
316
|
+
// try/catch, so it would kill the whole dashboard process. Guard with
|
|
317
|
+
// an explicit object check first — a non-object (or array) value is
|
|
318
|
+
// simply non-conforming, so it self-heals via the normal re-sync path
|
|
319
|
+
// instead of crashing.
|
|
320
|
+
const isObjectEntry = typeof entry === 'object' && entry !== null && !Array.isArray(entry);
|
|
321
|
+
const isConformingEntry = isObjectEntry && !('headers' in entry) && entry.type !== 'http';
|
|
322
|
+
|
|
323
|
+
// i-066 §3.5: if this project already leaked the token (a legacy literal
|
|
324
|
+
// bearer entry still in .mcp.json, or monoes-connection.json tracked by
|
|
325
|
+
// git), warn loudly on every status poll rather than migrating silently.
|
|
326
|
+
// Reviewer i-066 finding 4: detectMonoesTokenLeak() shells out to git —
|
|
327
|
+
// throttle to at most once per _leakCheckIntervalMs per process rather
|
|
328
|
+
// than spawning a subprocess on every single-threaded-server poll; the
|
|
329
|
+
// condition it detects changes on the order of "never", not per poll.
|
|
330
|
+
//
|
|
331
|
+
// Reviewer i-066 finding U5 [BLOCKER]: this MUST run and be SNAPSHOTTED
|
|
332
|
+
// before _syncMonoesMcpEntry below. detectMonoesTokenLeak() re-reads
|
|
333
|
+
// .mcp.json from disk, and _syncMonoesMcpEntry rewrites that same file —
|
|
334
|
+
// running the leak check after the migration inspects the
|
|
335
|
+
// ALREADY-MIGRATED file and always finds nothing. A connected victim's
|
|
336
|
+
// first-ever poll would migrate the token out of the file silently and
|
|
337
|
+
// never warn that it may already be committed and on teammates'
|
|
338
|
+
// machines — the exact silent-failure mode this warning exists to
|
|
339
|
+
// prevent. Compute (and throttle) the check here; only print it after
|
|
340
|
+
// the migration has actually happened, so one poll does both.
|
|
341
|
+
const now = Date.now();
|
|
342
|
+
let leakWarning = null;
|
|
343
|
+
if (now - _lastLeakCheckAt > _leakCheckIntervalMs) {
|
|
344
|
+
_lastLeakCheckAt = now;
|
|
345
|
+
leakWarning = formatMonoesLeakWarning(await detectMonoesTokenLeak(resolvedProjectDir));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (isConnected !== hasEntry || (hasEntry && !isConformingEntry)) {
|
|
349
|
+
_syncMonoesMcpEntry(resolvedProjectDir, isConnected);
|
|
269
350
|
}
|
|
351
|
+
|
|
352
|
+
if (leakWarning) console.error(leakWarning);
|
|
353
|
+
|
|
270
354
|
_json(res, corsOrigin, 200, {
|
|
271
|
-
connected:
|
|
272
|
-
username:
|
|
355
|
+
connected: isConnected,
|
|
356
|
+
username: isConnected ? afterConn?.connectedUsername || null : null,
|
|
273
357
|
});
|
|
274
358
|
return true;
|
|
275
359
|
}
|
|
@@ -277,7 +361,7 @@ export async function handleMonoesRoutes(req, res, url, corsOrigin, ctx) {
|
|
|
277
361
|
// ------------------------------------------------ POST /api/monoes/disconnect
|
|
278
362
|
if (req.method === 'POST' && url === '/api/monoes/disconnect') {
|
|
279
363
|
_deleteMonoesConnection(MONOMIND_HOME);
|
|
280
|
-
_syncMonoesMcpEntry(path.resolve(projectDir || process.cwd()),
|
|
364
|
+
_syncMonoesMcpEntry(path.resolve(projectDir || process.cwd()), false);
|
|
281
365
|
_json(res, corsOrigin, 200, { connected: false });
|
|
282
366
|
return true;
|
|
283
367
|
}
|
|
@@ -19,6 +19,23 @@ export declare function redactSecrets(text: string): string;
|
|
|
19
19
|
* `<user>`'s neighborhood correctly), and secret-pattern stripping runs
|
|
20
20
|
* before that path collapse too (a secret string that happens to look
|
|
21
21
|
* path-like should still hit the secret patterns first).
|
|
22
|
+
*
|
|
23
|
+
* i-116-redact: secret-pattern stripping now runs BEFORE stripSsnAndPhone(),
|
|
24
|
+
* not after. This is a hardening change, not a fix to any currently-shipped
|
|
25
|
+
* behaviour — verified (reviewer, through the real shipped redact()) that
|
|
26
|
+
* both orders leak identically for every pattern that existed before this
|
|
27
|
+
* item. The shipped keyword patterns use a permissive value class
|
|
28
|
+
* (`[^\s'"]`), which still matches through a `<phone>`/`<ssn>` placeholder,
|
|
29
|
+
* so going second never broke them. This item's new self-identifying-prefix
|
|
30
|
+
* patterns use restrictive classes (e.g. `[A-Za-z0-9-]`) that a placeholder
|
|
31
|
+
* falls outside of, so a value with a phone-shaped digit run in the middle
|
|
32
|
+
* (Slack's `xoxb-<team-id>-<bot-id>-<secret>`, where the IDs are always
|
|
33
|
+
* numeric) would have its PII-mangled remainder no longer match — the
|
|
34
|
+
* secret suffix would then survive, untouched, in the final output. Secrets
|
|
35
|
+
* must get first pass at the text: a cosmetic PII transform must never be
|
|
36
|
+
* able to defeat a security transform, independent of which patterns exist
|
|
37
|
+
* today, because the next pattern added after this one would inherit the
|
|
38
|
+
* same latent hazard otherwise.
|
|
22
39
|
*/
|
|
23
40
|
export declare function redact(text: string): string;
|
|
24
41
|
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../src/utils/redaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../src/utils/redaction.ts"],"names":[],"mappings":"AA4LA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY3C"}
|
|
@@ -62,15 +62,43 @@ function stripSsnAndPhone(text) {
|
|
|
62
62
|
return out;
|
|
63
63
|
}
|
|
64
64
|
const SECRET_PATTERNS = [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
// i-116-redact: `['"]?` inserted before `\s*[:=]` in these three so a
|
|
66
|
+
// quoted JSON key (`"accessToken":`, `"apiKey":`, `"secret":`) matches —
|
|
67
|
+
// previously the quote sat between the keyword and the colon and none of
|
|
68
|
+
// these fired on real JSON at all, the single most common shape.
|
|
69
|
+
/(?:api[_-]?key|apikey)['"]?\s*[:=]\s*['"]?[^\s'"]{8,}['"]?/gi,
|
|
70
|
+
/(?:secret|password|passwd|pwd)['"]?\s*[:=]\s*['"]?[^\s'"]{8,}['"]?/gi,
|
|
71
|
+
/(?:token|bearer)['"]?\s*[:=]\s*['"]?[^\s'"]{10,}['"]?/gi,
|
|
72
|
+
// i-116-redact: delimiterless header shape (`Authorization: Bearer <tok>`)
|
|
73
|
+
// has no `:`/`=` between "bearer" and the value at all — a space only —
|
|
74
|
+
// so none of the three keyword patterns above ever fired on it.
|
|
75
|
+
/\bbearer\s+['"]?[^\s'"]{10,}['"]?/gi,
|
|
68
76
|
/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,
|
|
69
77
|
/sk-ant-[a-zA-Z0-9_-]{20,}/g,
|
|
70
78
|
/sk-[a-zA-Z0-9_-]{20,}/g,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
// i-116-redact: self-identifying credential prefixes — the prefix itself
|
|
80
|
+
// carries the specificity, so a generous length bound costs nothing (it
|
|
81
|
+
// only widens what's caught, never what's falsely caught) and needs no
|
|
82
|
+
// keyword or delimiter at all. Replaces the old exact-{36} ghp_/gho_/npm_
|
|
83
|
+
// patterns, which only matched a conformant classic-format value and
|
|
84
|
+
// missed GitHub's current fine-grained format (`github_pat_`) entirely —
|
|
85
|
+
// the credential most likely to be present, since crash-reporter.ts files
|
|
86
|
+
// issues to GitHub.
|
|
87
|
+
//
|
|
88
|
+
// Deliberately NOT `\b`-anchored (review finding 1, round 2): the old
|
|
89
|
+
// ghp_/gho_/npm_ patterns these replace had no boundary assertion either,
|
|
90
|
+
// and adding one narrows coverage relative to what it replaces — a value
|
|
91
|
+
// glued directly onto a preceding word character (`Xghp_<36 chars>`, e.g.
|
|
92
|
+
// a log line with no separator before the token) would stop matching.
|
|
93
|
+
// The prefix plus the length bound already supplies all the specificity
|
|
94
|
+
// a `\b` would add; dropping it costs no precision and is measurably
|
|
95
|
+
// faster (no boundary check per candidate position).
|
|
96
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/g, // GitHub classic PAT/OAuth/user/server/refresh
|
|
97
|
+
/github_pat_[A-Za-z0-9_]{20,}/g, // GitHub fine-grained (current format)
|
|
98
|
+
/glpat-[A-Za-z0-9_-]{16,}/g, // GitLab
|
|
99
|
+
/xox[abprs]-[A-Za-z0-9-]{10,}/g, // Slack (bot/app/admin/refresh/other)
|
|
100
|
+
/sk_(?:live|test)_[A-Za-z0-9]{16,}/g, // Stripe
|
|
101
|
+
/npm_[A-Za-z0-9]{20,}/g, // npm, widened from {36}
|
|
74
102
|
/AKIA[0-9A-Z]{16}/g,
|
|
75
103
|
/eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/g, // JWT
|
|
76
104
|
/[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^:\s]+:[^@\s]+@[^\s'"]+/g, // user:pass@host connection strings
|
|
@@ -173,6 +201,23 @@ export function redactSecrets(text) {
|
|
|
173
201
|
* `<user>`'s neighborhood correctly), and secret-pattern stripping runs
|
|
174
202
|
* before that path collapse too (a secret string that happens to look
|
|
175
203
|
* path-like should still hit the secret patterns first).
|
|
204
|
+
*
|
|
205
|
+
* i-116-redact: secret-pattern stripping now runs BEFORE stripSsnAndPhone(),
|
|
206
|
+
* not after. This is a hardening change, not a fix to any currently-shipped
|
|
207
|
+
* behaviour — verified (reviewer, through the real shipped redact()) that
|
|
208
|
+
* both orders leak identically for every pattern that existed before this
|
|
209
|
+
* item. The shipped keyword patterns use a permissive value class
|
|
210
|
+
* (`[^\s'"]`), which still matches through a `<phone>`/`<ssn>` placeholder,
|
|
211
|
+
* so going second never broke them. This item's new self-identifying-prefix
|
|
212
|
+
* patterns use restrictive classes (e.g. `[A-Za-z0-9-]`) that a placeholder
|
|
213
|
+
* falls outside of, so a value with a phone-shaped digit run in the middle
|
|
214
|
+
* (Slack's `xoxb-<team-id>-<bot-id>-<secret>`, where the IDs are always
|
|
215
|
+
* numeric) would have its PII-mangled remainder no longer match — the
|
|
216
|
+
* secret suffix would then survive, untouched, in the final output. Secrets
|
|
217
|
+
* must get first pass at the text: a cosmetic PII transform must never be
|
|
218
|
+
* able to defeat a security transform, independent of which patterns exist
|
|
219
|
+
* today, because the next pattern added after this one would inherit the
|
|
220
|
+
* same latent hazard otherwise.
|
|
176
221
|
*/
|
|
177
222
|
export function redact(text) {
|
|
178
223
|
const home = homedir();
|
|
@@ -180,8 +225,8 @@ export function redact(text) {
|
|
|
180
225
|
out = stripGenericUserPrefixes(out);
|
|
181
226
|
out = stripIPv4(out);
|
|
182
227
|
out = stripEmail(out);
|
|
183
|
-
out = stripSsnAndPhone(out);
|
|
184
228
|
out = stripSecretPatterns(out);
|
|
229
|
+
out = stripSsnAndPhone(out);
|
|
185
230
|
out = collapseAbsolutePaths(out);
|
|
186
231
|
out = stripHostnames(out);
|
|
187
232
|
out = stripIPv6(out);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../../src/utils/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,2EAA2E;AAC3E,+DAA+D;AAE/D,SAAS,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAClD,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,IAAI,IAAI;QAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IACvC,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,QAAQ,KAAK,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,yEAAyE;AACzE,yDAAyD;AACzD,SAAS,wBAAwB,CAAC,IAAY;IAC5C,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IACtD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACxD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;IAC/D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,6EAA6E;AAC7E,2EAA2E;AAC3E,uEAAuE;AACvE,uEAAuE;AACvE,qEAAqE;AACrE,uEAAuE;AACvE,wEAAwE;AACxE,0EAA0E;AAC1E,0EAA0E;AAC1E,uEAAuE;AACvE,2EAA2E;AAC3E,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CACjB,qGAAqG,EACrG,SAAS,CACV,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IACrD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,8DAA8D,EAAE,SAAS,CAAC,CAAC;IAC7F,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,eAAe,GAAa;IAChC,
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../../src/utils/redaction.ts"],"names":[],"mappings":"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"}
|