@kyo-so/cli 0.7.1 → 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/.agents/skills/kyoso-review/SKILL.md +16 -4
- package/.agents/skills/kyoso-review/agents/openai.yaml +0 -7
- package/CHANGELOG.md +57 -0
- package/README.ja.md +74 -8
- package/README.md +74 -8
- package/README.zh-CN.md +74 -8
- package/dist/audit/safeTraceFile.d.ts +20 -0
- package/dist/audit/stateRoot.d.ts +38 -0
- package/dist/audit/trace.d.ts +15 -3
- package/dist/bin/kyoso.js +2702 -503
- package/dist/cli/codexPluginDetector.d.ts +70 -0
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/integration.d.ts +30 -0
- package/dist/cli/knownSkillDigests.d.ts +11 -0
- package/dist/cli/pluginRuntimeContract.d.ts +232 -0
- package/dist/cli/setup.d.ts +24 -4
- package/dist/cli/skillInstall.d.ts +16 -0
- package/dist/config/configOverrides.d.ts +2 -0
- package/dist/config/projectScope.d.ts +2 -0
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/runReview.d.ts +3 -0
- package/dist/index.js +755 -140
- package/dist/utils/pathContainment.d.ts +1 -0
- package/package.json +9 -2
package/dist/index.js
CHANGED
|
@@ -169498,7 +169498,7 @@ function defineConfig(config) {
|
|
|
169498
169498
|
return config;
|
|
169499
169499
|
}
|
|
169500
169500
|
// src/core/runReview.ts
|
|
169501
|
-
import { resolve as
|
|
169501
|
+
import { resolve as resolve6 } from "node:path";
|
|
169502
169502
|
|
|
169503
169503
|
// node_modules/zod/v4/classic/external.js
|
|
169504
169504
|
var exports_external = {};
|
|
@@ -184076,6 +184076,28 @@ import { createInterface } from "node:readline/promises";
|
|
|
184076
184076
|
|
|
184077
184077
|
// src/config/projectScope.ts
|
|
184078
184078
|
var PROJECT_GLOBAL_ONLY_MESSAGE = "Move global-only settings to the user global config:";
|
|
184079
|
+
var kyosoConfigOverridePaths = [
|
|
184080
|
+
"agents.codex.enabled",
|
|
184081
|
+
"agents.codex.model",
|
|
184082
|
+
"agents.codex.effort",
|
|
184083
|
+
"agents.codex.role",
|
|
184084
|
+
"agents.codex.timeoutMs",
|
|
184085
|
+
"agents.claude.enabled",
|
|
184086
|
+
"agents.claude.model",
|
|
184087
|
+
"agents.claude.effort",
|
|
184088
|
+
"agents.claude.role",
|
|
184089
|
+
"agents.claude.timeoutMs",
|
|
184090
|
+
"verification.enabled",
|
|
184091
|
+
"verification.maxFindings",
|
|
184092
|
+
"verification.timeoutMs",
|
|
184093
|
+
"judge.mode",
|
|
184094
|
+
"judge.provider",
|
|
184095
|
+
"judge.timeoutMs"
|
|
184096
|
+
];
|
|
184097
|
+
var CONFIG_OVERRIDE_PATHS = new Set(kyosoConfigOverridePaths);
|
|
184098
|
+
function isAllowedConfigOverridePath(path) {
|
|
184099
|
+
return CONFIG_OVERRIDE_PATHS.has(path.join("."));
|
|
184100
|
+
}
|
|
184079
184101
|
function mergeProjectTomlConfig(baseConfig, projectConfig, options) {
|
|
184080
184102
|
const violations = collectProjectScopeViolations(projectConfig);
|
|
184081
184103
|
if (violations.length > 0) {
|
|
@@ -184108,13 +184130,9 @@ function collectProjectScopeViolations(config2) {
|
|
|
184108
184130
|
}
|
|
184109
184131
|
function isAllowedProjectPath(path) {
|
|
184110
184132
|
const [top, second, third, fourth] = path;
|
|
184111
|
-
if (
|
|
184133
|
+
if (isAllowedConfigOverridePath(path))
|
|
184112
184134
|
return true;
|
|
184113
|
-
|
|
184114
|
-
if (top === "agents" && path.length === 3 && ["codex", "claude"].includes(second ?? "") && ["enabled", "model", "effort", "role", "timeoutMs"].includes(third ?? "")) {
|
|
184115
|
-
return true;
|
|
184116
|
-
}
|
|
184117
|
-
if (top === "verification" && path.length === 2 && ["enabled", "maxFindings", "timeoutMs"].includes(second ?? "")) {
|
|
184135
|
+
if (top === "tools" && path.length === 2 && ["planReview", "securityReview", "diffReview"].includes(second ?? "")) {
|
|
184118
184136
|
return true;
|
|
184119
184137
|
}
|
|
184120
184138
|
if (top === "workspace" && path.length === 2 && ["maxContextBytes", "maxDiffBytes", "deny"].includes(second ?? "")) {
|
|
@@ -184126,9 +184144,6 @@ function isAllowedProjectPath(path) {
|
|
|
184126
184144
|
if (top === "secrets" && path.length === 2 && ["blockOnDetectedSecret", "allowOverride"].includes(second ?? "")) {
|
|
184127
184145
|
return true;
|
|
184128
184146
|
}
|
|
184129
|
-
if (top === "judge" && path.length === 2 && ["mode", "provider", "timeoutMs"].includes(second ?? "")) {
|
|
184130
|
-
return true;
|
|
184131
|
-
}
|
|
184132
184147
|
if (top === "securityReview" && second === "cisaSecureByDesign" && path.length >= 3) {
|
|
184133
184148
|
if (third === "dimensions") {
|
|
184134
184149
|
return path.length === 4 && [
|
|
@@ -184246,6 +184261,7 @@ var REDACTION = "[KYOSO_REDACTED]";
|
|
|
184246
184261
|
// src/core/constants.ts
|
|
184247
184262
|
var DEFAULT_AGENT_TIMEOUT_MS = 120000;
|
|
184248
184263
|
var RAW_OUTPUT_MAX_CHARS = 16384;
|
|
184264
|
+
var TRACE_DIR = ".kyoso/traces";
|
|
184249
184265
|
var KYOSO_CHILD_AGENT = "KYOSO_CHILD_AGENT";
|
|
184250
184266
|
|
|
184251
184267
|
// src/security/sanitizeText.ts
|
|
@@ -185548,6 +185564,90 @@ async function exists(path) {
|
|
|
185548
185564
|
}
|
|
185549
185565
|
}
|
|
185550
185566
|
|
|
185567
|
+
// src/config/configOverrides.ts
|
|
185568
|
+
var NUMBER_VALUE = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
185569
|
+
function applyConfigOverrides(config2, assignments) {
|
|
185570
|
+
if (assignments.length === 0)
|
|
185571
|
+
return config2;
|
|
185572
|
+
const overrides = assignments.map(parseConfigOverride);
|
|
185573
|
+
const baseConfig = config2;
|
|
185574
|
+
const overridden = structuredClone(config2);
|
|
185575
|
+
for (const override of overrides) {
|
|
185576
|
+
writePath2(overridden, override.path, parseConfigOverrideValue(override.value, readPath2(baseConfig, override.path)));
|
|
185577
|
+
}
|
|
185578
|
+
const parsed = kyosoConfigSchema.safeParse(overridden);
|
|
185579
|
+
if (parsed.success)
|
|
185580
|
+
return parsed.data;
|
|
185581
|
+
const issue2 = parsed.error.issues[0];
|
|
185582
|
+
const issuePath = issue2?.path.map(String).join(".") ?? "config";
|
|
185583
|
+
const assignment = findAssignmentForPath(overrides, issuePath) ?? assignments.at(-1) ?? "";
|
|
185584
|
+
throw new Error(`Invalid --set value ${JSON.stringify(assignment)}: ${issuePath}: ${issue2?.message ?? "config validation failed"}.`);
|
|
185585
|
+
}
|
|
185586
|
+
function findAssignmentForPath(overrides, path) {
|
|
185587
|
+
for (let index = overrides.length - 1;index >= 0; index -= 1) {
|
|
185588
|
+
const override = overrides[index];
|
|
185589
|
+
if (override?.path.join(".") === path)
|
|
185590
|
+
return override.assignment;
|
|
185591
|
+
}
|
|
185592
|
+
return;
|
|
185593
|
+
}
|
|
185594
|
+
function parseConfigOverride(assignment) {
|
|
185595
|
+
const separator = assignment.indexOf("=");
|
|
185596
|
+
if (separator <= 0) {
|
|
185597
|
+
throw new Error(`Invalid --set value ${JSON.stringify(assignment)}. Expected key=value.`);
|
|
185598
|
+
}
|
|
185599
|
+
const key = assignment.slice(0, separator);
|
|
185600
|
+
const path = key.split(".");
|
|
185601
|
+
if (!isAllowedConfigOverridePath(path)) {
|
|
185602
|
+
throw new Error(`Unknown --set key ${JSON.stringify(key)}.`);
|
|
185603
|
+
}
|
|
185604
|
+
return {
|
|
185605
|
+
assignment,
|
|
185606
|
+
path,
|
|
185607
|
+
value: assignment.slice(separator + 1)
|
|
185608
|
+
};
|
|
185609
|
+
}
|
|
185610
|
+
function parseConfigOverrideValue(value, currentValue) {
|
|
185611
|
+
if (typeof currentValue === "boolean") {
|
|
185612
|
+
if (value === "true")
|
|
185613
|
+
return true;
|
|
185614
|
+
if (value === "false")
|
|
185615
|
+
return false;
|
|
185616
|
+
return value;
|
|
185617
|
+
}
|
|
185618
|
+
if (typeof currentValue === "number" && NUMBER_VALUE.test(value)) {
|
|
185619
|
+
const parsed = Number(value);
|
|
185620
|
+
if (Number.isFinite(parsed))
|
|
185621
|
+
return parsed;
|
|
185622
|
+
}
|
|
185623
|
+
return value;
|
|
185624
|
+
}
|
|
185625
|
+
function readPath2(target, path) {
|
|
185626
|
+
let current = target;
|
|
185627
|
+
for (const key of path) {
|
|
185628
|
+
if (!isRecord4(current))
|
|
185629
|
+
return;
|
|
185630
|
+
current = current[key];
|
|
185631
|
+
}
|
|
185632
|
+
return current;
|
|
185633
|
+
}
|
|
185634
|
+
function writePath2(target, path, value) {
|
|
185635
|
+
let current = target;
|
|
185636
|
+
for (const key of path.slice(0, -1)) {
|
|
185637
|
+
const child = current[key];
|
|
185638
|
+
if (!isRecord4(child)) {
|
|
185639
|
+
throw new Error(`Cannot apply --set key ${JSON.stringify(path.join("."))}.`);
|
|
185640
|
+
}
|
|
185641
|
+
current = child;
|
|
185642
|
+
}
|
|
185643
|
+
const leaf = path.at(-1);
|
|
185644
|
+
if (leaf)
|
|
185645
|
+
current[leaf] = value;
|
|
185646
|
+
}
|
|
185647
|
+
function isRecord4(value) {
|
|
185648
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
185649
|
+
}
|
|
185650
|
+
|
|
185551
185651
|
// src/acp/AcpAgentProcess.ts
|
|
185552
185652
|
import { spawn } from "node:child_process";
|
|
185553
185653
|
import { readFile as readFile4, realpath } from "node:fs/promises";
|
|
@@ -185622,6 +185722,48 @@ function requiredDefaultOnError(schema, fallback) {
|
|
|
185622
185722
|
return exports_external.NEVER;
|
|
185623
185723
|
});
|
|
185624
185724
|
}
|
|
185725
|
+
function stringTag(value, key) {
|
|
185726
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
185727
|
+
return;
|
|
185728
|
+
}
|
|
185729
|
+
const tag = value[key];
|
|
185730
|
+
return typeof tag === "string" ? tag : undefined;
|
|
185731
|
+
}
|
|
185732
|
+
function excludeKnownTags(schema, key, knownTags) {
|
|
185733
|
+
return schema.superRefine((value, context) => {
|
|
185734
|
+
const tag = stringTag(value, key);
|
|
185735
|
+
if (tag !== undefined && knownTags.includes(tag)) {
|
|
185736
|
+
context.addIssue({
|
|
185737
|
+
code: "custom",
|
|
185738
|
+
path: [key],
|
|
185739
|
+
message: `${key} ${JSON.stringify(tag)} is reserved by a known variant, ` + `but the value does not match that variant's schema`
|
|
185740
|
+
});
|
|
185741
|
+
}
|
|
185742
|
+
});
|
|
185743
|
+
}
|
|
185744
|
+
function preserveCustomPayload(schema, key, knownTags) {
|
|
185745
|
+
return exports_external.unknown().transform((value, context) => {
|
|
185746
|
+
const result = schema.safeParse(value);
|
|
185747
|
+
if (!result.success) {
|
|
185748
|
+
for (const issue2 of result.error.issues) {
|
|
185749
|
+
context.addIssue({ ...issue2, input: value });
|
|
185750
|
+
}
|
|
185751
|
+
return exports_external.NEVER;
|
|
185752
|
+
}
|
|
185753
|
+
const output = result.data;
|
|
185754
|
+
const tag = stringTag(value, key);
|
|
185755
|
+
if (tag !== undefined && !knownTags.includes(tag)) {
|
|
185756
|
+
const raw = value;
|
|
185757
|
+
for (const [property, rawValue] of Object.entries(raw)) {
|
|
185758
|
+
if (property === "__proto__")
|
|
185759
|
+
continue;
|
|
185760
|
+
if (!Object.hasOwn(output, property))
|
|
185761
|
+
output[property] = rawValue;
|
|
185762
|
+
}
|
|
185763
|
+
}
|
|
185764
|
+
return output;
|
|
185765
|
+
});
|
|
185766
|
+
}
|
|
185625
185767
|
function vecSkipError(itemSchema) {
|
|
185626
185768
|
return exports_external.array(itemSchema.catch(skippedItem)).transform((items) => items.filter((item) => item !== skippedItem));
|
|
185627
185769
|
}
|
|
@@ -186045,15 +186187,15 @@ var zTitledMultiSelectItems = object({
|
|
|
186045
186187
|
return;
|
|
186046
186188
|
})
|
|
186047
186189
|
});
|
|
186048
|
-
var zMultiSelectItems = union([
|
|
186190
|
+
var zMultiSelectItems = preserveCustomPayload(union([
|
|
186049
186191
|
zStringMultiSelectItems.and(object({
|
|
186050
186192
|
type: literal("string")
|
|
186051
186193
|
})),
|
|
186052
|
-
object({
|
|
186194
|
+
excludeKnownTags(object({
|
|
186053
186195
|
type: string2()
|
|
186054
|
-
}),
|
|
186196
|
+
}), "type", ["string"]),
|
|
186055
186197
|
zTitledMultiSelectItems
|
|
186056
|
-
]);
|
|
186198
|
+
]), "type", ["string"]);
|
|
186057
186199
|
var zMultiSelectPropertySchema = object({
|
|
186058
186200
|
title: defaultOnError(string2().nullish(), () => {
|
|
186059
186201
|
return;
|
|
@@ -186071,7 +186213,7 @@ var zMultiSelectPropertySchema = object({
|
|
|
186071
186213
|
return;
|
|
186072
186214
|
})
|
|
186073
186215
|
});
|
|
186074
|
-
var zElicitationPropertySchema = union([
|
|
186216
|
+
var zElicitationPropertySchema = preserveCustomPayload(union([
|
|
186075
186217
|
zStringPropertySchema.and(object({
|
|
186076
186218
|
type: literal("string")
|
|
186077
186219
|
})),
|
|
@@ -186087,10 +186229,10 @@ var zElicitationPropertySchema = union([
|
|
|
186087
186229
|
zMultiSelectPropertySchema.and(object({
|
|
186088
186230
|
type: literal("array")
|
|
186089
186231
|
})),
|
|
186090
|
-
object({
|
|
186232
|
+
excludeKnownTags(object({
|
|
186091
186233
|
type: string2()
|
|
186092
|
-
})
|
|
186093
|
-
]);
|
|
186234
|
+
}), "type", ["array", "boolean", "integer", "number", "string"])
|
|
186235
|
+
]), "type", ["array", "boolean", "integer", "number", "string"]);
|
|
186094
186236
|
var zElicitationSchema = object({
|
|
186095
186237
|
type: defaultOnError(zElicitationSchemaType.optional().default("object"), () => "object"),
|
|
186096
186238
|
title: defaultOnError(string2().nullish(), () => {
|
|
@@ -186113,22 +186255,22 @@ var zElicitationUrlMode = intersection(union([zElicitationSessionScope, zElicita
|
|
|
186113
186255
|
elicitationId: zElicitationId,
|
|
186114
186256
|
url: url()
|
|
186115
186257
|
}));
|
|
186116
|
-
var zCreateElicitationRequest = intersection(union([
|
|
186258
|
+
var zCreateElicitationRequest = preserveCustomPayload(intersection(union([
|
|
186117
186259
|
zElicitationFormMode.and(object({
|
|
186118
186260
|
mode: literal("form")
|
|
186119
186261
|
})),
|
|
186120
186262
|
zElicitationUrlMode.and(object({
|
|
186121
186263
|
mode: literal("url")
|
|
186122
186264
|
})),
|
|
186123
|
-
intersection(union([zElicitationSessionScope, zElicitationRequestScope]), object({
|
|
186265
|
+
excludeKnownTags(intersection(union([zElicitationSessionScope, zElicitationRequestScope]), object({
|
|
186124
186266
|
mode: string2()
|
|
186125
|
-
}))
|
|
186267
|
+
})), "mode", ["form", "url"])
|
|
186126
186268
|
]), object({
|
|
186127
186269
|
message: string2(),
|
|
186128
186270
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
186129
186271
|
return;
|
|
186130
186272
|
})
|
|
186131
|
-
}));
|
|
186273
|
+
})), "mode", ["form", "url"]);
|
|
186132
186274
|
var zMcpServerAcpId = string2();
|
|
186133
186275
|
var zConnectMcpRequest = object({
|
|
186134
186276
|
serverId: zMcpServerAcpId,
|
|
@@ -187728,7 +187870,7 @@ var zElicitationContentValue = union([
|
|
|
187728
187870
|
var zElicitationAcceptAction = object({
|
|
187729
187871
|
content: record(string2(), zElicitationContentValue).nullish()
|
|
187730
187872
|
});
|
|
187731
|
-
var zCreateElicitationResponse = intersection(union([
|
|
187873
|
+
var zCreateElicitationResponse = preserveCustomPayload(intersection(union([
|
|
187732
187874
|
zElicitationAcceptAction.and(object({
|
|
187733
187875
|
action: literal("accept")
|
|
187734
187876
|
})),
|
|
@@ -187738,14 +187880,14 @@ var zCreateElicitationResponse = intersection(union([
|
|
|
187738
187880
|
object({
|
|
187739
187881
|
action: literal("cancel")
|
|
187740
187882
|
}),
|
|
187741
|
-
object({
|
|
187883
|
+
excludeKnownTags(object({
|
|
187742
187884
|
action: string2()
|
|
187743
|
-
})
|
|
187885
|
+
}), "action", ["accept", "cancel", "decline"])
|
|
187744
187886
|
]), object({
|
|
187745
187887
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
187746
187888
|
return;
|
|
187747
187889
|
})
|
|
187748
|
-
}));
|
|
187890
|
+
})), "action", ["accept", "cancel", "decline"]);
|
|
187749
187891
|
var zConnectMcpResponse = object({
|
|
187750
187892
|
connectionId: zMcpConnectionId,
|
|
187751
187893
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
@@ -187881,16 +188023,34 @@ var zCancelRequestNotification = object({
|
|
|
187881
188023
|
return;
|
|
187882
188024
|
})
|
|
187883
188025
|
});
|
|
188026
|
+
|
|
188027
|
+
// node_modules/@agentclientprotocol/sdk/dist/schema/guards.gen.js
|
|
188028
|
+
var zGuardCreateElicitationRequestForm = zElicitationFormMode.and(object({ mode: literal("form") })).and(object({ message: string2() }));
|
|
188029
|
+
var zGuardCreateElicitationRequestUrl = zElicitationUrlMode.and(object({ mode: literal("url") })).and(object({ message: string2() }));
|
|
188030
|
+
var zGuardCreateElicitationRequestCustom = union([zElicitationSessionScope, zElicitationRequestScope]).and(object({ message: string2() }));
|
|
188031
|
+
var zGuardElicitationPropertySchemaString = zStringPropertySchema.and(object({ type: literal("string") }));
|
|
188032
|
+
var zGuardElicitationPropertySchemaNumber = zNumberPropertySchema.and(object({ type: literal("number") }));
|
|
188033
|
+
var zGuardElicitationPropertySchemaInteger = zIntegerPropertySchema.and(object({ type: literal("integer") }));
|
|
188034
|
+
var zGuardElicitationPropertySchemaBoolean = zBooleanPropertySchema.and(object({ type: literal("boolean") }));
|
|
188035
|
+
var zGuardElicitationPropertySchemaArray = zMultiSelectPropertySchema.and(object({ type: literal("array") }));
|
|
188036
|
+
var zGuardMultiSelectItemsString = zStringMultiSelectItems.and(object({ type: literal("string") }));
|
|
188037
|
+
var zGuardCreateElicitationResponseAccept = zElicitationAcceptAction.and(object({ action: literal("accept") }));
|
|
188038
|
+
var zGuardCreateElicitationResponseDecline = object({
|
|
188039
|
+
action: literal("decline")
|
|
188040
|
+
});
|
|
188041
|
+
var zGuardCreateElicitationResponseCancel = object({
|
|
188042
|
+
action: literal("cancel")
|
|
188043
|
+
});
|
|
187884
188044
|
// node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js
|
|
187885
188045
|
var CANCEL_REQUEST_METHOD = "$/cancel_request";
|
|
187886
|
-
function
|
|
188046
|
+
function isRecord5(value) {
|
|
187887
188047
|
return typeof value === "object" && value !== null;
|
|
187888
188048
|
}
|
|
187889
188049
|
function isJsonRpcId(value) {
|
|
187890
188050
|
return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
187891
188051
|
}
|
|
187892
188052
|
function cancelRequestId(params) {
|
|
187893
|
-
if (!
|
|
188053
|
+
if (!isRecord5(params) || !isJsonRpcId(params["requestId"])) {
|
|
187894
188054
|
return;
|
|
187895
188055
|
}
|
|
187896
188056
|
return params["requestId"];
|
|
@@ -188237,7 +188397,7 @@ class Connection {
|
|
|
188237
188397
|
if (this.abortController.signal.aborted) {
|
|
188238
188398
|
return;
|
|
188239
188399
|
}
|
|
188240
|
-
if (!
|
|
188400
|
+
if (!isRecord5(message)) {
|
|
188241
188401
|
console.error("Invalid message", { message });
|
|
188242
188402
|
return;
|
|
188243
188403
|
}
|
|
@@ -188330,7 +188490,7 @@ class Connection {
|
|
|
188330
188490
|
pendingResponse.cleanup?.();
|
|
188331
188491
|
if ("result" in response) {
|
|
188332
188492
|
pendingResponse.resolve(response.result);
|
|
188333
|
-
} else if ("error" in response &&
|
|
188493
|
+
} else if ("error" in response && isRecord5(response.error)) {
|
|
188334
188494
|
const { code, message, data } = response.error;
|
|
188335
188495
|
pendingResponse.reject(new RequestError(code, message, data));
|
|
188336
188496
|
} else {
|
|
@@ -188540,7 +188700,7 @@ function ndJsonStream(output, input) {
|
|
|
188540
188700
|
if (trimmedLine) {
|
|
188541
188701
|
try {
|
|
188542
188702
|
const message = JSON.parse(trimmedLine);
|
|
188543
|
-
if (
|
|
188703
|
+
if (isRecord5(message)) {
|
|
188544
188704
|
controller.enqueue(message);
|
|
188545
188705
|
} else {
|
|
188546
188706
|
console.warn("Skipping JSON line that is not an object:", trimmedLine);
|
|
@@ -189601,7 +189761,7 @@ function isSeverity(value) {
|
|
|
189601
189761
|
return typeof value === "string" && severities.includes(value);
|
|
189602
189762
|
}
|
|
189603
189763
|
function normalizeCisaSecureByDesign(value) {
|
|
189604
|
-
if (!
|
|
189764
|
+
if (!isRecord6(value))
|
|
189605
189765
|
return;
|
|
189606
189766
|
const normalized = {};
|
|
189607
189767
|
const customerSecurityOutcomes = normalizeGateStatus(value.customerSecurityOutcomes);
|
|
@@ -189642,7 +189802,7 @@ function normalizeFindingFiles(value) {
|
|
|
189642
189802
|
if (!Array.isArray(value))
|
|
189643
189803
|
return;
|
|
189644
189804
|
const files = value.flatMap((item) => {
|
|
189645
|
-
if (!
|
|
189805
|
+
if (!isRecord6(item) || typeof item.path !== "string" || item.path.trim().length === 0) {
|
|
189646
189806
|
return [];
|
|
189647
189807
|
}
|
|
189648
189808
|
const file2 = {
|
|
@@ -189661,7 +189821,7 @@ function normalizeFindingFiles(value) {
|
|
|
189661
189821
|
function normalizeLineNumber(value) {
|
|
189662
189822
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
189663
189823
|
}
|
|
189664
|
-
function
|
|
189824
|
+
function isRecord6(value) {
|
|
189665
189825
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
189666
189826
|
}
|
|
189667
189827
|
|
|
@@ -190622,9 +190782,10 @@ function normalizeTitle(value) {
|
|
|
190622
190782
|
return value.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
190623
190783
|
}
|
|
190624
190784
|
|
|
190625
|
-
// src/audit/
|
|
190626
|
-
import {
|
|
190627
|
-
import {
|
|
190785
|
+
// src/audit/stateRoot.ts
|
|
190786
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
190787
|
+
import { lstat, mkdir as mkdir2, realpath as realpath2 } from "node:fs/promises";
|
|
190788
|
+
import { basename, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve5 } from "node:path";
|
|
190628
190789
|
|
|
190629
190790
|
// src/context/pathPolicy.ts
|
|
190630
190791
|
import { normalize, sep } from "node:path";
|
|
@@ -190686,6 +190847,325 @@ function matchesPathPattern(path, patterns, mode) {
|
|
|
190686
190847
|
});
|
|
190687
190848
|
}
|
|
190688
190849
|
|
|
190850
|
+
// src/utils/pathContainment.ts
|
|
190851
|
+
import { resolve as resolve4, sep as sep2 } from "node:path";
|
|
190852
|
+
function isPathWithin(candidate, root) {
|
|
190853
|
+
const resolvedCandidate = resolve4(candidate);
|
|
190854
|
+
const resolvedRoot = resolve4(root);
|
|
190855
|
+
const boundary = resolvedRoot.endsWith(sep2) ? resolvedRoot : `${resolvedRoot}${sep2}`;
|
|
190856
|
+
return resolvedCandidate === resolvedRoot || resolvedCandidate.startsWith(boundary);
|
|
190857
|
+
}
|
|
190858
|
+
|
|
190859
|
+
// src/audit/stateRoot.ts
|
|
190860
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
190861
|
+
var UNSAFE_DIRECTORY_MODE = 18;
|
|
190862
|
+
var STICKY_DIRECTORY_MODE = 512;
|
|
190863
|
+
var AUDIT_WARNING_DIRECTORY_IGNORED = "AUDIT_DIRECTORY_IGNORED: Audit directory is invalid; using the default logical directory.";
|
|
190864
|
+
var AUDIT_WARNING_UNSUPPORTED_PLATFORM = "AUDIT_DISABLED_UNSUPPORTED_PLATFORM: Audit trace writing is unavailable on this platform.";
|
|
190865
|
+
var AUDIT_WARNING_UNSUPPORTED_CAPABILITY = "AUDIT_DISABLED_UNSUPPORTED_CAPABILITY: Audit trace writing requires unavailable filesystem capabilities.";
|
|
190866
|
+
var AUDIT_WARNING_UNSAFE_STATE_ROOT = "AUDIT_DISABLED_UNSAFE_STATE_ROOT: Audit state root could not be verified.";
|
|
190867
|
+
async function resolveAuditStateRoot(options) {
|
|
190868
|
+
const warnings = [];
|
|
190869
|
+
const logicalDirectory = validateAuditDirectory(options.directory, warnings);
|
|
190870
|
+
const platform = options.platform ?? process.platform;
|
|
190871
|
+
if (platform === "win32") {
|
|
190872
|
+
return { warnings: [...warnings, AUDIT_WARNING_UNSUPPORTED_PLATFORM] };
|
|
190873
|
+
}
|
|
190874
|
+
const uid = getCurrentUid(options.getuid);
|
|
190875
|
+
if (uid === undefined) {
|
|
190876
|
+
return { warnings: [...warnings, AUDIT_WARNING_UNSUPPORTED_CAPABILITY] };
|
|
190877
|
+
}
|
|
190878
|
+
try {
|
|
190879
|
+
const workspaceRoot = await realpath2(resolve5(options.cwd));
|
|
190880
|
+
const candidate = resolveStateBaseCandidate(options.env ?? process.env);
|
|
190881
|
+
if (!candidate)
|
|
190882
|
+
throw new Error("missing trusted state base");
|
|
190883
|
+
const stateBase = await ensureTrustedStateBase({
|
|
190884
|
+
candidate,
|
|
190885
|
+
workspaceRoot,
|
|
190886
|
+
uid
|
|
190887
|
+
});
|
|
190888
|
+
const kyosoRoot = await ensureTrustedDirectory({
|
|
190889
|
+
root: stateBase,
|
|
190890
|
+
segments: ["kyoso"],
|
|
190891
|
+
uid,
|
|
190892
|
+
workspaceRoot
|
|
190893
|
+
});
|
|
190894
|
+
return {
|
|
190895
|
+
stateBase,
|
|
190896
|
+
kyosoRoot,
|
|
190897
|
+
workspaceRoot,
|
|
190898
|
+
workspaceHash: createHash2("sha256").update(workspaceRoot).digest("hex"),
|
|
190899
|
+
logicalDirectory,
|
|
190900
|
+
uid,
|
|
190901
|
+
warnings
|
|
190902
|
+
};
|
|
190903
|
+
} catch {
|
|
190904
|
+
return { warnings: [...warnings, AUDIT_WARNING_UNSAFE_STATE_ROOT] };
|
|
190905
|
+
}
|
|
190906
|
+
}
|
|
190907
|
+
async function ensureTrustedDirectory(options) {
|
|
190908
|
+
const realRoot = await realpath2(options.root);
|
|
190909
|
+
assertSafeDirectory(realRoot, options.uid, await lstat(realRoot));
|
|
190910
|
+
if (options.workspaceRoot && isPathWithin(realRoot, options.workspaceRoot)) {
|
|
190911
|
+
throw new Error("trusted directory resolves inside workspace");
|
|
190912
|
+
}
|
|
190913
|
+
await assertTrustedAncestorChain(realRoot, options.uid);
|
|
190914
|
+
let current = realRoot;
|
|
190915
|
+
for (const segment of options.segments) {
|
|
190916
|
+
if (!isSafePathSegment(segment))
|
|
190917
|
+
throw new Error("unsafe path segment");
|
|
190918
|
+
const next = join3(current, segment);
|
|
190919
|
+
let entry = await optionalLstat(next);
|
|
190920
|
+
if (!entry) {
|
|
190921
|
+
await createDirectory(next);
|
|
190922
|
+
entry = await lstat(next);
|
|
190923
|
+
}
|
|
190924
|
+
assertSafeDirectory(next, options.uid, entry);
|
|
190925
|
+
const realNext = await realpath2(next);
|
|
190926
|
+
if (!isPathWithin(realNext, realRoot)) {
|
|
190927
|
+
throw new Error("managed directory escaped trusted root");
|
|
190928
|
+
}
|
|
190929
|
+
if (options.workspaceRoot && isPathWithin(realNext, options.workspaceRoot)) {
|
|
190930
|
+
throw new Error("managed directory resolves inside workspace");
|
|
190931
|
+
}
|
|
190932
|
+
current = realNext;
|
|
190933
|
+
}
|
|
190934
|
+
return current;
|
|
190935
|
+
}
|
|
190936
|
+
function isResolvedAuditStateRoot(resolution) {
|
|
190937
|
+
return "kyosoRoot" in resolution;
|
|
190938
|
+
}
|
|
190939
|
+
function validateAuditDirectory(directory, warnings) {
|
|
190940
|
+
try {
|
|
190941
|
+
if (directory.trim().length === 0 || isAbsolute2(directory) || directory.split(/[\\/]+/).includes("..")) {
|
|
190942
|
+
throw new Error("unsafe logical directory");
|
|
190943
|
+
}
|
|
190944
|
+
const normalized = normalizeRelativePath(directory);
|
|
190945
|
+
if (normalized === "." || normalized.split("/").includes("..")) {
|
|
190946
|
+
throw new Error("unsafe logical directory");
|
|
190947
|
+
}
|
|
190948
|
+
return normalized;
|
|
190949
|
+
} catch {
|
|
190950
|
+
warnings.push(AUDIT_WARNING_DIRECTORY_IGNORED);
|
|
190951
|
+
return TRACE_DIR;
|
|
190952
|
+
}
|
|
190953
|
+
}
|
|
190954
|
+
function resolveStateBaseCandidate(env) {
|
|
190955
|
+
const xdgStateHome = env.XDG_STATE_HOME?.trim();
|
|
190956
|
+
if (xdgStateHome && isAbsolute2(xdgStateHome)) {
|
|
190957
|
+
return resolve5(xdgStateHome);
|
|
190958
|
+
}
|
|
190959
|
+
const home = env.HOME?.trim();
|
|
190960
|
+
if (!home || !isAbsolute2(home))
|
|
190961
|
+
return;
|
|
190962
|
+
return join3(resolve5(home), ".local", "state");
|
|
190963
|
+
}
|
|
190964
|
+
async function ensureTrustedStateBase(options) {
|
|
190965
|
+
if (isPathWithin(options.candidate, options.workspaceRoot)) {
|
|
190966
|
+
throw new Error("state base is inside workspace");
|
|
190967
|
+
}
|
|
190968
|
+
const existing = await findExistingAncestor(options.candidate);
|
|
190969
|
+
assertSafeDirectory(existing.path, options.uid, await lstat(existing.path), {
|
|
190970
|
+
allowFilesystemRoot: true
|
|
190971
|
+
});
|
|
190972
|
+
const realExisting = await realpath2(existing.path);
|
|
190973
|
+
if (isPathWithin(realExisting, options.workspaceRoot)) {
|
|
190974
|
+
throw new Error("state base resolves inside workspace");
|
|
190975
|
+
}
|
|
190976
|
+
await assertTrustedAncestorChain(realExisting, options.uid);
|
|
190977
|
+
let current = realExisting;
|
|
190978
|
+
for (const segment of existing.missingSegments) {
|
|
190979
|
+
current = join3(current, segment);
|
|
190980
|
+
await createDirectory(current);
|
|
190981
|
+
const entry = await lstat(current);
|
|
190982
|
+
assertSafeDirectory(current, options.uid, entry);
|
|
190983
|
+
const realCurrent = await realpath2(current);
|
|
190984
|
+
if (!isPathWithin(realCurrent, realExisting)) {
|
|
190985
|
+
throw new Error("state base changed while being created");
|
|
190986
|
+
}
|
|
190987
|
+
if (isPathWithin(realCurrent, options.workspaceRoot)) {
|
|
190988
|
+
throw new Error("state base resolves inside workspace");
|
|
190989
|
+
}
|
|
190990
|
+
current = realCurrent;
|
|
190991
|
+
}
|
|
190992
|
+
const stateBase = await realpath2(current);
|
|
190993
|
+
assertSafeDirectory(stateBase, options.uid, await lstat(stateBase));
|
|
190994
|
+
if (isPathWithin(stateBase, options.workspaceRoot)) {
|
|
190995
|
+
throw new Error("state base resolves inside workspace");
|
|
190996
|
+
}
|
|
190997
|
+
await assertTrustedAncestorChain(stateBase, options.uid);
|
|
190998
|
+
return stateBase;
|
|
190999
|
+
}
|
|
191000
|
+
async function findExistingAncestor(candidate) {
|
|
191001
|
+
let current = resolve5(candidate);
|
|
191002
|
+
const missingSegments = [];
|
|
191003
|
+
while (true) {
|
|
191004
|
+
const entry = await optionalLstat(current);
|
|
191005
|
+
if (entry) {
|
|
191006
|
+
if (entry.isSymbolicLink() || !entry.isDirectory()) {
|
|
191007
|
+
throw new Error("state base ancestor is unsafe");
|
|
191008
|
+
}
|
|
191009
|
+
return { path: current, missingSegments };
|
|
191010
|
+
}
|
|
191011
|
+
const parent = dirname3(current);
|
|
191012
|
+
if (parent === current)
|
|
191013
|
+
throw new Error("state base has no existing ancestor");
|
|
191014
|
+
missingSegments.unshift(basename(current));
|
|
191015
|
+
current = parent;
|
|
191016
|
+
}
|
|
191017
|
+
}
|
|
191018
|
+
function assertSafeDirectory(path, uid, entry, options = {}) {
|
|
191019
|
+
const stat = entry;
|
|
191020
|
+
if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
191021
|
+
throw new Error("state directory is unsafe");
|
|
191022
|
+
}
|
|
191023
|
+
if (numericStatValue(stat.uid) !== uid && !(options.allowFilesystemRoot && isFilesystemRoot(path))) {
|
|
191024
|
+
throw new Error("state directory owner is unsafe");
|
|
191025
|
+
}
|
|
191026
|
+
const mode = numericStatValue(stat.mode);
|
|
191027
|
+
if ((mode & UNSAFE_DIRECTORY_MODE) !== 0) {
|
|
191028
|
+
throw new Error("state directory mode is unsafe");
|
|
191029
|
+
}
|
|
191030
|
+
}
|
|
191031
|
+
function numericStatValue(value) {
|
|
191032
|
+
return typeof value === "number" ? value : Number(value);
|
|
191033
|
+
}
|
|
191034
|
+
function getCurrentUid(getuid) {
|
|
191035
|
+
const resolveUid = getuid ?? (typeof process.getuid === "function" ? process.getuid.bind(process) : undefined);
|
|
191036
|
+
try {
|
|
191037
|
+
const uid = resolveUid?.();
|
|
191038
|
+
return typeof uid === "number" && Number.isInteger(uid) && uid >= 0 ? uid : undefined;
|
|
191039
|
+
} catch {
|
|
191040
|
+
return;
|
|
191041
|
+
}
|
|
191042
|
+
}
|
|
191043
|
+
function isFilesystemRoot(path) {
|
|
191044
|
+
return dirname3(path) === path;
|
|
191045
|
+
}
|
|
191046
|
+
async function assertTrustedAncestorChain(path, uid) {
|
|
191047
|
+
let child = path;
|
|
191048
|
+
while (!isFilesystemRoot(child)) {
|
|
191049
|
+
const parent = dirname3(child);
|
|
191050
|
+
const [parentStat, childStat] = await Promise.all([
|
|
191051
|
+
lstat(parent),
|
|
191052
|
+
lstat(child)
|
|
191053
|
+
]);
|
|
191054
|
+
if (parentStat.isSymbolicLink() || !parentStat.isDirectory()) {
|
|
191055
|
+
throw new Error("state directory ancestor is unsafe");
|
|
191056
|
+
}
|
|
191057
|
+
const parentMode = numericStatValue(parentStat.mode);
|
|
191058
|
+
const parentUid = numericStatValue(parentStat.uid);
|
|
191059
|
+
const childUid = numericStatValue(childStat.uid);
|
|
191060
|
+
const parentWritableByOthers = (parentMode & UNSAFE_DIRECTORY_MODE) !== 0;
|
|
191061
|
+
const stickyChildEntry = (parentMode & STICKY_DIRECTORY_MODE) !== 0 && childUid === uid;
|
|
191062
|
+
if (parentUid !== uid && parentUid !== 0 || parentWritableByOthers && !stickyChildEntry) {
|
|
191063
|
+
throw new Error("state directory ancestor permissions are unsafe");
|
|
191064
|
+
}
|
|
191065
|
+
child = parent;
|
|
191066
|
+
}
|
|
191067
|
+
}
|
|
191068
|
+
function isSafePathSegment(segment) {
|
|
191069
|
+
return segment.length > 0 && segment !== "." && segment !== ".." && !segment.includes("/") && !segment.includes("\\");
|
|
191070
|
+
}
|
|
191071
|
+
async function optionalLstat(path) {
|
|
191072
|
+
try {
|
|
191073
|
+
return await lstat(path);
|
|
191074
|
+
} catch (error51) {
|
|
191075
|
+
if (isMissingPathError3(error51))
|
|
191076
|
+
return;
|
|
191077
|
+
throw error51;
|
|
191078
|
+
}
|
|
191079
|
+
}
|
|
191080
|
+
async function createDirectory(path) {
|
|
191081
|
+
try {
|
|
191082
|
+
await mkdir2(path, { mode: PRIVATE_DIRECTORY_MODE });
|
|
191083
|
+
} catch (error51) {
|
|
191084
|
+
if (!isAlreadyExistsError(error51))
|
|
191085
|
+
throw error51;
|
|
191086
|
+
}
|
|
191087
|
+
}
|
|
191088
|
+
function isMissingPathError3(error51) {
|
|
191089
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
|
|
191090
|
+
}
|
|
191091
|
+
function isAlreadyExistsError(error51) {
|
|
191092
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "EEXIST";
|
|
191093
|
+
}
|
|
191094
|
+
|
|
191095
|
+
// src/audit/safeTraceFile.ts
|
|
191096
|
+
import { constants } from "node:fs";
|
|
191097
|
+
import { lstat as lstat2, open, realpath as realpath3, stat } from "node:fs/promises";
|
|
191098
|
+
import { join as join4 } from "node:path";
|
|
191099
|
+
var AUDIT_WARNING_UNSUPPORTED_OPEN_CAPABILITY = "AUDIT_DISABLED_UNSUPPORTED_CAPABILITY: Audit trace writing requires unavailable filesystem capabilities.";
|
|
191100
|
+
async function openVerifiedTraceFile(options) {
|
|
191101
|
+
const flags = secureOpenFlags(options.openConstants);
|
|
191102
|
+
if (flags === undefined)
|
|
191103
|
+
throw new Error("secure open capability unavailable");
|
|
191104
|
+
if (!isSafeTraceId(options.traceId))
|
|
191105
|
+
throw new Error("unsafe trace id");
|
|
191106
|
+
const traceDirectory = await ensureTrustedDirectory({
|
|
191107
|
+
root: options.kyosoRoot,
|
|
191108
|
+
segments: [
|
|
191109
|
+
"workspaces",
|
|
191110
|
+
options.workspaceHash,
|
|
191111
|
+
...options.logicalDirectory.split("/"),
|
|
191112
|
+
options.date
|
|
191113
|
+
],
|
|
191114
|
+
uid: options.uid,
|
|
191115
|
+
workspaceRoot: options.workspaceRoot
|
|
191116
|
+
});
|
|
191117
|
+
const tracePath = join4(traceDirectory, `${options.traceId}.jsonl`);
|
|
191118
|
+
if (await optionalLstat2(tracePath)) {
|
|
191119
|
+
throw new Error("trace path already exists");
|
|
191120
|
+
}
|
|
191121
|
+
await options.beforeOpen?.(tracePath);
|
|
191122
|
+
const handle = await open(tracePath, flags, 384);
|
|
191123
|
+
try {
|
|
191124
|
+
const [handleStat, pathStat, realTracePath] = await Promise.all([
|
|
191125
|
+
handle.stat({ bigint: true }),
|
|
191126
|
+
stat(tracePath, { bigint: true }),
|
|
191127
|
+
realpath3(tracePath)
|
|
191128
|
+
]);
|
|
191129
|
+
if (!handleStat.isFile() || !pathStat.isFile() || handleStat.dev !== pathStat.dev || handleStat.ino !== pathStat.ino || !isPathWithin(realTracePath, options.kyosoRoot)) {
|
|
191130
|
+
throw new Error("trace file identity could not be verified");
|
|
191131
|
+
}
|
|
191132
|
+
return { handle, tracePath };
|
|
191133
|
+
} catch (error51) {
|
|
191134
|
+
try {
|
|
191135
|
+
await handle.close();
|
|
191136
|
+
} catch {}
|
|
191137
|
+
throw error51;
|
|
191138
|
+
}
|
|
191139
|
+
}
|
|
191140
|
+
function secureOpenFlags(provided) {
|
|
191141
|
+
const openConstants = provided ?? constants;
|
|
191142
|
+
const required2 = [
|
|
191143
|
+
openConstants.O_CREAT,
|
|
191144
|
+
openConstants.O_EXCL,
|
|
191145
|
+
openConstants.O_APPEND,
|
|
191146
|
+
openConstants.O_WRONLY,
|
|
191147
|
+
openConstants.O_NOFOLLOW,
|
|
191148
|
+
openConstants.O_NONBLOCK
|
|
191149
|
+
];
|
|
191150
|
+
if (required2.some((flag) => typeof flag !== "number" || flag <= 0)) {
|
|
191151
|
+
return;
|
|
191152
|
+
}
|
|
191153
|
+
return required2.reduce((combined, flag) => combined | flag, 0);
|
|
191154
|
+
}
|
|
191155
|
+
function isSafeTraceId(traceId) {
|
|
191156
|
+
return traceId.length > 0 && traceId !== "." && traceId !== ".." && !traceId.includes("/") && !traceId.includes("\\");
|
|
191157
|
+
}
|
|
191158
|
+
async function optionalLstat2(path) {
|
|
191159
|
+
try {
|
|
191160
|
+
return await lstat2(path);
|
|
191161
|
+
} catch (error51) {
|
|
191162
|
+
if (typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT") {
|
|
191163
|
+
return;
|
|
191164
|
+
}
|
|
191165
|
+
throw error51;
|
|
191166
|
+
}
|
|
191167
|
+
}
|
|
191168
|
+
|
|
190689
191169
|
// src/audit/sanitize.ts
|
|
190690
191170
|
function sanitizeForAudit(value, options = {}) {
|
|
190691
191171
|
if (typeof value === "string")
|
|
@@ -190706,46 +191186,149 @@ function sanitizeForAudit(value, options = {}) {
|
|
|
190706
191186
|
}
|
|
190707
191187
|
|
|
190708
191188
|
// src/audit/trace.ts
|
|
191189
|
+
var AUDIT_WARNING_WRITE_FAILED = "AUDIT_WRITE_FAILED: Audit trace writing failed; no further audit events will be written.";
|
|
191190
|
+
var AUDIT_WARNING_FINALIZE_FAILED = "AUDIT_FINALIZE_FAILED: Audit trace close failed.";
|
|
191191
|
+
var AUDIT_WARNING_WRITE_AFTER_FINALIZE = "AUDIT_WRITE_AFTER_FINALIZE: Audit trace is already finalized.";
|
|
190709
191192
|
function createTraceWriter(options) {
|
|
190710
191193
|
const warnings = [];
|
|
190711
|
-
|
|
190712
|
-
return {
|
|
190713
|
-
warnings,
|
|
190714
|
-
async write() {
|
|
190715
|
-
return;
|
|
190716
|
-
}
|
|
190717
|
-
};
|
|
190718
|
-
}
|
|
191194
|
+
const warningSet = new Set;
|
|
190719
191195
|
const date5 = new Date().toISOString().slice(0, 10);
|
|
190720
|
-
|
|
190721
|
-
|
|
191196
|
+
let tracePath;
|
|
191197
|
+
let handle;
|
|
191198
|
+
let disabled = !options.enabled;
|
|
191199
|
+
let finalizing = false;
|
|
191200
|
+
let finalized = false;
|
|
191201
|
+
let queue = Promise.resolve();
|
|
191202
|
+
let finalizePromise;
|
|
191203
|
+
const addWarning = (warning) => {
|
|
191204
|
+
if (warningSet.has(warning))
|
|
191205
|
+
return;
|
|
191206
|
+
warningSet.add(warning);
|
|
191207
|
+
warnings.push(warning);
|
|
191208
|
+
};
|
|
191209
|
+
const closeHandle = async () => {
|
|
191210
|
+
const current = handle;
|
|
191211
|
+
handle = undefined;
|
|
191212
|
+
if (!current)
|
|
191213
|
+
return;
|
|
191214
|
+
try {
|
|
191215
|
+
await (options.closeHandle ?? defaultCloseHandle)(current);
|
|
191216
|
+
} catch {
|
|
191217
|
+
addWarning(AUDIT_WARNING_FINALIZE_FAILED);
|
|
191218
|
+
}
|
|
191219
|
+
};
|
|
191220
|
+
const disableAfterWriteFailure = async () => {
|
|
191221
|
+
disabled = true;
|
|
191222
|
+
addWarning(AUDIT_WARNING_WRITE_FAILED);
|
|
191223
|
+
await closeHandle();
|
|
191224
|
+
};
|
|
191225
|
+
const openIfNeeded = async () => {
|
|
191226
|
+
if (handle || disabled)
|
|
191227
|
+
return;
|
|
191228
|
+
if (secureOpenFlags(options.openConstants) === undefined) {
|
|
191229
|
+
disabled = true;
|
|
191230
|
+
addWarning(AUDIT_WARNING_UNSUPPORTED_OPEN_CAPABILITY);
|
|
191231
|
+
return;
|
|
191232
|
+
}
|
|
191233
|
+
const stateRoot = await resolveAuditStateRoot({
|
|
191234
|
+
cwd: options.cwd,
|
|
191235
|
+
directory: options.directory,
|
|
191236
|
+
env: options.env,
|
|
191237
|
+
platform: options.platform,
|
|
191238
|
+
getuid: options.getuid
|
|
191239
|
+
});
|
|
191240
|
+
for (const warning of stateRoot.warnings)
|
|
191241
|
+
addWarning(warning);
|
|
191242
|
+
if (!isResolvedAuditStateRoot(stateRoot)) {
|
|
191243
|
+
disabled = true;
|
|
191244
|
+
return;
|
|
191245
|
+
}
|
|
191246
|
+
try {
|
|
191247
|
+
const opened = await openVerifiedTraceFile({
|
|
191248
|
+
kyosoRoot: stateRoot.kyosoRoot,
|
|
191249
|
+
workspaceHash: stateRoot.workspaceHash,
|
|
191250
|
+
logicalDirectory: stateRoot.logicalDirectory,
|
|
191251
|
+
date: date5,
|
|
191252
|
+
traceId: options.traceId,
|
|
191253
|
+
uid: stateRoot.uid,
|
|
191254
|
+
workspaceRoot: stateRoot.workspaceRoot,
|
|
191255
|
+
openConstants: options.openConstants,
|
|
191256
|
+
beforeOpen: options.beforeOpen
|
|
191257
|
+
});
|
|
191258
|
+
handle = opened.handle;
|
|
191259
|
+
tracePath = opened.tracePath;
|
|
191260
|
+
} catch {
|
|
191261
|
+
disabled = true;
|
|
191262
|
+
addWarning(AUDIT_WARNING_WRITE_FAILED);
|
|
191263
|
+
}
|
|
191264
|
+
};
|
|
191265
|
+
const writeOne = async (event) => {
|
|
191266
|
+
if (disabled)
|
|
191267
|
+
return;
|
|
191268
|
+
try {
|
|
191269
|
+
await openIfNeeded();
|
|
191270
|
+
if (disabled || !handle)
|
|
191271
|
+
return;
|
|
191272
|
+
const line = Buffer.from(`${JSON.stringify(sanitizeForAudit(event, {
|
|
191273
|
+
includeRawAgentOutput: options.includeRawAgentOutput
|
|
191274
|
+
}))}
|
|
191275
|
+
`, "utf8");
|
|
191276
|
+
await writeFully(handle, line, options.writeChunk);
|
|
191277
|
+
} catch {
|
|
191278
|
+
await disableAfterWriteFailure();
|
|
191279
|
+
}
|
|
191280
|
+
};
|
|
190722
191281
|
return {
|
|
190723
|
-
tracePath
|
|
191282
|
+
get tracePath() {
|
|
191283
|
+
return tracePath;
|
|
191284
|
+
},
|
|
190724
191285
|
warnings,
|
|
190725
|
-
|
|
190726
|
-
|
|
190727
|
-
|
|
190728
|
-
|
|
190729
|
-
|
|
190730
|
-
|
|
190731
|
-
|
|
190732
|
-
|
|
190733
|
-
|
|
190734
|
-
|
|
191286
|
+
write(event) {
|
|
191287
|
+
if (finalizing || finalized) {
|
|
191288
|
+
addWarning(AUDIT_WARNING_WRITE_AFTER_FINALIZE);
|
|
191289
|
+
return Promise.resolve();
|
|
191290
|
+
}
|
|
191291
|
+
const task = queue.then(() => writeOne(event));
|
|
191292
|
+
queue = task.catch(async () => {
|
|
191293
|
+
await disableAfterWriteFailure();
|
|
191294
|
+
});
|
|
191295
|
+
return task.catch(() => {
|
|
191296
|
+
return;
|
|
191297
|
+
});
|
|
191298
|
+
},
|
|
191299
|
+
finalize() {
|
|
191300
|
+
if (finalizePromise)
|
|
191301
|
+
return finalizePromise;
|
|
191302
|
+
finalizing = true;
|
|
191303
|
+
finalizePromise = queue.then(async () => {
|
|
191304
|
+
await closeHandle();
|
|
191305
|
+
finalized = true;
|
|
191306
|
+
}).catch(() => {
|
|
191307
|
+
disabled = true;
|
|
191308
|
+
addWarning(AUDIT_WARNING_FINALIZE_FAILED);
|
|
191309
|
+
finalized = true;
|
|
191310
|
+
});
|
|
191311
|
+
return finalizePromise;
|
|
190735
191312
|
}
|
|
190736
191313
|
};
|
|
190737
191314
|
}
|
|
190738
|
-
function
|
|
190739
|
-
|
|
190740
|
-
|
|
190741
|
-
|
|
191315
|
+
async function writeFully(handle, buffer, writeChunk) {
|
|
191316
|
+
let offset = 0;
|
|
191317
|
+
while (offset < buffer.byteLength) {
|
|
191318
|
+
const bytesWritten = await (writeChunk ?? defaultWriteChunk)(handle, buffer, offset);
|
|
191319
|
+
if (!Number.isInteger(bytesWritten) || bytesWritten <= 0) {
|
|
191320
|
+
throw new Error("partial audit write could not advance");
|
|
190742
191321
|
}
|
|
190743
|
-
|
|
190744
|
-
} catch {
|
|
190745
|
-
warnings.push(`Unsafe audit directory ignored: ${directory}`);
|
|
190746
|
-
return ".kyoso/traces";
|
|
191322
|
+
offset += bytesWritten;
|
|
190747
191323
|
}
|
|
190748
191324
|
}
|
|
191325
|
+
async function defaultWriteChunk(handle, buffer, offset) {
|
|
191326
|
+
const { bytesWritten } = await handle.write(buffer, offset, buffer.byteLength - offset, null);
|
|
191327
|
+
return bytesWritten;
|
|
191328
|
+
}
|
|
191329
|
+
async function defaultCloseHandle(handle) {
|
|
191330
|
+
await handle.close();
|
|
191331
|
+
}
|
|
190749
191332
|
|
|
190750
191333
|
// src/context/truncate.ts
|
|
190751
191334
|
function truncateUtf8(input, maxBytes) {
|
|
@@ -191019,7 +191602,7 @@ function parseJudgeOutput(text, fallbackSummaryText) {
|
|
|
191019
191602
|
const parsed = JSON.parse(json2);
|
|
191020
191603
|
const summaryText = typeof parsed.summaryText === "string" && parsed.summaryText.trim().length > 0 ? sanitizeText(parsed.summaryText) : fallbackSummaryText;
|
|
191021
191604
|
const disagreementComments = Array.isArray(parsed.disagreementComments) ? parsed.disagreementComments.flatMap((item) => {
|
|
191022
|
-
if (!
|
|
191605
|
+
if (!isRecord7(item) || typeof item.topic !== "string" || typeof item.judgeComment !== "string") {
|
|
191023
191606
|
return [];
|
|
191024
191607
|
}
|
|
191025
191608
|
return [
|
|
@@ -191035,7 +191618,7 @@ function parseJudgeOutput(text, fallbackSummaryText) {
|
|
|
191035
191618
|
return { summaryText, disagreementComments, analysis };
|
|
191036
191619
|
}
|
|
191037
191620
|
function parseAnalysis(value) {
|
|
191038
|
-
if (!
|
|
191621
|
+
if (!isRecord7(value))
|
|
191039
191622
|
return;
|
|
191040
191623
|
if (!Array.isArray(value.blindSpots) || !Array.isArray(value.contradictions) || !Array.isArray(value.partialCoverage)) {
|
|
191041
191624
|
return;
|
|
@@ -191043,7 +191626,7 @@ function parseAnalysis(value) {
|
|
|
191043
191626
|
return {
|
|
191044
191627
|
blindSpots: value.blindSpots.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => typeof item === "string" ? [sanitizeAnalysisText(item)] : []),
|
|
191045
191628
|
contradictions: value.contradictions.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => {
|
|
191046
|
-
if (!
|
|
191629
|
+
if (!isRecord7(item) || typeof item.topic !== "string" || typeof item.detail !== "string") {
|
|
191047
191630
|
return [];
|
|
191048
191631
|
}
|
|
191049
191632
|
return [
|
|
@@ -191054,7 +191637,7 @@ function parseAnalysis(value) {
|
|
|
191054
191637
|
];
|
|
191055
191638
|
}),
|
|
191056
191639
|
partialCoverage: value.partialCoverage.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => {
|
|
191057
|
-
if (!
|
|
191640
|
+
if (!isRecord7(item) || typeof item.note !== "string")
|
|
191058
191641
|
return [];
|
|
191059
191642
|
const findingId = typeof item.findingId === "string" ? sanitizeAnalysisText(item.findingId) : undefined;
|
|
191060
191643
|
return [
|
|
@@ -191101,7 +191684,7 @@ function extractFirstJsonObject2(text) {
|
|
|
191101
191684
|
}
|
|
191102
191685
|
return;
|
|
191103
191686
|
}
|
|
191104
|
-
function
|
|
191687
|
+
function isRecord7(value) {
|
|
191105
191688
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
191106
191689
|
}
|
|
191107
191690
|
|
|
@@ -191437,12 +192020,12 @@ function decide(input) {
|
|
|
191437
192020
|
|
|
191438
192021
|
// src/workspace/createSnapshot.ts
|
|
191439
192022
|
import { chmod, mkdir as mkdir3, mkdtemp, writeFile as writeFile2 } from "node:fs/promises";
|
|
191440
|
-
import { dirname as dirname4, join as
|
|
192023
|
+
import { dirname as dirname4, join as join5 } from "node:path";
|
|
191441
192024
|
import { tmpdir } from "node:os";
|
|
191442
192025
|
async function createSnapshot(traceId, tool, request, options = {}) {
|
|
191443
|
-
const root = await mkdtemp(
|
|
191444
|
-
const repoDir =
|
|
191445
|
-
const contextDir =
|
|
192026
|
+
const root = await mkdtemp(join5(tmpdir(), `kyoso-${traceId}-`));
|
|
192027
|
+
const repoDir = join5(root, "repo");
|
|
192028
|
+
const contextDir = join5(root, "context");
|
|
191446
192029
|
await mkdir3(repoDir, { recursive: true });
|
|
191447
192030
|
await mkdir3(contextDir, { recursive: true });
|
|
191448
192031
|
let fileCount = 0;
|
|
@@ -191452,7 +192035,7 @@ async function createSnapshot(traceId, tool, request, options = {}) {
|
|
|
191452
192035
|
continue;
|
|
191453
192036
|
if (!isAllowedPath(relative2, options.allowPatterns ?? []))
|
|
191454
192037
|
continue;
|
|
191455
|
-
const dest =
|
|
192038
|
+
const dest = join5(repoDir, relative2);
|
|
191456
192039
|
await mkdir3(dirname4(dest), { recursive: true });
|
|
191457
192040
|
await writeFile2(dest, file2.content, "utf8");
|
|
191458
192041
|
await chmod(dest, 292).catch(() => {
|
|
@@ -191460,16 +192043,16 @@ async function createSnapshot(traceId, tool, request, options = {}) {
|
|
|
191460
192043
|
});
|
|
191461
192044
|
fileCount += 1;
|
|
191462
192045
|
}
|
|
191463
|
-
await writeFile2(
|
|
191464
|
-
await writeFile2(
|
|
191465
|
-
await writeFile2(
|
|
191466
|
-
await writeFile2(
|
|
192046
|
+
await writeFile2(join5(contextDir, "request.json"), JSON.stringify(stripContents(request), null, 2), "utf8");
|
|
192047
|
+
await writeFile2(join5(contextDir, "selected_files_manifest.json"), JSON.stringify(buildSelectedFilesManifest(request), null, 2), "utf8");
|
|
192048
|
+
await writeFile2(join5(contextDir, "instructions.codex.md"), buildAgentPrompt(tool, request, "codex", options.agentRoles?.codex ?? "implementation_reviewer"), "utf8");
|
|
192049
|
+
await writeFile2(join5(contextDir, "instructions.claude.md"), buildAgentPrompt(tool, request, "claude", options.agentRoles?.claude ?? "architecture_security_reviewer"), "utf8");
|
|
191467
192050
|
if (request.repoSummary)
|
|
191468
|
-
await writeFile2(
|
|
192051
|
+
await writeFile2(join5(contextDir, "repo_summary.md"), request.repoSummary, "utf8");
|
|
191469
192052
|
if (request.currentPlan)
|
|
191470
|
-
await writeFile2(
|
|
192053
|
+
await writeFile2(join5(contextDir, "current_plan.md"), request.currentPlan, "utf8");
|
|
191471
192054
|
if (request.diff?.unifiedDiff)
|
|
191472
|
-
await writeFile2(
|
|
192055
|
+
await writeFile2(join5(contextDir, "diff.patch"), request.diff.unifiedDiff, "utf8");
|
|
191473
192056
|
return { root, repoDir, contextDir, fileCount };
|
|
191474
192057
|
}
|
|
191475
192058
|
function stripContents(request) {
|
|
@@ -191559,7 +192142,7 @@ function parseVerificationVerdicts(rawText) {
|
|
|
191559
192142
|
if (!Array.isArray(parsed.verdicts))
|
|
191560
192143
|
return;
|
|
191561
192144
|
return parsed.verdicts.flatMap((item) => {
|
|
191562
|
-
if (!
|
|
192145
|
+
if (!isRecord8(item))
|
|
191563
192146
|
return [];
|
|
191564
192147
|
if (typeof item.findingId !== "string")
|
|
191565
192148
|
return [];
|
|
@@ -191637,7 +192220,7 @@ function verificationNote(reasoning) {
|
|
|
191637
192220
|
function isVerdict(value) {
|
|
191638
192221
|
return value === "confirmed" || value === "refuted" || value === "uncertain";
|
|
191639
192222
|
}
|
|
191640
|
-
function
|
|
192223
|
+
function isRecord8(value) {
|
|
191641
192224
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
191642
192225
|
}
|
|
191643
192226
|
|
|
@@ -191646,47 +192229,54 @@ async function runReview(tool, request, options = {}) {
|
|
|
191646
192229
|
const cwd = options.cwd ?? process.cwd();
|
|
191647
192230
|
const traceId = newTraceId();
|
|
191648
192231
|
const startedAt = new Date().toISOString();
|
|
192232
|
+
const auditEnv = { ...process.env, ...options.env };
|
|
192233
|
+
const traceWriterFactory = options.traceWriterFactory ?? createTraceWriter;
|
|
191649
192234
|
let snapshot;
|
|
191650
192235
|
try {
|
|
191651
192236
|
assertNotChildAgent(options.env ?? process.env);
|
|
191652
192237
|
} catch (error51) {
|
|
191653
192238
|
if (error51 instanceof KyosoRequestError) {
|
|
191654
192239
|
const config2 = kyosoConfigSchema.parse(defaultConfig);
|
|
191655
|
-
const trace2 =
|
|
192240
|
+
const trace2 = traceWriterFactory({
|
|
191656
192241
|
enabled: config2.audit.enabled,
|
|
191657
192242
|
directory: config2.audit.directory,
|
|
191658
192243
|
traceId,
|
|
191659
|
-
cwd
|
|
191660
|
-
|
|
191661
|
-
await trace2.write({
|
|
191662
|
-
type: "request_received",
|
|
191663
|
-
traceId,
|
|
191664
|
-
tool,
|
|
191665
|
-
timestamp: new Date().toISOString()
|
|
191666
|
-
});
|
|
191667
|
-
return await buildPolicyBlockResult({
|
|
191668
|
-
tool,
|
|
191669
|
-
trace: trace2,
|
|
191670
|
-
traceId,
|
|
191671
|
-
startedAt,
|
|
191672
|
-
networkMode: config2.network.defaultMode,
|
|
191673
|
-
warning: error51.message,
|
|
191674
|
-
finding: {
|
|
191675
|
-
id: "KYOSO-1",
|
|
191676
|
-
severity: "critical",
|
|
191677
|
-
category: "other",
|
|
191678
|
-
title: "Recursive Kyoso invocation blocked",
|
|
191679
|
-
evidence: error51.message,
|
|
191680
|
-
recommendation: "Do not expose Kyoso MCP tools to Kyoso child agents.",
|
|
191681
|
-
sourceAgents: ["kyoso_policy"],
|
|
191682
|
-
confidence: "high"
|
|
191683
|
-
},
|
|
191684
|
-
redactionsApplied: 0
|
|
192244
|
+
cwd,
|
|
192245
|
+
env: auditEnv
|
|
191685
192246
|
});
|
|
192247
|
+
try {
|
|
192248
|
+
await trace2.write({
|
|
192249
|
+
type: "request_received",
|
|
192250
|
+
traceId,
|
|
192251
|
+
tool,
|
|
192252
|
+
timestamp: new Date().toISOString()
|
|
192253
|
+
});
|
|
192254
|
+
return await buildPolicyBlockResult({
|
|
192255
|
+
tool,
|
|
192256
|
+
trace: trace2,
|
|
192257
|
+
traceId,
|
|
192258
|
+
startedAt,
|
|
192259
|
+
networkMode: config2.network.defaultMode,
|
|
192260
|
+
warning: error51.message,
|
|
192261
|
+
finding: {
|
|
192262
|
+
id: "KYOSO-1",
|
|
192263
|
+
severity: "critical",
|
|
192264
|
+
category: "other",
|
|
192265
|
+
title: "Recursive Kyoso invocation blocked",
|
|
192266
|
+
evidence: error51.message,
|
|
192267
|
+
recommendation: "Do not expose Kyoso MCP tools to Kyoso child agents.",
|
|
192268
|
+
sourceAgents: ["kyoso_policy"],
|
|
192269
|
+
confidence: "high"
|
|
192270
|
+
},
|
|
192271
|
+
redactionsApplied: 0
|
|
192272
|
+
});
|
|
192273
|
+
} finally {
|
|
192274
|
+
await trace2.finalize();
|
|
192275
|
+
}
|
|
191686
192276
|
}
|
|
191687
192277
|
throw error51;
|
|
191688
192278
|
}
|
|
191689
|
-
const
|
|
192279
|
+
const baseLoaded = options.config !== undefined ? {
|
|
191690
192280
|
config: options.config,
|
|
191691
192281
|
configHash: options.configHash,
|
|
191692
192282
|
configTrustStatus: "trusted",
|
|
@@ -191703,12 +192293,17 @@ async function runReview(tool, request, options = {}) {
|
|
|
191703
192293
|
env: options.env,
|
|
191704
192294
|
trustPrompt: options.trustPrompt
|
|
191705
192295
|
});
|
|
191706
|
-
const
|
|
192296
|
+
const loaded = options.configOverrides && options.configOverrides.length > 0 ? {
|
|
192297
|
+
...baseLoaded,
|
|
192298
|
+
config: applyConfigOverrides(baseLoaded.config, options.configOverrides)
|
|
192299
|
+
} : baseLoaded;
|
|
192300
|
+
const trace = traceWriterFactory({
|
|
191707
192301
|
enabled: loaded.config.audit.enabled,
|
|
191708
192302
|
directory: loaded.config.audit.directory,
|
|
191709
192303
|
traceId,
|
|
191710
192304
|
cwd,
|
|
191711
|
-
includeRawAgentOutput: loaded.config.audit.includeRawAgentOutput
|
|
192305
|
+
includeRawAgentOutput: loaded.config.audit.includeRawAgentOutput,
|
|
192306
|
+
env: auditEnv
|
|
191712
192307
|
});
|
|
191713
192308
|
const warnings = [...loaded.warnings, ...trace.warnings];
|
|
191714
192309
|
try {
|
|
@@ -191790,11 +192385,11 @@ async function runReview(tool, request, options = {}) {
|
|
|
191790
192385
|
manager,
|
|
191791
192386
|
trace
|
|
191792
192387
|
});
|
|
191793
|
-
warnings.push(...agentResults.flatMap((
|
|
192388
|
+
warnings.push(...agentResults.flatMap((result) => (result.warnings ?? []).map((warning) => `Agent ${result.agent} ${warning}`)));
|
|
191794
192389
|
const normalizedAgentResults = agentResults.map(normalizeAgentRunResult);
|
|
191795
|
-
const agentsUsed = normalizedAgentResults.map((
|
|
192390
|
+
const agentsUsed = normalizedAgentResults.map((result) => result.agent);
|
|
191796
192391
|
const reviewMode = agentsUsed.length === 1 ? "single_agent" : "multi_agent";
|
|
191797
|
-
const completed = normalizedAgentResults.filter((
|
|
192392
|
+
const completed = normalizedAgentResults.filter((result) => result.status === "completed");
|
|
191798
192393
|
const degraded = completed.length !== agentResults.length;
|
|
191799
192394
|
let aggregate = aggregateAgentResults(normalizedAgentResults, {
|
|
191800
192395
|
reviewMode
|
|
@@ -191821,7 +192416,7 @@ async function runReview(tool, request, options = {}) {
|
|
|
191821
192416
|
severity: "critical",
|
|
191822
192417
|
category: "other",
|
|
191823
192418
|
title: "All backend agents failed",
|
|
191824
|
-
evidence: normalizedAgentResults.map((
|
|
192419
|
+
evidence: normalizedAgentResults.map((result) => `${result.agent}: ${result.error?.code ?? result.status}`).join("; "),
|
|
191825
192420
|
recommendation: "Run kyoso doctor and retry after agent authentication or adapter issues are fixed.",
|
|
191826
192421
|
sourceAgents: ["kyoso_policy"],
|
|
191827
192422
|
confidence: "high"
|
|
@@ -191871,7 +192466,7 @@ async function runReview(tool, request, options = {}) {
|
|
|
191871
192466
|
residualRisks: tool === "security_review" && aggregate.residualRisks.length === 0 ? [
|
|
191872
192467
|
"No residual risks were reported by completed agents; verify security assumptions before release."
|
|
191873
192468
|
] : aggregate.residualRisks,
|
|
191874
|
-
agentOpinions: normalizedAgentResults.map((
|
|
192469
|
+
agentOpinions: normalizedAgentResults.map((result) => agentOpinionSummary(result, request.options?.includeAgentRawOutputs === true)),
|
|
191875
192470
|
audit: {
|
|
191876
192471
|
traceId,
|
|
191877
192472
|
startedAt,
|
|
@@ -191903,15 +192498,10 @@ async function runReview(tool, request, options = {}) {
|
|
|
191903
192498
|
judgeComment: judgeComments.get(disagreement.topic) ?? disagreement.judgeComment
|
|
191904
192499
|
}));
|
|
191905
192500
|
const crossModelAnalysis = buildCrossModelAnalysis(judge, reviewMode);
|
|
191906
|
-
const
|
|
192501
|
+
const resultAfterJudge = {
|
|
191907
192502
|
...resultWithoutMarkdown,
|
|
191908
192503
|
disagreements,
|
|
191909
|
-
...crossModelAnalysis ? { crossModelAnalysis } : {}
|
|
191910
|
-
summaryMarkdown: renderMarkdownResult(tool, {
|
|
191911
|
-
...resultWithoutMarkdown,
|
|
191912
|
-
disagreements,
|
|
191913
|
-
...crossModelAnalysis ? { crossModelAnalysis } : {}
|
|
191914
|
-
}, { summaryText: judge.output.summaryText })
|
|
192504
|
+
...crossModelAnalysis ? { crossModelAnalysis } : {}
|
|
191915
192505
|
};
|
|
191916
192506
|
const judgeEvent = {
|
|
191917
192507
|
type: "judge_completed",
|
|
@@ -191923,7 +192513,7 @@ async function runReview(tool, request, options = {}) {
|
|
|
191923
192513
|
if (judge.error)
|
|
191924
192514
|
judgeEvent.error = judge.error;
|
|
191925
192515
|
await trace.write(judgeEvent);
|
|
191926
|
-
|
|
192516
|
+
resultAfterJudge.audit.completedAt = new Date().toISOString();
|
|
191927
192517
|
await trace.write({
|
|
191928
192518
|
type: "decision_completed",
|
|
191929
192519
|
traceId,
|
|
@@ -191935,8 +192525,14 @@ async function runReview(tool, request, options = {}) {
|
|
|
191935
192525
|
traceId,
|
|
191936
192526
|
timestamp: new Date().toISOString()
|
|
191937
192527
|
});
|
|
191938
|
-
return
|
|
192528
|
+
return await finalizeReviewResult({
|
|
192529
|
+
tool,
|
|
192530
|
+
trace,
|
|
192531
|
+
result: resultAfterJudge,
|
|
192532
|
+
summaryText: judge.output.summaryText
|
|
192533
|
+
});
|
|
191939
192534
|
} finally {
|
|
192535
|
+
await trace.finalize();
|
|
191940
192536
|
if (snapshot)
|
|
191941
192537
|
await cleanupSnapshot(snapshot.root);
|
|
191942
192538
|
}
|
|
@@ -192185,10 +192781,6 @@ async function buildSecretBlockResult(input) {
|
|
|
192185
192781
|
warnings: input.warnings
|
|
192186
192782
|
}
|
|
192187
192783
|
};
|
|
192188
|
-
const result = {
|
|
192189
|
-
...resultWithoutMarkdown,
|
|
192190
|
-
summaryMarkdown: renderMarkdownResult(input.tool, resultWithoutMarkdown)
|
|
192191
|
-
};
|
|
192192
192784
|
await input.trace.write({
|
|
192193
192785
|
type: "decision_completed",
|
|
192194
192786
|
traceId: input.traceId,
|
|
@@ -192200,7 +192792,11 @@ async function buildSecretBlockResult(input) {
|
|
|
192200
192792
|
traceId: input.traceId,
|
|
192201
192793
|
timestamp: new Date().toISOString()
|
|
192202
192794
|
});
|
|
192203
|
-
return
|
|
192795
|
+
return await finalizeReviewResult({
|
|
192796
|
+
tool: input.tool,
|
|
192797
|
+
trace: input.trace,
|
|
192798
|
+
result: resultWithoutMarkdown
|
|
192799
|
+
});
|
|
192204
192800
|
}
|
|
192205
192801
|
function buildSecretFinding(secretScan, options) {
|
|
192206
192802
|
return {
|
|
@@ -192250,10 +192846,6 @@ async function buildPolicyBlockResult(input) {
|
|
|
192250
192846
|
warnings: [input.warning]
|
|
192251
192847
|
}
|
|
192252
192848
|
};
|
|
192253
|
-
const result = {
|
|
192254
|
-
...resultWithoutMarkdown,
|
|
192255
|
-
summaryMarkdown: renderMarkdownResult(input.tool, resultWithoutMarkdown)
|
|
192256
|
-
};
|
|
192257
192849
|
await input.trace.write({
|
|
192258
192850
|
type: "decision_completed",
|
|
192259
192851
|
traceId: input.traceId,
|
|
@@ -192265,7 +192857,30 @@ async function buildPolicyBlockResult(input) {
|
|
|
192265
192857
|
traceId: input.traceId,
|
|
192266
192858
|
timestamp: new Date().toISOString()
|
|
192267
192859
|
});
|
|
192268
|
-
return
|
|
192860
|
+
return await finalizeReviewResult({
|
|
192861
|
+
tool: input.tool,
|
|
192862
|
+
trace: input.trace,
|
|
192863
|
+
result: resultWithoutMarkdown
|
|
192864
|
+
});
|
|
192865
|
+
}
|
|
192866
|
+
async function finalizeReviewResult(input) {
|
|
192867
|
+
await input.trace.finalize();
|
|
192868
|
+
const result = {
|
|
192869
|
+
...input.result,
|
|
192870
|
+
audit: {
|
|
192871
|
+
...input.result.audit,
|
|
192872
|
+
warnings: Array.from(new Set([
|
|
192873
|
+
...input.result.audit.warnings ?? [],
|
|
192874
|
+
...input.trace.warnings
|
|
192875
|
+
]))
|
|
192876
|
+
}
|
|
192877
|
+
};
|
|
192878
|
+
return {
|
|
192879
|
+
...result,
|
|
192880
|
+
summaryMarkdown: renderMarkdownResult(input.tool, result, {
|
|
192881
|
+
summaryText: input.summaryText
|
|
192882
|
+
})
|
|
192883
|
+
};
|
|
192269
192884
|
}
|
|
192270
192885
|
function mergeDenyPatterns(configDeny, requestDeny) {
|
|
192271
192886
|
return Array.from(new Set([...configDeny, ...requestDeny ?? []]));
|
|
@@ -192273,7 +192888,7 @@ function mergeDenyPatterns(configDeny, requestDeny) {
|
|
|
192273
192888
|
function assertTrustedWorkspaceRoot(requestRoot, configRoot, cwd) {
|
|
192274
192889
|
if (!requestRoot)
|
|
192275
192890
|
return;
|
|
192276
|
-
if (
|
|
192891
|
+
if (resolve6(cwd, requestRoot) !== resolve6(cwd, configRoot)) {
|
|
192277
192892
|
throw new KyosoRequestError("workspace.root is not trusted by config", "UNTRUSTED_WORKSPACE_ROOT");
|
|
192278
192893
|
}
|
|
192279
192894
|
}
|