@akasecurity/ai-tc-claude-code 0.9.5 → 0.9.6
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-plugin/plugin.json +1 -1
- package/commands/setup.md +23 -0
- package/package.json +4 -4
- package/scripts/apply-suppressions.js +61 -13
- package/scripts/backfill.js +64 -15
- package/scripts/filescan.js +73 -24
- package/scripts/firstrun.js +52 -8
- package/scripts/intro.js +49 -5
- package/scripts/message-display.js +58 -10
- package/scripts/onboard.js +49 -5
- package/scripts/post-tool-use.js +62 -13
- package/scripts/pre-tool-use.js +62 -13
- package/scripts/query.js +54 -10
- package/scripts/reconcile.js +60 -12
- package/scripts/remediate.js +67 -18
- package/scripts/scan-worker.js +61 -12
- package/scripts/session-start.js +86 -32
- package/scripts/start-light.js +52 -8
- package/scripts/statusline.js +51 -7
- package/scripts/stop.js +49 -5
- package/scripts/user-prompt-submit.js +175 -108
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aka",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "AI Traffic Control — inspect and govern AI prompts in Claude Code. Detection runs locally; events are recorded to a local SQLite store on your machine.",
|
|
5
5
|
"homepage": "https://github.com/akasecurity/ai-tc",
|
|
6
6
|
"author": { "name": "AKA Security" }
|
package/commands/setup.md
CHANGED
|
@@ -892,3 +892,26 @@ declined, or a failed install you already reported — end with one warm close:
|
|
|
892
892
|
|
|
893
893
|
Before you finish, confirm every AKA_SHOW region on the path you took was
|
|
894
894
|
relayed to the user. If you summarized one instead of pasting it, paste it now.
|
|
895
|
+
|
|
896
|
+
## Known limitations
|
|
897
|
+
|
|
898
|
+
Be honest about every one of these if the user asks why something wasn't caught
|
|
899
|
+
— never imply coverage this plugin does not have.
|
|
900
|
+
|
|
901
|
+
**The model-judge step in step 3 cannot run on native Windows.** The judge
|
|
902
|
+
spawns the `claude` CLI through a shell-free `execFileSync`, and an
|
|
903
|
+
npm-installed CLI is a `.cmd` shim on Windows, which Node has refused to spawn
|
|
904
|
+
without a shell since the CVE-2024-27980 fix. So a user who grants model-judge
|
|
905
|
+
consent gets a spawn failure at that step rather than a rated set of findings,
|
|
906
|
+
and the step exits non-zero instead of completing. Everything before it is
|
|
907
|
+
unaffected — the posture check, the consent-gated historical read, and the local
|
|
908
|
+
ruleset scan all run, and every finding is still detected and redacted locally.
|
|
909
|
+
What is unavailable is only the model pass that rates false positives and
|
|
910
|
+
severity.
|
|
911
|
+
|
|
912
|
+
Say this plainly if a Windows user asks why setup stopped there, and do not
|
|
913
|
+
offer to retry it: the fix is a code change, tracked separately. Two things
|
|
914
|
+
worth getting right if it comes up — running under WSL2 is Linux rather than
|
|
915
|
+
Windows and is not affected, and declining model-judge consent in step 1 is not
|
|
916
|
+
a workaround so much as the other supported path, since the local scan is what
|
|
917
|
+
produces the findings in the first place.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akasecurity/ai-tc-claude-code",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "AI Traffic Control — inspect and govern AI prompts in Claude Code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"typescript": "^5.8.0",
|
|
28
28
|
"vitest": "^4.1.10",
|
|
29
29
|
"zod": "^4.0.0",
|
|
30
|
-
"@akasecurity/persistence": "0.8.0",
|
|
31
30
|
"@akasecurity/eslint-config": "0.8.0",
|
|
31
|
+
"@akasecurity/persistence": "0.8.0",
|
|
32
32
|
"@akasecurity/plugin-sdk": "0.8.0",
|
|
33
33
|
"@akasecurity/scanner": "0.8.0",
|
|
34
|
+
"@akasecurity/schema": "0.8.0",
|
|
34
35
|
"@akasecurity/plugin-runtime": "0.8.0",
|
|
35
|
-
"@akasecurity/setup-wizard": "0.8.0"
|
|
36
|
-
"@akasecurity/schema": "0.8.0"
|
|
36
|
+
"@akasecurity/setup-wizard": "0.8.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsup",
|
|
@@ -25890,6 +25890,40 @@ function escapeRegExp2(value) {
|
|
|
25890
25890
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25891
25891
|
}
|
|
25892
25892
|
|
|
25893
|
+
// ../../packages/detections/src/regex-cache.ts
|
|
25894
|
+
var singles = /* @__PURE__ */ new WeakMap();
|
|
25895
|
+
var keywordLists = /* @__PURE__ */ new WeakMap();
|
|
25896
|
+
var labelLists = /* @__PURE__ */ new WeakMap();
|
|
25897
|
+
function listCache(kind) {
|
|
25898
|
+
return kind === "keyword" ? keywordLists : labelLists;
|
|
25899
|
+
}
|
|
25900
|
+
function memoizedRegExp(owner, build) {
|
|
25901
|
+
const cached2 = singles.get(owner);
|
|
25902
|
+
if (cached2 !== void 0) {
|
|
25903
|
+
cached2.lastIndex = 0;
|
|
25904
|
+
return cached2;
|
|
25905
|
+
}
|
|
25906
|
+
const compiled = build();
|
|
25907
|
+
singles.set(owner, compiled);
|
|
25908
|
+
return compiled;
|
|
25909
|
+
}
|
|
25910
|
+
function memoizedRegExpList(kind, owner, build) {
|
|
25911
|
+
const cache = listCache(kind);
|
|
25912
|
+
const cached2 = cache.get(owner);
|
|
25913
|
+
if (cached2 !== void 0) {
|
|
25914
|
+
if (cached2.stateful) {
|
|
25915
|
+
for (const re of cached2.entries) if (re !== void 0) re.lastIndex = 0;
|
|
25916
|
+
}
|
|
25917
|
+
return cached2.entries;
|
|
25918
|
+
}
|
|
25919
|
+
const entries = build();
|
|
25920
|
+
cache.set(owner, {
|
|
25921
|
+
entries,
|
|
25922
|
+
stateful: entries.some((re) => re !== void 0 && (re.global || re.sticky))
|
|
25923
|
+
});
|
|
25924
|
+
return entries;
|
|
25925
|
+
}
|
|
25926
|
+
|
|
25893
25927
|
// ../../packages/detections/src/matchers/limits.ts
|
|
25894
25928
|
var MAX_MATCHES_PER_RULE = 1e4;
|
|
25895
25929
|
var MAX_REGEX_INPUT_LENGTH = 2e5;
|
|
@@ -25900,10 +25934,17 @@ var KeywordMatcher2 = class {
|
|
|
25900
25934
|
if (rule.matcher.type !== "keyword") return [];
|
|
25901
25935
|
const { keywords, caseSensitive } = rule.matcher;
|
|
25902
25936
|
const spans = [];
|
|
25903
|
-
|
|
25904
|
-
|
|
25937
|
+
const compiled = memoizedRegExpList(
|
|
25938
|
+
"keyword",
|
|
25939
|
+
rule.matcher,
|
|
25940
|
+
() => keywords.map((kw) => {
|
|
25941
|
+
if (kw.length === 0) return void 0;
|
|
25942
|
+
return new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
25943
|
+
})
|
|
25944
|
+
);
|
|
25945
|
+
for (const re of compiled) {
|
|
25946
|
+
if (re === void 0) continue;
|
|
25905
25947
|
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
25906
|
-
const re = new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
25907
25948
|
let m;
|
|
25908
25949
|
while ((m = re.exec(text)) !== null) {
|
|
25909
25950
|
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
@@ -25919,7 +25960,10 @@ var RegexMatcher2 = class {
|
|
|
25919
25960
|
match(text, rule) {
|
|
25920
25961
|
if (rule.matcher.type !== "regex") return [];
|
|
25921
25962
|
const { pattern, flags, captureGroup } = rule.matcher;
|
|
25922
|
-
const re =
|
|
25963
|
+
const re = memoizedRegExp(
|
|
25964
|
+
rule.matcher,
|
|
25965
|
+
() => new RegExp(pattern, flags.includes("d") ? flags : `${flags}d`)
|
|
25966
|
+
);
|
|
25923
25967
|
const scanText2 = text.length > MAX_REGEX_INPUT_LENGTH ? text.slice(0, MAX_REGEX_INPUT_LENGTH) : text;
|
|
25924
25968
|
const spans = [];
|
|
25925
25969
|
let m;
|
|
@@ -26027,11 +26071,15 @@ function isCorroborated(candidate, candidates, text) {
|
|
|
26027
26071
|
const labels = req.labels;
|
|
26028
26072
|
if (labels && labels.length > 0) {
|
|
26029
26073
|
const haystack = text.slice(Math.max(0, winStart), winEnd);
|
|
26030
|
-
for (const
|
|
26031
|
-
|
|
26032
|
-
|
|
26033
|
-
|
|
26034
|
-
|
|
26074
|
+
for (const re of memoizedRegExpList(
|
|
26075
|
+
"label",
|
|
26076
|
+
req,
|
|
26077
|
+
() => labels.map((label) => {
|
|
26078
|
+
const trimmed = label.trim();
|
|
26079
|
+
return trimmed.length === 0 ? void 0 : new RegExp(`(?<![A-Za-z0-9])${escapeRegExp2(trimmed)}(?![A-Za-z0-9])`, "i");
|
|
26080
|
+
})
|
|
26081
|
+
)) {
|
|
26082
|
+
if (re?.test(haystack)) return true;
|
|
26035
26083
|
}
|
|
26036
26084
|
}
|
|
26037
26085
|
return false;
|
|
@@ -28339,7 +28387,7 @@ function applyCategoryPosture(posture, repo, mode = "fill-gaps") {
|
|
|
28339
28387
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
28340
28388
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
28341
28389
|
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
28342
|
-
import { basename as basename5, join as join12
|
|
28390
|
+
import { basename as basename5, join as join12 } from "path";
|
|
28343
28391
|
|
|
28344
28392
|
// ../../packages/plugin-sdk/src/provider-env-antigravity.ts
|
|
28345
28393
|
var optionalBaseUrl2 = external_exports.preprocess((v) => {
|
|
@@ -29433,8 +29481,8 @@ function table(headers, rows, opts = {}) {
|
|
|
29433
29481
|
const widths = headers.map(
|
|
29434
29482
|
(h, i) => Math.max(visibleLength(h), ...rows.map((r) => visibleLength(r[i] ?? "")))
|
|
29435
29483
|
);
|
|
29436
|
-
const
|
|
29437
|
-
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(
|
|
29484
|
+
const sep4 = " ".repeat(gap);
|
|
29485
|
+
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(sep4);
|
|
29438
29486
|
const headerLine = fmt(headers.map((h) => h.toUpperCase()));
|
|
29439
29487
|
if (opts.rowSep === true) {
|
|
29440
29488
|
const fullWidth = widths.reduce((n, w) => n + w, 0) + gap * Math.max(0, widths.length - 1);
|
|
@@ -29446,7 +29494,7 @@ function table(headers, rows, opts = {}) {
|
|
|
29446
29494
|
});
|
|
29447
29495
|
return [headerLine, rule, ...body].join("\n");
|
|
29448
29496
|
}
|
|
29449
|
-
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(
|
|
29497
|
+
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(sep4);
|
|
29450
29498
|
return [headerLine, ruleLine, ...rows.map(fmt)].join("\n");
|
|
29451
29499
|
}
|
|
29452
29500
|
function fenced(body) {
|
package/scripts/backfill.js
CHANGED
|
@@ -26973,6 +26973,40 @@ function escapeRegExp2(value) {
|
|
|
26973
26973
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26974
26974
|
}
|
|
26975
26975
|
|
|
26976
|
+
// ../../packages/detections/src/regex-cache.ts
|
|
26977
|
+
var singles = /* @__PURE__ */ new WeakMap();
|
|
26978
|
+
var keywordLists = /* @__PURE__ */ new WeakMap();
|
|
26979
|
+
var labelLists = /* @__PURE__ */ new WeakMap();
|
|
26980
|
+
function listCache(kind) {
|
|
26981
|
+
return kind === "keyword" ? keywordLists : labelLists;
|
|
26982
|
+
}
|
|
26983
|
+
function memoizedRegExp(owner, build) {
|
|
26984
|
+
const cached2 = singles.get(owner);
|
|
26985
|
+
if (cached2 !== void 0) {
|
|
26986
|
+
cached2.lastIndex = 0;
|
|
26987
|
+
return cached2;
|
|
26988
|
+
}
|
|
26989
|
+
const compiled = build();
|
|
26990
|
+
singles.set(owner, compiled);
|
|
26991
|
+
return compiled;
|
|
26992
|
+
}
|
|
26993
|
+
function memoizedRegExpList(kind, owner, build) {
|
|
26994
|
+
const cache = listCache(kind);
|
|
26995
|
+
const cached2 = cache.get(owner);
|
|
26996
|
+
if (cached2 !== void 0) {
|
|
26997
|
+
if (cached2.stateful) {
|
|
26998
|
+
for (const re of cached2.entries) if (re !== void 0) re.lastIndex = 0;
|
|
26999
|
+
}
|
|
27000
|
+
return cached2.entries;
|
|
27001
|
+
}
|
|
27002
|
+
const entries = build();
|
|
27003
|
+
cache.set(owner, {
|
|
27004
|
+
entries,
|
|
27005
|
+
stateful: entries.some((re) => re !== void 0 && (re.global || re.sticky))
|
|
27006
|
+
});
|
|
27007
|
+
return entries;
|
|
27008
|
+
}
|
|
27009
|
+
|
|
26976
27010
|
// ../../packages/detections/src/matchers/limits.ts
|
|
26977
27011
|
var MAX_MATCHES_PER_RULE = 1e4;
|
|
26978
27012
|
var MAX_REGEX_INPUT_LENGTH = 2e5;
|
|
@@ -26983,10 +27017,17 @@ var KeywordMatcher2 = class {
|
|
|
26983
27017
|
if (rule.matcher.type !== "keyword") return [];
|
|
26984
27018
|
const { keywords, caseSensitive } = rule.matcher;
|
|
26985
27019
|
const spans = [];
|
|
26986
|
-
|
|
26987
|
-
|
|
27020
|
+
const compiled = memoizedRegExpList(
|
|
27021
|
+
"keyword",
|
|
27022
|
+
rule.matcher,
|
|
27023
|
+
() => keywords.map((kw) => {
|
|
27024
|
+
if (kw.length === 0) return void 0;
|
|
27025
|
+
return new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
27026
|
+
})
|
|
27027
|
+
);
|
|
27028
|
+
for (const re of compiled) {
|
|
27029
|
+
if (re === void 0) continue;
|
|
26988
27030
|
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
26989
|
-
const re = new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
26990
27031
|
let m;
|
|
26991
27032
|
while ((m = re.exec(text)) !== null) {
|
|
26992
27033
|
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
@@ -27002,7 +27043,10 @@ var RegexMatcher2 = class {
|
|
|
27002
27043
|
match(text, rule) {
|
|
27003
27044
|
if (rule.matcher.type !== "regex") return [];
|
|
27004
27045
|
const { pattern, flags, captureGroup } = rule.matcher;
|
|
27005
|
-
const re =
|
|
27046
|
+
const re = memoizedRegExp(
|
|
27047
|
+
rule.matcher,
|
|
27048
|
+
() => new RegExp(pattern, flags.includes("d") ? flags : `${flags}d`)
|
|
27049
|
+
);
|
|
27006
27050
|
const scanText2 = text.length > MAX_REGEX_INPUT_LENGTH ? text.slice(0, MAX_REGEX_INPUT_LENGTH) : text;
|
|
27007
27051
|
const spans = [];
|
|
27008
27052
|
let m;
|
|
@@ -27110,11 +27154,15 @@ function isCorroborated(candidate, candidates, text) {
|
|
|
27110
27154
|
const labels = req.labels;
|
|
27111
27155
|
if (labels && labels.length > 0) {
|
|
27112
27156
|
const haystack = text.slice(Math.max(0, winStart), winEnd);
|
|
27113
|
-
for (const
|
|
27114
|
-
|
|
27115
|
-
|
|
27116
|
-
|
|
27117
|
-
|
|
27157
|
+
for (const re of memoizedRegExpList(
|
|
27158
|
+
"label",
|
|
27159
|
+
req,
|
|
27160
|
+
() => labels.map((label) => {
|
|
27161
|
+
const trimmed = label.trim();
|
|
27162
|
+
return trimmed.length === 0 ? void 0 : new RegExp(`(?<![A-Za-z0-9])${escapeRegExp2(trimmed)}(?![A-Za-z0-9])`, "i");
|
|
27163
|
+
})
|
|
27164
|
+
)) {
|
|
27165
|
+
if (re?.test(haystack)) return true;
|
|
27118
27166
|
}
|
|
27119
27167
|
}
|
|
27120
27168
|
return false;
|
|
@@ -27382,13 +27430,14 @@ function probesFor(rule) {
|
|
|
27382
27430
|
const derived = rule.matcher.type === "regex" ? derivedProbes(rule.matcher.pattern) : [];
|
|
27383
27431
|
return [...derived, ...EXPONENTIAL_PROBES, ...POLYNOMIAL_PROBES];
|
|
27384
27432
|
}
|
|
27385
|
-
|
|
27433
|
+
var wallClock = () => performance.now();
|
|
27434
|
+
function worstProbeMs(rule, now = wallClock) {
|
|
27386
27435
|
let ms = 0;
|
|
27387
27436
|
let probe = "";
|
|
27388
27437
|
for (const text of probesFor(rule)) {
|
|
27389
|
-
const start =
|
|
27438
|
+
const start = now();
|
|
27390
27439
|
scan(text, [rule]);
|
|
27391
|
-
const elapsed =
|
|
27440
|
+
const elapsed = now() - start;
|
|
27392
27441
|
if (elapsed > ms) {
|
|
27393
27442
|
ms = elapsed;
|
|
27394
27443
|
probe = text;
|
|
@@ -30105,7 +30154,7 @@ import { basename as basename4, dirname as dirname3, sep as sep3 } from "path";
|
|
|
30105
30154
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
30106
30155
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
30107
30156
|
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
30108
|
-
import { basename as basename5, join as join12
|
|
30157
|
+
import { basename as basename5, join as join12 } from "path";
|
|
30109
30158
|
|
|
30110
30159
|
// ../../packages/plugin-sdk/src/provider-env-antigravity.ts
|
|
30111
30160
|
var optionalBaseUrl2 = external_exports.preprocess((v) => {
|
|
@@ -31583,7 +31632,7 @@ import { readFileSync as readFileSync12, renameSync as renameSync6, rmSync as rm
|
|
|
31583
31632
|
|
|
31584
31633
|
// src/remediation/redact.ts
|
|
31585
31634
|
import { readFileSync as readFileSync11, realpathSync as realpathSync3, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync9 } from "fs";
|
|
31586
|
-
import { isAbsolute as isAbsolute2, relative
|
|
31635
|
+
import { isAbsolute as isAbsolute2, relative, resolve } from "path";
|
|
31587
31636
|
function platformRedactionScope(home) {
|
|
31588
31637
|
return { artifactRoots: [transcriptsDir(home)] };
|
|
31589
31638
|
}
|
|
@@ -31597,7 +31646,7 @@ function realPathOrNull(path) {
|
|
|
31597
31646
|
function isWithinRoot(realTarget, root) {
|
|
31598
31647
|
const realRoot = realPathOrNull(root);
|
|
31599
31648
|
if (realRoot === null) return false;
|
|
31600
|
-
const rel =
|
|
31649
|
+
const rel = relative(realRoot, realTarget);
|
|
31601
31650
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
31602
31651
|
}
|
|
31603
31652
|
function resolveRedactableArtifact(filePath, scope) {
|
package/scripts/filescan.js
CHANGED
|
@@ -26912,6 +26912,40 @@ function escapeRegExp2(value) {
|
|
|
26912
26912
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26913
26913
|
}
|
|
26914
26914
|
|
|
26915
|
+
// ../../packages/detections/src/regex-cache.ts
|
|
26916
|
+
var singles = /* @__PURE__ */ new WeakMap();
|
|
26917
|
+
var keywordLists = /* @__PURE__ */ new WeakMap();
|
|
26918
|
+
var labelLists = /* @__PURE__ */ new WeakMap();
|
|
26919
|
+
function listCache(kind) {
|
|
26920
|
+
return kind === "keyword" ? keywordLists : labelLists;
|
|
26921
|
+
}
|
|
26922
|
+
function memoizedRegExp(owner, build) {
|
|
26923
|
+
const cached2 = singles.get(owner);
|
|
26924
|
+
if (cached2 !== void 0) {
|
|
26925
|
+
cached2.lastIndex = 0;
|
|
26926
|
+
return cached2;
|
|
26927
|
+
}
|
|
26928
|
+
const compiled = build();
|
|
26929
|
+
singles.set(owner, compiled);
|
|
26930
|
+
return compiled;
|
|
26931
|
+
}
|
|
26932
|
+
function memoizedRegExpList(kind, owner, build) {
|
|
26933
|
+
const cache = listCache(kind);
|
|
26934
|
+
const cached2 = cache.get(owner);
|
|
26935
|
+
if (cached2 !== void 0) {
|
|
26936
|
+
if (cached2.stateful) {
|
|
26937
|
+
for (const re of cached2.entries) if (re !== void 0) re.lastIndex = 0;
|
|
26938
|
+
}
|
|
26939
|
+
return cached2.entries;
|
|
26940
|
+
}
|
|
26941
|
+
const entries = build();
|
|
26942
|
+
cache.set(owner, {
|
|
26943
|
+
entries,
|
|
26944
|
+
stateful: entries.some((re) => re !== void 0 && (re.global || re.sticky))
|
|
26945
|
+
});
|
|
26946
|
+
return entries;
|
|
26947
|
+
}
|
|
26948
|
+
|
|
26915
26949
|
// ../../packages/detections/src/matchers/limits.ts
|
|
26916
26950
|
var MAX_MATCHES_PER_RULE = 1e4;
|
|
26917
26951
|
var MAX_REGEX_INPUT_LENGTH = 2e5;
|
|
@@ -26922,10 +26956,17 @@ var KeywordMatcher2 = class {
|
|
|
26922
26956
|
if (rule.matcher.type !== "keyword") return [];
|
|
26923
26957
|
const { keywords, caseSensitive } = rule.matcher;
|
|
26924
26958
|
const spans = [];
|
|
26925
|
-
|
|
26926
|
-
|
|
26959
|
+
const compiled = memoizedRegExpList(
|
|
26960
|
+
"keyword",
|
|
26961
|
+
rule.matcher,
|
|
26962
|
+
() => keywords.map((kw) => {
|
|
26963
|
+
if (kw.length === 0) return void 0;
|
|
26964
|
+
return new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
26965
|
+
})
|
|
26966
|
+
);
|
|
26967
|
+
for (const re of compiled) {
|
|
26968
|
+
if (re === void 0) continue;
|
|
26927
26969
|
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
26928
|
-
const re = new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
26929
26970
|
let m;
|
|
26930
26971
|
while ((m = re.exec(text)) !== null) {
|
|
26931
26972
|
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
@@ -26941,7 +26982,10 @@ var RegexMatcher2 = class {
|
|
|
26941
26982
|
match(text, rule) {
|
|
26942
26983
|
if (rule.matcher.type !== "regex") return [];
|
|
26943
26984
|
const { pattern, flags, captureGroup } = rule.matcher;
|
|
26944
|
-
const re =
|
|
26985
|
+
const re = memoizedRegExp(
|
|
26986
|
+
rule.matcher,
|
|
26987
|
+
() => new RegExp(pattern, flags.includes("d") ? flags : `${flags}d`)
|
|
26988
|
+
);
|
|
26945
26989
|
const scanText2 = text.length > MAX_REGEX_INPUT_LENGTH ? text.slice(0, MAX_REGEX_INPUT_LENGTH) : text;
|
|
26946
26990
|
const spans = [];
|
|
26947
26991
|
let m;
|
|
@@ -27049,11 +27093,15 @@ function isCorroborated(candidate, candidates, text) {
|
|
|
27049
27093
|
const labels = req.labels;
|
|
27050
27094
|
if (labels && labels.length > 0) {
|
|
27051
27095
|
const haystack = text.slice(Math.max(0, winStart), winEnd);
|
|
27052
|
-
for (const
|
|
27053
|
-
|
|
27054
|
-
|
|
27055
|
-
|
|
27056
|
-
|
|
27096
|
+
for (const re of memoizedRegExpList(
|
|
27097
|
+
"label",
|
|
27098
|
+
req,
|
|
27099
|
+
() => labels.map((label) => {
|
|
27100
|
+
const trimmed = label.trim();
|
|
27101
|
+
return trimmed.length === 0 ? void 0 : new RegExp(`(?<![A-Za-z0-9])${escapeRegExp2(trimmed)}(?![A-Za-z0-9])`, "i");
|
|
27102
|
+
})
|
|
27103
|
+
)) {
|
|
27104
|
+
if (re?.test(haystack)) return true;
|
|
27057
27105
|
}
|
|
27058
27106
|
}
|
|
27059
27107
|
return false;
|
|
@@ -27321,13 +27369,14 @@ function probesFor(rule) {
|
|
|
27321
27369
|
const derived = rule.matcher.type === "regex" ? derivedProbes(rule.matcher.pattern) : [];
|
|
27322
27370
|
return [...derived, ...EXPONENTIAL_PROBES, ...POLYNOMIAL_PROBES];
|
|
27323
27371
|
}
|
|
27324
|
-
|
|
27372
|
+
var wallClock = () => performance.now();
|
|
27373
|
+
function worstProbeMs(rule, now = wallClock) {
|
|
27325
27374
|
let ms = 0;
|
|
27326
27375
|
let probe = "";
|
|
27327
27376
|
for (const text of probesFor(rule)) {
|
|
27328
|
-
const start =
|
|
27377
|
+
const start = now();
|
|
27329
27378
|
scan(text, [rule]);
|
|
27330
|
-
const elapsed =
|
|
27379
|
+
const elapsed = now() - start;
|
|
27331
27380
|
if (elapsed > ms) {
|
|
27332
27381
|
ms = elapsed;
|
|
27333
27382
|
probe = text;
|
|
@@ -29989,7 +30038,7 @@ function resolveNonGitProject(startDir, recognizeMarker) {
|
|
|
29989
30038
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
29990
30039
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
29991
30040
|
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
29992
|
-
import { basename as basename5, join as join12
|
|
30041
|
+
import { basename as basename5, join as join12 } from "path";
|
|
29993
30042
|
|
|
29994
30043
|
// ../../packages/plugin-sdk/src/provider-env-antigravity.ts
|
|
29995
30044
|
var optionalBaseUrl2 = external_exports.preprocess((v) => {
|
|
@@ -30416,7 +30465,7 @@ function discoverGitRepos(opts) {
|
|
|
30416
30465
|
}
|
|
30417
30466
|
|
|
30418
30467
|
// ../../packages/scanner/src/render.ts
|
|
30419
|
-
import { basename as basename6, relative
|
|
30468
|
+
import { basename as basename6, relative } from "path";
|
|
30420
30469
|
var SEVERITY_ORDER3 = ["critical", "high", "medium", "low"];
|
|
30421
30470
|
var SEVERITY_GLYPH = {
|
|
30422
30471
|
critical: "\u2588",
|
|
@@ -30434,9 +30483,9 @@ function indent(text, spaces = 2) {
|
|
|
30434
30483
|
}
|
|
30435
30484
|
function table(headers, rows, gap = 3) {
|
|
30436
30485
|
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
|
|
30437
|
-
const
|
|
30438
|
-
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(
|
|
30439
|
-
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(
|
|
30486
|
+
const sep5 = " ".repeat(gap);
|
|
30487
|
+
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(sep5);
|
|
30488
|
+
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(sep5);
|
|
30440
30489
|
return [fmt(headers.map((h) => h.toUpperCase())), ruleLine, ...rows.map(fmt)].join("\n");
|
|
30441
30490
|
}
|
|
30442
30491
|
function metaBlock(rows) {
|
|
@@ -30458,7 +30507,7 @@ function followUpSection(opts) {
|
|
|
30458
30507
|
return opts.followUp !== void 0 ? ["", ` ${opts.followUp}`] : [];
|
|
30459
30508
|
}
|
|
30460
30509
|
function renderWorktreeSummary(summary, opts = {}) {
|
|
30461
|
-
const rootLabel =
|
|
30510
|
+
const rootLabel = relative(process.cwd(), summary.rootDir) || ".";
|
|
30462
30511
|
const meta3 = metaBlock([
|
|
30463
30512
|
["Root", rootLabel],
|
|
30464
30513
|
["Scanned", `${String(summary.scanned)} files`],
|
|
@@ -30510,7 +30559,7 @@ function renderMultiRepoSummary(summary, opts = {}) {
|
|
|
30510
30559
|
|
|
30511
30560
|
// ../../packages/scanner/src/scan.ts
|
|
30512
30561
|
import { existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
|
|
30513
|
-
import { extname as extname2, isAbsolute as isAbsolute2, relative as
|
|
30562
|
+
import { extname as extname2, isAbsolute as isAbsolute2, relative as relative3 } from "path";
|
|
30514
30563
|
|
|
30515
30564
|
// ../../packages/plugin-runtime/src/standalone-gateway.ts
|
|
30516
30565
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
@@ -30837,7 +30886,7 @@ import { statSync as statSync8 } from "fs";
|
|
|
30837
30886
|
// ../../packages/scanner/src/walk.ts
|
|
30838
30887
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
30839
30888
|
import { readdirSync as readdirSync6, readFileSync as readFileSync9, statSync as statSync7 } from "fs";
|
|
30840
|
-
import { extname, join as join15, relative as
|
|
30889
|
+
import { extname, join as join15, relative as relative2, sep as sep4 } from "path";
|
|
30841
30890
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
30842
30891
|
".ts",
|
|
30843
30892
|
".tsx",
|
|
@@ -30878,7 +30927,7 @@ function readIgnoreLayer(dir, filename) {
|
|
|
30878
30927
|
function evaluate(layers, absPath, isDir) {
|
|
30879
30928
|
let state = "unmatched";
|
|
30880
30929
|
for (const layer of layers) {
|
|
30881
|
-
const rel =
|
|
30930
|
+
const rel = relative2(layer.base, absPath).split(sep4).join("/") + (isDir ? "/" : "");
|
|
30882
30931
|
const verdict = layer.matcher.test(rel);
|
|
30883
30932
|
if (verdict.ignored) state = "ignored";
|
|
30884
30933
|
else if (verdict.unignored) state = "unignored";
|
|
@@ -30947,7 +30996,7 @@ function* walkSourceFiles(opts = {}) {
|
|
|
30947
30996
|
// Posix-separated like every stored relative path (and the ignore
|
|
30948
30997
|
// matching inside walkTree) — native separators must not leak into the
|
|
30949
30998
|
// contract.
|
|
30950
|
-
relativePath:
|
|
30999
|
+
relativePath: relative2(rootDir, file2.path).split(sep4).join("/"),
|
|
30951
31000
|
mtime: mtime.toISOString(),
|
|
30952
31001
|
size,
|
|
30953
31002
|
gitignored: file2.gitignored
|
|
@@ -31015,7 +31064,7 @@ function resolveEgressProject(rootDir) {
|
|
|
31015
31064
|
}
|
|
31016
31065
|
}
|
|
31017
31066
|
function egressKey(root, absPath) {
|
|
31018
|
-
const rel = toPosix(
|
|
31067
|
+
const rel = toPosix(relative3(root, absPath));
|
|
31019
31068
|
return rel === "" || rel.startsWith("../") ? null : rel;
|
|
31020
31069
|
}
|
|
31021
31070
|
function startEgress(rootDir) {
|
|
@@ -31069,7 +31118,7 @@ async function reopenRedetectedFindings(gateway, path, currentKeys, evidence, re
|
|
|
31069
31118
|
}
|
|
31070
31119
|
}
|
|
31071
31120
|
function isUnderRoot(path, rootDir) {
|
|
31072
|
-
const rel =
|
|
31121
|
+
const rel = relative3(rootDir, path);
|
|
31073
31122
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
31074
31123
|
}
|
|
31075
31124
|
async function sweepDeletedFiles(gateway, rootDir, previous) {
|
package/scripts/firstrun.js
CHANGED
|
@@ -25926,6 +25926,40 @@ function escapeRegExp2(value) {
|
|
|
25926
25926
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25927
25927
|
}
|
|
25928
25928
|
|
|
25929
|
+
// ../../packages/detections/src/regex-cache.ts
|
|
25930
|
+
var singles = /* @__PURE__ */ new WeakMap();
|
|
25931
|
+
var keywordLists = /* @__PURE__ */ new WeakMap();
|
|
25932
|
+
var labelLists = /* @__PURE__ */ new WeakMap();
|
|
25933
|
+
function listCache(kind) {
|
|
25934
|
+
return kind === "keyword" ? keywordLists : labelLists;
|
|
25935
|
+
}
|
|
25936
|
+
function memoizedRegExp(owner, build) {
|
|
25937
|
+
const cached2 = singles.get(owner);
|
|
25938
|
+
if (cached2 !== void 0) {
|
|
25939
|
+
cached2.lastIndex = 0;
|
|
25940
|
+
return cached2;
|
|
25941
|
+
}
|
|
25942
|
+
const compiled = build();
|
|
25943
|
+
singles.set(owner, compiled);
|
|
25944
|
+
return compiled;
|
|
25945
|
+
}
|
|
25946
|
+
function memoizedRegExpList(kind, owner, build) {
|
|
25947
|
+
const cache = listCache(kind);
|
|
25948
|
+
const cached2 = cache.get(owner);
|
|
25949
|
+
if (cached2 !== void 0) {
|
|
25950
|
+
if (cached2.stateful) {
|
|
25951
|
+
for (const re of cached2.entries) if (re !== void 0) re.lastIndex = 0;
|
|
25952
|
+
}
|
|
25953
|
+
return cached2.entries;
|
|
25954
|
+
}
|
|
25955
|
+
const entries = build();
|
|
25956
|
+
cache.set(owner, {
|
|
25957
|
+
entries,
|
|
25958
|
+
stateful: entries.some((re) => re !== void 0 && (re.global || re.sticky))
|
|
25959
|
+
});
|
|
25960
|
+
return entries;
|
|
25961
|
+
}
|
|
25962
|
+
|
|
25929
25963
|
// ../../packages/detections/src/matchers/limits.ts
|
|
25930
25964
|
var MAX_MATCHES_PER_RULE = 1e4;
|
|
25931
25965
|
var MAX_REGEX_INPUT_LENGTH = 2e5;
|
|
@@ -25936,10 +25970,17 @@ var KeywordMatcher2 = class {
|
|
|
25936
25970
|
if (rule.matcher.type !== "keyword") return [];
|
|
25937
25971
|
const { keywords, caseSensitive } = rule.matcher;
|
|
25938
25972
|
const spans = [];
|
|
25939
|
-
|
|
25940
|
-
|
|
25973
|
+
const compiled = memoizedRegExpList(
|
|
25974
|
+
"keyword",
|
|
25975
|
+
rule.matcher,
|
|
25976
|
+
() => keywords.map((kw) => {
|
|
25977
|
+
if (kw.length === 0) return void 0;
|
|
25978
|
+
return new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
25979
|
+
})
|
|
25980
|
+
);
|
|
25981
|
+
for (const re of compiled) {
|
|
25982
|
+
if (re === void 0) continue;
|
|
25941
25983
|
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
25942
|
-
const re = new RegExp(escapeRegExp2(kw), caseSensitive ? "gu" : "giu");
|
|
25943
25984
|
let m;
|
|
25944
25985
|
while ((m = re.exec(text)) !== null) {
|
|
25945
25986
|
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
@@ -25955,7 +25996,10 @@ var RegexMatcher2 = class {
|
|
|
25955
25996
|
match(text, rule) {
|
|
25956
25997
|
if (rule.matcher.type !== "regex") return [];
|
|
25957
25998
|
const { pattern, flags, captureGroup } = rule.matcher;
|
|
25958
|
-
const re =
|
|
25999
|
+
const re = memoizedRegExp(
|
|
26000
|
+
rule.matcher,
|
|
26001
|
+
() => new RegExp(pattern, flags.includes("d") ? flags : `${flags}d`)
|
|
26002
|
+
);
|
|
25959
26003
|
const scanText2 = text.length > MAX_REGEX_INPUT_LENGTH ? text.slice(0, MAX_REGEX_INPUT_LENGTH) : text;
|
|
25960
26004
|
const spans = [];
|
|
25961
26005
|
let m;
|
|
@@ -28113,7 +28157,7 @@ import { basename as basename4, dirname as dirname3, sep as sep3 } from "path";
|
|
|
28113
28157
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
28114
28158
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
28115
28159
|
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
28116
|
-
import { basename as basename5, join as join12
|
|
28160
|
+
import { basename as basename5, join as join12 } from "path";
|
|
28117
28161
|
|
|
28118
28162
|
// ../../packages/plugin-sdk/src/provider-env-antigravity.ts
|
|
28119
28163
|
var optionalBaseUrl2 = external_exports.preprocess((v) => {
|
|
@@ -28557,8 +28601,8 @@ function table(headers, rows, opts = {}) {
|
|
|
28557
28601
|
const widths = headers.map(
|
|
28558
28602
|
(h, i) => Math.max(visibleLength(h), ...rows.map((r) => visibleLength(r[i] ?? "")))
|
|
28559
28603
|
);
|
|
28560
|
-
const
|
|
28561
|
-
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(
|
|
28604
|
+
const sep4 = " ".repeat(gap);
|
|
28605
|
+
const fmt = (cells) => cells.map((cell, i) => padEnd(cell, widths[i] ?? 0)).join(sep4);
|
|
28562
28606
|
const headerLine = fmt(headers.map((h) => h.toUpperCase()));
|
|
28563
28607
|
if (opts.rowSep === true) {
|
|
28564
28608
|
const fullWidth = widths.reduce((n, w) => n + w, 0) + gap * Math.max(0, widths.length - 1);
|
|
@@ -28570,7 +28614,7 @@ function table(headers, rows, opts = {}) {
|
|
|
28570
28614
|
});
|
|
28571
28615
|
return [headerLine, rule, ...body].join("\n");
|
|
28572
28616
|
}
|
|
28573
|
-
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(
|
|
28617
|
+
const ruleLine = widths.map((w) => "\u2500".repeat(w)).join(sep4);
|
|
28574
28618
|
return [headerLine, ruleLine, ...rows.map(fmt)].join("\n");
|
|
28575
28619
|
}
|
|
28576
28620
|
function fenced(body) {
|