@wrongstack/plugins 0.295.0 → 0.295.1
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/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +19 -2
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-i18n-extractor.js +5 -0
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +103 -1
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +2 -0
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +34 -8
- package/dist/code-metrics.js +5 -0
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +17 -7
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +101 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector.js +5 -0
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +43 -8
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +100 -1
- package/dist/doc-sync-guard.js +5 -0
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +102 -2
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +30 -4
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +2 -0
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +288 -59
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +140 -20
- package/dist/index.js +1265 -544
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +60 -26
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +103 -1
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +15 -5
- package/dist/migration-planner.js +3 -0
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +119 -4
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +291 -22
- package/dist/schema-evolution-guard.js +5 -0
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +175 -48
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +132 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +21 -2
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +30 -2
- package/dist/test-coverage-gate.js +5 -0
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +130 -8
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +30 -1
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +96 -16
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAqLD,QAAA,MAAM,MAAM,EAAE,MAyNb,CAAC;eAEa,MAAM"}
|
|
@@ -4,6 +4,11 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 }
|
|
|
4
4
|
|
|
5
5
|
// src/runtime/index.ts
|
|
6
6
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/index.ts
|
|
7
12
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
8
13
|
function hasLeadingDash(arg) {
|
|
9
14
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -74,7 +79,8 @@ var state = {
|
|
|
74
79
|
var DEFAULTS = {
|
|
75
80
|
enabled: false,
|
|
76
81
|
extensions: [".ts", ".tsx"],
|
|
77
|
-
maxFindings: 50
|
|
82
|
+
maxFindings: 50,
|
|
83
|
+
maxFiles: 2e3
|
|
78
84
|
};
|
|
79
85
|
function readConfig(raw) {
|
|
80
86
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
@@ -82,7 +88,8 @@ function readConfig(raw) {
|
|
|
82
88
|
return {
|
|
83
89
|
enabled: r["enabled"] !== false,
|
|
84
90
|
extensions: Array.isArray(r["extensions"]) ? r["extensions"].filter((x) => typeof x === "string") : DEFAULTS.extensions,
|
|
85
|
-
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS.maxFindings
|
|
91
|
+
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS.maxFindings,
|
|
92
|
+
maxFiles: typeof r["maxFiles"] === "number" && r["maxFiles"] >= 1 && r["maxFiles"] <= 5e4 ? Math.floor(r["maxFiles"]) : DEFAULTS.maxFiles
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
function normalizeExtensions(exts) {
|
|
@@ -98,47 +105,60 @@ var INTERFACE_RE = /(?:export\s+)?interface\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
|
98
105
|
function extractInterfaceNames(content) {
|
|
99
106
|
const names = [];
|
|
100
107
|
INTERFACE_RE.lastIndex = 0;
|
|
108
|
+
let searchedUpTo = 0;
|
|
109
|
+
let line = 1;
|
|
101
110
|
for (const m of content.matchAll(INTERFACE_RE)) {
|
|
102
|
-
|
|
111
|
+
const index = m.index ?? 0;
|
|
112
|
+
for (let i = searchedUpTo; i < index; i++) {
|
|
113
|
+
if (content.charCodeAt(i) === 10) line += 1;
|
|
114
|
+
}
|
|
115
|
+
searchedUpTo = index;
|
|
116
|
+
names.push({ name: m[1], line });
|
|
103
117
|
}
|
|
104
118
|
return names;
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
var IMPLEMENTER_RE = /(?:implements|satisfies|\bas)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
121
|
+
function collectImplementedNames(content, into) {
|
|
122
|
+
IMPLEMENTER_RE.lastIndex = 0;
|
|
123
|
+
for (const m of content.matchAll(IMPLEMENTER_RE)) {
|
|
124
|
+
const name = m[1];
|
|
125
|
+
if (name) into.add(name);
|
|
110
126
|
}
|
|
111
|
-
return false;
|
|
112
127
|
}
|
|
113
128
|
async function scanPath(rawPath, cfg) {
|
|
114
129
|
const root = process.cwd();
|
|
115
130
|
const resolved = isAbsolute2(rawPath) ? resolve2(rawPath) : resolve2(root, rawPath);
|
|
116
131
|
const exts = normalizeExtensions(cfg.extensions);
|
|
117
|
-
const
|
|
118
|
-
const
|
|
132
|
+
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
133
|
+
const files = allFiles.slice(0, cfg.maxFiles);
|
|
134
|
+
const implemented = /* @__PURE__ */ new Set();
|
|
135
|
+
const declarations = [];
|
|
136
|
+
let scannedFiles = 0;
|
|
119
137
|
for (const p of files) {
|
|
138
|
+
let content;
|
|
120
139
|
try {
|
|
121
|
-
|
|
140
|
+
content = await readFile(p, "utf-8");
|
|
122
141
|
} catch {
|
|
142
|
+
continue;
|
|
123
143
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const findings = [];
|
|
127
|
-
for (const { path, content } of contents) {
|
|
144
|
+
scannedFiles += 1;
|
|
145
|
+
collectImplementedNames(content, implemented);
|
|
128
146
|
for (const { name, line } of extractInterfaceNames(content)) {
|
|
129
|
-
|
|
130
|
-
findings.push({
|
|
131
|
-
interfaceName: name,
|
|
132
|
-
file: relativePath(path),
|
|
133
|
-
line,
|
|
134
|
-
message: `interface "${name}" is declared but has no visible implementer`
|
|
135
|
-
});
|
|
136
|
-
if (findings.length >= cfg.maxFindings) break;
|
|
137
|
-
}
|
|
147
|
+
declarations.push({ name, line, file: p });
|
|
138
148
|
}
|
|
149
|
+
}
|
|
150
|
+
const findings = [];
|
|
151
|
+
for (const { name, line, file } of declarations) {
|
|
152
|
+
if (implemented.has(name)) continue;
|
|
153
|
+
findings.push({
|
|
154
|
+
interfaceName: name,
|
|
155
|
+
file: relativePath(file),
|
|
156
|
+
line,
|
|
157
|
+
message: `interface "${name}" is declared but has no visible implementer`
|
|
158
|
+
});
|
|
139
159
|
if (findings.length >= cfg.maxFindings) break;
|
|
140
160
|
}
|
|
141
|
-
return { findings, scannedFiles:
|
|
161
|
+
return { findings, scannedFiles, truncated: allFiles.length > files.length };
|
|
142
162
|
}
|
|
143
163
|
var plugin = {
|
|
144
164
|
name: "interface-contract-guard",
|
|
@@ -157,6 +177,13 @@ var plugin = {
|
|
|
157
177
|
default: [".ts", ".tsx"],
|
|
158
178
|
description: "File extensions to scan."
|
|
159
179
|
},
|
|
180
|
+
maxFiles: {
|
|
181
|
+
type: "number",
|
|
182
|
+
minimum: 1,
|
|
183
|
+
maximum: 5e4,
|
|
184
|
+
default: 2e3,
|
|
185
|
+
description: "Upper bound on files read per scan."
|
|
186
|
+
},
|
|
160
187
|
maxFindings: {
|
|
161
188
|
type: "number",
|
|
162
189
|
minimum: 1,
|
|
@@ -240,7 +267,14 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
240
267
|
ok: true,
|
|
241
268
|
path: relativePath(resolve2(process.cwd(), rawPath)),
|
|
242
269
|
scannedFiles: result.scannedFiles,
|
|
243
|
-
findings: result.findings
|
|
270
|
+
findings: result.findings,
|
|
271
|
+
// Say so when the corpus was cut short. A partial scan that
|
|
272
|
+
// reports "no findings" is not the same as a clean result, and
|
|
273
|
+
// the caller has no other way to tell the difference.
|
|
274
|
+
truncated: result.truncated,
|
|
275
|
+
...result.truncated ? {
|
|
276
|
+
note: `Scan stopped at the maxFiles limit (${cfg.maxFiles}); results are partial. Raise \`maxFiles\` or scan a narrower path for full coverage.`
|
|
277
|
+
} : {}
|
|
244
278
|
};
|
|
245
279
|
}
|
|
246
280
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/knowledge-graph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/knowledge-graph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAiID,QAAA,MAAM,MAAM,EAAE,MA2Sb,CAAC;eAEa,MAAM"}
|
package/dist/knowledge-graph.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/knowledge-graph/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4
5
|
var API_VERSION = "^0.1.10";
|
|
5
6
|
var state = {
|
|
6
7
|
facts: [],
|
|
@@ -52,11 +53,11 @@ function loadFacts(filePath) {
|
|
|
52
53
|
return { facts: [], nextId: 1 };
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
|
-
function persistFacts(filePath) {
|
|
56
|
+
async function persistFacts(filePath) {
|
|
56
57
|
if (!filePath) return true;
|
|
57
58
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
await ensureDir(dirname(filePath));
|
|
60
|
+
await atomicWrite(
|
|
60
61
|
filePath,
|
|
61
62
|
JSON.stringify({ facts: state.facts, nextId: state.nextId }, null, 2)
|
|
62
63
|
);
|
|
@@ -187,7 +188,7 @@ var plugin = {
|
|
|
187
188
|
state.facts.push(fact);
|
|
188
189
|
state.adds += 1;
|
|
189
190
|
api.metrics.counter("adds");
|
|
190
|
-
const persisted = persistFacts(resolved);
|
|
191
|
+
const persisted = await persistFacts(resolved);
|
|
191
192
|
return { ok: true, fact, persisted, totalFacts: state.facts.length };
|
|
192
193
|
}
|
|
193
194
|
});
|
|
@@ -247,7 +248,7 @@ var plugin = {
|
|
|
247
248
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id}"` };
|
|
248
249
|
state.removals += removed;
|
|
249
250
|
api.metrics.counter("removals", removed);
|
|
250
|
-
const persisted = persistFacts(resolved);
|
|
251
|
+
const persisted = await persistFacts(resolved);
|
|
251
252
|
return { ok: true, removed, persisted, totalFacts: state.facts.length };
|
|
252
253
|
}
|
|
253
254
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+VrD,QAAA,MAAM,MAAM,EAAE,MA2Wb,CAAC;eAEa,MAAM"}
|
package/dist/lint-gate.js
CHANGED
|
@@ -5,6 +5,108 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
8
|
+
|
|
9
|
+
// src/runtime/local-bin.ts
|
|
10
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
11
|
+
|
|
12
|
+
// src/runtime/bounded-map.ts
|
|
13
|
+
var BoundedMap = class {
|
|
14
|
+
map = /* @__PURE__ */ new Map();
|
|
15
|
+
max;
|
|
16
|
+
ttlMs;
|
|
17
|
+
now;
|
|
18
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
19
|
+
evictions = 0;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
const normalizedMax = Math.floor(options.max);
|
|
22
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
23
|
+
this.ttlMs = options.ttlMs;
|
|
24
|
+
this.now = options.now ?? Date.now;
|
|
25
|
+
}
|
|
26
|
+
expired(entry) {
|
|
27
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
28
|
+
}
|
|
29
|
+
get(key) {
|
|
30
|
+
const entry = this.map.get(key);
|
|
31
|
+
if (entry === void 0) return void 0;
|
|
32
|
+
if (this.expired(entry)) {
|
|
33
|
+
this.map.delete(key);
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
this.map.delete(key);
|
|
37
|
+
this.map.set(key, entry);
|
|
38
|
+
return entry.value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
42
|
+
* diagnostics that must not perturb the eviction order.
|
|
43
|
+
*/
|
|
44
|
+
peek(key) {
|
|
45
|
+
const entry = this.map.get(key);
|
|
46
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
47
|
+
return entry.value;
|
|
48
|
+
}
|
|
49
|
+
has(key) {
|
|
50
|
+
const entry = this.map.get(key);
|
|
51
|
+
if (entry === void 0) return false;
|
|
52
|
+
if (this.expired(entry)) {
|
|
53
|
+
this.map.delete(key);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
set(key, value) {
|
|
59
|
+
this.map.delete(key);
|
|
60
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
61
|
+
while (this.map.size > this.max) {
|
|
62
|
+
const coldest = this.map.keys().next().value;
|
|
63
|
+
if (coldest === void 0) break;
|
|
64
|
+
this.map.delete(coldest);
|
|
65
|
+
this.evictions += 1;
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
delete(key) {
|
|
70
|
+
return this.map.delete(key);
|
|
71
|
+
}
|
|
72
|
+
clear() {
|
|
73
|
+
this.map.clear();
|
|
74
|
+
this.evictions = 0;
|
|
75
|
+
}
|
|
76
|
+
get size() {
|
|
77
|
+
return this.map.size;
|
|
78
|
+
}
|
|
79
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
80
|
+
get evictionCount() {
|
|
81
|
+
return this.evictions;
|
|
82
|
+
}
|
|
83
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
84
|
+
prune() {
|
|
85
|
+
if (this.ttlMs === void 0) return 0;
|
|
86
|
+
let removed = 0;
|
|
87
|
+
for (const [key, entry] of this.map) {
|
|
88
|
+
if (this.expired(entry)) {
|
|
89
|
+
this.map.delete(key);
|
|
90
|
+
removed += 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return removed;
|
|
94
|
+
}
|
|
95
|
+
/** Live (non-expired) entries, coldest first. */
|
|
96
|
+
*entries() {
|
|
97
|
+
for (const [key, entry] of this.map) {
|
|
98
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
[Symbol.iterator]() {
|
|
102
|
+
return this.entries();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/runtime/index.ts
|
|
107
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
108
|
+
|
|
109
|
+
// src/lint-gate/index.ts
|
|
8
110
|
var API_VERSION = "^0.1.10";
|
|
9
111
|
var state = {
|
|
10
112
|
/** Total PreToolUse invocations. */
|
|
@@ -42,7 +144,7 @@ var LINTER_PACKAGES = {
|
|
|
42
144
|
biome: "@biomejs/biome",
|
|
43
145
|
eslint: "eslint"
|
|
44
146
|
};
|
|
45
|
-
var linterCache =
|
|
147
|
+
var linterCache = new BoundedMap({ max: 32, ttlMs: 3e5 });
|
|
46
148
|
function isInside(parent, candidate) {
|
|
47
149
|
const rel = relative(parent, candidate);
|
|
48
150
|
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loop-breaker/index.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loop-breaker/index.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAmSrD,QAAA,MAAM,MAAM,EAAE,MA+Yb,CAAC;eAEa,MAAM"}
|
package/dist/loop-breaker.js
CHANGED
|
@@ -66,16 +66,26 @@ function canonicalize(value) {
|
|
|
66
66
|
return String(value);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (value
|
|
69
|
+
var CANONICALIZE_MAX_DEPTH = 12;
|
|
70
|
+
function sortKeys(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
71
|
+
if (value === null || typeof value !== "object") return value;
|
|
72
|
+
if (seen.has(value)) return "[circular]";
|
|
73
|
+
if (depth >= CANONICALIZE_MAX_DEPTH) {
|
|
74
|
+
return Array.isArray(value) ? `[array:${value.length}]` : "[deep-object]";
|
|
75
|
+
}
|
|
76
|
+
seen.add(value);
|
|
77
|
+
try {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
return value.map((v) => sortKeys(v, depth + 1, seen));
|
|
80
|
+
}
|
|
72
81
|
const out = {};
|
|
73
82
|
for (const key of Object.keys(value).sort()) {
|
|
74
|
-
out[key] = sortKeys(value[key]);
|
|
83
|
+
out[key] = sortKeys(value[key], depth + 1, seen);
|
|
75
84
|
}
|
|
76
85
|
return out;
|
|
86
|
+
} finally {
|
|
87
|
+
seen.delete(value);
|
|
77
88
|
}
|
|
78
|
-
return value;
|
|
79
89
|
}
|
|
80
90
|
function fingerprint(toolName, toolInput) {
|
|
81
91
|
return `${toolName}\0${canonicalize(toolInput)}`;
|
|
@@ -50,6 +50,9 @@ async function runOptionalPluginLlm(request) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// src/runtime/local-bin.ts
|
|
54
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
55
|
+
|
|
53
56
|
// src/runtime/index.ts
|
|
54
57
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
55
58
|
function hasLeadingDash(arg) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notify-hub/index.ts"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notify-hub/index.ts"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAiP7D,QAAA,MAAM,MAAM,EAAE,MAwRb,CAAC;eAEa,MAAM"}
|
package/dist/notify-hub.js
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
// src/notify-hub/index.ts
|
|
2
2
|
import { lookup } from "node:dns/promises";
|
|
3
3
|
|
|
4
|
+
// src/runtime/local-bin.ts
|
|
5
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
6
|
+
|
|
7
|
+
// src/runtime/safe-json.ts
|
|
8
|
+
var UNSERIALIZABLE = "[unserializable]";
|
|
9
|
+
function safeJsonStringify(value, indent) {
|
|
10
|
+
try {
|
|
11
|
+
const stack = [];
|
|
12
|
+
const out = JSON.stringify(
|
|
13
|
+
value,
|
|
14
|
+
function replacer(_key, val) {
|
|
15
|
+
if (typeof val === "bigint") return `${val.toString()}n`;
|
|
16
|
+
if (val === null || typeof val !== "object") return val;
|
|
17
|
+
while (stack.length > 0 && stack[stack.length - 1] !== this) stack.pop();
|
|
18
|
+
if (stack.includes(val)) return "[circular]";
|
|
19
|
+
stack.push(val);
|
|
20
|
+
return val;
|
|
21
|
+
},
|
|
22
|
+
indent
|
|
23
|
+
);
|
|
24
|
+
return out ?? String(value);
|
|
25
|
+
} catch {
|
|
26
|
+
return UNSERIALIZABLE;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/runtime/index.ts
|
|
31
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
32
|
+
|
|
4
33
|
// src/notify-hub/webhook-channel.ts
|
|
5
34
|
function freshCircuit() {
|
|
6
35
|
return { open: false, consecutiveFailures: 0 };
|
|
@@ -202,13 +231,21 @@ async function deliver(event, payload) {
|
|
|
202
231
|
}
|
|
203
232
|
const result = await deliverViaChannel(ch, event, {
|
|
204
233
|
title: typeof payload.title === "string" ? payload.title : event,
|
|
205
|
-
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error :
|
|
234
|
+
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : safeJsonStringify(payload),
|
|
206
235
|
level: event === "tool.error" || event === "budget.threshold" ? "warning" : "info",
|
|
207
236
|
source: event,
|
|
208
237
|
metadata: payload
|
|
209
238
|
});
|
|
210
239
|
return result.ok;
|
|
211
240
|
}
|
|
241
|
+
function deliverDetached(event, payload) {
|
|
242
|
+
deliver(event, payload).catch((err) => {
|
|
243
|
+
_pluginLog?.warn("notify-hub: notification delivery failed", {
|
|
244
|
+
event,
|
|
245
|
+
error: err instanceof Error ? err.message : String(err)
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
212
249
|
async function deliverViaChannel(ch, event, msg) {
|
|
213
250
|
const result = await ch.deliver(msg);
|
|
214
251
|
if (result.ok) {
|
|
@@ -317,7 +354,7 @@ var plugin = {
|
|
|
317
354
|
}
|
|
318
355
|
if (active && cfg.events.includes("session.stop")) {
|
|
319
356
|
const stopHook = (input) => {
|
|
320
|
-
|
|
357
|
+
deliverDetached("session.stop", {
|
|
321
358
|
sessionId: input.sessionId ?? null,
|
|
322
359
|
cwd: input.cwd ?? null
|
|
323
360
|
});
|
|
@@ -328,7 +365,7 @@ var plugin = {
|
|
|
328
365
|
const off = api.onPattern("tool.*", (eventName, payload) => {
|
|
329
366
|
if (!/error|failed/.test(eventName)) return;
|
|
330
367
|
const p = payload;
|
|
331
|
-
|
|
368
|
+
deliverDetached("tool.error", {
|
|
332
369
|
tool: p?.tool ?? p?.name ?? "unknown",
|
|
333
370
|
busEvent: eventName,
|
|
334
371
|
error: truncateText(
|
|
@@ -342,7 +379,7 @@ var plugin = {
|
|
|
342
379
|
if (active && cfg.events.includes("budget.threshold")) {
|
|
343
380
|
const off = api.onPattern("budget.*", (eventName, payload) => {
|
|
344
381
|
if (!eventName.includes("threshold")) return;
|
|
345
|
-
|
|
382
|
+
deliverDetached("budget.threshold", { busEvent: eventName, detail: payload });
|
|
346
383
|
});
|
|
347
384
|
state.eventUnsubscribers.push(off);
|
|
348
385
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompt-firewall/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompt-firewall/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AA2EhE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAcxE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAWjG;AA0CD,KAAK,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CA0B7D;AAgCD,QAAA,MAAM,MAAM,EAAE,MAkNb,CAAC;eAEa,MAAM"}
|
package/dist/prompt-firewall.js
CHANGED
|
@@ -1,23 +1,152 @@
|
|
|
1
|
+
// src/runtime/credential-patterns.ts
|
|
2
|
+
var CREDENTIAL_PATTERNS = [
|
|
3
|
+
// LLM provider keys
|
|
4
|
+
{
|
|
5
|
+
type: "anthropic_key",
|
|
6
|
+
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
7
|
+
},
|
|
8
|
+
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?!ant)(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
9
|
+
// GitHub. `ghp_` is only the personal-access-token prefix — the OAuth
|
|
10
|
+
// (`gho_`), user-to-server (`ghu_`), server-to-server (`ghs_`) and
|
|
11
|
+
// refresh (`ghr_`) tokens grant the same or broader access and were
|
|
12
|
+
// previously not detected at all.
|
|
13
|
+
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
14
|
+
{
|
|
15
|
+
type: "github_oauth_token",
|
|
16
|
+
regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g
|
|
17
|
+
},
|
|
18
|
+
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
19
|
+
// GitLab
|
|
20
|
+
{ type: "gitlab_pat", regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
21
|
+
{
|
|
22
|
+
type: "gitlab_runner_token",
|
|
23
|
+
regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
24
|
+
},
|
|
25
|
+
// npm — a leaked publish token is a supply-chain compromise.
|
|
26
|
+
{ type: "npm_token", regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g },
|
|
27
|
+
// AWS
|
|
28
|
+
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
29
|
+
// GCP
|
|
30
|
+
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
31
|
+
// Slack. `xoxe` (token-rotation) and `xapp` (app-level) were missing;
|
|
32
|
+
// both are as sensitive as the bot/user tokens already covered.
|
|
33
|
+
{
|
|
34
|
+
type: "slack_token",
|
|
35
|
+
regex: /(?<![A-Za-z0-9-])xox[abposer]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g
|
|
36
|
+
},
|
|
37
|
+
{ type: "slack_app_token", regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
38
|
+
{
|
|
39
|
+
type: "slack_webhook",
|
|
40
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g
|
|
41
|
+
},
|
|
42
|
+
// Stripe
|
|
43
|
+
{
|
|
44
|
+
type: "stripe_key",
|
|
45
|
+
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g
|
|
46
|
+
},
|
|
47
|
+
// Twilio
|
|
48
|
+
{ type: "twilio_sid", regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g },
|
|
49
|
+
// Telegram
|
|
50
|
+
{
|
|
51
|
+
type: "telegram_bot_token",
|
|
52
|
+
regex: /(?:(?<![A-Za-z0-9_])|(?<=(?:^|[^A-Za-z0-9_])bot))\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
53
|
+
},
|
|
54
|
+
// JWT
|
|
55
|
+
{
|
|
56
|
+
type: "jwt",
|
|
57
|
+
regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g
|
|
58
|
+
},
|
|
59
|
+
// Private keys
|
|
60
|
+
{
|
|
61
|
+
type: "private_key",
|
|
62
|
+
regex: /(?:^|\n)(?:-----BEGIN (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----[\s\S]*?-----END (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----|-----BEGIN PGP PRIVATE KEY BLOCK-----[\s\S]*?-----END PGP PRIVATE KEY BLOCK-----)(?!\S)/g
|
|
63
|
+
},
|
|
64
|
+
// AI/ML provider tokens
|
|
65
|
+
{ type: "huggingface_token", regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g },
|
|
66
|
+
{ type: "replicate_token", regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
67
|
+
{ type: "perplexity_key", regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
68
|
+
{ type: "groq_key", regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
69
|
+
// SaaS / infrastructure tokens — each grants API access on the user's
|
|
70
|
+
// account, and each was previously invisible to this gate.
|
|
71
|
+
{ type: "sendgrid_key", regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
72
|
+
{ type: "digitalocean_token", regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g },
|
|
73
|
+
{ type: "doppler_token", regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
74
|
+
{ type: "shopify_token", regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g },
|
|
75
|
+
{ type: "docker_pat", regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
76
|
+
{ type: "linear_key", regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
77
|
+
{ type: "atlassian_token", regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g },
|
|
78
|
+
{ type: "square_token", regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
79
|
+
{
|
|
80
|
+
type: "azure_storage_key",
|
|
81
|
+
regex: /AccountKey=[A-Za-z0-9+/]{80,}={0,2}/g
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
type: "google_oauth_client_secret",
|
|
85
|
+
regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
86
|
+
},
|
|
87
|
+
// Bearer tokens
|
|
88
|
+
{
|
|
89
|
+
type: "bearer_token",
|
|
90
|
+
regex: /(?<![A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?![A-Za-z0-9._~+/-])/g
|
|
91
|
+
},
|
|
92
|
+
// Database URIs. Require password-bearing user-info; credential-free values stay scannable.
|
|
93
|
+
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
94
|
+
{
|
|
95
|
+
type: "postgres_uri",
|
|
96
|
+
// Query parsers decode percent-encoded parameter names. Recognize each
|
|
97
|
+
// encoded character in `password` so mixed forms such as `pass%77ord`
|
|
98
|
+
// cannot bypass detection while keeping the scan strictly bounded.
|
|
99
|
+
regex: /postgres(?:ql)?:\/\/(?:[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+|[^&\s?"'`#]{1,2048}\?(?:(?!(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=)[^&\s#"'`]{1,256}&){0,32}(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=[^&\s#"'`]{1,4096})/g
|
|
100
|
+
},
|
|
101
|
+
{ type: "mysql_uri", regex: /mysql:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
102
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g }
|
|
103
|
+
];
|
|
104
|
+
function cloneCredentialPatterns() {
|
|
105
|
+
return CREDENTIAL_PATTERNS.map((p) => ({
|
|
106
|
+
type: p.type,
|
|
107
|
+
regex: new RegExp(p.regex.source, p.regex.flags)
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
|
|
1
111
|
// src/prompt-firewall/index.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
112
|
+
var KIND_ALIASES = {
|
|
113
|
+
aws_access_key: "aws-access-key",
|
|
114
|
+
private_key: "private-key-block",
|
|
115
|
+
github_pat: "github-token",
|
|
116
|
+
github_oauth_token: "github-token",
|
|
117
|
+
openai_key: "openai-key",
|
|
118
|
+
anthropic_key: "anthropic-key",
|
|
119
|
+
slack_token: "slack-token",
|
|
120
|
+
gcp_key: "google-api-key",
|
|
121
|
+
bearer_token: "bearer-token"
|
|
122
|
+
};
|
|
123
|
+
var EXTRA_PATTERNS = [
|
|
4
124
|
{
|
|
125
|
+
// AWS secret access keys have no prefix — only a 40-char base64-ish
|
|
126
|
+
// shape — so they need a nearby `aws`/`secret` mention to be worth
|
|
127
|
+
// acting on.
|
|
128
|
+
//
|
|
129
|
+
// The previous spelling required the word "aws" to appear AFTER the
|
|
130
|
+
// key and wrapped the run in `\b`. Both are wrong: the real layout is
|
|
131
|
+
// `AWS_SECRET_ACCESS_KEY=<key>` (context first), and a `\b` cannot
|
|
132
|
+
// hold next to the `+` or `/` that base64 keys routinely end with. The
|
|
133
|
+
// pattern therefore never fired on a real key. Anchor on the context
|
|
134
|
+
// token instead and let the key follow it.
|
|
5
135
|
kind: "aws-secret-key",
|
|
6
|
-
re:
|
|
136
|
+
re: /(?:aws|amazon)[A-Za-z0-9_-]*(?:secret|key)[A-Za-z0-9_-]*\s*[:=]\s*['"]?([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/gi
|
|
7
137
|
},
|
|
8
|
-
{ kind: "private-key-block", re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g },
|
|
9
|
-
{ kind: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
10
|
-
{ kind: "openai-key", re: /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g },
|
|
11
|
-
{ kind: "anthropic-key", re: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g },
|
|
12
|
-
{ kind: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
13
|
-
{ kind: "google-api-key", re: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
14
|
-
{ kind: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
15
|
-
{ kind: "bearer-token", re: /\bBearer\s+[A-Za-z0-9._-]{20,}\b/g },
|
|
16
138
|
{
|
|
17
139
|
kind: "generic-secret-assignment",
|
|
18
140
|
re: /\b(?:api[_-]?key|secret|password|passwd|token)\s*[:=]\s*['"]?[A-Za-z0-9._/+-]{12,}['"]?/gi
|
|
19
141
|
}
|
|
20
142
|
];
|
|
143
|
+
var PATTERNS = [
|
|
144
|
+
...cloneCredentialPatterns().map((p) => ({
|
|
145
|
+
kind: KIND_ALIASES[p.type] ?? p.type,
|
|
146
|
+
re: p.regex
|
|
147
|
+
})),
|
|
148
|
+
...EXTRA_PATTERNS
|
|
149
|
+
];
|
|
21
150
|
function detectSecrets(text, allow) {
|
|
22
151
|
const counts = /* @__PURE__ */ new Map();
|
|
23
152
|
for (const p of PATTERNS) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refactor-suggester/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refactor-suggester/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,aAAa,CAAC;AASlB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA8PD,QAAA,MAAM,MAAM,EAAE,MAwOb,CAAC;eAEa,MAAM"}
|