@akasecurity/ai-tc-claude-code 0.8.2 → 0.9.0
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/README.md +11 -3
- package/commands/setup.md +563 -151
- package/package.json +5 -5
- package/scripts/apply-suppressions.js +821 -115
- package/scripts/backfill.js +364 -91
- package/scripts/filescan.js +341 -76
- package/scripts/firstrun.js +476 -107
- package/scripts/intro.js +328 -137
- package/scripts/onboard.js +406 -83
- package/scripts/package.json +1 -0
- package/scripts/post-tool-use.js +344 -77
- package/scripts/pre-tool-use.js +342 -76
- package/scripts/query.js +332 -66
- package/scripts/reconcile.js +329 -69
- package/scripts/remediate.js +26695 -0
- package/scripts/session-start.js +329 -69
- package/scripts/start-light.js +17542 -0
- package/scripts/statusline.js +334 -66
- package/scripts/stop.js +234 -51
- package/scripts/triage-rubric.md +10 -2
- package/scripts/user-prompt-submit.js +345 -79
package/scripts/post-tool-use.js
CHANGED
|
@@ -538,6 +538,10 @@ var SQLITE_MIGRATIONS = [
|
|
|
538
538
|
{
|
|
539
539
|
tag: "0009_findings_path_expression_index",
|
|
540
540
|
sql: "-- Custom migration: partial expression index for the resolver's per-path reads.\n--\n-- openAtRestKeysForPath / resolvedAtRestKeysForPath (and the scanner's tier-3\n-- open-key probe) filter at-rest events by\n-- e.kind = 'code_change' AND json_extract(e.metadata, '$.filePath') = :path\n-- once per changed/deleted file on every scan \u2014 previously a full events scan\n-- per file. json_extract is deterministic, so SQLite allows it in an index;\n-- the WHERE kind = 'code_change' keeps the index to exactly the rows those\n-- queries can match (in-flight events are never path-addressed).\nCREATE INDEX `idx_events_code_change_path` ON `events` (json_extract(`metadata`, '$.filePath')) WHERE `kind` = 'code_change';\n"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
tag: "0010_events_session_expression_index",
|
|
544
|
+
sql: "-- Custom migration: partial expression index for session-scoped finding reads.\n--\n-- sessionFindingsCount, the session-scoped listGroupedFindings paths, and the\n-- insert-time session dedup all filter live-capture events by\n-- json_extract(e.metadata, '$.sessionId') = :sessionId\n-- \u2014 previously a full findings-join scan with a JSON parse per row. The\n-- IS NOT NULL predicate keeps the index to session-stamped events only (an\n-- equality probe implies non-null, so SQLite still uses it).\nCREATE INDEX `idx_events_session_id` ON `events` (json_extract(`metadata`, '$.sessionId')) WHERE json_extract(`metadata`, '$.sessionId') IS NOT NULL;\n"
|
|
541
545
|
}
|
|
542
546
|
];
|
|
543
547
|
|
|
@@ -640,6 +644,12 @@ var defaultCostModel = {
|
|
|
640
644
|
}
|
|
641
645
|
};
|
|
642
646
|
|
|
647
|
+
// ../../packages/schema/src/token/format.ts
|
|
648
|
+
var COMPACT = new Intl.NumberFormat("en-US", {
|
|
649
|
+
notation: "compact",
|
|
650
|
+
maximumFractionDigits: 1
|
|
651
|
+
});
|
|
652
|
+
|
|
643
653
|
// ../../packages/schema/src/token/token-report.ts
|
|
644
654
|
var num = (value) => value ?? 0;
|
|
645
655
|
function costUsageOf(a) {
|
|
@@ -15311,6 +15321,12 @@ var FindingInstance = external_exports.object({
|
|
|
15311
15321
|
provider: FindingProvider,
|
|
15312
15322
|
repo: external_exports.string(),
|
|
15313
15323
|
file: external_exports.string(),
|
|
15324
|
+
// Host tool that produced the scanned text (event metadata's toolName).
|
|
15325
|
+
// Present whenever the capturing hook recorded one — including
|
|
15326
|
+
// file-attributed captures (views prefer `file`); its display value is
|
|
15327
|
+
// the location fallback ("via Bash") when no filePath exists. Absent for
|
|
15328
|
+
// legacy rows and non-tool captures (prompts, worktree scans).
|
|
15329
|
+
toolName: external_exports.string().optional(),
|
|
15314
15330
|
// Effective action: override.action ?? actionTaken, translated to FindingAction.
|
|
15315
15331
|
action: FindingAction,
|
|
15316
15332
|
detectedAt: external_exports.iso.datetime(),
|
|
@@ -15367,6 +15383,9 @@ var ListGroupedFindingsQuery = external_exports.object({
|
|
|
15367
15383
|
provider: external_exports.array(FindingProvider).optional(),
|
|
15368
15384
|
action: external_exports.array(FindingAction).optional(),
|
|
15369
15385
|
q: external_exports.string().optional(),
|
|
15386
|
+
// Scope to findings whose event carries this session id (the Activity page's
|
|
15387
|
+
// session → findings drilldown). Findings without a session never match.
|
|
15388
|
+
sessionId: external_exports.string().optional(),
|
|
15370
15389
|
groupBy: external_exports.literal("type").optional(),
|
|
15371
15390
|
limit: external_exports.coerce.number().int().min(1).max(100).optional(),
|
|
15372
15391
|
cursor: external_exports.string().optional()
|
|
@@ -15378,7 +15397,13 @@ var ListGroupedFindingsResponse = external_exports.object({
|
|
|
15378
15397
|
}),
|
|
15379
15398
|
facets: FindingFacets,
|
|
15380
15399
|
items: external_exports.array(FindingGroup),
|
|
15381
|
-
nextCursor: external_exports.string().nullable()
|
|
15400
|
+
nextCursor: external_exports.string().nullable(),
|
|
15401
|
+
// Present only on session-scoped queries (`sessionId` set): per ruleId, how
|
|
15402
|
+
// many times that rule fired in the session's persisted transcript. Findings
|
|
15403
|
+
// here are deduplicated to unique values while the transcript tally counts
|
|
15404
|
+
// every firing, so the two numbers legitimately differ — this map lets a
|
|
15405
|
+
// session-scoped view show both.
|
|
15406
|
+
sessionFirings: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()).optional()
|
|
15382
15407
|
}).meta({ id: "ListGroupedFindingsResponse" });
|
|
15383
15408
|
var ApplyFindingActionRequest = external_exports.object({
|
|
15384
15409
|
// 'quarantined' is system-assigned (see FindingAction) — clients may not set
|
|
@@ -15786,6 +15811,10 @@ var ListActivitySessionsQuery = external_exports.object({
|
|
|
15786
15811
|
from: external_exports.union([external_exports.iso.date(), external_exports.iso.datetime()]).optional(),
|
|
15787
15812
|
/** Upper bound on startedAt; omitted defaults to now. */
|
|
15788
15813
|
to: external_exports.union([external_exports.iso.date(), external_exports.iso.datetime()]).optional(),
|
|
15814
|
+
/** Exclude zero-activity sessions — roots whose only recorded children are
|
|
15815
|
+
* bookkeeping rows (hooks, config scans), typically background `claude`
|
|
15816
|
+
* launches. Omitted = list everything. `z.stringbool()` per the note above. */
|
|
15817
|
+
excludeEmpty: external_exports.stringbool().optional(),
|
|
15789
15818
|
/** Page size, 1–100; out-of-range values are a 400. `z.coerce` — query params arrive as strings. */
|
|
15790
15819
|
limit: external_exports.coerce.number().int().min(1).max(100).default(50),
|
|
15791
15820
|
/** Opaque pagination cursor (most-recent first). */
|
|
@@ -15794,7 +15823,11 @@ var ListActivitySessionsQuery = external_exports.object({
|
|
|
15794
15823
|
var ListActivitySessionsResponse = external_exports.object({
|
|
15795
15824
|
items: external_exports.array(ActivitySessionSummary),
|
|
15796
15825
|
/** `null` once the last page is reached. */
|
|
15797
|
-
nextCursor: external_exports.string().nullable()
|
|
15826
|
+
nextCursor: external_exports.string().nullable(),
|
|
15827
|
+
/** Zero-activity sessions matching the query's filters/range (whether or
|
|
15828
|
+
* not `excludeEmpty` dropped them from `items`) — the count a UI toggle
|
|
15829
|
+
* shows when collapsing them. */
|
|
15830
|
+
emptyCount: external_exports.number().int().nonnegative()
|
|
15798
15831
|
}).meta({ id: "ListActivitySessionsResponse" });
|
|
15799
15832
|
var ListSessionEventsQuery = external_exports.object({
|
|
15800
15833
|
/** Default 100, range 1–500. */
|
|
@@ -15829,6 +15862,12 @@ var EventMetadata = external_exports.object({
|
|
|
15829
15862
|
sessionId: external_exports.string().optional(),
|
|
15830
15863
|
repo: external_exports.string().optional(),
|
|
15831
15864
|
filePath: external_exports.string().optional(),
|
|
15865
|
+
// The host tool whose input/output was scanned (e.g. 'Bash', 'WebFetch'),
|
|
15866
|
+
// set by the tool-scanning hooks. The tool NAME only — never the tool's
|
|
15867
|
+
// arguments or output, which can carry the very value a finding masked
|
|
15868
|
+
// (metadata is stored unredacted). Gives findings on non-file captures a
|
|
15869
|
+
// display location ("via Bash") when no filePath exists.
|
|
15870
|
+
toolName: external_exports.string().optional(),
|
|
15832
15871
|
// Set (true) by the worktree scanner when the file is excluded by the
|
|
15833
15872
|
// repo's .gitignore. Gitignored files ARE still scanned — local scratch and
|
|
15834
15873
|
// generated code can leak real secrets — but the provenance is recorded so
|
|
@@ -16160,7 +16199,10 @@ var ExceptionBundleEntry = DetectionException.pick({
|
|
|
16160
16199
|
var MatcherType = external_exports.enum(["keyword", "regex", "validator"]).meta({ id: "MatcherType" });
|
|
16161
16200
|
var KeywordMatcher = external_exports.object({
|
|
16162
16201
|
type: external_exports.literal("keyword"),
|
|
16163
|
-
|
|
16202
|
+
// An empty keyword matches at every position, yielding one zero-length span
|
|
16203
|
+
// per character. Rejected here because a keyword that matches everything is
|
|
16204
|
+
// never intentional.
|
|
16205
|
+
keywords: external_exports.array(external_exports.string().min(1)).min(1),
|
|
16164
16206
|
caseSensitive: external_exports.boolean().default(false)
|
|
16165
16207
|
});
|
|
16166
16208
|
function isValidRegex(pattern, flags) {
|
|
@@ -16409,6 +16451,10 @@ var ListEventsResponse = external_exports.object({
|
|
|
16409
16451
|
items: external_exports.array(Event),
|
|
16410
16452
|
nextCursor: external_exports.string().nullable()
|
|
16411
16453
|
}).meta({ id: "ListEventsResponse" });
|
|
16454
|
+
var IngestResponse = external_exports.object({
|
|
16455
|
+
accepted: external_exports.number().int().nonnegative(),
|
|
16456
|
+
duplicates: external_exports.number().int().nonnegative()
|
|
16457
|
+
}).meta({ id: "IngestResponse" });
|
|
16412
16458
|
var ListFindingsQuery = external_exports.object({
|
|
16413
16459
|
cursor: external_exports.string().optional(),
|
|
16414
16460
|
limit: external_exports.coerce.number().int().min(1).max(LIST_QUERY_MAX_LIMIT).default(50),
|
|
@@ -16798,6 +16844,7 @@ function buildFindingGroups(rows, opts = {}) {
|
|
|
16798
16844
|
provider: toApiProvider(r.sourceTool),
|
|
16799
16845
|
repo: r.repo,
|
|
16800
16846
|
file: r.file,
|
|
16847
|
+
...r.toolName === void 0 ? {} : { toolName: r.toolName },
|
|
16801
16848
|
action: toApiAction(effectiveDbAction),
|
|
16802
16849
|
detectedAt: r.occurredAt,
|
|
16803
16850
|
confidence: r.confidence,
|
|
@@ -16870,6 +16917,7 @@ function buildHaystack(g, extra) {
|
|
|
16870
16917
|
g.id,
|
|
16871
16918
|
...g.instances.map((i) => i.repo),
|
|
16872
16919
|
...g.instances.map((i) => i.file),
|
|
16920
|
+
...g.instances.map((i) => i.toolName ? `via ${i.toolName}` : ""),
|
|
16873
16921
|
...g.instances.map((i) => i.id),
|
|
16874
16922
|
...extra === void 0 ? [] : [extra]
|
|
16875
16923
|
].join(" ").toLowerCase();
|
|
@@ -17136,6 +17184,71 @@ var ProjectFilesScan = external_exports.object({
|
|
|
17136
17184
|
scannedAt: external_exports.string()
|
|
17137
17185
|
});
|
|
17138
17186
|
|
|
17187
|
+
// ../../packages/schema/src/zod/ranges.ts
|
|
17188
|
+
var TIME_RANGES = ["7d", "30d", "3m", "6m"];
|
|
17189
|
+
var TimeRange = external_exports.enum(TIME_RANGES).meta({ id: "TimeRange" });
|
|
17190
|
+
var DEFAULT_TIME_RANGE = "7d";
|
|
17191
|
+
var RANGE_DAYS = {
|
|
17192
|
+
"7d": 7,
|
|
17193
|
+
"30d": 30,
|
|
17194
|
+
"3m": 90,
|
|
17195
|
+
"6m": 180
|
|
17196
|
+
};
|
|
17197
|
+
var TIME_RANGE_OR_DEFAULT = TimeRange.catch(DEFAULT_TIME_RANGE);
|
|
17198
|
+
|
|
17199
|
+
// ../../packages/schema/src/zod/remediation.ts
|
|
17200
|
+
var SecretFindingState = external_exports.enum(["still-valid", "unknown", "invalid"]);
|
|
17201
|
+
var MaskedFindingLocation = external_exports.object({
|
|
17202
|
+
filePath: external_exports.string(),
|
|
17203
|
+
span: Span.optional()
|
|
17204
|
+
}).strict();
|
|
17205
|
+
var MaskedSecretFinding = external_exports.object({
|
|
17206
|
+
provider: external_exports.string(),
|
|
17207
|
+
maskedToken: external_exports.string(),
|
|
17208
|
+
where: MaskedFindingLocation,
|
|
17209
|
+
state: SecretFindingState,
|
|
17210
|
+
observedAt: external_exports.iso.datetime().optional()
|
|
17211
|
+
}).strict();
|
|
17212
|
+
var RotationChecklistEntry = external_exports.object({
|
|
17213
|
+
provider: external_exports.string(),
|
|
17214
|
+
maskedToken: external_exports.string(),
|
|
17215
|
+
consolePath: external_exports.string(),
|
|
17216
|
+
occurrenceSpread: external_exports.number().int().positive()
|
|
17217
|
+
}).strict();
|
|
17218
|
+
var RemediationOption = external_exports.enum([
|
|
17219
|
+
"redact-rotation-checklist",
|
|
17220
|
+
"redact-only",
|
|
17221
|
+
"set-secret-redact",
|
|
17222
|
+
"leave"
|
|
17223
|
+
]);
|
|
17224
|
+
var RemediationEntrySource = external_exports.enum(["first-run", "pre-push", "secret-scan"]);
|
|
17225
|
+
var RemediationEntryContext = external_exports.object({
|
|
17226
|
+
entrySource: RemediationEntrySource
|
|
17227
|
+
}).strict();
|
|
17228
|
+
var RemediationOptionChoice = external_exports.object({
|
|
17229
|
+
id: RemediationOption,
|
|
17230
|
+
label: external_exports.string()
|
|
17231
|
+
});
|
|
17232
|
+
var BatchedRemediationDecision = external_exports.object({
|
|
17233
|
+
kind: external_exports.literal("decision"),
|
|
17234
|
+
entrySource: RemediationEntrySource,
|
|
17235
|
+
secretCount: external_exports.number().int().positive(),
|
|
17236
|
+
prompt: external_exports.string(),
|
|
17237
|
+
options: external_exports.tuple([
|
|
17238
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("redact-rotation-checklist") }),
|
|
17239
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("redact-only") }),
|
|
17240
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("set-secret-redact") }),
|
|
17241
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("leave") })
|
|
17242
|
+
])
|
|
17243
|
+
});
|
|
17244
|
+
var NoRemediationDecision = external_exports.object({
|
|
17245
|
+
kind: external_exports.literal("no-decision")
|
|
17246
|
+
});
|
|
17247
|
+
var BatchedRemediation = external_exports.discriminatedUnion("kind", [
|
|
17248
|
+
BatchedRemediationDecision,
|
|
17249
|
+
NoRemediationDecision
|
|
17250
|
+
]);
|
|
17251
|
+
|
|
17139
17252
|
// ../../packages/schema/src/zod/rule-test.ts
|
|
17140
17253
|
var TestRulesRequest = external_exports.object({
|
|
17141
17254
|
rules: external_exports.array(Rule).min(1).max(100),
|
|
@@ -17194,10 +17307,8 @@ var SeveritySummaryResponse = external_exports.object({
|
|
|
17194
17307
|
// All four severity levels are always present (count may be 0).
|
|
17195
17308
|
bySeverity: external_exports.array(SeveritySummaryItem)
|
|
17196
17309
|
}).meta({ id: "SeveritySummaryResponse" });
|
|
17197
|
-
var SECURITY_RANGES = ["7d", "30d", "3m", "6m"];
|
|
17198
|
-
var SecurityRange = external_exports.enum(SECURITY_RANGES).meta({ id: "SecurityRange" });
|
|
17199
17310
|
var SecurityRangeQuery = external_exports.object({
|
|
17200
|
-
range: external_exports.enum(
|
|
17311
|
+
range: external_exports.enum(TIME_RANGES).default(DEFAULT_TIME_RANGE)
|
|
17201
17312
|
});
|
|
17202
17313
|
var EnforcementActionKind = external_exports.enum(["blocked", "redacted", "warned"]).meta({ id: "EnforcementActionKind" });
|
|
17203
17314
|
var EnforcementAction = external_exports.object({
|
|
@@ -17207,7 +17318,7 @@ var EnforcementAction = external_exports.object({
|
|
|
17207
17318
|
delta: external_exports.number().int()
|
|
17208
17319
|
}).meta({ id: "EnforcementAction" });
|
|
17209
17320
|
var EnforcementActionsResponse = external_exports.object({
|
|
17210
|
-
range:
|
|
17321
|
+
range: TimeRange,
|
|
17211
17322
|
// Sum of actions[].count in the window.
|
|
17212
17323
|
total: external_exports.number().int().nonnegative(),
|
|
17213
17324
|
// One entry per kind, always all three present (count may be 0).
|
|
@@ -17222,7 +17333,7 @@ var FindingsTimeseriesPoint = external_exports.object({
|
|
|
17222
17333
|
medium: external_exports.number().int().nonnegative()
|
|
17223
17334
|
}).meta({ id: "FindingsTimeseriesPoint" });
|
|
17224
17335
|
var FindingsTimeseriesResponse = external_exports.object({
|
|
17225
|
-
range:
|
|
17336
|
+
range: TimeRange,
|
|
17226
17337
|
granularity: TimeseriesGranularity,
|
|
17227
17338
|
points: external_exports.array(FindingsTimeseriesPoint)
|
|
17228
17339
|
}).meta({ id: "FindingsTimeseriesResponse" });
|
|
@@ -17237,7 +17348,7 @@ var MttrTrendPoint = external_exports.object({
|
|
|
17237
17348
|
})
|
|
17238
17349
|
}).meta({ id: "MttrTrendPoint" });
|
|
17239
17350
|
var MttrTrendResponse = external_exports.object({
|
|
17240
|
-
range:
|
|
17351
|
+
range: TimeRange,
|
|
17241
17352
|
granularity: TimeseriesGranularity,
|
|
17242
17353
|
points: external_exports.array(MttrTrendPoint)
|
|
17243
17354
|
}).meta({ id: "MttrTrendResponse" });
|
|
@@ -17264,11 +17375,11 @@ var TopSource = external_exports.object({
|
|
|
17264
17375
|
findingsCount: external_exports.number().int().nonnegative()
|
|
17265
17376
|
}).meta({ id: "TopSource" });
|
|
17266
17377
|
var TopSourcesResponse = external_exports.object({
|
|
17267
|
-
range:
|
|
17378
|
+
range: TimeRange,
|
|
17268
17379
|
items: external_exports.array(TopSource)
|
|
17269
17380
|
}).meta({ id: "TopSourcesResponse" });
|
|
17270
17381
|
var TopSourcesQuery = external_exports.object({
|
|
17271
|
-
range: external_exports.enum(
|
|
17382
|
+
range: external_exports.enum(TIME_RANGES).default(DEFAULT_TIME_RANGE),
|
|
17272
17383
|
limit: external_exports.coerce.number().int().min(1).max(50).default(5),
|
|
17273
17384
|
// Omit for both kinds.
|
|
17274
17385
|
kind: external_exports.enum(SOURCE_KINDS).optional()
|
|
@@ -17281,7 +17392,7 @@ var ScanCoverageProvider = external_exports.object({
|
|
|
17281
17392
|
supported: external_exports.boolean()
|
|
17282
17393
|
}).meta({ id: "ScanCoverageProvider" });
|
|
17283
17394
|
var ScanCoverageResponse = external_exports.object({
|
|
17284
|
-
range:
|
|
17395
|
+
range: TimeRange,
|
|
17285
17396
|
providers: external_exports.array(ScanCoverageProvider)
|
|
17286
17397
|
}).meta({ id: "ScanCoverageResponse" });
|
|
17287
17398
|
var SubjectType = external_exports.enum(["repo", "user", "team", "policy", "share", "rule"]).meta({
|
|
@@ -17330,6 +17441,114 @@ var ApplyRecommendedActionResponse = external_exports.object({
|
|
|
17330
17441
|
var DismissRecommendedActionResponse = external_exports.object({ id: external_exports.string(), status: external_exports.literal("dismissed") }).meta({ id: "DismissRecommendedActionResponse" });
|
|
17331
17442
|
var RecommendedActionIdParam = external_exports.object({ id: external_exports.string() });
|
|
17332
17443
|
|
|
17444
|
+
// ../../packages/schema/src/zod/triage.ts
|
|
17445
|
+
var TriageHit = external_exports.object({
|
|
17446
|
+
ruleId: external_exports.string(),
|
|
17447
|
+
category: DetectionCategory,
|
|
17448
|
+
severity: Severity,
|
|
17449
|
+
maskedMatch: external_exports.string(),
|
|
17450
|
+
rawMatch: external_exports.string(),
|
|
17451
|
+
context: external_exports.string(),
|
|
17452
|
+
filePath: external_exports.string().optional(),
|
|
17453
|
+
confidence: external_exports.number().min(0).max(1),
|
|
17454
|
+
id: external_exports.string().optional(),
|
|
17455
|
+
valueFingerprint: external_exports.string().optional(),
|
|
17456
|
+
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
17457
|
+
});
|
|
17458
|
+
var TriagePolicy = BuiltinPolicyId;
|
|
17459
|
+
var TriageCategoryRec = external_exports.object({
|
|
17460
|
+
category: DetectionCategory,
|
|
17461
|
+
action: TriagePolicy,
|
|
17462
|
+
reasoning: external_exports.string(),
|
|
17463
|
+
genuineCount: external_exports.number().int().nonnegative(),
|
|
17464
|
+
fpCount: external_exports.number().int().nonnegative(),
|
|
17465
|
+
// TriageHit ids judged false-positive in this category. fpCount must equal
|
|
17466
|
+
// this array's length — enforced by the consumer, not this schema.
|
|
17467
|
+
fpIds: external_exports.array(external_exports.string())
|
|
17468
|
+
});
|
|
17469
|
+
var TriageRecommendation = external_exports.object({
|
|
17470
|
+
perCategory: external_exports.array(TriageCategoryRec),
|
|
17471
|
+
notes: external_exports.string()
|
|
17472
|
+
});
|
|
17473
|
+
|
|
17474
|
+
// ../../packages/schema/src/zod/setup-frame.ts
|
|
17475
|
+
var CalibrationCounts = external_exports.object({
|
|
17476
|
+
total: external_exports.number().int().nonnegative(),
|
|
17477
|
+
important: external_exports.number().int().nonnegative(),
|
|
17478
|
+
routine: external_exports.number().int().nonnegative()
|
|
17479
|
+
}).refine((c) => c.total === c.important + c.routine, {
|
|
17480
|
+
message: "total must equal important + routine",
|
|
17481
|
+
path: ["total"]
|
|
17482
|
+
});
|
|
17483
|
+
var FalsePositivePatternValue = external_exports.object({
|
|
17484
|
+
ruleId: external_exports.string(),
|
|
17485
|
+
category: DetectionCategory,
|
|
17486
|
+
valueFingerprint: external_exports.string(),
|
|
17487
|
+
keyVersion: external_exports.number().int().nonnegative()
|
|
17488
|
+
});
|
|
17489
|
+
var FalsePositivePatternGroup = external_exports.object({
|
|
17490
|
+
pattern: external_exports.string(),
|
|
17491
|
+
count: external_exports.number().int().nonnegative(),
|
|
17492
|
+
values: external_exports.array(FalsePositivePatternValue).min(1)
|
|
17493
|
+
});
|
|
17494
|
+
var CalibrationFindingKind = external_exports.object({
|
|
17495
|
+
category: DetectionCategory,
|
|
17496
|
+
count: external_exports.number().int().nonnegative(),
|
|
17497
|
+
egress: external_exports.boolean()
|
|
17498
|
+
});
|
|
17499
|
+
var CalibrationFrame = external_exports.object({
|
|
17500
|
+
counts: CalibrationCounts,
|
|
17501
|
+
routineCategories: external_exports.array(DetectionCategory),
|
|
17502
|
+
surfacedCategories: external_exports.array(DetectionCategory),
|
|
17503
|
+
findingKinds: external_exports.array(CalibrationFindingKind),
|
|
17504
|
+
posture: external_exports.record(DetectionCategory, BuiltinPolicyId),
|
|
17505
|
+
maskedFindings: external_exports.array(MaskedSecretFinding).optional(),
|
|
17506
|
+
falsePositivePatterns: external_exports.array(FalsePositivePatternGroup).optional()
|
|
17507
|
+
});
|
|
17508
|
+
var CalibrationPreviewCategory = TriageCategoryRec.pick({
|
|
17509
|
+
category: true,
|
|
17510
|
+
genuineCount: true,
|
|
17511
|
+
fpCount: true
|
|
17512
|
+
}).extend({
|
|
17513
|
+
egress: external_exports.boolean()
|
|
17514
|
+
});
|
|
17515
|
+
var CalibrationPreview = external_exports.object({
|
|
17516
|
+
categories: external_exports.array(CalibrationPreviewCategory),
|
|
17517
|
+
posture: external_exports.record(DetectionCategory, BuiltinPolicyId)
|
|
17518
|
+
});
|
|
17519
|
+
var CalibrationResult = external_exports.object({
|
|
17520
|
+
frame: CalibrationFrame,
|
|
17521
|
+
copy: external_exports.string()
|
|
17522
|
+
});
|
|
17523
|
+
var FirstRunCalibration = external_exports.enum(["scan", "floor"]);
|
|
17524
|
+
var SetupHandoffOption = external_exports.object({
|
|
17525
|
+
id: external_exports.enum(["enter-remediation", "open-dashboard", "not-now"]),
|
|
17526
|
+
label: external_exports.string()
|
|
17527
|
+
});
|
|
17528
|
+
var DashboardHandoffOptions = external_exports.tuple([
|
|
17529
|
+
SetupHandoffOption.extend({ id: external_exports.literal("open-dashboard") }),
|
|
17530
|
+
SetupHandoffOption.extend({ id: external_exports.literal("not-now") })
|
|
17531
|
+
]);
|
|
17532
|
+
var ComposedRemediationOptions = external_exports.tuple([
|
|
17533
|
+
SetupHandoffOption.extend({ id: external_exports.literal("enter-remediation") }),
|
|
17534
|
+
SetupHandoffOption.extend({ id: external_exports.literal("open-dashboard") }),
|
|
17535
|
+
SetupHandoffOption.extend({ id: external_exports.literal("not-now") })
|
|
17536
|
+
]);
|
|
17537
|
+
var SetupHandoffOffer = external_exports.object({
|
|
17538
|
+
worthALook: external_exports.number().int().nonnegative(),
|
|
17539
|
+
liveKeys: external_exports.number().int().nonnegative().optional(),
|
|
17540
|
+
options: external_exports.union([DashboardHandoffOptions, ComposedRemediationOptions])
|
|
17541
|
+
}).refine(
|
|
17542
|
+
(o) => o.options.some((opt) => opt.id === "enter-remediation") === (o.liveKeys ?? 0) > 0,
|
|
17543
|
+
{
|
|
17544
|
+
message: "the chain-entry option is present exactly when liveKeys > 0",
|
|
17545
|
+
path: ["options"]
|
|
17546
|
+
}
|
|
17547
|
+
).refine((o) => (o.liveKeys ?? 0) <= o.worthALook, {
|
|
17548
|
+
message: "liveKeys is a subset of worthALook and cannot exceed it",
|
|
17549
|
+
path: ["liveKeys"]
|
|
17550
|
+
});
|
|
17551
|
+
|
|
17333
17552
|
// ../../packages/schema/src/zod/shares.ts
|
|
17334
17553
|
var DestinationKind = external_exports.enum(["provider", "internal", "ip"]).meta({ id: "DestinationKind" });
|
|
17335
17554
|
var Transport = external_exports.enum(["https", "http", "sftp", "grpc", "smtp"]).meta({ id: "Transport" });
|
|
@@ -17515,36 +17734,6 @@ function reviewSeverityRank(reasons) {
|
|
|
17515
17734
|
return Math.min(...reasons.map((r) => REVIEW_SEVERITY_RANK[r]));
|
|
17516
17735
|
}
|
|
17517
17736
|
|
|
17518
|
-
// ../../packages/schema/src/zod/triage.ts
|
|
17519
|
-
var TriageHit = external_exports.object({
|
|
17520
|
-
ruleId: external_exports.string(),
|
|
17521
|
-
category: DetectionCategory,
|
|
17522
|
-
severity: Severity,
|
|
17523
|
-
maskedMatch: external_exports.string(),
|
|
17524
|
-
rawMatch: external_exports.string(),
|
|
17525
|
-
context: external_exports.string(),
|
|
17526
|
-
filePath: external_exports.string().optional(),
|
|
17527
|
-
confidence: external_exports.number().min(0).max(1),
|
|
17528
|
-
id: external_exports.string().optional(),
|
|
17529
|
-
valueFingerprint: external_exports.string().optional(),
|
|
17530
|
-
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
17531
|
-
});
|
|
17532
|
-
var TriagePolicy = BuiltinPolicyId;
|
|
17533
|
-
var TriageCategoryRec = external_exports.object({
|
|
17534
|
-
category: DetectionCategory,
|
|
17535
|
-
action: TriagePolicy,
|
|
17536
|
-
reasoning: external_exports.string(),
|
|
17537
|
-
genuineCount: external_exports.number().int().nonnegative(),
|
|
17538
|
-
fpCount: external_exports.number().int().nonnegative(),
|
|
17539
|
-
// TriageHit ids judged false-positive in this category. fpCount must equal
|
|
17540
|
-
// this array's length — enforced by the consumer, not this schema.
|
|
17541
|
-
fpIds: external_exports.array(external_exports.string())
|
|
17542
|
-
});
|
|
17543
|
-
var TriageRecommendation = external_exports.object({
|
|
17544
|
-
perCategory: external_exports.array(TriageCategoryRec),
|
|
17545
|
-
notes: external_exports.string()
|
|
17546
|
-
});
|
|
17547
|
-
|
|
17548
17737
|
// ../../packages/persistence/src/internal/sql-text.ts
|
|
17549
17738
|
function escapeLikePattern(s) {
|
|
17550
17739
|
return s.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
@@ -18118,6 +18307,10 @@ var TIMELINE_COLUMNS = `
|
|
|
18118
18307
|
json_extract(attributes, '$.internal') AS internal,
|
|
18119
18308
|
json_extract(attributes, '$.flagged') AS flagged`;
|
|
18120
18309
|
var SESSION_ROOT = `event_type = 'session'`;
|
|
18310
|
+
var HAS_ACTIVITY = `EXISTS (
|
|
18311
|
+
SELECT 1 FROM audit_events c
|
|
18312
|
+
WHERE c.root_session_id = audit_events.id
|
|
18313
|
+
AND c.event_type NOT IN ('hook', 'config_scan'))`;
|
|
18121
18314
|
var SqliteActivityRepository = class {
|
|
18122
18315
|
constructor(db, now = () => Date.now()) {
|
|
18123
18316
|
this.db = db;
|
|
@@ -18131,7 +18324,8 @@ var SqliteActivityRepository = class {
|
|
|
18131
18324
|
const sessionsToday = countScalar(
|
|
18132
18325
|
this.db,
|
|
18133
18326
|
`SELECT count(*) AS n FROM audit_events
|
|
18134
|
-
WHERE ${SESSION_ROOT} AND started_at >= ? AND started_at <
|
|
18327
|
+
WHERE ${SESSION_ROOT} AND started_at >= ? AND started_at < ?
|
|
18328
|
+
AND ${HAS_ACTIVITY}`,
|
|
18135
18329
|
[startMs, endMs]
|
|
18136
18330
|
);
|
|
18137
18331
|
const liveThreshold = this.now() - LIVE_ACTIVITY_WINDOW_MS;
|
|
@@ -18203,6 +18397,13 @@ var SqliteActivityRepository = class {
|
|
|
18203
18397
|
);
|
|
18204
18398
|
params.push(pattern, pattern, pattern, pattern, pattern, pattern);
|
|
18205
18399
|
}
|
|
18400
|
+
const emptyCount = countScalar(
|
|
18401
|
+
this.db,
|
|
18402
|
+
`SELECT count(*) AS n FROM audit_events
|
|
18403
|
+
WHERE ${[...conditions, `NOT ${HAS_ACTIVITY}`].join(" AND ")}`,
|
|
18404
|
+
params
|
|
18405
|
+
);
|
|
18406
|
+
if (query.excludeEmpty) conditions.push(HAS_ACTIVITY);
|
|
18206
18407
|
if (cursor) {
|
|
18207
18408
|
conditions.push("(started_at < ? OR (started_at = ? AND id < ?))");
|
|
18208
18409
|
params.push(cursor.startedAtMs, cursor.startedAtMs, cursor.id);
|
|
@@ -18239,7 +18440,7 @@ var SqliteActivityRepository = class {
|
|
|
18239
18440
|
);
|
|
18240
18441
|
const last = page[page.length - 1];
|
|
18241
18442
|
const nextCursor = hasMore && last ? encodeCursor({ startedAtMs: last.started_at, id: last.id }) : null;
|
|
18242
|
-
return Promise.resolve({ items, nextCursor });
|
|
18443
|
+
return Promise.resolve({ items, nextCursor, emptyCount });
|
|
18243
18444
|
}
|
|
18244
18445
|
getSession(sessionId) {
|
|
18245
18446
|
const rootRow = getRow(
|
|
@@ -19545,9 +19746,43 @@ var SqliteFindingsRepository = class {
|
|
|
19545
19746
|
}))
|
|
19546
19747
|
);
|
|
19547
19748
|
}
|
|
19749
|
+
/** Live-enforced findings recorded for one session — a bare COUNT over the
|
|
19750
|
+
* session-stamped events (served by idx_events_session_id), so the Activity
|
|
19751
|
+
* page can label its findings link without the grouped pipeline. */
|
|
19752
|
+
sessionFindingsCount(sessionId) {
|
|
19753
|
+
if (!sessionId) return Promise.resolve(0);
|
|
19754
|
+
return Promise.resolve(
|
|
19755
|
+
countScalar(
|
|
19756
|
+
this.db,
|
|
19757
|
+
`SELECT count(*) AS n FROM findings f
|
|
19758
|
+
JOIN events e ON e.id = f.event_id
|
|
19759
|
+
WHERE json_extract(e.metadata, '$.sessionId') = :sessionId`,
|
|
19760
|
+
{ sessionId }
|
|
19761
|
+
)
|
|
19762
|
+
);
|
|
19763
|
+
}
|
|
19764
|
+
/** Per-rule transcript firing tally for one session — reads the OTHER finding
|
|
19765
|
+
* store (inspection_findings, keyed to audit_events): every detection the
|
|
19766
|
+
* transcript pass recorded, counted per firing rather than per unique value.
|
|
19767
|
+
* Rides on session-scoped grouped responses so the findings view can
|
|
19768
|
+
* reconcile the Activity page's tally with the deduped groups it lists. */
|
|
19769
|
+
sessionFirings(sessionId) {
|
|
19770
|
+
return Object.fromEntries(
|
|
19771
|
+
countBy(
|
|
19772
|
+
this.db,
|
|
19773
|
+
`SELECT d.rule_id AS k, count(*) AS n
|
|
19774
|
+
FROM inspection_findings f
|
|
19775
|
+
JOIN audit_events e ON e.id = f.audit_event_id
|
|
19776
|
+
JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
19777
|
+
WHERE e.root_session_id = :sessionId
|
|
19778
|
+
GROUP BY d.rule_id`,
|
|
19779
|
+
{ sessionId }
|
|
19780
|
+
)
|
|
19781
|
+
);
|
|
19782
|
+
}
|
|
19548
19783
|
/**
|
|
19549
|
-
* Grouped findings for the dashboard — joins findings⋈events (repo/file
|
|
19550
|
-
* from event metadata), groups by ruleId, computes per-filter-excluded facets,
|
|
19784
|
+
* Grouped findings for the dashboard — joins findings⋈events (repo/file/
|
|
19785
|
+
* toolName from event metadata), groups by ruleId, computes per-filter-excluded facets,
|
|
19551
19786
|
* applies the requested filters, and sorts by severity then recency. Filtering
|
|
19552
19787
|
* and faceting run in JS via the shared @akasecurity/schema helpers. `totals`
|
|
19553
19788
|
* reflect the full filtered set; `items` is the requested
|
|
@@ -19564,11 +19799,16 @@ var SqliteFindingsRepository = class {
|
|
|
19564
19799
|
* rule is ever restated in SQL.
|
|
19565
19800
|
*/
|
|
19566
19801
|
listGroupedFindings(query) {
|
|
19567
|
-
const
|
|
19802
|
+
const sessionPredicate = query.sessionId ? `WHERE json_extract(e.metadata, '$.sessionId') = :sessionId` : "";
|
|
19803
|
+
const sessionParams = query.sessionId ? { sessionId: query.sessionId } : {};
|
|
19804
|
+
const aggregates = this.groupAggregates(query.q !== void 0 && query.q !== "", {
|
|
19805
|
+
predicate: sessionPredicate,
|
|
19806
|
+
params: sessionParams
|
|
19807
|
+
});
|
|
19568
19808
|
const rows = allRows(
|
|
19569
19809
|
this.db.prepare(
|
|
19570
19810
|
`SELECT id, rule_id, category, severity, masked_match, action_taken, confidence,
|
|
19571
|
-
occurred_at, source_tool, repo, file, kind, finding_key, latest_status
|
|
19811
|
+
occurred_at, source_tool, repo, file, tool_name, kind, finding_key, latest_status
|
|
19572
19812
|
FROM (
|
|
19573
19813
|
SELECT f.id AS id, f.rule_id AS rule_id, f.category AS category,
|
|
19574
19814
|
f.severity AS severity, f.masked_match AS masked_match,
|
|
@@ -19576,6 +19816,7 @@ var SqliteFindingsRepository = class {
|
|
|
19576
19816
|
e.occurred_at AS occurred_at, e.source_tool AS source_tool,
|
|
19577
19817
|
json_extract(e.metadata, '$.repo') AS repo,
|
|
19578
19818
|
json_extract(e.metadata, '$.filePath') AS file,
|
|
19819
|
+
json_extract(e.metadata, '$.toolName') AS tool_name,
|
|
19579
19820
|
e.kind AS kind, f.finding_key AS finding_key,
|
|
19580
19821
|
latest.status AS latest_status,
|
|
19581
19822
|
ROW_NUMBER() OVER (
|
|
@@ -19586,11 +19827,12 @@ var SqliteFindingsRepository = class {
|
|
|
19586
19827
|
JOIN events e ON e.id = f.event_id
|
|
19587
19828
|
LEFT JOIN ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
19588
19829
|
ON latest.finding_key = f.finding_key
|
|
19830
|
+
${sessionPredicate}
|
|
19589
19831
|
)
|
|
19590
19832
|
WHERE rn <= :cap
|
|
19591
19833
|
ORDER BY occurred_at DESC, id DESC`
|
|
19592
19834
|
),
|
|
19593
|
-
{ cap: PREVIEW_INSTANCES_PER_GROUP }
|
|
19835
|
+
{ cap: PREVIEW_INSTANCES_PER_GROUP, ...sessionParams }
|
|
19594
19836
|
);
|
|
19595
19837
|
const groupable = rows.map((r) => ({
|
|
19596
19838
|
id: r.id,
|
|
@@ -19604,6 +19846,7 @@ var SqliteFindingsRepository = class {
|
|
|
19604
19846
|
sourceTool: r.source_tool,
|
|
19605
19847
|
repo: r.repo ?? "",
|
|
19606
19848
|
file: r.file ?? "",
|
|
19849
|
+
...r.tool_name === null ? {} : { toolName: r.tool_name },
|
|
19607
19850
|
status: deriveInstanceStatus(r)
|
|
19608
19851
|
}));
|
|
19609
19852
|
const allGroups = buildFindingGroups(groupable, { aggregates });
|
|
@@ -19622,7 +19865,13 @@ var SqliteFindingsRepository = class {
|
|
|
19622
19865
|
};
|
|
19623
19866
|
const limit = query.limit ?? DEFAULT_GROUPED_FINDINGS_LIMIT;
|
|
19624
19867
|
const items = sorted.slice(0, limit);
|
|
19625
|
-
return Promise.resolve({
|
|
19868
|
+
return Promise.resolve({
|
|
19869
|
+
totals,
|
|
19870
|
+
facets,
|
|
19871
|
+
items,
|
|
19872
|
+
nextCursor: null,
|
|
19873
|
+
...query.sessionId ? { sessionFirings: this.sessionFirings(query.sessionId) } : {}
|
|
19874
|
+
});
|
|
19626
19875
|
}
|
|
19627
19876
|
/**
|
|
19628
19877
|
* One row per rule_id, folding EVERY instance of the group into the values
|
|
@@ -19646,9 +19895,10 @@ var SqliteFindingsRepository = class {
|
|
|
19646
19895
|
* would silently lose, so it is fetched only when the request actually
|
|
19647
19896
|
* carries a `q`.
|
|
19648
19897
|
*/
|
|
19649
|
-
groupAggregates(withSearchText) {
|
|
19898
|
+
groupAggregates(withSearchText, scope) {
|
|
19650
19899
|
const searchTextColumns = withSearchText ? `, group_concat(DISTINCT json_extract(e.metadata, '$.repo')) AS repos,
|
|
19651
|
-
group_concat(DISTINCT json_extract(e.metadata, '$.filePath')) AS files
|
|
19900
|
+
group_concat(DISTINCT json_extract(e.metadata, '$.filePath')) AS files,
|
|
19901
|
+
group_concat(DISTINCT 'via ' || json_extract(e.metadata, '$.toolName')) AS tool_names` : `, NULL AS repos, NULL AS files, NULL AS tool_names`;
|
|
19652
19902
|
const rows = this.db.prepare(
|
|
19653
19903
|
`SELECT f.rule_id AS rule_id,
|
|
19654
19904
|
count(*) AS instance_count,
|
|
@@ -19665,8 +19915,9 @@ var SqliteFindingsRepository = class {
|
|
|
19665
19915
|
JOIN events e ON e.id = f.event_id
|
|
19666
19916
|
LEFT JOIN ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
19667
19917
|
ON latest.finding_key = f.finding_key
|
|
19918
|
+
${scope.predicate}
|
|
19668
19919
|
GROUP BY f.rule_id`
|
|
19669
|
-
).all();
|
|
19920
|
+
).all(scope.params);
|
|
19670
19921
|
return new Map(
|
|
19671
19922
|
rows.map((r) => [
|
|
19672
19923
|
r.rule_id,
|
|
@@ -19690,7 +19941,9 @@ var SqliteFindingsRepository = class {
|
|
|
19690
19941
|
// Left undefined (not '') when unfetched, so buildFindingGroups can
|
|
19691
19942
|
// tell "no q this request" from "a group with no repo/file at all"
|
|
19692
19943
|
// and skip priming a haystack nothing will read.
|
|
19693
|
-
...withSearchText ? {
|
|
19944
|
+
...withSearchText ? {
|
|
19945
|
+
searchText: [r.repos ?? "", r.files ?? "", r.tool_names ?? ""].filter((s) => s !== "").join(" ")
|
|
19946
|
+
} : {}
|
|
19694
19947
|
}
|
|
19695
19948
|
])
|
|
19696
19949
|
);
|
|
@@ -21426,7 +21679,6 @@ var SqliteScanLedgerRepository = class {
|
|
|
21426
21679
|
// ../../packages/persistence/src/repositories/security.ts
|
|
21427
21680
|
var DAY_MS4 = 864e5;
|
|
21428
21681
|
var SEVERITIES = ["critical", "high", "medium", "low"];
|
|
21429
|
-
var RANGE_DAYS = { "7d": 7, "30d": 30, "3m": 90, "6m": 180 };
|
|
21430
21682
|
var ACTION_TO_KIND = {
|
|
21431
21683
|
block: "blocked",
|
|
21432
21684
|
redact: "redacted",
|
|
@@ -21441,8 +21693,14 @@ var SCAN_COVERAGE = [
|
|
|
21441
21693
|
{ provider: "copilot", coverage: 0, supported: false },
|
|
21442
21694
|
{ provider: "api", coverage: 0, supported: false }
|
|
21443
21695
|
];
|
|
21696
|
+
var GRANULARITY = {
|
|
21697
|
+
"7d": "day",
|
|
21698
|
+
"30d": "day",
|
|
21699
|
+
"3m": "week",
|
|
21700
|
+
"6m": "week"
|
|
21701
|
+
};
|
|
21444
21702
|
function granularityFor(range) {
|
|
21445
|
-
return range
|
|
21703
|
+
return GRANULARITY[range];
|
|
21446
21704
|
}
|
|
21447
21705
|
function startOfUtcDay2(ms) {
|
|
21448
21706
|
return Math.floor(ms / DAY_MS4) * DAY_MS4;
|
|
@@ -22660,21 +22918,28 @@ import { readdirSync, readFileSync as readFileSync4, realpathSync, statSync as s
|
|
|
22660
22918
|
import { homedir as homedir2 } from "os";
|
|
22661
22919
|
import { basename as basename2, join as join7 } from "path";
|
|
22662
22920
|
|
|
22921
|
+
// ../../packages/detections/src/escape-regexp.ts
|
|
22922
|
+
function escapeRegExp(value) {
|
|
22923
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22924
|
+
}
|
|
22925
|
+
|
|
22926
|
+
// ../../packages/detections/src/matchers/limits.ts
|
|
22927
|
+
var MAX_MATCHES_PER_RULE = 1e4;
|
|
22928
|
+
|
|
22663
22929
|
// ../../packages/detections/src/matchers/keyword.ts
|
|
22664
22930
|
var KeywordMatcher2 = class {
|
|
22665
22931
|
match(text, rule) {
|
|
22666
22932
|
if (rule.matcher.type !== "keyword") return [];
|
|
22667
22933
|
const { keywords, caseSensitive } = rule.matcher;
|
|
22668
|
-
const haystack = caseSensitive ? text : text.toLowerCase();
|
|
22669
22934
|
const spans = [];
|
|
22670
22935
|
for (const kw of keywords) {
|
|
22671
|
-
|
|
22672
|
-
|
|
22673
|
-
|
|
22674
|
-
|
|
22675
|
-
|
|
22676
|
-
spans.push({ start:
|
|
22677
|
-
|
|
22936
|
+
if (kw.length === 0) continue;
|
|
22937
|
+
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
22938
|
+
const re = new RegExp(escapeRegExp(kw), caseSensitive ? "gu" : "giu");
|
|
22939
|
+
let m;
|
|
22940
|
+
while ((m = re.exec(text)) !== null) {
|
|
22941
|
+
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
22942
|
+
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
22678
22943
|
}
|
|
22679
22944
|
}
|
|
22680
22945
|
return spans;
|
|
@@ -22682,7 +22947,6 @@ var KeywordMatcher2 = class {
|
|
|
22682
22947
|
};
|
|
22683
22948
|
|
|
22684
22949
|
// ../../packages/detections/src/matchers/regex.ts
|
|
22685
|
-
var MAX_MATCHES_PER_RULE = 1e4;
|
|
22686
22950
|
var RegexMatcher2 = class {
|
|
22687
22951
|
match(text, rule) {
|
|
22688
22952
|
if (rule.matcher.type !== "regex") return [];
|
|
@@ -22768,9 +23032,6 @@ function registerPack(pack) {
|
|
|
22768
23032
|
function getLoadedRules() {
|
|
22769
23033
|
return [...packs.values()].flatMap((p) => p.rules);
|
|
22770
23034
|
}
|
|
22771
|
-
function escapeRegExp(value) {
|
|
22772
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22773
|
-
}
|
|
22774
23035
|
function isCorroborated(candidate, candidates, text) {
|
|
22775
23036
|
const req = candidate.rule.requiresNearby;
|
|
22776
23037
|
if (!req) return true;
|
|
@@ -23552,7 +23813,6 @@ var db_table_name_default = {
|
|
|
23552
23813
|
"SELECT * FROM ",
|
|
23553
23814
|
"SELECT COUNT(*) FROM ",
|
|
23554
23815
|
"INSERT INTO ",
|
|
23555
|
-
"UPDATE ",
|
|
23556
23816
|
"DELETE FROM ",
|
|
23557
23817
|
"CREATE TABLE ",
|
|
23558
23818
|
"ALTER TABLE ",
|
|
@@ -25201,17 +25461,22 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
25201
25461
|
const fallback = DEFAULT_ACTIONS[category];
|
|
25202
25462
|
return fallback ?? "log";
|
|
25203
25463
|
}
|
|
25464
|
+
function actionForFinding(finding, excepted) {
|
|
25465
|
+
if (excepted?.has(finding)) return "allow";
|
|
25466
|
+
const action = resolveAction(finding.ruleId, finding.category);
|
|
25467
|
+
if (ENFORCEMENT_CEILING_ENABLED && policyMode === "warn" && (action === "block" || action === "redact")) {
|
|
25468
|
+
return "warn";
|
|
25469
|
+
}
|
|
25470
|
+
return action;
|
|
25471
|
+
}
|
|
25204
25472
|
function decide(findings, text, excepted) {
|
|
25205
25473
|
if (findings.length === 0) return { action: "log", text, findings: [] };
|
|
25206
|
-
const actionFor = (finding) =>
|
|
25474
|
+
const actionFor = (finding) => actionForFinding(finding, excepted);
|
|
25207
25475
|
let worst = "log";
|
|
25208
25476
|
for (const finding of findings) {
|
|
25209
25477
|
const action = actionFor(finding);
|
|
25210
25478
|
if (ACTION_PRIORITY.indexOf(action) < ACTION_PRIORITY.indexOf(worst)) worst = action;
|
|
25211
25479
|
}
|
|
25212
|
-
if (ENFORCEMENT_CEILING_ENABLED && policyMode === "warn" && (worst === "block" || worst === "redact")) {
|
|
25213
|
-
return { action: "warn", text, findings };
|
|
25214
|
-
}
|
|
25215
25480
|
if (worst === "block") return { action: "block", text: null, findings };
|
|
25216
25481
|
if (worst === "redact") {
|
|
25217
25482
|
const redactFindings = findings.filter((f) => actionFor(f) === "redact");
|
|
@@ -25284,8 +25549,8 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
25284
25549
|
if (!key) return references;
|
|
25285
25550
|
const seen = /* @__PURE__ */ new Set();
|
|
25286
25551
|
for (const finding of decision.findings) {
|
|
25287
|
-
const action =
|
|
25288
|
-
if (action !== "block" && action !== "redact"
|
|
25552
|
+
const action = actionForFinding(finding, excepted);
|
|
25553
|
+
if (action !== "block" && action !== "redact") continue;
|
|
25289
25554
|
const fp = fingerprintOf(key, finding, fpCache);
|
|
25290
25555
|
const pair = `${finding.ruleId}:${fp}`;
|
|
25291
25556
|
if (seen.has(pair)) continue;
|
|
@@ -25374,7 +25639,7 @@ function createPluginRuntime(gateway, settings, opts) {
|
|
|
25374
25639
|
severity: match.severity,
|
|
25375
25640
|
span: match.span,
|
|
25376
25641
|
maskedMatch,
|
|
25377
|
-
actionTaken:
|
|
25642
|
+
actionTaken: actionForFinding(match, excepted),
|
|
25378
25643
|
confidence: match.confidence,
|
|
25379
25644
|
...findingKey ? { findingKey } : {}
|
|
25380
25645
|
};
|
|
@@ -25917,7 +26182,8 @@ function baseMetadata(input) {
|
|
|
25917
26182
|
async function main() {
|
|
25918
26183
|
const input = parseJson(await readStdin());
|
|
25919
26184
|
if (!input) return;
|
|
25920
|
-
const
|
|
26185
|
+
const rawToolName = getString(input, "tool_name");
|
|
26186
|
+
const toolName = rawToolName ?? "tool";
|
|
25921
26187
|
let response = input.tool_response ?? input.tool_output;
|
|
25922
26188
|
let fields = scannableResponseFields(toolName, response);
|
|
25923
26189
|
if (fields.length === 0 && input.tool_output !== void 0 && response !== input.tool_output) {
|
|
@@ -25926,6 +26192,7 @@ async function main() {
|
|
|
25926
26192
|
}
|
|
25927
26193
|
if (fields.length === 0) return;
|
|
25928
26194
|
const metadata = baseMetadata(input) ?? {};
|
|
26195
|
+
if (rawToolName) metadata.toolName = rawToolName;
|
|
25929
26196
|
const rawToolInput = input.tool_input;
|
|
25930
26197
|
const filePath = typeof rawToolInput === "object" && rawToolInput !== null ? getString(rawToolInput, "file_path") : void 0;
|
|
25931
26198
|
if (filePath) metadata.filePath = filePath;
|