dsh-pentester 2.2.0 → 2.3.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/README.md +54 -6
- package/agents/vulnerability/profile.yml +6 -3
- package/lib/build-id.json +1 -1
- package/lib/client.js +668 -165
- package/lib/client.js.map +3 -3
- package/lib/index.js +97 -38
- package/lib/index.js.map +1 -1
- package/package.json +5 -3
package/lib/index.js
CHANGED
|
@@ -1050,7 +1050,7 @@ function readJsonFile(file) {
|
|
|
1050
1050
|
return;
|
|
1051
1051
|
}
|
|
1052
1052
|
}
|
|
1053
|
-
function readJsonArray(file) {
|
|
1053
|
+
function readJsonArray$1(file) {
|
|
1054
1054
|
const parsed = readJsonFile(file);
|
|
1055
1055
|
if (Array.isArray(parsed)) return parsed.filter((entry) => entry !== null && typeof entry === "object");
|
|
1056
1056
|
return [];
|
|
@@ -1066,7 +1066,7 @@ async function promoteAssets(ctx, stage, delegationDirs, delegationIds) {
|
|
|
1066
1066
|
const assetMap = /* @__PURE__ */ new Map();
|
|
1067
1067
|
for (let index = 0; index < delegationDirs.length; index += 1) {
|
|
1068
1068
|
const delegationId = delegationIds[index] ?? `D-${String(index + 1).padStart(3, "0")}`;
|
|
1069
|
-
const entries = readJsonArray(join(delegationDirs[index], "assets.json"));
|
|
1069
|
+
const entries = readJsonArray$1(join(delegationDirs[index], "artifacts", "assets.json"));
|
|
1070
1070
|
for (const entry of entries) {
|
|
1071
1071
|
const key = assetKey(entry);
|
|
1072
1072
|
if (key === "") continue;
|
|
@@ -1082,7 +1082,7 @@ async function promoteAssets(ctx, stage, delegationDirs, delegationIds) {
|
|
|
1082
1082
|
const serviceMap = /* @__PURE__ */ new Map();
|
|
1083
1083
|
for (let index = 0; index < delegationDirs.length; index += 1) {
|
|
1084
1084
|
const delegationId = delegationIds[index] ?? `D-${String(index + 1).padStart(3, "0")}`;
|
|
1085
|
-
const entries = readJsonArray(join(delegationDirs[index], "services.json"));
|
|
1085
|
+
const entries = readJsonArray$1(join(delegationDirs[index], "artifacts", "services.json"));
|
|
1086
1086
|
for (const entry of entries) {
|
|
1087
1087
|
const key = serviceKey(entry);
|
|
1088
1088
|
if (key === "") continue;
|
|
@@ -1115,46 +1115,92 @@ async function promoteAssets(ctx, stage, delegationDirs, delegationIds) {
|
|
|
1115
1115
|
*/
|
|
1116
1116
|
/**
|
|
1117
1117
|
* Aggregate findings from every delegation directory in the completed stage,
|
|
1118
|
-
* index them in `findings/findings.json`, and write each
|
|
1119
|
-
* as `findings/<
|
|
1118
|
+
* index them in `findings/findings.json`, and write each finding's detail
|
|
1119
|
+
* as `findings/<findingId>-findings.md` with a provenance header.
|
|
1120
1120
|
*
|
|
1121
|
-
*
|
|
1122
|
-
*
|
|
1121
|
+
* Worker contract:
|
|
1122
|
+
* artifacts/findings.json — structured array of finding entries
|
|
1123
|
+
* artifacts/findings.md — human-readable detail (used as fallback if
|
|
1124
|
+
* no structured entries exist)
|
|
1123
1125
|
*/
|
|
1124
1126
|
async function promoteFindings(ctx, stage, delegationDirs, delegationIds) {
|
|
1125
1127
|
const root = ctx.targetRoot;
|
|
1126
1128
|
const findingsDir = join(root, "findings");
|
|
1127
1129
|
await mkdir(findingsDir, { recursive: true });
|
|
1128
1130
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1129
|
-
const entries = [];
|
|
1130
1131
|
const existingIndex = loadExistingIndex(findingsDir);
|
|
1132
|
+
const entries = [];
|
|
1133
|
+
const touchedDelegationIds = /* @__PURE__ */ new Set();
|
|
1131
1134
|
for (let index = 0; index < delegationDirs.length; index += 1) {
|
|
1132
1135
|
const delegationId = delegationIds[index] ?? `D-${String(index + 1).padStart(3, "0")}`;
|
|
1133
1136
|
const delegationDir = delegationDirs[index];
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1137
|
+
touchedDelegationIds.add(delegationId);
|
|
1138
|
+
const structuredFile = join(delegationDir, "artifacts", "findings.json");
|
|
1139
|
+
const detailFile = join(delegationDir, "artifacts", "findings.md");
|
|
1140
|
+
const structured = readJsonArray(structuredFile);
|
|
1141
|
+
if (structured.length > 0) for (const entry of structured) {
|
|
1142
|
+
const findingId = typeof entry.id === "string" && entry.id.length > 0 ? entry.id : `${delegationId}-${crypto.randomUUID().slice(0, 8)}`;
|
|
1143
|
+
const title = typeof entry.title === "string" && entry.title.length > 0 ? entry.title : findingId;
|
|
1144
|
+
const severity = typeof entry.severity === "string" ? entry.severity : "info";
|
|
1145
|
+
const affectedAsset = typeof entry.affectedAsset === "string" && entry.affectedAsset.length > 0 ? entry.affectedAsset : void 0;
|
|
1146
|
+
const confidence = typeof entry.confidence === "string" && entry.confidence.length > 0 ? entry.confidence : void 0;
|
|
1147
|
+
const detailFileName = `${findingId}-findings.md`;
|
|
1148
|
+
const detailPath = join(findingsDir, detailFileName);
|
|
1149
|
+
let body = "";
|
|
1150
|
+
if (existsSync(detailFile)) body = readFileSync(detailFile, "utf8").trim();
|
|
1151
|
+
if (body === "") {
|
|
1152
|
+
body = `# ${title}\n\n**Severity**: ${severity}\n\n${affectedAsset !== void 0 ? `**Affected Asset**: ${affectedAsset}\n\n` : ""}`;
|
|
1153
|
+
if (typeof entry.description === "string" && entry.description.length > 0) body += `${entry.description}\n`;
|
|
1154
|
+
}
|
|
1155
|
+
await writeFile(detailPath, `# ${title}\n\n**Source Stage**: ${stage}\n**Source Delegation**: ${delegationId}\n**Updated**: ${updatedAt}\n\n---\n\n${body}\n`, "utf8");
|
|
1156
|
+
entries.push({
|
|
1157
|
+
id: findingId,
|
|
1158
|
+
title,
|
|
1159
|
+
severity,
|
|
1160
|
+
...affectedAsset !== void 0 ? { affectedAsset } : {},
|
|
1161
|
+
...confidence !== void 0 ? { confidence } : {},
|
|
1162
|
+
sourceDelegationId: delegationId,
|
|
1163
|
+
sourceStage: stage,
|
|
1164
|
+
detailFile: detailFileName,
|
|
1165
|
+
updatedAt
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
else if (existsSync(detailFile)) {
|
|
1169
|
+
const content = readFileSync(detailFile, "utf8").trim();
|
|
1170
|
+
if (content !== "") {
|
|
1171
|
+
const detailFileName = `${delegationId}-findings.md`;
|
|
1172
|
+
const detailPath = join(findingsDir, detailFileName);
|
|
1173
|
+
await writeFile(detailPath, `# ${delegationId} Findings\n\n**Source Stage**: ${stage}\n**Updated**: ${updatedAt}\n\n---\n\n${content}\n`, "utf8");
|
|
1174
|
+
entries.push({
|
|
1175
|
+
id: delegationId,
|
|
1176
|
+
title: `${delegationId} Findings`,
|
|
1177
|
+
severity: "info",
|
|
1178
|
+
sourceDelegationId: delegationId,
|
|
1179
|
+
sourceStage: stage,
|
|
1180
|
+
detailFile: detailFileName,
|
|
1181
|
+
updatedAt
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1153
1185
|
}
|
|
1154
|
-
for (const [id, entry] of existingIndex) if (!
|
|
1155
|
-
entries.sort((a, b) =>
|
|
1186
|
+
for (const [id, entry] of existingIndex) if (!touchedDelegationIds.has(entry.sourceDelegationId)) entries.push(entry);
|
|
1187
|
+
entries.sort((a, b) => {
|
|
1188
|
+
const cmp = a.sourceDelegationId.localeCompare(b.sourceDelegationId);
|
|
1189
|
+
if (cmp !== 0) return cmp;
|
|
1190
|
+
return a.id.localeCompare(b.id);
|
|
1191
|
+
});
|
|
1156
1192
|
if (entries.length > 0) await writeFile(join(findingsDir, "findings.json"), `${JSON.stringify(entries, null, 2)}\n`, "utf8");
|
|
1157
1193
|
}
|
|
1194
|
+
function readJsonArray(file) {
|
|
1195
|
+
if (!existsSync(file)) return [];
|
|
1196
|
+
try {
|
|
1197
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
1198
|
+
if (Array.isArray(parsed)) return parsed.filter((entry) => entry !== null && typeof entry === "object");
|
|
1199
|
+
return [];
|
|
1200
|
+
} catch {
|
|
1201
|
+
return [];
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1158
1204
|
function loadExistingIndex(findingsDir) {
|
|
1159
1205
|
const file = join(findingsDir, "findings.json");
|
|
1160
1206
|
if (!existsSync(file)) return /* @__PURE__ */ new Map();
|
|
@@ -1162,9 +1208,10 @@ function loadExistingIndex(findingsDir) {
|
|
|
1162
1208
|
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
1163
1209
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Map();
|
|
1164
1210
|
const map = /* @__PURE__ */ new Map();
|
|
1165
|
-
for (const entry of parsed) if (entry !== null && typeof entry === "object"
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1211
|
+
for (const entry of parsed) if (entry !== null && typeof entry === "object") {
|
|
1212
|
+
const e = entry;
|
|
1213
|
+
const id = typeof e.id === "string" ? e.id : "";
|
|
1214
|
+
if (id !== "") map.set(id, e);
|
|
1168
1215
|
}
|
|
1169
1216
|
return map;
|
|
1170
1217
|
} catch {
|
|
@@ -3474,17 +3521,29 @@ async function parseFindingsIndex(ctx) {
|
|
|
3474
3521
|
const raw = await readFile(indexFile, "utf8");
|
|
3475
3522
|
const entries = JSON.parse(raw);
|
|
3476
3523
|
if (!Array.isArray(entries)) return [];
|
|
3524
|
+
const validSeverities = /* @__PURE__ */ new Set([
|
|
3525
|
+
"critical",
|
|
3526
|
+
"high",
|
|
3527
|
+
"medium",
|
|
3528
|
+
"low",
|
|
3529
|
+
"info"
|
|
3530
|
+
]);
|
|
3477
3531
|
return entries.filter((e) => e !== null && typeof e === "object").map((e) => {
|
|
3478
3532
|
const detailFile = typeof e.detailFile === "string" ? e.detailFile : "";
|
|
3479
|
-
const
|
|
3533
|
+
const fallbackId = detailFile.replace(/-findings\.md$/, "");
|
|
3534
|
+
const id = typeof e.id === "string" && e.id.length > 0 ? e.id : fallbackId;
|
|
3535
|
+
const rawSeverity = typeof e.severity === "string" ? e.severity : "";
|
|
3536
|
+
const severity = validSeverities.has(rawSeverity) ? rawSeverity : "info";
|
|
3480
3537
|
return {
|
|
3481
3538
|
id,
|
|
3482
|
-
title: id,
|
|
3483
|
-
severity
|
|
3539
|
+
title: typeof e.title === "string" && e.title.length > 0 ? e.title : id,
|
|
3540
|
+
severity,
|
|
3484
3541
|
sourceStage: typeof e.sourceStage === "string" ? e.sourceStage : "",
|
|
3485
3542
|
sourceDelegationId: typeof e.sourceDelegationId === "string" ? e.sourceDelegationId : "",
|
|
3486
3543
|
detailFile,
|
|
3487
|
-
updatedAt: typeof e.updatedAt === "string" ? e.updatedAt : ""
|
|
3544
|
+
updatedAt: typeof e.updatedAt === "string" ? e.updatedAt : "",
|
|
3545
|
+
...typeof e.affectedAsset === "string" && e.affectedAsset.length > 0 ? { affectedAsset: e.affectedAsset } : {},
|
|
3546
|
+
...typeof e.confidence === "string" && e.confidence.length > 0 ? { confidence: e.confidence } : {}
|
|
3488
3547
|
};
|
|
3489
3548
|
});
|
|
3490
3549
|
} catch {
|
|
@@ -4074,9 +4133,9 @@ async function resolveBinding(deps, sessionId) {
|
|
|
4074
4133
|
* Generated by scripts/build-id.mjs before each build.
|
|
4075
4134
|
* Both host (tsdown) and client (esbuild) import this module.
|
|
4076
4135
|
*
|
|
4077
|
-
* Format: version+shortSha
|
|
4136
|
+
* Format: version+shortSha
|
|
4078
4137
|
*/
|
|
4079
|
-
const BUILD_ID = "2.
|
|
4138
|
+
const BUILD_ID = "2.3.0+2a31301";
|
|
4080
4139
|
//#endregion
|
|
4081
4140
|
//#region src/ui-view/invocations.ts
|
|
4082
4141
|
/**
|