@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/onboard.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, flags2) {
|
|
@@ -16414,6 +16456,10 @@ var ListEventsResponse = external_exports.object({
|
|
|
16414
16456
|
items: external_exports.array(Event),
|
|
16415
16457
|
nextCursor: external_exports.string().nullable()
|
|
16416
16458
|
}).meta({ id: "ListEventsResponse" });
|
|
16459
|
+
var IngestResponse = external_exports.object({
|
|
16460
|
+
accepted: external_exports.number().int().nonnegative(),
|
|
16461
|
+
duplicates: external_exports.number().int().nonnegative()
|
|
16462
|
+
}).meta({ id: "IngestResponse" });
|
|
16417
16463
|
var ListFindingsQuery = external_exports.object({
|
|
16418
16464
|
cursor: external_exports.string().optional(),
|
|
16419
16465
|
limit: external_exports.coerce.number().int().min(1).max(LIST_QUERY_MAX_LIMIT).default(50),
|
|
@@ -16803,6 +16849,7 @@ function buildFindingGroups(rows, opts = {}) {
|
|
|
16803
16849
|
provider: toApiProvider(r.sourceTool),
|
|
16804
16850
|
repo: r.repo,
|
|
16805
16851
|
file: r.file,
|
|
16852
|
+
...r.toolName === void 0 ? {} : { toolName: r.toolName },
|
|
16806
16853
|
action: toApiAction(effectiveDbAction),
|
|
16807
16854
|
detectedAt: r.occurredAt,
|
|
16808
16855
|
confidence: r.confidence,
|
|
@@ -16875,6 +16922,7 @@ function buildHaystack(g, extra) {
|
|
|
16875
16922
|
g.id,
|
|
16876
16923
|
...g.instances.map((i) => i.repo),
|
|
16877
16924
|
...g.instances.map((i) => i.file),
|
|
16925
|
+
...g.instances.map((i) => i.toolName ? `via ${i.toolName}` : ""),
|
|
16878
16926
|
...g.instances.map((i) => i.id),
|
|
16879
16927
|
...extra === void 0 ? [] : [extra]
|
|
16880
16928
|
].join(" ").toLowerCase();
|
|
@@ -17141,6 +17189,71 @@ var ProjectFilesScan = external_exports.object({
|
|
|
17141
17189
|
scannedAt: external_exports.string()
|
|
17142
17190
|
});
|
|
17143
17191
|
|
|
17192
|
+
// ../../packages/schema/src/zod/ranges.ts
|
|
17193
|
+
var TIME_RANGES = ["7d", "30d", "3m", "6m"];
|
|
17194
|
+
var TimeRange = external_exports.enum(TIME_RANGES).meta({ id: "TimeRange" });
|
|
17195
|
+
var DEFAULT_TIME_RANGE = "7d";
|
|
17196
|
+
var RANGE_DAYS = {
|
|
17197
|
+
"7d": 7,
|
|
17198
|
+
"30d": 30,
|
|
17199
|
+
"3m": 90,
|
|
17200
|
+
"6m": 180
|
|
17201
|
+
};
|
|
17202
|
+
var TIME_RANGE_OR_DEFAULT = TimeRange.catch(DEFAULT_TIME_RANGE);
|
|
17203
|
+
|
|
17204
|
+
// ../../packages/schema/src/zod/remediation.ts
|
|
17205
|
+
var SecretFindingState = external_exports.enum(["still-valid", "unknown", "invalid"]);
|
|
17206
|
+
var MaskedFindingLocation = external_exports.object({
|
|
17207
|
+
filePath: external_exports.string(),
|
|
17208
|
+
span: Span.optional()
|
|
17209
|
+
}).strict();
|
|
17210
|
+
var MaskedSecretFinding = external_exports.object({
|
|
17211
|
+
provider: external_exports.string(),
|
|
17212
|
+
maskedToken: external_exports.string(),
|
|
17213
|
+
where: MaskedFindingLocation,
|
|
17214
|
+
state: SecretFindingState,
|
|
17215
|
+
observedAt: external_exports.iso.datetime().optional()
|
|
17216
|
+
}).strict();
|
|
17217
|
+
var RotationChecklistEntry = external_exports.object({
|
|
17218
|
+
provider: external_exports.string(),
|
|
17219
|
+
maskedToken: external_exports.string(),
|
|
17220
|
+
consolePath: external_exports.string(),
|
|
17221
|
+
occurrenceSpread: external_exports.number().int().positive()
|
|
17222
|
+
}).strict();
|
|
17223
|
+
var RemediationOption = external_exports.enum([
|
|
17224
|
+
"redact-rotation-checklist",
|
|
17225
|
+
"redact-only",
|
|
17226
|
+
"set-secret-redact",
|
|
17227
|
+
"leave"
|
|
17228
|
+
]);
|
|
17229
|
+
var RemediationEntrySource = external_exports.enum(["first-run", "pre-push", "secret-scan"]);
|
|
17230
|
+
var RemediationEntryContext = external_exports.object({
|
|
17231
|
+
entrySource: RemediationEntrySource
|
|
17232
|
+
}).strict();
|
|
17233
|
+
var RemediationOptionChoice = external_exports.object({
|
|
17234
|
+
id: RemediationOption,
|
|
17235
|
+
label: external_exports.string()
|
|
17236
|
+
});
|
|
17237
|
+
var BatchedRemediationDecision = external_exports.object({
|
|
17238
|
+
kind: external_exports.literal("decision"),
|
|
17239
|
+
entrySource: RemediationEntrySource,
|
|
17240
|
+
secretCount: external_exports.number().int().positive(),
|
|
17241
|
+
prompt: external_exports.string(),
|
|
17242
|
+
options: external_exports.tuple([
|
|
17243
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("redact-rotation-checklist") }),
|
|
17244
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("redact-only") }),
|
|
17245
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("set-secret-redact") }),
|
|
17246
|
+
RemediationOptionChoice.extend({ id: external_exports.literal("leave") })
|
|
17247
|
+
])
|
|
17248
|
+
});
|
|
17249
|
+
var NoRemediationDecision = external_exports.object({
|
|
17250
|
+
kind: external_exports.literal("no-decision")
|
|
17251
|
+
});
|
|
17252
|
+
var BatchedRemediation = external_exports.discriminatedUnion("kind", [
|
|
17253
|
+
BatchedRemediationDecision,
|
|
17254
|
+
NoRemediationDecision
|
|
17255
|
+
]);
|
|
17256
|
+
|
|
17144
17257
|
// ../../packages/schema/src/zod/rule-test.ts
|
|
17145
17258
|
var TestRulesRequest = external_exports.object({
|
|
17146
17259
|
rules: external_exports.array(Rule).min(1).max(100),
|
|
@@ -17199,10 +17312,8 @@ var SeveritySummaryResponse = external_exports.object({
|
|
|
17199
17312
|
// All four severity levels are always present (count may be 0).
|
|
17200
17313
|
bySeverity: external_exports.array(SeveritySummaryItem)
|
|
17201
17314
|
}).meta({ id: "SeveritySummaryResponse" });
|
|
17202
|
-
var SECURITY_RANGES = ["7d", "30d", "3m", "6m"];
|
|
17203
|
-
var SecurityRange = external_exports.enum(SECURITY_RANGES).meta({ id: "SecurityRange" });
|
|
17204
17315
|
var SecurityRangeQuery = external_exports.object({
|
|
17205
|
-
range: external_exports.enum(
|
|
17316
|
+
range: external_exports.enum(TIME_RANGES).default(DEFAULT_TIME_RANGE)
|
|
17206
17317
|
});
|
|
17207
17318
|
var EnforcementActionKind = external_exports.enum(["blocked", "redacted", "warned"]).meta({ id: "EnforcementActionKind" });
|
|
17208
17319
|
var EnforcementAction = external_exports.object({
|
|
@@ -17212,7 +17323,7 @@ var EnforcementAction = external_exports.object({
|
|
|
17212
17323
|
delta: external_exports.number().int()
|
|
17213
17324
|
}).meta({ id: "EnforcementAction" });
|
|
17214
17325
|
var EnforcementActionsResponse = external_exports.object({
|
|
17215
|
-
range:
|
|
17326
|
+
range: TimeRange,
|
|
17216
17327
|
// Sum of actions[].count in the window.
|
|
17217
17328
|
total: external_exports.number().int().nonnegative(),
|
|
17218
17329
|
// One entry per kind, always all three present (count may be 0).
|
|
@@ -17227,7 +17338,7 @@ var FindingsTimeseriesPoint = external_exports.object({
|
|
|
17227
17338
|
medium: external_exports.number().int().nonnegative()
|
|
17228
17339
|
}).meta({ id: "FindingsTimeseriesPoint" });
|
|
17229
17340
|
var FindingsTimeseriesResponse = external_exports.object({
|
|
17230
|
-
range:
|
|
17341
|
+
range: TimeRange,
|
|
17231
17342
|
granularity: TimeseriesGranularity,
|
|
17232
17343
|
points: external_exports.array(FindingsTimeseriesPoint)
|
|
17233
17344
|
}).meta({ id: "FindingsTimeseriesResponse" });
|
|
@@ -17242,7 +17353,7 @@ var MttrTrendPoint = external_exports.object({
|
|
|
17242
17353
|
})
|
|
17243
17354
|
}).meta({ id: "MttrTrendPoint" });
|
|
17244
17355
|
var MttrTrendResponse = external_exports.object({
|
|
17245
|
-
range:
|
|
17356
|
+
range: TimeRange,
|
|
17246
17357
|
granularity: TimeseriesGranularity,
|
|
17247
17358
|
points: external_exports.array(MttrTrendPoint)
|
|
17248
17359
|
}).meta({ id: "MttrTrendResponse" });
|
|
@@ -17269,11 +17380,11 @@ var TopSource = external_exports.object({
|
|
|
17269
17380
|
findingsCount: external_exports.number().int().nonnegative()
|
|
17270
17381
|
}).meta({ id: "TopSource" });
|
|
17271
17382
|
var TopSourcesResponse = external_exports.object({
|
|
17272
|
-
range:
|
|
17383
|
+
range: TimeRange,
|
|
17273
17384
|
items: external_exports.array(TopSource)
|
|
17274
17385
|
}).meta({ id: "TopSourcesResponse" });
|
|
17275
17386
|
var TopSourcesQuery = external_exports.object({
|
|
17276
|
-
range: external_exports.enum(
|
|
17387
|
+
range: external_exports.enum(TIME_RANGES).default(DEFAULT_TIME_RANGE),
|
|
17277
17388
|
limit: external_exports.coerce.number().int().min(1).max(50).default(5),
|
|
17278
17389
|
// Omit for both kinds.
|
|
17279
17390
|
kind: external_exports.enum(SOURCE_KINDS).optional()
|
|
@@ -17286,7 +17397,7 @@ var ScanCoverageProvider = external_exports.object({
|
|
|
17286
17397
|
supported: external_exports.boolean()
|
|
17287
17398
|
}).meta({ id: "ScanCoverageProvider" });
|
|
17288
17399
|
var ScanCoverageResponse = external_exports.object({
|
|
17289
|
-
range:
|
|
17400
|
+
range: TimeRange,
|
|
17290
17401
|
providers: external_exports.array(ScanCoverageProvider)
|
|
17291
17402
|
}).meta({ id: "ScanCoverageResponse" });
|
|
17292
17403
|
var SubjectType = external_exports.enum(["repo", "user", "team", "policy", "share", "rule"]).meta({
|
|
@@ -17335,6 +17446,114 @@ var ApplyRecommendedActionResponse = external_exports.object({
|
|
|
17335
17446
|
var DismissRecommendedActionResponse = external_exports.object({ id: external_exports.string(), status: external_exports.literal("dismissed") }).meta({ id: "DismissRecommendedActionResponse" });
|
|
17336
17447
|
var RecommendedActionIdParam = external_exports.object({ id: external_exports.string() });
|
|
17337
17448
|
|
|
17449
|
+
// ../../packages/schema/src/zod/triage.ts
|
|
17450
|
+
var TriageHit = external_exports.object({
|
|
17451
|
+
ruleId: external_exports.string(),
|
|
17452
|
+
category: DetectionCategory,
|
|
17453
|
+
severity: Severity,
|
|
17454
|
+
maskedMatch: external_exports.string(),
|
|
17455
|
+
rawMatch: external_exports.string(),
|
|
17456
|
+
context: external_exports.string(),
|
|
17457
|
+
filePath: external_exports.string().optional(),
|
|
17458
|
+
confidence: external_exports.number().min(0).max(1),
|
|
17459
|
+
id: external_exports.string().optional(),
|
|
17460
|
+
valueFingerprint: external_exports.string().optional(),
|
|
17461
|
+
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
17462
|
+
});
|
|
17463
|
+
var TriagePolicy = BuiltinPolicyId;
|
|
17464
|
+
var TriageCategoryRec = external_exports.object({
|
|
17465
|
+
category: DetectionCategory,
|
|
17466
|
+
action: TriagePolicy,
|
|
17467
|
+
reasoning: external_exports.string(),
|
|
17468
|
+
genuineCount: external_exports.number().int().nonnegative(),
|
|
17469
|
+
fpCount: external_exports.number().int().nonnegative(),
|
|
17470
|
+
// TriageHit ids judged false-positive in this category. fpCount must equal
|
|
17471
|
+
// this array's length — enforced by the consumer, not this schema.
|
|
17472
|
+
fpIds: external_exports.array(external_exports.string())
|
|
17473
|
+
});
|
|
17474
|
+
var TriageRecommendation = external_exports.object({
|
|
17475
|
+
perCategory: external_exports.array(TriageCategoryRec),
|
|
17476
|
+
notes: external_exports.string()
|
|
17477
|
+
});
|
|
17478
|
+
|
|
17479
|
+
// ../../packages/schema/src/zod/setup-frame.ts
|
|
17480
|
+
var CalibrationCounts = external_exports.object({
|
|
17481
|
+
total: external_exports.number().int().nonnegative(),
|
|
17482
|
+
important: external_exports.number().int().nonnegative(),
|
|
17483
|
+
routine: external_exports.number().int().nonnegative()
|
|
17484
|
+
}).refine((c) => c.total === c.important + c.routine, {
|
|
17485
|
+
message: "total must equal important + routine",
|
|
17486
|
+
path: ["total"]
|
|
17487
|
+
});
|
|
17488
|
+
var FalsePositivePatternValue = external_exports.object({
|
|
17489
|
+
ruleId: external_exports.string(),
|
|
17490
|
+
category: DetectionCategory,
|
|
17491
|
+
valueFingerprint: external_exports.string(),
|
|
17492
|
+
keyVersion: external_exports.number().int().nonnegative()
|
|
17493
|
+
});
|
|
17494
|
+
var FalsePositivePatternGroup = external_exports.object({
|
|
17495
|
+
pattern: external_exports.string(),
|
|
17496
|
+
count: external_exports.number().int().nonnegative(),
|
|
17497
|
+
values: external_exports.array(FalsePositivePatternValue).min(1)
|
|
17498
|
+
});
|
|
17499
|
+
var CalibrationFindingKind = external_exports.object({
|
|
17500
|
+
category: DetectionCategory,
|
|
17501
|
+
count: external_exports.number().int().nonnegative(),
|
|
17502
|
+
egress: external_exports.boolean()
|
|
17503
|
+
});
|
|
17504
|
+
var CalibrationFrame = external_exports.object({
|
|
17505
|
+
counts: CalibrationCounts,
|
|
17506
|
+
routineCategories: external_exports.array(DetectionCategory),
|
|
17507
|
+
surfacedCategories: external_exports.array(DetectionCategory),
|
|
17508
|
+
findingKinds: external_exports.array(CalibrationFindingKind),
|
|
17509
|
+
posture: external_exports.record(DetectionCategory, BuiltinPolicyId),
|
|
17510
|
+
maskedFindings: external_exports.array(MaskedSecretFinding).optional(),
|
|
17511
|
+
falsePositivePatterns: external_exports.array(FalsePositivePatternGroup).optional()
|
|
17512
|
+
});
|
|
17513
|
+
var CalibrationPreviewCategory = TriageCategoryRec.pick({
|
|
17514
|
+
category: true,
|
|
17515
|
+
genuineCount: true,
|
|
17516
|
+
fpCount: true
|
|
17517
|
+
}).extend({
|
|
17518
|
+
egress: external_exports.boolean()
|
|
17519
|
+
});
|
|
17520
|
+
var CalibrationPreview = external_exports.object({
|
|
17521
|
+
categories: external_exports.array(CalibrationPreviewCategory),
|
|
17522
|
+
posture: external_exports.record(DetectionCategory, BuiltinPolicyId)
|
|
17523
|
+
});
|
|
17524
|
+
var CalibrationResult = external_exports.object({
|
|
17525
|
+
frame: CalibrationFrame,
|
|
17526
|
+
copy: external_exports.string()
|
|
17527
|
+
});
|
|
17528
|
+
var FirstRunCalibration = external_exports.enum(["scan", "floor"]);
|
|
17529
|
+
var SetupHandoffOption = external_exports.object({
|
|
17530
|
+
id: external_exports.enum(["enter-remediation", "open-dashboard", "not-now"]),
|
|
17531
|
+
label: external_exports.string()
|
|
17532
|
+
});
|
|
17533
|
+
var DashboardHandoffOptions = external_exports.tuple([
|
|
17534
|
+
SetupHandoffOption.extend({ id: external_exports.literal("open-dashboard") }),
|
|
17535
|
+
SetupHandoffOption.extend({ id: external_exports.literal("not-now") })
|
|
17536
|
+
]);
|
|
17537
|
+
var ComposedRemediationOptions = external_exports.tuple([
|
|
17538
|
+
SetupHandoffOption.extend({ id: external_exports.literal("enter-remediation") }),
|
|
17539
|
+
SetupHandoffOption.extend({ id: external_exports.literal("open-dashboard") }),
|
|
17540
|
+
SetupHandoffOption.extend({ id: external_exports.literal("not-now") })
|
|
17541
|
+
]);
|
|
17542
|
+
var SetupHandoffOffer = external_exports.object({
|
|
17543
|
+
worthALook: external_exports.number().int().nonnegative(),
|
|
17544
|
+
liveKeys: external_exports.number().int().nonnegative().optional(),
|
|
17545
|
+
options: external_exports.union([DashboardHandoffOptions, ComposedRemediationOptions])
|
|
17546
|
+
}).refine(
|
|
17547
|
+
(o) => o.options.some((opt) => opt.id === "enter-remediation") === (o.liveKeys ?? 0) > 0,
|
|
17548
|
+
{
|
|
17549
|
+
message: "the chain-entry option is present exactly when liveKeys > 0",
|
|
17550
|
+
path: ["options"]
|
|
17551
|
+
}
|
|
17552
|
+
).refine((o) => (o.liveKeys ?? 0) <= o.worthALook, {
|
|
17553
|
+
message: "liveKeys is a subset of worthALook and cannot exceed it",
|
|
17554
|
+
path: ["liveKeys"]
|
|
17555
|
+
});
|
|
17556
|
+
|
|
17338
17557
|
// ../../packages/schema/src/zod/shares.ts
|
|
17339
17558
|
var DestinationKind = external_exports.enum(["provider", "internal", "ip"]).meta({ id: "DestinationKind" });
|
|
17340
17559
|
var Transport = external_exports.enum(["https", "http", "sftp", "grpc", "smtp"]).meta({ id: "Transport" });
|
|
@@ -17520,36 +17739,6 @@ function reviewSeverityRank(reasons) {
|
|
|
17520
17739
|
return Math.min(...reasons.map((r) => REVIEW_SEVERITY_RANK[r]));
|
|
17521
17740
|
}
|
|
17522
17741
|
|
|
17523
|
-
// ../../packages/schema/src/zod/triage.ts
|
|
17524
|
-
var TriageHit = external_exports.object({
|
|
17525
|
-
ruleId: external_exports.string(),
|
|
17526
|
-
category: DetectionCategory,
|
|
17527
|
-
severity: Severity,
|
|
17528
|
-
maskedMatch: external_exports.string(),
|
|
17529
|
-
rawMatch: external_exports.string(),
|
|
17530
|
-
context: external_exports.string(),
|
|
17531
|
-
filePath: external_exports.string().optional(),
|
|
17532
|
-
confidence: external_exports.number().min(0).max(1),
|
|
17533
|
-
id: external_exports.string().optional(),
|
|
17534
|
-
valueFingerprint: external_exports.string().optional(),
|
|
17535
|
-
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
17536
|
-
});
|
|
17537
|
-
var TriagePolicy = BuiltinPolicyId;
|
|
17538
|
-
var TriageCategoryRec = external_exports.object({
|
|
17539
|
-
category: DetectionCategory,
|
|
17540
|
-
action: TriagePolicy,
|
|
17541
|
-
reasoning: external_exports.string(),
|
|
17542
|
-
genuineCount: external_exports.number().int().nonnegative(),
|
|
17543
|
-
fpCount: external_exports.number().int().nonnegative(),
|
|
17544
|
-
// TriageHit ids judged false-positive in this category. fpCount must equal
|
|
17545
|
-
// this array's length — enforced by the consumer, not this schema.
|
|
17546
|
-
fpIds: external_exports.array(external_exports.string())
|
|
17547
|
-
});
|
|
17548
|
-
var TriageRecommendation = external_exports.object({
|
|
17549
|
-
perCategory: external_exports.array(TriageCategoryRec),
|
|
17550
|
-
notes: external_exports.string()
|
|
17551
|
-
});
|
|
17552
|
-
|
|
17553
17742
|
// ../../packages/persistence/src/internal/sql-text.ts
|
|
17554
17743
|
function escapeLikePattern(s) {
|
|
17555
17744
|
return s.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
@@ -17634,9 +17823,9 @@ function schemaObjectExists(db, kind, name) {
|
|
|
17634
17823
|
function indexExists(db, name) {
|
|
17635
17824
|
return schemaObjectExists(db, "index", name);
|
|
17636
17825
|
}
|
|
17637
|
-
function columnNames(db,
|
|
17826
|
+
function columnNames(db, table2, opts) {
|
|
17638
17827
|
const pragma = opts?.includeGenerated ? "table_xinfo" : "table_info";
|
|
17639
|
-
const columns = db.prepare(`PRAGMA ${pragma}(${
|
|
17828
|
+
const columns = db.prepare(`PRAGMA ${pragma}(${table2})`).all();
|
|
17640
17829
|
return columns.map((c) => c.name);
|
|
17641
17830
|
}
|
|
17642
17831
|
function evidenceExists(db, object2) {
|
|
@@ -17804,12 +17993,12 @@ function reconcileSourceProjectIds(db) {
|
|
|
17804
17993
|
const repointCallSite = db.prepare(
|
|
17805
17994
|
"UPDATE share_call_site SET project_id = ? WHERE project_id = ?"
|
|
17806
17995
|
);
|
|
17807
|
-
const pathTables = ["project_file", "file_access_override"].map((
|
|
17996
|
+
const pathTables = ["project_file", "file_access_override"].map((table2) => ({
|
|
17808
17997
|
dropCollisions: db.prepare(
|
|
17809
|
-
`DELETE FROM ${
|
|
17810
|
-
AND path IN (SELECT path FROM ${
|
|
17998
|
+
`DELETE FROM ${table2} WHERE project_id = ?
|
|
17999
|
+
AND path IN (SELECT path FROM ${table2} WHERE project_id = ?)`
|
|
17811
18000
|
),
|
|
17812
|
-
repoint: db.prepare(`UPDATE ${
|
|
18001
|
+
repoint: db.prepare(`UPDATE ${table2} SET project_id = ? WHERE project_id = ?`)
|
|
17813
18002
|
}));
|
|
17814
18003
|
const deleteLegacy = db.prepare("DELETE FROM source_project WHERE id = ?");
|
|
17815
18004
|
withTransaction(
|
|
@@ -17843,9 +18032,9 @@ function isForeignSqliteLineage(db) {
|
|
|
17843
18032
|
if (schemaObjectExists(db, "table", "tenants")) return true;
|
|
17844
18033
|
return columnNames(db, "events").includes("tenant_id");
|
|
17845
18034
|
}
|
|
17846
|
-
function ensureSyncedAtColumn(db,
|
|
17847
|
-
if (!columnNames(db,
|
|
17848
|
-
db.exec(`ALTER TABLE ${
|
|
18035
|
+
function ensureSyncedAtColumn(db, table2) {
|
|
18036
|
+
if (!columnNames(db, table2).includes("synced_at")) {
|
|
18037
|
+
db.exec(`ALTER TABLE ${table2} ADD COLUMN synced_at integer`);
|
|
17849
18038
|
}
|
|
17850
18039
|
}
|
|
17851
18040
|
function ensureScanLedgerTable(db) {
|
|
@@ -18112,6 +18301,10 @@ var TIMELINE_COLUMNS = `
|
|
|
18112
18301
|
json_extract(attributes, '$.internal') AS internal,
|
|
18113
18302
|
json_extract(attributes, '$.flagged') AS flagged`;
|
|
18114
18303
|
var SESSION_ROOT = `event_type = 'session'`;
|
|
18304
|
+
var HAS_ACTIVITY = `EXISTS (
|
|
18305
|
+
SELECT 1 FROM audit_events c
|
|
18306
|
+
WHERE c.root_session_id = audit_events.id
|
|
18307
|
+
AND c.event_type NOT IN ('hook', 'config_scan'))`;
|
|
18115
18308
|
var SqliteActivityRepository = class {
|
|
18116
18309
|
constructor(db, now = () => Date.now()) {
|
|
18117
18310
|
this.db = db;
|
|
@@ -18125,7 +18318,8 @@ var SqliteActivityRepository = class {
|
|
|
18125
18318
|
const sessionsToday = countScalar(
|
|
18126
18319
|
this.db,
|
|
18127
18320
|
`SELECT count(*) AS n FROM audit_events
|
|
18128
|
-
WHERE ${SESSION_ROOT} AND started_at >= ? AND started_at <
|
|
18321
|
+
WHERE ${SESSION_ROOT} AND started_at >= ? AND started_at < ?
|
|
18322
|
+
AND ${HAS_ACTIVITY}`,
|
|
18129
18323
|
[startMs, endMs]
|
|
18130
18324
|
);
|
|
18131
18325
|
const liveThreshold = this.now() - LIVE_ACTIVITY_WINDOW_MS;
|
|
@@ -18197,6 +18391,13 @@ var SqliteActivityRepository = class {
|
|
|
18197
18391
|
);
|
|
18198
18392
|
params.push(pattern, pattern, pattern, pattern, pattern, pattern);
|
|
18199
18393
|
}
|
|
18394
|
+
const emptyCount = countScalar(
|
|
18395
|
+
this.db,
|
|
18396
|
+
`SELECT count(*) AS n FROM audit_events
|
|
18397
|
+
WHERE ${[...conditions, `NOT ${HAS_ACTIVITY}`].join(" AND ")}`,
|
|
18398
|
+
params
|
|
18399
|
+
);
|
|
18400
|
+
if (query.excludeEmpty) conditions.push(HAS_ACTIVITY);
|
|
18200
18401
|
if (cursor) {
|
|
18201
18402
|
conditions.push("(started_at < ? OR (started_at = ? AND id < ?))");
|
|
18202
18403
|
params.push(cursor.startedAtMs, cursor.startedAtMs, cursor.id);
|
|
@@ -18233,7 +18434,7 @@ var SqliteActivityRepository = class {
|
|
|
18233
18434
|
);
|
|
18234
18435
|
const last = page[page.length - 1];
|
|
18235
18436
|
const nextCursor = hasMore && last ? encodeCursor({ startedAtMs: last.started_at, id: last.id }) : null;
|
|
18236
|
-
return Promise.resolve({ items, nextCursor });
|
|
18437
|
+
return Promise.resolve({ items, nextCursor, emptyCount });
|
|
18237
18438
|
}
|
|
18238
18439
|
getSession(sessionId) {
|
|
18239
18440
|
const rootRow = getRow(
|
|
@@ -19539,9 +19740,43 @@ var SqliteFindingsRepository = class {
|
|
|
19539
19740
|
}))
|
|
19540
19741
|
);
|
|
19541
19742
|
}
|
|
19743
|
+
/** Live-enforced findings recorded for one session — a bare COUNT over the
|
|
19744
|
+
* session-stamped events (served by idx_events_session_id), so the Activity
|
|
19745
|
+
* page can label its findings link without the grouped pipeline. */
|
|
19746
|
+
sessionFindingsCount(sessionId) {
|
|
19747
|
+
if (!sessionId) return Promise.resolve(0);
|
|
19748
|
+
return Promise.resolve(
|
|
19749
|
+
countScalar(
|
|
19750
|
+
this.db,
|
|
19751
|
+
`SELECT count(*) AS n FROM findings f
|
|
19752
|
+
JOIN events e ON e.id = f.event_id
|
|
19753
|
+
WHERE json_extract(e.metadata, '$.sessionId') = :sessionId`,
|
|
19754
|
+
{ sessionId }
|
|
19755
|
+
)
|
|
19756
|
+
);
|
|
19757
|
+
}
|
|
19758
|
+
/** Per-rule transcript firing tally for one session — reads the OTHER finding
|
|
19759
|
+
* store (inspection_findings, keyed to audit_events): every detection the
|
|
19760
|
+
* transcript pass recorded, counted per firing rather than per unique value.
|
|
19761
|
+
* Rides on session-scoped grouped responses so the findings view can
|
|
19762
|
+
* reconcile the Activity page's tally with the deduped groups it lists. */
|
|
19763
|
+
sessionFirings(sessionId) {
|
|
19764
|
+
return Object.fromEntries(
|
|
19765
|
+
countBy(
|
|
19766
|
+
this.db,
|
|
19767
|
+
`SELECT d.rule_id AS k, count(*) AS n
|
|
19768
|
+
FROM inspection_findings f
|
|
19769
|
+
JOIN audit_events e ON e.id = f.audit_event_id
|
|
19770
|
+
JOIN inspection_definitions d ON d.id = f.inspection_definition_id
|
|
19771
|
+
WHERE e.root_session_id = :sessionId
|
|
19772
|
+
GROUP BY d.rule_id`,
|
|
19773
|
+
{ sessionId }
|
|
19774
|
+
)
|
|
19775
|
+
);
|
|
19776
|
+
}
|
|
19542
19777
|
/**
|
|
19543
|
-
* Grouped findings for the dashboard — joins findings⋈events (repo/file
|
|
19544
|
-
* from event metadata), groups by ruleId, computes per-filter-excluded facets,
|
|
19778
|
+
* Grouped findings for the dashboard — joins findings⋈events (repo/file/
|
|
19779
|
+
* toolName from event metadata), groups by ruleId, computes per-filter-excluded facets,
|
|
19545
19780
|
* applies the requested filters, and sorts by severity then recency. Filtering
|
|
19546
19781
|
* and faceting run in JS via the shared @akasecurity/schema helpers. `totals`
|
|
19547
19782
|
* reflect the full filtered set; `items` is the requested
|
|
@@ -19558,11 +19793,16 @@ var SqliteFindingsRepository = class {
|
|
|
19558
19793
|
* rule is ever restated in SQL.
|
|
19559
19794
|
*/
|
|
19560
19795
|
listGroupedFindings(query) {
|
|
19561
|
-
const
|
|
19796
|
+
const sessionPredicate = query.sessionId ? `WHERE json_extract(e.metadata, '$.sessionId') = :sessionId` : "";
|
|
19797
|
+
const sessionParams = query.sessionId ? { sessionId: query.sessionId } : {};
|
|
19798
|
+
const aggregates = this.groupAggregates(query.q !== void 0 && query.q !== "", {
|
|
19799
|
+
predicate: sessionPredicate,
|
|
19800
|
+
params: sessionParams
|
|
19801
|
+
});
|
|
19562
19802
|
const rows = allRows(
|
|
19563
19803
|
this.db.prepare(
|
|
19564
19804
|
`SELECT id, rule_id, category, severity, masked_match, action_taken, confidence,
|
|
19565
|
-
occurred_at, source_tool, repo, file, kind, finding_key, latest_status
|
|
19805
|
+
occurred_at, source_tool, repo, file, tool_name, kind, finding_key, latest_status
|
|
19566
19806
|
FROM (
|
|
19567
19807
|
SELECT f.id AS id, f.rule_id AS rule_id, f.category AS category,
|
|
19568
19808
|
f.severity AS severity, f.masked_match AS masked_match,
|
|
@@ -19570,6 +19810,7 @@ var SqliteFindingsRepository = class {
|
|
|
19570
19810
|
e.occurred_at AS occurred_at, e.source_tool AS source_tool,
|
|
19571
19811
|
json_extract(e.metadata, '$.repo') AS repo,
|
|
19572
19812
|
json_extract(e.metadata, '$.filePath') AS file,
|
|
19813
|
+
json_extract(e.metadata, '$.toolName') AS tool_name,
|
|
19573
19814
|
e.kind AS kind, f.finding_key AS finding_key,
|
|
19574
19815
|
latest.status AS latest_status,
|
|
19575
19816
|
ROW_NUMBER() OVER (
|
|
@@ -19580,11 +19821,12 @@ var SqliteFindingsRepository = class {
|
|
|
19580
19821
|
JOIN events e ON e.id = f.event_id
|
|
19581
19822
|
LEFT JOIN ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
19582
19823
|
ON latest.finding_key = f.finding_key
|
|
19824
|
+
${sessionPredicate}
|
|
19583
19825
|
)
|
|
19584
19826
|
WHERE rn <= :cap
|
|
19585
19827
|
ORDER BY occurred_at DESC, id DESC`
|
|
19586
19828
|
),
|
|
19587
|
-
{ cap: PREVIEW_INSTANCES_PER_GROUP }
|
|
19829
|
+
{ cap: PREVIEW_INSTANCES_PER_GROUP, ...sessionParams }
|
|
19588
19830
|
);
|
|
19589
19831
|
const groupable = rows.map((r) => ({
|
|
19590
19832
|
id: r.id,
|
|
@@ -19598,6 +19840,7 @@ var SqliteFindingsRepository = class {
|
|
|
19598
19840
|
sourceTool: r.source_tool,
|
|
19599
19841
|
repo: r.repo ?? "",
|
|
19600
19842
|
file: r.file ?? "",
|
|
19843
|
+
...r.tool_name === null ? {} : { toolName: r.tool_name },
|
|
19601
19844
|
status: deriveInstanceStatus(r)
|
|
19602
19845
|
}));
|
|
19603
19846
|
const allGroups = buildFindingGroups(groupable, { aggregates });
|
|
@@ -19616,7 +19859,13 @@ var SqliteFindingsRepository = class {
|
|
|
19616
19859
|
};
|
|
19617
19860
|
const limit = query.limit ?? DEFAULT_GROUPED_FINDINGS_LIMIT;
|
|
19618
19861
|
const items = sorted.slice(0, limit);
|
|
19619
|
-
return Promise.resolve({
|
|
19862
|
+
return Promise.resolve({
|
|
19863
|
+
totals,
|
|
19864
|
+
facets,
|
|
19865
|
+
items,
|
|
19866
|
+
nextCursor: null,
|
|
19867
|
+
...query.sessionId ? { sessionFirings: this.sessionFirings(query.sessionId) } : {}
|
|
19868
|
+
});
|
|
19620
19869
|
}
|
|
19621
19870
|
/**
|
|
19622
19871
|
* One row per rule_id, folding EVERY instance of the group into the values
|
|
@@ -19640,9 +19889,10 @@ var SqliteFindingsRepository = class {
|
|
|
19640
19889
|
* would silently lose, so it is fetched only when the request actually
|
|
19641
19890
|
* carries a `q`.
|
|
19642
19891
|
*/
|
|
19643
|
-
groupAggregates(withSearchText) {
|
|
19892
|
+
groupAggregates(withSearchText, scope) {
|
|
19644
19893
|
const searchTextColumns = withSearchText ? `, group_concat(DISTINCT json_extract(e.metadata, '$.repo')) AS repos,
|
|
19645
|
-
group_concat(DISTINCT json_extract(e.metadata, '$.filePath')) AS files
|
|
19894
|
+
group_concat(DISTINCT json_extract(e.metadata, '$.filePath')) AS files,
|
|
19895
|
+
group_concat(DISTINCT 'via ' || json_extract(e.metadata, '$.toolName')) AS tool_names` : `, NULL AS repos, NULL AS files, NULL AS tool_names`;
|
|
19646
19896
|
const rows = this.db.prepare(
|
|
19647
19897
|
`SELECT f.rule_id AS rule_id,
|
|
19648
19898
|
count(*) AS instance_count,
|
|
@@ -19659,8 +19909,9 @@ var SqliteFindingsRepository = class {
|
|
|
19659
19909
|
JOIN events e ON e.id = f.event_id
|
|
19660
19910
|
LEFT JOIN ${LATEST_RESOLUTION_BY_KEY_SQL} latest
|
|
19661
19911
|
ON latest.finding_key = f.finding_key
|
|
19912
|
+
${scope.predicate}
|
|
19662
19913
|
GROUP BY f.rule_id`
|
|
19663
|
-
).all();
|
|
19914
|
+
).all(scope.params);
|
|
19664
19915
|
return new Map(
|
|
19665
19916
|
rows.map((r) => [
|
|
19666
19917
|
r.rule_id,
|
|
@@ -19684,7 +19935,9 @@ var SqliteFindingsRepository = class {
|
|
|
19684
19935
|
// Left undefined (not '') when unfetched, so buildFindingGroups can
|
|
19685
19936
|
// tell "no q this request" from "a group with no repo/file at all"
|
|
19686
19937
|
// and skip priming a haystack nothing will read.
|
|
19687
|
-
...withSearchText ? {
|
|
19938
|
+
...withSearchText ? {
|
|
19939
|
+
searchText: [r.repos ?? "", r.files ?? "", r.tool_names ?? ""].filter((s) => s !== "").join(" ")
|
|
19940
|
+
} : {}
|
|
19688
19941
|
}
|
|
19689
19942
|
])
|
|
19690
19943
|
);
|
|
@@ -21420,7 +21673,6 @@ var SqliteScanLedgerRepository = class {
|
|
|
21420
21673
|
// ../../packages/persistence/src/repositories/security.ts
|
|
21421
21674
|
var DAY_MS4 = 864e5;
|
|
21422
21675
|
var SEVERITIES = ["critical", "high", "medium", "low"];
|
|
21423
|
-
var RANGE_DAYS = { "7d": 7, "30d": 30, "3m": 90, "6m": 180 };
|
|
21424
21676
|
var ACTION_TO_KIND = {
|
|
21425
21677
|
block: "blocked",
|
|
21426
21678
|
redact: "redacted",
|
|
@@ -21435,8 +21687,14 @@ var SCAN_COVERAGE = [
|
|
|
21435
21687
|
{ provider: "copilot", coverage: 0, supported: false },
|
|
21436
21688
|
{ provider: "api", coverage: 0, supported: false }
|
|
21437
21689
|
];
|
|
21690
|
+
var GRANULARITY = {
|
|
21691
|
+
"7d": "day",
|
|
21692
|
+
"30d": "day",
|
|
21693
|
+
"3m": "week",
|
|
21694
|
+
"6m": "week"
|
|
21695
|
+
};
|
|
21438
21696
|
function granularityFor(range) {
|
|
21439
|
-
return range
|
|
21697
|
+
return GRANULARITY[range];
|
|
21440
21698
|
}
|
|
21441
21699
|
function startOfUtcDay2(ms) {
|
|
21442
21700
|
return Math.floor(ms / DAY_MS4) * DAY_MS4;
|
|
@@ -22610,21 +22868,28 @@ import { readdirSync, readFileSync as readFileSync4, realpathSync, statSync as s
|
|
|
22610
22868
|
import { homedir as homedir2 } from "os";
|
|
22611
22869
|
import { basename as basename2, join as join7 } from "path";
|
|
22612
22870
|
|
|
22871
|
+
// ../../packages/detections/src/escape-regexp.ts
|
|
22872
|
+
function escapeRegExp(value) {
|
|
22873
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22874
|
+
}
|
|
22875
|
+
|
|
22876
|
+
// ../../packages/detections/src/matchers/limits.ts
|
|
22877
|
+
var MAX_MATCHES_PER_RULE = 1e4;
|
|
22878
|
+
|
|
22613
22879
|
// ../../packages/detections/src/matchers/keyword.ts
|
|
22614
22880
|
var KeywordMatcher2 = class {
|
|
22615
22881
|
match(text, rule) {
|
|
22616
22882
|
if (rule.matcher.type !== "keyword") return [];
|
|
22617
22883
|
const { keywords, caseSensitive } = rule.matcher;
|
|
22618
|
-
const haystack = caseSensitive ? text : text.toLowerCase();
|
|
22619
22884
|
const spans = [];
|
|
22620
22885
|
for (const kw of keywords) {
|
|
22621
|
-
|
|
22622
|
-
|
|
22623
|
-
|
|
22624
|
-
|
|
22625
|
-
|
|
22626
|
-
spans.push({ start:
|
|
22627
|
-
|
|
22886
|
+
if (kw.length === 0) continue;
|
|
22887
|
+
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
22888
|
+
const re = new RegExp(escapeRegExp(kw), caseSensitive ? "gu" : "giu");
|
|
22889
|
+
let m;
|
|
22890
|
+
while ((m = re.exec(text)) !== null) {
|
|
22891
|
+
spans.push({ start: m.index, end: m.index + m[0].length });
|
|
22892
|
+
if (spans.length >= MAX_MATCHES_PER_RULE) break;
|
|
22628
22893
|
}
|
|
22629
22894
|
}
|
|
22630
22895
|
return spans;
|
|
@@ -22632,7 +22897,6 @@ var KeywordMatcher2 = class {
|
|
|
22632
22897
|
};
|
|
22633
22898
|
|
|
22634
22899
|
// ../../packages/detections/src/matchers/regex.ts
|
|
22635
|
-
var MAX_MATCHES_PER_RULE = 1e4;
|
|
22636
22900
|
var RegexMatcher2 = class {
|
|
22637
22901
|
match(text, rule) {
|
|
22638
22902
|
if (rule.matcher.type !== "regex") return [];
|
|
@@ -22776,6 +23040,68 @@ function parsePosture(json2) {
|
|
|
22776
23040
|
return out;
|
|
22777
23041
|
}
|
|
22778
23042
|
|
|
23043
|
+
// src/setup-show.ts
|
|
23044
|
+
var SHOW_BEGIN = "<<<AKA_SHOW";
|
|
23045
|
+
var SHOW_END = "AKA_SHOW>>>";
|
|
23046
|
+
function showBlock(body) {
|
|
23047
|
+
return `${SHOW_BEGIN}
|
|
23048
|
+
${body}
|
|
23049
|
+
${SHOW_END}
|
|
23050
|
+
`;
|
|
23051
|
+
}
|
|
23052
|
+
|
|
23053
|
+
// src/present.ts
|
|
23054
|
+
var SHADE = {
|
|
23055
|
+
light: "\u2591",
|
|
23056
|
+
medium: "\u2592",
|
|
23057
|
+
dark: "\u2593",
|
|
23058
|
+
full: "\u2588"
|
|
23059
|
+
};
|
|
23060
|
+
var fg = (hex3) => (text) => {
|
|
23061
|
+
const r = Number.parseInt(hex3.slice(1, 3), 16);
|
|
23062
|
+
const g = Number.parseInt(hex3.slice(3, 5), 16);
|
|
23063
|
+
const b = Number.parseInt(hex3.slice(5, 7), 16);
|
|
23064
|
+
return `\x1B[38;2;${String(r)};${String(g)};${String(b)}m${text}\x1B[0m`;
|
|
23065
|
+
};
|
|
23066
|
+
var paint = {
|
|
23067
|
+
brand: fg("#33e6c6"),
|
|
23068
|
+
// --color-brand · ▸▸ AKA wordmark (accent text)
|
|
23069
|
+
dim: fg("#838995"),
|
|
23070
|
+
// --color-text-3 · separators · "/100" · the "unreviewed" label
|
|
23071
|
+
bold: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
23072
|
+
// the health score number
|
|
23073
|
+
ok: fg("#0db15f"),
|
|
23074
|
+
// --color-ok · healthy ● dot
|
|
23075
|
+
critical: fg("#e63448"),
|
|
23076
|
+
// --color-sev-critical · ■ and the open-findings flag
|
|
23077
|
+
high: fg("#e97a0a"),
|
|
23078
|
+
// --color-sev-high · ■ and the mid-health dot
|
|
23079
|
+
medium: fg("#f7bd00"),
|
|
23080
|
+
// --color-sev-medium · ■
|
|
23081
|
+
low: fg("#0581d4")
|
|
23082
|
+
// --color-sev-low · ■ (azure blue, not purple)
|
|
23083
|
+
};
|
|
23084
|
+
function show(body) {
|
|
23085
|
+
return showBlock(body);
|
|
23086
|
+
}
|
|
23087
|
+
|
|
23088
|
+
// src/command-registry.ts
|
|
23089
|
+
import { readdirSync as readdirSync3 } from "fs";
|
|
23090
|
+
import { fileURLToPath } from "url";
|
|
23091
|
+
var COMMANDS_DIR = fileURLToPath(new URL("../commands", import.meta.url));
|
|
23092
|
+
|
|
23093
|
+
// src/render.ts
|
|
23094
|
+
var SEVERITY_GLYPH = {
|
|
23095
|
+
critical: SHADE.full,
|
|
23096
|
+
high: SHADE.dark,
|
|
23097
|
+
medium: SHADE.medium,
|
|
23098
|
+
low: SHADE.light
|
|
23099
|
+
};
|
|
23100
|
+
var CATEGORY_ORDER2 = DetectionCategory.options;
|
|
23101
|
+
function renderCategoriesTuned(categoriesTuned) {
|
|
23102
|
+
return `\u2713 Set all ${String(categoriesTuned)} detection categories`;
|
|
23103
|
+
}
|
|
23104
|
+
|
|
22779
23105
|
// src/onboard.ts
|
|
22780
23106
|
function parseFlags(argv) {
|
|
22781
23107
|
const flags2 = /* @__PURE__ */ new Map();
|
|
@@ -22825,10 +23151,7 @@ if (Object.keys(answers).length === 0 && rawPosture === void 0 && !useFloor) {
|
|
|
22825
23151
|
if (Object.keys(answers).length > 0) {
|
|
22826
23152
|
try {
|
|
22827
23153
|
const settings = applyOnboarding(answers);
|
|
22828
|
-
process.stdout.write(
|
|
22829
|
-
`AKA configured: policy=${settings.policy}, historicalAccess=${settings.historicalAccess}. Settings saved to ~/.aka/settings/settings.json.
|
|
22830
|
-
`
|
|
22831
|
-
);
|
|
23154
|
+
process.stdout.write(show("Got it \u2014 I'll look over Claude's recent work to tune things."));
|
|
22832
23155
|
try {
|
|
22833
23156
|
const dataDir2 = loadConfig().dataDir;
|
|
22834
23157
|
const db = openLocalDatabase(dataDir2);
|
|
@@ -22836,8 +23159,9 @@ if (Object.keys(answers).length > 0) {
|
|
|
22836
23159
|
const { capped } = capWarnEraEnforcementOnce(db, settings.policy, dataDir2);
|
|
22837
23160
|
if (capped > 0) {
|
|
22838
23161
|
process.stdout.write(
|
|
22839
|
-
|
|
22840
|
-
`
|
|
23162
|
+
show(
|
|
23163
|
+
`I eased ${String(capped)} detection level${capped === 1 ? "" : "s"} back to "warn" to match the new defaults \u2014 you can raise any of them again in this setup.`
|
|
23164
|
+
)
|
|
22841
23165
|
);
|
|
22842
23166
|
}
|
|
22843
23167
|
} finally {
|
|
@@ -22846,7 +23170,7 @@ if (Object.keys(answers).length > 0) {
|
|
|
22846
23170
|
} catch {
|
|
22847
23171
|
}
|
|
22848
23172
|
} catch (err) {
|
|
22849
|
-
fail(err instanceof Error ? err.message : "could not
|
|
23173
|
+
fail(err instanceof Error ? err.message : "could not save your settings");
|
|
22850
23174
|
}
|
|
22851
23175
|
}
|
|
22852
23176
|
if (rawPosture !== void 0 || useFloor) {
|
|
@@ -22861,8 +23185,7 @@ if (rawPosture !== void 0 || useFloor) {
|
|
|
22861
23185
|
applyCategoryPosture(posture, db.policies, mode);
|
|
22862
23186
|
const categoryCount = Object.keys(posture).length;
|
|
22863
23187
|
process.stdout.write(
|
|
22864
|
-
|
|
22865
|
-
`
|
|
23188
|
+
show(renderCategoriesTuned(categoryCount) + (useFloor ? " \u2014 safe defaults" : ""))
|
|
22866
23189
|
);
|
|
22867
23190
|
} finally {
|
|
22868
23191
|
db.close();
|