0sec-cli 0.22.0 → 0.22.4
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/0.js +56 -45
- package/README.md +12 -0
- package/chunks/{adapt-loop-7I57LXXR.js → adapt-loop-3CCOWE43.js} +4 -4
- package/chunks/{artifact-scraper-PYZ3RU3O.js → artifact-scraper-Z4UUIOH3.js} +2 -2
- package/chunks/{assumption-mining-MFLF43IR.js → assumption-mining-2UAKQB6V.js} +18 -14
- package/chunks/{chunk-RE5EZDG2.js → chunk-2WWAPKAW.js} +126 -1089
- package/chunks/{chunk-LPTRPRZR.js → chunk-3BPX75OR.js} +1 -1
- package/chunks/chunk-4ZYYX5GY.js +74 -0
- package/chunks/{chunk-RSIUX3RW.js → chunk-5JNTMWPK.js} +2 -2
- package/chunks/{chunk-RRD4XXPU.js → chunk-5WAJGLCW.js} +3 -3
- package/chunks/{chunk-76KSBWOQ.js → chunk-6KFB6AYN.js} +515 -20
- package/chunks/{chunk-HR2TU42B.js → chunk-6WQDXWQC.js} +169 -15
- package/chunks/chunk-6YZE552K.js +5603 -0
- package/chunks/chunk-BGX53365.js +309 -0
- package/chunks/{chunk-7DEHG7YT.js → chunk-C6JPA32H.js} +1 -1
- package/chunks/chunk-CF3MNS3O.js +990 -0
- package/chunks/{chunk-4VGLO2YS.js → chunk-CPCHLL6A.js} +5 -2
- package/chunks/{chunk-DM5C5L5D.js → chunk-DPUXXMJW.js} +1 -1
- package/chunks/{chunk-LYUAM3TG.js → chunk-E3OOBVOK.js} +30 -12
- package/chunks/{chunk-HUNAPTKV.js → chunk-E74LXQFY.js} +1 -1
- package/chunks/{chunk-UU7PQP6N.js → chunk-ELI3BVIK.js} +3 -3
- package/chunks/chunk-FFHRANYC.js +547 -0
- package/chunks/{chunk-IO7R7WBM.js → chunk-G2BE2FC7.js} +1 -1
- package/chunks/chunk-GQ3DGHWE.js +1659 -0
- package/chunks/{chunk-V36HVTUL.js → chunk-GVY3S5E5.js} +21 -18
- package/chunks/{chunk-UV5QWZGE.js → chunk-H4DH7COV.js} +192 -40
- package/chunks/{chunk-SJBCK2EI.js → chunk-H6Q2QAIY.js} +23475 -22747
- package/chunks/{chunk-VMRRNRMR.js → chunk-IHPTOTLL.js} +1 -1
- package/chunks/chunk-IXAHQICR.js +31 -0
- package/chunks/{chunk-TH2LW437.js → chunk-KCA35IL3.js} +2 -190
- package/chunks/{chunk-VNRY6AWF.js → chunk-L2CCO4KE.js} +282 -34
- package/chunks/{chunk-6YNKRUMC.js → chunk-NJLKFC66.js} +321 -5
- package/chunks/{chunk-W6UWZFKL.js → chunk-O6KPVYOI.js} +100 -5
- package/chunks/{chunk-EGZGZFAH.js → chunk-OAS5SAVZ.js} +6768 -2100
- package/chunks/chunk-PS5E7LUQ.js +277 -0
- package/chunks/{chunk-2GV4HQKE.js → chunk-QVIRWJ45.js} +257 -145
- package/chunks/{chunk-OWLJYJ5O.js → chunk-QWK4R3DB.js} +9 -9
- package/chunks/{chunk-XFCTUKXR.js → chunk-RCRTSKQN.js} +1 -1
- package/chunks/chunk-RS4MAN3Q.js +73 -0
- package/chunks/{chunk-7UFUALR2.js → chunk-RTBZ36BD.js} +8 -274
- package/chunks/{chunk-TZFIAMWZ.js → chunk-SCWWLABR.js} +1 -1
- package/chunks/chunk-VDOWARMJ.js +63 -0
- package/chunks/{chunk-5MWAG3FT.js → chunk-WBRGXCU2.js} +79 -18
- package/chunks/{chunk-LCRTAQN2.js → chunk-WHUAUFSX.js} +1 -1
- package/chunks/{chunk-YIQSGNAA.js → chunk-XODDLNBI.js} +1535 -1306
- package/chunks/chunk-YAZARMJY.js +355 -0
- package/chunks/{chunk-OAYUPGF6.js → chunk-YED25PA4.js} +1 -1
- package/chunks/{codex-models-7TLJSY3L.js → codex-models-Z43V3427.js} +9 -3
- package/chunks/{commands-NEI7L3QA.js → commands-EUGF4FUZ.js} +5844 -4095
- package/chunks/{db-5AP3JB4W.js → db-NVAW4WWR.js} +3 -3
- package/chunks/{dist-3FNZIBB4.js → dist-27BNG6WD.js} +195 -112
- package/chunks/{dist-5YHYNLI3.js → dist-7RUOKPRJ.js} +12 -2
- package/chunks/{dist-KEULE5IQ.js → dist-LNXGATR2.js} +2 -2
- package/chunks/{dist-XZB53PS5.js → dist-M2X367VW.js} +2 -2
- package/chunks/{dist-DD4H6HMQ.js → dist-NG2HT5XU.js} +27 -1
- package/chunks/{eval-runner-43BO2C4T.js → eval-runner-6Q3H52SP.js} +13 -9
- package/chunks/{exploit-agent-N4A5ELBK.js → exploit-agent-FCCR2HYX.js} +1 -1
- package/chunks/{exploit-autoclimb-N7P6KIF5.js → exploit-autoclimb-X5ZS5FAO.js} +1 -1
- package/chunks/{exploit-climb-WNEJUB5W.js → exploit-climb-3JHGEO36.js} +2 -2
- package/chunks/{fix-Z452M4EC.js → fix-NSNPU33B.js} +12 -6
- package/chunks/{harness-QJJJVSG4.js → harness-KXQOVIDQ.js} +3 -3
- package/chunks/{hunt-scan-K6D2V3PX.js → hunt-scan-ELTKGKC4.js} +16 -12
- package/chunks/{kernel-primitive-TKUACPKD.js → kernel-primitive-MT7YZSIG.js} +2 -2
- package/chunks/{kernel-vm-runner-RAAO2PGT.js → kernel-vm-runner-YFRHYC6G.js} +2 -2
- package/chunks/{native-loop-2ZRJENZ3.js → native-loop-OFJDRHPI.js} +18 -8
- package/chunks/orchestrate-DRZ2SVCP.js +62 -0
- package/chunks/{prepare-KYHGFWCJ.js → prepare-72GWTRVI.js} +6 -2
- package/chunks/{process-N245QIQG.js → process-MJYJ2K5E.js} +2 -1
- package/chunks/{run-U3XU4CTC.js → run-WTJCZZHV.js} +3091 -6037
- package/chunks/{runtime-G75TEWQY.js → runtime-FCKOUB7V.js} +10 -4
- package/chunks/{runtime-XFWJTBUO.js → runtime-LCJ4XSKE.js} +5 -1
- package/chunks/{scan-stream-BMOCPKQX.js → scan-stream-GT6GKQ3U.js} +7 -1
- package/chunks/{scope-WXI46UHJ.js → scope-E5QZUOOH.js} +2 -2
- package/chunks/service-plugins-MSK2EQP6.js +62 -0
- package/chunks/{session-store-27L3ZU73.js → session-store-H3Q7KCYG.js} +6 -4
- package/chunks/{variant-candidates-YWZORZMK.js → variant-candidates-SZKDCOLK.js} +9 -3
- package/chunks/{web-recon-prepass-YVMFXCIK.js → web-recon-prepass-IO3GXQMW.js} +11 -6
- package/dashboard/apple-touch-icon.png +0 -0
- package/dashboard/assets/operations-BvB5Qpmk.css +1 -0
- package/dashboard/assets/operations-D8Ii01SV.js +114 -0
- package/dashboard/assets/zero-peek-Dzm3MT3X.png +0 -0
- package/dashboard/favicon.ico +0 -0
- package/dashboard/favicon.svg +10 -0
- package/dashboard/index.html +5 -3
- package/package.json +1 -1
- package/chunks/chunk-6GHSR47F.js +0 -147
- package/chunks/chunk-CAYANSH6.js +0 -3524
- package/chunks/chunk-GHWODZMR.js +0 -16
- package/chunks/chunk-MICHDTBK.js +0 -193
- package/chunks/orchestrate-2GWGNTBF.js +0 -58
- package/dashboard/assets/bot-Bg1Tp9_d.js +0 -1
- package/dashboard/assets/dist-B_dDCPbu.js +0 -1
- package/dashboard/assets/findings-page-mayGhNx6.js +0 -5
- package/dashboard/assets/format--susmHX7.js +0 -1
- package/dashboard/assets/input-TuVPR3Zl.js +0 -1
- package/dashboard/assets/jsx-runtime-MGseXjj5.js +0 -3
- package/dashboard/assets/live-page-HWWHX99U.js +0 -1
- package/dashboard/assets/meta-tile-ckHo-w7k.js +0 -1
- package/dashboard/assets/operations-BxZ0OoXO.js +0 -10
- package/dashboard/assets/operations-CMFVrXEe.css +0 -2
- package/dashboard/assets/operations-app-D3d35rgo.js +0 -46
- package/dashboard/assets/overview-page-W_4IteEr.js +0 -1
- package/dashboard/assets/page-header-Bw9AJgBV.js +0 -1
- package/dashboard/assets/scans-page-CgzVXHnn.js +0 -1
- package/dashboard/assets/siren-KQj8QAnJ.js +0 -1
- package/dashboard/assets/table-8EDklulN.js +0 -1
- package/dashboard/assets/tabs-CFHPOwg8.js +0 -1
|
@@ -5,6 +5,28 @@ import {
|
|
|
5
5
|
external_exports
|
|
6
6
|
} from "./chunk-VIT5ALXF.js";
|
|
7
7
|
|
|
8
|
+
// packages/shared/dist/types.js
|
|
9
|
+
function validateScanPlan(plan) {
|
|
10
|
+
if (!Number.isInteger(plan.runCount) || plan.runCount < 1) {
|
|
11
|
+
throw new Error("Scan plan runCount must be a positive integer");
|
|
12
|
+
}
|
|
13
|
+
if (plan.depth !== "quick" && plan.depth !== "default" && plan.depth !== "deep") {
|
|
14
|
+
throw new Error(`Unknown scan depth "${String(plan.depth)}"`);
|
|
15
|
+
}
|
|
16
|
+
if (!Number.isFinite(plan.timeCapMs) || plan.timeCapMs <= 0) {
|
|
17
|
+
throw new Error("Scan plan timeCapMs must be a positive finite number");
|
|
18
|
+
}
|
|
19
|
+
if (!Number.isFinite(plan.costCapUsd) || plan.costCapUsd <= 0) {
|
|
20
|
+
throw new Error("Scan plan costCapUsd must be a positive finite number");
|
|
21
|
+
}
|
|
22
|
+
if (plan.executionMode !== "sequential" && plan.executionMode !== "parallel") {
|
|
23
|
+
throw new Error(`Unknown scan execution mode "${String(plan.executionMode)}"`);
|
|
24
|
+
}
|
|
25
|
+
if (plan.goal !== "known-vulnerabilities" && plan.goal !== "unknown-vulnerabilities" && plan.goal !== "misconfigurations") {
|
|
26
|
+
throw new Error(`Unknown scan goal "${String(plan.goal)}"`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
// packages/shared/dist/identity.js
|
|
9
31
|
function defaultRoleFor(auth) {
|
|
10
32
|
return auth ? "user" : "anonymous";
|
|
@@ -45,7 +67,7 @@ import { fileURLToPath } from "node:url";
|
|
|
45
67
|
import { dirname, join } from "node:path";
|
|
46
68
|
function loadVersion() {
|
|
47
69
|
if (true) {
|
|
48
|
-
return "0.22.
|
|
70
|
+
return "0.22.4";
|
|
49
71
|
}
|
|
50
72
|
try {
|
|
51
73
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -224,13 +246,14 @@ var MODEL_PRICING = {
|
|
|
224
246
|
};
|
|
225
247
|
var DISCOVERED_PRICING = /* @__PURE__ */ new Map();
|
|
226
248
|
function registerModelPricing(model, rates) {
|
|
227
|
-
if (!model || model !== model.trim() || /[\s\x00-\x1f\x7f]/.test(model) || Object.hasOwn(MODEL_PRICING, model) || !Number.isFinite(rates.input) || rates.input < 0 || !Number.isFinite(rates.output) || rates.output < 0 || rates.cachedInput !== void 0 && (!Number.isFinite(rates.cachedInput) || rates.cachedInput < 0)) {
|
|
249
|
+
if (!model || model !== model.trim() || /[\s\x00-\x1f\x7f]/.test(model) || Object.hasOwn(MODEL_PRICING, model) || !Number.isFinite(rates.input) || rates.input < 0 || !Number.isFinite(rates.output) || rates.output < 0 || rates.cachedInput !== void 0 && (!Number.isFinite(rates.cachedInput) || rates.cachedInput < 0) || rates.cacheWrite !== void 0 && (!Number.isFinite(rates.cacheWrite) || rates.cacheWrite < 0)) {
|
|
228
250
|
return false;
|
|
229
251
|
}
|
|
230
252
|
DISCOVERED_PRICING.set(model, Object.freeze({
|
|
231
253
|
input: rates.input,
|
|
232
254
|
output: rates.output,
|
|
233
|
-
...rates.cachedInput !== void 0 ? { cachedInput: rates.cachedInput } : {}
|
|
255
|
+
...rates.cachedInput !== void 0 ? { cachedInput: rates.cachedInput } : {},
|
|
256
|
+
...rates.cacheWrite !== void 0 ? { cacheWrite: rates.cacheWrite } : {}
|
|
234
257
|
}));
|
|
235
258
|
return true;
|
|
236
259
|
}
|
|
@@ -302,8 +325,9 @@ function estimateCost(usage, model) {
|
|
|
302
325
|
const rates = getRates(model);
|
|
303
326
|
const cachedInputRate = rates.cachedInput ?? rates.input;
|
|
304
327
|
const cached = usage.cachedInputTokens ?? 0;
|
|
305
|
-
const
|
|
306
|
-
|
|
328
|
+
const writes = usage.cacheWriteTokens ?? 0;
|
|
329
|
+
const uncachedInput = Math.max(0, usage.inputTokens - cached - writes);
|
|
330
|
+
return uncachedInput / 1e6 * rates.input + cached / 1e6 * cachedInputRate + writes / 1e6 * (rates.cacheWrite ?? rates.input * 1.25) + usage.outputTokens / 1e6 * rates.output;
|
|
307
331
|
}
|
|
308
332
|
function priceRun(usage, model) {
|
|
309
333
|
return estimateCost(usage, model);
|
|
@@ -367,9 +391,10 @@ function splitCost(usage, model) {
|
|
|
367
391
|
const rates = getRates(model);
|
|
368
392
|
const cachedInputRate = rates.cachedInput ?? rates.input;
|
|
369
393
|
const cached = usage.cachedInputTokens ?? 0;
|
|
370
|
-
const
|
|
394
|
+
const writes = usage.cacheWriteTokens ?? 0;
|
|
395
|
+
const uncachedInput = Math.max(0, usage.inputTokens - cached - writes);
|
|
371
396
|
const split = {
|
|
372
|
-
cost_in: uncachedInput / 1e6 * rates.input,
|
|
397
|
+
cost_in: uncachedInput / 1e6 * rates.input + writes / 1e6 * (rates.cacheWrite ?? rates.input * 1.25),
|
|
373
398
|
cost_out: usage.outputTokens / 1e6 * rates.output
|
|
374
399
|
};
|
|
375
400
|
if (usage.cachedInputTokens !== void 0) {
|
|
@@ -769,27 +794,27 @@ var DANGEROUS_WINDOWS_PRIVILEGES = /* @__PURE__ */ new Set([
|
|
|
769
794
|
"SeTakeOwnershipPrivilege",
|
|
770
795
|
"SeLoadDriverPrivilege"
|
|
771
796
|
]);
|
|
772
|
-
function coherentTokenSnapshot(
|
|
773
|
-
if (typeof
|
|
797
|
+
function coherentTokenSnapshot(token2) {
|
|
798
|
+
if (typeof token2 !== "object" || token2 === null)
|
|
774
799
|
return false;
|
|
775
|
-
const candidate =
|
|
800
|
+
const candidate = token2;
|
|
776
801
|
return TOKEN_ID.test(candidate.tokenId) && SID.test(candidate.userSid) && Number.isSafeInteger(candidate.integrityRid) && candidate.integrityRid >= 0 && ["default", "limited", "full"].includes(candidate.elevationType) && typeof candidate.elevated === "boolean" && ["absent", "deny-only", "enabled"].includes(candidate.adminGroup) && typeof candidate.appContainer === "boolean" && Number.isSafeInteger(candidate.restrictedSidCount) && candidate.restrictedSidCount >= 0 && Array.isArray(candidate.enabledPrivileges) && candidate.enabledPrivileges.length <= 128 && candidate.enabledPrivileges.every((privilege) => typeof privilege === "string" && PRIVILEGE.test(privilege)) && new Set(candidate.enabledPrivileges).size === candidate.enabledPrivileges.length;
|
|
777
802
|
}
|
|
778
803
|
function equalTokenSnapshot(left, right) {
|
|
779
804
|
return left.tokenId === right.tokenId && left.userSid === right.userSid && left.integrityRid === right.integrityRid && left.elevationType === right.elevationType && left.elevated === right.elevated && left.adminGroup === right.adminGroup && left.appContainer === right.appContainer && left.restrictedSidCount === right.restrictedSidCount && left.enabledPrivileges.length === right.enabledPrivileges.length && left.enabledPrivileges.every((privilege, index) => privilege === right.enabledPrivileges[index]);
|
|
780
805
|
}
|
|
781
|
-
function unprivilegedWindowsToken(
|
|
782
|
-
return
|
|
806
|
+
function unprivilegedWindowsToken(token2) {
|
|
807
|
+
return token2.integrityRid <= 8448 && !token2.elevated && token2.elevationType !== "full" && token2.adminGroup !== "enabled" && (token2.appContainer || token2.restrictedSidCount > 0 || token2.adminGroup === "absent") && !token2.enabledPrivileges.some((privilege) => DANGEROUS_WINDOWS_PRIVILEGES.has(privilege));
|
|
783
808
|
}
|
|
784
|
-
function validWindowsStart(startingContext,
|
|
809
|
+
function validWindowsStart(startingContext, token2) {
|
|
785
810
|
if (startingContext === "lpac")
|
|
786
811
|
return false;
|
|
787
812
|
if (startingContext === "standard-user") {
|
|
788
|
-
return !
|
|
813
|
+
return !token2.appContainer && token2.restrictedSidCount === 0;
|
|
789
814
|
}
|
|
790
815
|
if (startingContext === "appcontainer")
|
|
791
|
-
return
|
|
792
|
-
return
|
|
816
|
+
return token2.appContainer;
|
|
817
|
+
return token2.appContainer || token2.restrictedSidCount > 0;
|
|
793
818
|
}
|
|
794
819
|
function validWindowsFinish(principal, start, finish) {
|
|
795
820
|
if (finish.appContainer || finish.restrictedSidCount !== 0)
|
|
@@ -1062,7 +1087,7 @@ var DEFAULT_AUTONOMY_MODE = "yolo";
|
|
|
1062
1087
|
var DEFAULT_ALLOW_MODEL_SELF_EXTENSION = true;
|
|
1063
1088
|
|
|
1064
1089
|
// packages/shared/dist/jev.js
|
|
1065
|
-
var FEATURES = ["browser", "memory", "dedupe", "redteam", "kernel", "crash", "radar", "foxguard"];
|
|
1090
|
+
var FEATURES = ["browser", "memory", "dedupe", "rank", "specialist", "redteam", "kernel", "crash", "radar", "foxguard"];
|
|
1066
1091
|
var INPUT_USD_PER_TOKEN = 0.042 / 1e6;
|
|
1067
1092
|
var MAX_INPUT_TOKENS = 65536;
|
|
1068
1093
|
var REQUEST_RESERVATION_USD = MAX_INPUT_TOKENS * INPUT_USD_PER_TOKEN;
|
|
@@ -1180,8 +1205,8 @@ function createJevEvaluator(config) {
|
|
|
1180
1205
|
rawAnswers = body.answers;
|
|
1181
1206
|
} else {
|
|
1182
1207
|
const [{ experimental_evaluate: evaluate }, { createGateway }] = await Promise.all([
|
|
1183
|
-
import("./dist-
|
|
1184
|
-
import("./dist-
|
|
1208
|
+
import("./dist-LNXGATR2.js"),
|
|
1209
|
+
import("./dist-M2X367VW.js")
|
|
1185
1210
|
]);
|
|
1186
1211
|
signal.throwIfAborted();
|
|
1187
1212
|
const gateway = createGateway({ apiKey: config.apiKey, fetch: fetchImpl });
|
|
@@ -1231,7 +1256,465 @@ function createJevEvaluator(config) {
|
|
|
1231
1256
|
};
|
|
1232
1257
|
}
|
|
1233
1258
|
|
|
1259
|
+
// packages/shared/dist/slash-commands.js
|
|
1260
|
+
var SLASH_COMMANDS = [
|
|
1261
|
+
// ── info ────────────────────────────────────────────────────────────────
|
|
1262
|
+
{
|
|
1263
|
+
name: "help",
|
|
1264
|
+
aliases: ["?", "commands"],
|
|
1265
|
+
category: "info",
|
|
1266
|
+
description: "List commands",
|
|
1267
|
+
usage: "/help [command]"
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
name: "capabilities",
|
|
1271
|
+
aliases: ["caps"],
|
|
1272
|
+
category: "info",
|
|
1273
|
+
description: "What 0 can do and what needs approval",
|
|
1274
|
+
usage: "/capabilities",
|
|
1275
|
+
tuiOnly: true
|
|
1276
|
+
},
|
|
1277
|
+
{
|
|
1278
|
+
name: "status",
|
|
1279
|
+
aliases: [],
|
|
1280
|
+
category: "info",
|
|
1281
|
+
description: "Session status"
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
name: "tools",
|
|
1285
|
+
aliases: [],
|
|
1286
|
+
category: "info",
|
|
1287
|
+
description: "List available tools"
|
|
1288
|
+
},
|
|
1289
|
+
{
|
|
1290
|
+
name: "new-chat",
|
|
1291
|
+
aliases: ["new"],
|
|
1292
|
+
category: "navigation",
|
|
1293
|
+
description: "Start a fresh audit",
|
|
1294
|
+
tuiOnly: true
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
name: "onboard",
|
|
1298
|
+
aliases: [],
|
|
1299
|
+
category: "navigation",
|
|
1300
|
+
description: "Run setup again",
|
|
1301
|
+
tuiOnly: true
|
|
1302
|
+
},
|
|
1303
|
+
// ── session ─────────────────────────────────────────────────────────────
|
|
1304
|
+
{
|
|
1305
|
+
name: "clear",
|
|
1306
|
+
aliases: [],
|
|
1307
|
+
category: "session",
|
|
1308
|
+
description: "Clear the conversation"
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
name: "history",
|
|
1312
|
+
aliases: [],
|
|
1313
|
+
category: "session",
|
|
1314
|
+
description: "Past scans",
|
|
1315
|
+
tuiOnly: true
|
|
1316
|
+
},
|
|
1317
|
+
{
|
|
1318
|
+
name: "findings",
|
|
1319
|
+
aliases: ["finds"],
|
|
1320
|
+
category: "session",
|
|
1321
|
+
description: "Show findings",
|
|
1322
|
+
tuiOnly: true
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
name: "fix",
|
|
1326
|
+
aliases: [],
|
|
1327
|
+
category: "session",
|
|
1328
|
+
description: "Write and test a fix; you approve any PR",
|
|
1329
|
+
usage: "/fix [finding-id] | /fix publish <finding-id> | /fix cancel",
|
|
1330
|
+
tuiOnly: true
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
name: "copy",
|
|
1334
|
+
aliases: ["export", "dump"],
|
|
1335
|
+
category: "session",
|
|
1336
|
+
description: "Copy the conversation",
|
|
1337
|
+
usage: "/copy",
|
|
1338
|
+
tuiOnly: true
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
name: "sessions",
|
|
1342
|
+
aliases: [],
|
|
1343
|
+
category: "session",
|
|
1344
|
+
description: "Switch or resume a conversation",
|
|
1345
|
+
usage: "/sessions",
|
|
1346
|
+
tuiOnly: true
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
name: "explain",
|
|
1350
|
+
aliases: ["eli5"],
|
|
1351
|
+
category: "session",
|
|
1352
|
+
description: "Explain simply",
|
|
1353
|
+
usage: "/explain [topic]",
|
|
1354
|
+
tuiOnly: true
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
name: "feedback",
|
|
1358
|
+
aliases: [],
|
|
1359
|
+
category: "system",
|
|
1360
|
+
description: "Send feedback",
|
|
1361
|
+
usage: "/feedback <message> | /feedback submit <message> | /feedback send | /feedback cancel",
|
|
1362
|
+
tuiOnly: true
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
name: "settings",
|
|
1366
|
+
aliases: ["config", "prefs"],
|
|
1367
|
+
category: "system",
|
|
1368
|
+
description: "Open settings",
|
|
1369
|
+
usage: "/settings",
|
|
1370
|
+
tuiOnly: true
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
name: "keybindings",
|
|
1374
|
+
aliases: ["keys", "keymap"],
|
|
1375
|
+
category: "system",
|
|
1376
|
+
description: "Keyboard shortcuts",
|
|
1377
|
+
usage: "/keybindings",
|
|
1378
|
+
tuiOnly: true
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
name: "theme",
|
|
1382
|
+
aliases: ["themes"],
|
|
1383
|
+
category: "system",
|
|
1384
|
+
description: "Change the colour theme",
|
|
1385
|
+
usage: "/theme [name]",
|
|
1386
|
+
tuiOnly: true
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
name: "model",
|
|
1390
|
+
aliases: ["models"],
|
|
1391
|
+
category: "session",
|
|
1392
|
+
description: "Choose a model",
|
|
1393
|
+
usage: "/model [id]",
|
|
1394
|
+
tuiOnly: true
|
|
1395
|
+
},
|
|
1396
|
+
// ── navigation ──────────────────────────────────────────────────────────
|
|
1397
|
+
{
|
|
1398
|
+
name: "chat",
|
|
1399
|
+
aliases: [],
|
|
1400
|
+
category: "navigation",
|
|
1401
|
+
description: "Back to the conversation",
|
|
1402
|
+
tuiOnly: true
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
name: "launcher",
|
|
1406
|
+
aliases: ["run", "home"],
|
|
1407
|
+
category: "navigation",
|
|
1408
|
+
description: "Scan one target",
|
|
1409
|
+
tuiOnly: true
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
name: "ops",
|
|
1413
|
+
aliases: ["runs"],
|
|
1414
|
+
category: "navigation",
|
|
1415
|
+
description: "Running and recent scans",
|
|
1416
|
+
tuiOnly: true
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
name: "hackstore",
|
|
1420
|
+
aliases: ["store", "market", "marketplace"],
|
|
1421
|
+
category: "navigation",
|
|
1422
|
+
description: "Install extensions and themes",
|
|
1423
|
+
tuiOnly: true
|
|
1424
|
+
},
|
|
1425
|
+
{
|
|
1426
|
+
name: "connect",
|
|
1427
|
+
aliases: [],
|
|
1428
|
+
category: "navigation",
|
|
1429
|
+
description: "Add an API key or sign in",
|
|
1430
|
+
usage: "/connect",
|
|
1431
|
+
tuiOnly: true
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
name: "usage",
|
|
1435
|
+
aliases: ["cost", "tokens"],
|
|
1436
|
+
category: "navigation",
|
|
1437
|
+
description: "Tokens, cost and context",
|
|
1438
|
+
usage: "/usage",
|
|
1439
|
+
tuiOnly: true
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
name: "back",
|
|
1443
|
+
aliases: [],
|
|
1444
|
+
category: "navigation",
|
|
1445
|
+
description: "Previous screen",
|
|
1446
|
+
tuiOnly: true
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
name: "scope",
|
|
1450
|
+
aliases: [],
|
|
1451
|
+
category: "navigation",
|
|
1452
|
+
description: "What 0 is allowed to test",
|
|
1453
|
+
tuiOnly: true
|
|
1454
|
+
},
|
|
1455
|
+
// ── system ──────────────────────────────────────────────────────────────
|
|
1456
|
+
{
|
|
1457
|
+
name: "doctor",
|
|
1458
|
+
aliases: [],
|
|
1459
|
+
category: "system",
|
|
1460
|
+
description: "Check your setup",
|
|
1461
|
+
tuiOnly: true
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
name: "exit",
|
|
1465
|
+
aliases: ["quit"],
|
|
1466
|
+
category: "system",
|
|
1467
|
+
description: "Quit"
|
|
1468
|
+
}
|
|
1469
|
+
];
|
|
1470
|
+
var NAME_INDEX = {};
|
|
1471
|
+
for (const cmd of SLASH_COMMANDS) {
|
|
1472
|
+
NAME_INDEX[cmd.name] = cmd.name;
|
|
1473
|
+
for (const alias of cmd.aliases) {
|
|
1474
|
+
NAME_INDEX[alias] = cmd.name;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
function getCommandByName(name) {
|
|
1478
|
+
const canonical = NAME_INDEX[name];
|
|
1479
|
+
if (!canonical)
|
|
1480
|
+
return void 0;
|
|
1481
|
+
for (const cmd of SLASH_COMMANDS) {
|
|
1482
|
+
if (cmd.name === canonical)
|
|
1483
|
+
return cmd;
|
|
1484
|
+
}
|
|
1485
|
+
return void 0;
|
|
1486
|
+
}
|
|
1487
|
+
function findCommand(input) {
|
|
1488
|
+
const trimmed = input.trimStart();
|
|
1489
|
+
if (!trimmed.startsWith("/")) {
|
|
1490
|
+
return {
|
|
1491
|
+
isSlash: false,
|
|
1492
|
+
command: void 0,
|
|
1493
|
+
rawName: "",
|
|
1494
|
+
args: "",
|
|
1495
|
+
isKnown: false,
|
|
1496
|
+
isUnknown: false
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
const afterSlash = trimmed.slice(1);
|
|
1500
|
+
const spaceIndex = afterSlash.indexOf(" ");
|
|
1501
|
+
const rawName = spaceIndex >= 0 ? afterSlash.slice(0, spaceIndex) : afterSlash;
|
|
1502
|
+
const args = spaceIndex >= 0 ? afterSlash.slice(spaceIndex + 1).trim() : "";
|
|
1503
|
+
const canonical = NAME_INDEX[rawName];
|
|
1504
|
+
if (canonical) {
|
|
1505
|
+
return {
|
|
1506
|
+
isSlash: true,
|
|
1507
|
+
command: canonical,
|
|
1508
|
+
rawName,
|
|
1509
|
+
args,
|
|
1510
|
+
isKnown: true,
|
|
1511
|
+
isUnknown: false
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
return {
|
|
1515
|
+
isSlash: true,
|
|
1516
|
+
command: void 0,
|
|
1517
|
+
rawName,
|
|
1518
|
+
args,
|
|
1519
|
+
isKnown: false,
|
|
1520
|
+
isUnknown: true
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
function filterCommands(query) {
|
|
1524
|
+
const trimmed = query.trim().toLowerCase();
|
|
1525
|
+
if (!trimmed)
|
|
1526
|
+
return [...SLASH_COMMANDS];
|
|
1527
|
+
return SLASH_COMMANDS.filter((cmd) => {
|
|
1528
|
+
if (cmd.name.startsWith(trimmed))
|
|
1529
|
+
return true;
|
|
1530
|
+
return cmd.aliases.some((a) => a.startsWith(trimmed));
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// packages/shared/dist/security-workflows.js
|
|
1535
|
+
var DEFAULT_SECURITY_WORKFLOW_PLAN = Object.freeze({ goal: "known-vulnerabilities", depth: "default", runCount: 1, executionMode: "sequential", timeCapMs: 6e5, costCapUsd: 5 });
|
|
1536
|
+
var identifier = external_exports.string().min(1).max(128).regex(/^[A-Za-z0-9_-]+$/).refine((value) => !["__proto__", "constructor", "prototype"].includes(value), "Reserved identifier.");
|
|
1537
|
+
var planSchema = external_exports.object({
|
|
1538
|
+
goal: external_exports.enum(["known-vulnerabilities", "unknown-vulnerabilities", "misconfigurations"]),
|
|
1539
|
+
depth: external_exports.enum(["quick", "default", "deep"]),
|
|
1540
|
+
runCount: external_exports.number().int().min(1).max(16),
|
|
1541
|
+
executionMode: external_exports.enum(["sequential", "parallel"]),
|
|
1542
|
+
timeCapMs: external_exports.number().int().finite().positive().max(864e5),
|
|
1543
|
+
costCapUsd: external_exports.number().finite().positive().max(1e3)
|
|
1544
|
+
}).strict();
|
|
1545
|
+
var executionSchema = external_exports.object({
|
|
1546
|
+
instructions: external_exports.string().trim().max(16e3),
|
|
1547
|
+
allowedAgentTools: external_exports.array(external_exports.string().trim().min(1).max(128).regex(/^[A-Za-z0-9_.:-]+$/)).max(128).refine((tools) => new Set(tools).size === tools.length, "Agent tool names must be unique.").optional()
|
|
1548
|
+
}).strict();
|
|
1549
|
+
var nodeSchema = external_exports.object({ id: identifier, type: external_exports.enum(["trigger", "audit", "report"]), label: external_exports.string().trim().min(1).max(160), enabled: external_exports.boolean(), plan: planSchema.optional(), execution: executionSchema.optional() }).strict();
|
|
1550
|
+
var SecurityWorkflowInputSchema = external_exports.object({
|
|
1551
|
+
id: identifier.optional(),
|
|
1552
|
+
revision: external_exports.number().int().positive().optional(),
|
|
1553
|
+
name: external_exports.string().trim().min(1).max(160),
|
|
1554
|
+
instructions: external_exports.string().trim().max(16e3),
|
|
1555
|
+
target: external_exports.string().trim().max(4096),
|
|
1556
|
+
nodes: external_exports.array(nodeSchema).min(2).max(16),
|
|
1557
|
+
edges: external_exports.array(external_exports.object({ source: identifier, target: identifier }).strict()).min(1).max(120)
|
|
1558
|
+
}).strict().superRefine((workflow, context) => {
|
|
1559
|
+
const issue = (message) => context.addIssue({ code: external_exports.ZodIssueCode.custom, message });
|
|
1560
|
+
const ids = new Set(workflow.nodes.map((node) => node.id));
|
|
1561
|
+
if (ids.size !== workflow.nodes.length)
|
|
1562
|
+
issue("Workflow node IDs must be unique.");
|
|
1563
|
+
const triggers = workflow.nodes.filter((node) => node.type === "trigger");
|
|
1564
|
+
if (triggers.length !== 1)
|
|
1565
|
+
issue("A workflow requires exactly one trigger.");
|
|
1566
|
+
if (triggers.some((node) => !node.enabled))
|
|
1567
|
+
issue("The manual trigger must remain enabled.");
|
|
1568
|
+
if (!workflow.nodes.some((node) => node.type === "audit"))
|
|
1569
|
+
issue("A workflow requires at least one audit.");
|
|
1570
|
+
if (workflow.nodes.filter((node) => node.type === "report").length > 1)
|
|
1571
|
+
issue("A workflow supports at most one report.");
|
|
1572
|
+
if (workflow.nodes.some((node) => node.type !== "audit" && (node.plan !== void 0 || node.execution !== void 0)))
|
|
1573
|
+
issue("Only audit nodes accept scan plans and execution policies.");
|
|
1574
|
+
const edges = /* @__PURE__ */ new Set();
|
|
1575
|
+
const successors = /* @__PURE__ */ new Map();
|
|
1576
|
+
for (const edge of workflow.edges) {
|
|
1577
|
+
if (!ids.has(edge.source) || !ids.has(edge.target))
|
|
1578
|
+
issue("Edges must reference existing nodes.");
|
|
1579
|
+
const key = `${edge.source}:${edge.target}`;
|
|
1580
|
+
if (edges.has(key))
|
|
1581
|
+
issue("Workflow edges must be unique.");
|
|
1582
|
+
edges.add(key);
|
|
1583
|
+
successors.set(edge.source, [...successors.get(edge.source) ?? [], edge.target]);
|
|
1584
|
+
const source = workflow.nodes.find((node) => node.id === edge.source);
|
|
1585
|
+
const target = workflow.nodes.find((node) => node.id === edge.target);
|
|
1586
|
+
if (target?.type === "trigger" || source?.type === "report")
|
|
1587
|
+
issue("Triggers must start the graph and reports must end it.");
|
|
1588
|
+
}
|
|
1589
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
1590
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1591
|
+
const visit = (id) => {
|
|
1592
|
+
if (visiting.has(id))
|
|
1593
|
+
return false;
|
|
1594
|
+
if (visited.has(id))
|
|
1595
|
+
return true;
|
|
1596
|
+
visiting.add(id);
|
|
1597
|
+
for (const next of successors.get(id) ?? [])
|
|
1598
|
+
if (!visit(next))
|
|
1599
|
+
return false;
|
|
1600
|
+
visiting.delete(id);
|
|
1601
|
+
visited.add(id);
|
|
1602
|
+
return true;
|
|
1603
|
+
};
|
|
1604
|
+
if (workflow.nodes.some((node) => !visit(node.id)))
|
|
1605
|
+
issue("Workflow graphs cannot contain cycles.");
|
|
1606
|
+
if (triggers.length === 1) {
|
|
1607
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
1608
|
+
const walk = (id) => {
|
|
1609
|
+
if (reachable.has(id))
|
|
1610
|
+
return;
|
|
1611
|
+
reachable.add(id);
|
|
1612
|
+
for (const next of successors.get(id) ?? [])
|
|
1613
|
+
walk(next);
|
|
1614
|
+
};
|
|
1615
|
+
walk(triggers[0].id);
|
|
1616
|
+
if (workflow.nodes.some((node) => !reachable.has(node.id)))
|
|
1617
|
+
issue("Every node must be reachable from the trigger.");
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
function parseSecurityWorkflowInput(value) {
|
|
1621
|
+
const workflow = SecurityWorkflowInputSchema.parse(value);
|
|
1622
|
+
return { ...workflow, nodes: workflow.nodes.map((node) => node.type === "audit" ? { ...node, plan: node.plan ?? { ...DEFAULT_SECURITY_WORKFLOW_PLAN } } : node) };
|
|
1623
|
+
}
|
|
1624
|
+
var codeEnvelope = external_exports.object({ schemaVersion: external_exports.literal(1), workflow: external_exports.unknown() }).strict();
|
|
1625
|
+
function exportSecurityWorkflowCode(value) {
|
|
1626
|
+
const { name, instructions, target, nodes, edges } = value;
|
|
1627
|
+
const parsed = parseSecurityWorkflowInput({ name, instructions, target, nodes, edges });
|
|
1628
|
+
const json = JSON.stringify({ schemaVersion: 1, workflow: parsed }, null, 2);
|
|
1629
|
+
if (new TextEncoder().encode(json).byteLength > 65536)
|
|
1630
|
+
throw new Error("Workflow JSON must be at most 64 KiB.");
|
|
1631
|
+
return json;
|
|
1632
|
+
}
|
|
1633
|
+
function parseSecurityWorkflowCode(value) {
|
|
1634
|
+
if (typeof value === "string") {
|
|
1635
|
+
if (new TextEncoder().encode(value).byteLength > 65536)
|
|
1636
|
+
throw new Error("Workflow JSON must be at most 64 KiB.");
|
|
1637
|
+
value = JSON.parse(value);
|
|
1638
|
+
}
|
|
1639
|
+
const envelope = codeEnvelope.parse(value);
|
|
1640
|
+
if (!envelope.workflow || typeof envelope.workflow !== "object" || Array.isArray(envelope.workflow))
|
|
1641
|
+
throw new Error("Workflow must be an object.");
|
|
1642
|
+
const { id: _id, revision: _revision, createdAt: _createdAt, updatedAt: _updatedAt, ...draft } = envelope.workflow;
|
|
1643
|
+
if (new TextEncoder().encode(JSON.stringify(envelope)).byteLength > 65536)
|
|
1644
|
+
throw new Error("Workflow JSON must be at most 64 KiB.");
|
|
1645
|
+
return parseSecurityWorkflowInput(draft);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// packages/shared/dist/security-workflow-templates.js
|
|
1649
|
+
function phase(id, label, goal, instructions, depth = "default") {
|
|
1650
|
+
return { id, type: "audit", label, enabled: true, plan: { goal, depth, runCount: 1, executionMode: "sequential", timeCapMs: 6e5, costCapUsd: 5 }, execution: { instructions } };
|
|
1651
|
+
}
|
|
1652
|
+
function template(id, name, description, category, phases) {
|
|
1653
|
+
const nodes = [{ id: "start", type: "trigger", label: "Start manually", enabled: true }, ...phases, { id: "report", type: "report", label: "Collect reports", enabled: true }];
|
|
1654
|
+
return { id, name, description, category, definition: parseSecurityWorkflowInput({ name, instructions: description, target: "", nodes, edges: nodes.slice(1).map((node, index) => ({ source: nodes[index].id, target: node.id })) }) };
|
|
1655
|
+
}
|
|
1656
|
+
var SECURITY_WORKFLOW_TEMPLATES = [
|
|
1657
|
+
template("repository-review", "Repository security review", "Review a local repository's trust boundaries, dependency exposure, and security-sensitive code.", "repository", [
|
|
1658
|
+
phase("dependencies", "Dependency exposure", "known-vulnerabilities", "Inspect dependency manifests and lockfiles. Prioritize reachable vulnerable dependencies and supply-chain trust boundaries; distinguish confirmed exposure from version-only matches.", "quick"),
|
|
1659
|
+
phase("boundaries", "Trust boundaries", "unknown-vulnerabilities", "Trace authentication, authorization, tenant isolation, and privileged entry points in the authorized repository. Follow input-to-sink paths and report only supported security findings.", "deep"),
|
|
1660
|
+
phase("configuration", "Configuration and secrets", "misconfigurations", "Review repository configuration, credential handling, unsafe defaults, and sensitive debug surfaces. Do not expose secret values in reports.")
|
|
1661
|
+
]),
|
|
1662
|
+
template("dependency-review", "Dependency and supply-chain review", "Assess an authorized package or repository for advisories and suspicious dependency behavior.", "package", [
|
|
1663
|
+
phase("advisories", "Advisory triage", "known-vulnerabilities", "Review declared and locked dependencies against supported advisory sources. Check affected versions and whether vulnerable functionality is used.", "quick"),
|
|
1664
|
+
phase("lifecycle", "Lifecycle and trust", "unknown-vulnerabilities", "Inspect package installation hooks, dynamic downloads, credential access, and dependency trust changes. Support suspicious behavior with code evidence, without executing untrusted installation scripts.", "deep")
|
|
1665
|
+
]),
|
|
1666
|
+
template("api-security", "API authorization review", "Review an explicitly authorized API for authorization gaps, unsafe inputs, and exposed configuration.", "web", [
|
|
1667
|
+
phase("surface", "API surface and defaults", "misconfigurations", "Map documented and reachable authorized API endpoints, exposed documentation, error disclosures, and security defaults. Stay within the supplied scope and avoid destructive requests.", "quick"),
|
|
1668
|
+
phase("authorization", "Authorization boundaries", "unknown-vulnerabilities", "Assess object ownership, role boundaries, tenant isolation, and authentication requirements using only identities and targets explicitly authorized for the engagement. Do not invent credentials.", "deep"),
|
|
1669
|
+
phase("inputs", "Input handling", "unknown-vulnerabilities", "Review request parsing, injection boundaries, resource references, and validation. Use bounded non-destructive checks and retain evidence for confirmed impact.")
|
|
1670
|
+
]),
|
|
1671
|
+
template("web-configuration", "Web configuration review", "Assess an authorized web target's exposure, browser security controls, and session configuration.", "web", [
|
|
1672
|
+
phase("exposure", "Public exposure", "misconfigurations", "Review in-scope publicly reachable files, admin/debug surfaces, transport defaults, and error disclosures using non-destructive checks.", "quick"),
|
|
1673
|
+
phase("sessions", "Browser and session controls", "misconfigurations", "Review observed cookie attributes, cache handling of sensitive responses, cross-origin policy, redirect handling, and browser security headers. Explain practical impact rather than treating every absent header as a vulnerability."),
|
|
1674
|
+
phase("advisories", "Known component exposure", "known-vulnerabilities", "Assess observed components against supported known-vulnerability sources. Separate inferred versions from verified affected versions and avoid unsupported exploit claims.")
|
|
1675
|
+
]),
|
|
1676
|
+
template("scoped-penetration-test", "Scoped penetration test", "Plan and assess only an explicitly authorized target, with bounded discovery and non-destructive validation.", "security", [
|
|
1677
|
+
phase("discovery", "Scoped discovery", "misconfigurations", "Map only the authorized attack surface and identify exposed configuration and trust boundaries. Honor exclusions and rate limits; do not enumerate unrelated hosts.", "quick"),
|
|
1678
|
+
phase("known", "Known vulnerability triage", "known-vulnerabilities", "Check supported known-vulnerability leads against observed target behavior. Verify applicability with bounded evidence; do not run broad third-party scanners or destructive exploit payloads."),
|
|
1679
|
+
phase("validation", "Targeted validation", "unknown-vulnerabilities", "Investigate authorization, input handling, and sensitive state transitions within explicit scope. Prefer minimal non-destructive proof; stop before destructive actions or accessing unrelated user data.", "deep")
|
|
1680
|
+
]),
|
|
1681
|
+
template("package-behavior", "Package behavior investigation", "Review an authorized package's security-relevant code paths and suspicious behavior.", "package", [
|
|
1682
|
+
phase("entrypoints", "Entrypoints and advisories", "known-vulnerabilities", "Inspect package metadata, entrypoints, and supported advisories; identify security-sensitive or remotely reachable behavior.", "quick"),
|
|
1683
|
+
phase("behavior", "Suspicious behavior", "unknown-vulnerabilities", "Trace filesystem and credential access, network destinations, obfuscated code, dynamic evaluation, and lifecycle hooks. Distinguish legitimate functionality from suspicious behavior with evidence; do not execute untrusted install scripts.", "deep")
|
|
1684
|
+
]),
|
|
1685
|
+
template("contract-review", "Smart contract source review", "Review an authorized contract source repository for access control and asset-accounting defects.", "contracts", [
|
|
1686
|
+
phase("access", "Authority and upgrade paths", "unknown-vulnerabilities", "Review contract source for privileged roles, initialization, upgrades, trust in external calls, and missing authorization. Identify the contract ecosystem from source; do not submit transactions or invent specialized verification results.", "deep"),
|
|
1687
|
+
phase("accounting", "Asset and state invariants", "unknown-vulnerabilities", "Trace value transfers, balance accounting, state transitions, rounding, and reentrancy boundaries in the authorized source. Support findings with concrete call sequences; do not move assets or publish exploits.", "deep"),
|
|
1688
|
+
phase("configuration", "Deployment assumptions", "misconfigurations", "Review source-visible deployment and initialization assumptions, privileged configuration, and dependency trust. Clearly distinguish code evidence from unverified deployed state.")
|
|
1689
|
+
]),
|
|
1690
|
+
template("native-code-review", "Native code boundary review", "Review an authorized native source repository for parser, memory, and privilege-boundary issues.", "repository", [
|
|
1691
|
+
phase("parsers", "Parsers and memory boundaries", "unknown-vulnerabilities", "Trace untrusted input through parsing, length calculations, ownership, and memory operations. Prioritize reachable paths and concrete invalid-state evidence in the authorized source.", "deep"),
|
|
1692
|
+
phase("privileges", "Privilege and resource boundaries", "unknown-vulnerabilities", "Review privilege transitions, filesystem paths, subprocess inputs, concurrency, and resource lifetime. Avoid speculative issues without a supported attacker-controlled path.", "deep")
|
|
1693
|
+
])
|
|
1694
|
+
];
|
|
1695
|
+
function createSecurityWorkflowTemplate(id) {
|
|
1696
|
+
const found = SECURITY_WORKFLOW_TEMPLATES.find((entry) => entry.id === id);
|
|
1697
|
+
if (!found)
|
|
1698
|
+
throw new Error("Unknown security workflow template.");
|
|
1699
|
+
return parseSecurityWorkflowInput(found.definition);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// packages/shared/dist/service-plugins.js
|
|
1703
|
+
var token = { key: "token", label: "API token", type: "secret", required: true };
|
|
1704
|
+
var SERVICE_PLUGIN_CATALOG = [
|
|
1705
|
+
{ id: "github", name: "GitHub", description: "Review repositories, security alerts and pull requests.", category: "Code", docsUrl: "https://github.com/github/github-mcp-server", fields: [{ ...token, label: "Personal access token" }] },
|
|
1706
|
+
{ id: "elastic", name: "Elastic", description: "Search security alerts and telemetry.", category: "Security", docsUrl: "https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/mcp-server-api-keys", fields: [{ key: "url", label: "Kibana URL", type: "url", required: true }, { ...token, label: "Encoded API key" }], credentialNote: "Requires Elastic Agent Builder access." },
|
|
1707
|
+
{ id: "semgrep", name: "Semgrep", description: "Investigate code, dependency and secret findings.", category: "Security", docsUrl: "https://semgrep.dev/docs/semgrep-appsec-platform/api", fields: [token, { key: "deploymentId", label: "Deployment ID", type: "text", required: true }] },
|
|
1708
|
+
{ id: "snyk", name: "Snyk", description: "Review vulnerable projects and dependencies.", category: "Security", docsUrl: "https://docs.snyk.io/snyk-api", fields: [token, { key: "organizationId", label: "Organization ID", type: "text", required: true }, { key: "url", label: "API URL (optional)", type: "url", required: false }] },
|
|
1709
|
+
{ id: "linear", name: "Linear", description: "Create and track remediation issues.", category: "Issues", docsUrl: "https://linear.app/developers/graphql", fields: [token] },
|
|
1710
|
+
{ id: "jira", name: "Jira", description: "Turn security findings into assigned issues.", category: "Issues", docsUrl: "https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/", fields: [{ key: "url", label: "Jira Cloud URL", type: "url", required: true }, { key: "email", label: "Account email", type: "text", required: true }, token] },
|
|
1711
|
+
{ id: "cloudflare", name: "Cloudflare", description: "Inspect zones, DNS and security configuration.", category: "Cloud", docsUrl: "https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", fields: [token] },
|
|
1712
|
+
{ id: "slack", name: "Slack", description: "Read channels and share workflow summaries.", category: "Messaging", docsUrl: "https://docs.slack.dev/authentication/tokens/", fields: [{ ...token, label: "Bot or user token" }] },
|
|
1713
|
+
{ id: "teams", name: "Microsoft Teams", description: "Read teams and share channel summaries.", category: "Messaging", docsUrl: "https://learn.microsoft.com/en-us/graph/auth/auth-concepts", fields: [{ ...token, label: "Microsoft Graph access token" }], credentialNote: "Delegated token with Teams access. Reconnect when it expires." }
|
|
1714
|
+
];
|
|
1715
|
+
|
|
1234
1716
|
export {
|
|
1717
|
+
validateScanPlan,
|
|
1235
1718
|
defaultRoleFor,
|
|
1236
1719
|
resolveIdentities,
|
|
1237
1720
|
hasMultipleIdentities,
|
|
@@ -1310,5 +1793,17 @@ export {
|
|
|
1310
1793
|
DEFAULT_AUTONOMY_MODE,
|
|
1311
1794
|
DEFAULT_ALLOW_MODEL_SELF_EXTENSION,
|
|
1312
1795
|
jevConfigFromEnvironment,
|
|
1313
|
-
createJevEvaluator
|
|
1796
|
+
createJevEvaluator,
|
|
1797
|
+
SLASH_COMMANDS,
|
|
1798
|
+
getCommandByName,
|
|
1799
|
+
findCommand,
|
|
1800
|
+
filterCommands,
|
|
1801
|
+
DEFAULT_SECURITY_WORKFLOW_PLAN,
|
|
1802
|
+
SecurityWorkflowInputSchema,
|
|
1803
|
+
parseSecurityWorkflowInput,
|
|
1804
|
+
exportSecurityWorkflowCode,
|
|
1805
|
+
parseSecurityWorkflowCode,
|
|
1806
|
+
SECURITY_WORKFLOW_TEMPLATES,
|
|
1807
|
+
createSecurityWorkflowTemplate,
|
|
1808
|
+
SERVICE_PLUGIN_CATALOG
|
|
1314
1809
|
};
|