@pensar/apex 2.6.1-canary.e936ec17 → 2.6.1
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/build/agent-6w7egcf1.js +13 -0
- package/build/agent-9zx75feh.js +13 -0
- package/build/{agent-t2g0e5v1.js → agent-ayreaj6z.js} +5 -5
- package/build/{agent-runs-mw4bp0n5.js → agent-runs-g37vkrjr.js} +16 -16
- package/build/{agent-x8wxd9ma.js → agent-yby11zaq.js} +6 -6
- package/build/{apps-b2x50tm7.js → apps-xn6km9yn.js} +13 -13
- package/build/{auth-0rfqyw3s.js → auth-d105wc64.js} +13 -13
- package/build/{blackboxAgent-7bapanbv.js → blackboxAgent-s56sgx9b.js} +6 -6
- package/build/{blackboxPentest-ngs99vv8.js → blackboxPentest-ps78v3w7.js} +11 -11
- package/build/{cli-tt7d70n9.js → cli-1ve18npr.js} +1 -1
- package/build/{cli-en2trtdx.js → cli-3sp6nd8d.js} +2 -2
- package/build/{cli-k594kwq8.js → cli-65g6rcat.js} +1 -1
- package/build/{cli-w9d2bnf3.js → cli-709rvekb.js} +1 -1
- package/build/{cli-rwnm0p5r.js → cli-7eea4e2y.js} +39 -7
- package/build/{cli-1b0pw0wp.js → cli-ae8jqxqr.js} +2 -2
- package/build/{cli-raavtvwt.js → cli-az3xq70v.js} +1 -1
- package/build/{cli-c2nb79ce.js → cli-c05y640n.js} +1 -1
- package/build/{cli-9d8m1qw2.js → cli-d37a42dc.js} +8 -8
- package/build/{cli-jpa3w5b4.js → cli-dpsw2fe6.js} +5 -5
- package/build/{cli-9a7b3x56.js → cli-fy6vh2a7.js} +1 -1
- package/build/{cli-72aenzba.js → cli-gx71jcke.js} +1 -1
- package/build/{cli-84qrqxjc.js → cli-k2nwxta0.js} +2 -2
- package/build/{cli-ay461rtr.js → cli-kb21qhvm.js} +2 -2
- package/build/{cli-sf6x1vjx.js → cli-n2en7j5b.js} +1 -1
- package/build/{cli-zahhskff.js → cli-ngq9dr8n.js} +3 -3
- package/build/{cli-8q41y2ss.js → cli-qgz1q9g5.js} +12 -12
- package/build/{cli-h68jfmth.js → cli-xtc2t6me.js} +3 -3
- package/build/cli.js +40 -36
- package/build/{config-8eg7v57g.js → config-zpqkd5cz.js} +1 -1
- package/build/{fastStrike-6pejawnd.js → fastStrike-mcjdvwez.js} +5 -5
- package/build/{fixes-94pbkpy6.js → fixes-kytx5dmj.js} +13 -13
- package/build/{index-xavch1zh.js → index-4vqdgb42.js} +19 -19
- package/build/{index-k3vaa38r.js → index-dr3tg1w3.js} +1 -1
- package/build/{index-g8z6kn6v.js → index-fv64eb32.js} +2 -2
- package/build/{index-bsdq9wd9.js → index-je6hcsqr.js} +1 -1
- package/build/{index-c6szs0vn.js → index-n65z6v7b.js} +6 -6
- package/build/{index-jvpmhhqm.js → index-ns4m4s01.js} +4 -4
- package/build/{index-9hnznpdk.js → index-qv4cc65p.js} +28 -14
- package/build/{index-2sc33n6h.js → index-r9yjkfrv.js} +4 -4
- package/build/{index-yt0n80v2.js → index-wqetp6gq.js} +5 -5
- package/build/{issues-hxcq3q0g.js → issues-eb3q9d3a.js} +13 -13
- package/build/knowledge-fqsvtx0f.js +139 -0
- package/build/lib/{chunk-nv32cpyc.js → chunk-1azdancq.js} +1 -1
- package/build/lib/{chunk-9yjz0ynw.js → chunk-1fy8azee.js} +1 -1
- package/build/lib/{chunk-zfp495pt.js → chunk-1jvwqnem.js} +3 -3
- package/build/lib/{chunk-dj3q3fxw.js → chunk-1yct6cra.js} +1 -1
- package/build/lib/{chunk-gt5gf7ps.js → chunk-2qsq76xq.js} +3 -3
- package/build/lib/{chunk-tjch07p0.js → chunk-3c00n0cy.js} +3 -3
- package/build/lib/{chunk-86z9yr32.js → chunk-4hwzqthr.js} +1 -1
- package/build/lib/{chunk-9jfybqs2.js → chunk-7pwa92rn.js} +1 -1
- package/build/lib/{chunk-pcpzbdnn.js → chunk-9tt2021m.js} +9 -9
- package/build/lib/{chunk-xqygd85b.js → chunk-9yksqgzr.js} +52 -13
- package/build/lib/{chunk-xw3w0xzz.js → chunk-acgbyf5h.js} +1 -1
- package/build/lib/{chunk-5wt0sejb.js → chunk-ba41jh41.js} +1 -1
- package/build/lib/{chunk-r18sc80z.js → chunk-bb0ekhkw.js} +8 -8
- package/build/lib/{chunk-shtrgm3j.js → chunk-e8yy2k73.js} +1 -1
- package/build/lib/{chunk-0z4r4r0x.js → chunk-mg03jdmt.js} +1 -1
- package/build/lib/{chunk-nhnhhnk1.js → chunk-nhfax4gb.js} +1 -1
- package/build/lib/{chunk-521eq8kw.js → chunk-r2dkp4tb.js} +1 -1
- package/build/lib/{chunk-mqftsw7s.js → chunk-r4j8ybn9.js} +3 -3
- package/build/lib/{chunk-v8p7j8br.js → chunk-v3dk9j7k.js} +11 -11
- package/build/lib/{chunk-afc4wybp.js → chunk-w66ce82a.js} +1 -1
- package/build/lib/{chunk-ydgsc09t.js → chunk-xhdpgpkm.js} +2 -2
- package/build/lib/{chunk-837ga30c.js → chunk-yrnrbjes.js} +1 -1
- package/build/lib/{chunk-m9anmxyq.js → chunk-z137x08b.js} +5 -5
- package/build/lib/{chunk-pnnj2k0n.js → chunk-z96pbjhd.js} +1 -1
- package/build/lib/core/agents/offSecAgent/index.js +7 -7
- package/build/lib/core/agents/offSecAgent/subagentSpawner.js +5 -5
- package/build/lib/core/agents/offSecAgent/tools/index.js +4 -4
- package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +9 -9
- package/build/lib/core/agents/specialized/attackSurface/schemas.js +9 -9
- package/build/lib/core/agents/specialized/authenticationAgent/index.js +10 -10
- package/build/lib/core/agents/specialized/codeAgent/agent.js +9 -9
- package/build/lib/core/agents/specialized/findingJudge/agent.js +8 -8
- package/build/lib/core/agents/specialized/findingJudge/index.js +3 -3
- package/build/lib/core/agents/specialized/patching/index.js +10 -10
- package/build/lib/core/agents/specialized/pentest/agent.js +9 -9
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +9 -9
- package/build/lib/core/ai/ai.js +2 -2
- package/build/lib/core/ai/index.js +2 -2
- package/build/lib/core/ai/utils.js +2 -2
- package/build/lib/core/api/index.d.ts +2 -0
- package/build/lib/core/api/index.js +34 -20
- package/build/lib/core/api/issues.d.ts +1 -0
- package/build/lib/core/api/knowledge.d.ts +33 -0
- package/build/lib/core/api/targetedPentest.js +10 -10
- package/build/lib/core/config/index.js +1 -1
- package/build/lib/core/findings/registry.js +3 -3
- package/build/lib/core/session/index.js +2 -2
- package/build/lib/core/session/persistence.js +3 -3
- package/build/lib/core/workflows/pentest.js +15 -15
- package/build/lib/core/workflows/seams.js +4 -4
- package/build/lib/core/workflows/whiteboxAttackSurface.js +11 -11
- package/build/lib/index.js +22 -22
- package/build/{logs-szgf3e9j.js → logs-x62b7hk1.js} +13 -13
- package/build/{native-rollout-evidence-zep91dya.js → native-rollout-evidence-c9yhfqcs.js} +3 -3
- package/build/{offesecAgent-g9a7jvmb.js → offesecAgent-5whnpeta.js} +4 -4
- package/build/pentest-e61hc38s.js +22 -0
- package/build/{pentests-pk66smvx.js → pentests-e0f32aqx.js} +21 -14
- package/build/recordedRunClient-dp032c32.js +11 -0
- package/build/{targetedPentest-t7f2vdpk.js → targetedPentest-rcbs4nvp.js} +6 -6
- package/build/{targets-5dp972y7.js → targets-xj9g3q0z.js} +13 -13
- package/build/threatModel-jkxfa40s.js +21 -0
- package/build/{uninstall-qshcasbp.js → uninstall-7s784q4a.js} +1 -1
- package/build/{upload-jy6hp68b.js → upload-4gvhwmvr.js} +4 -4
- package/build/{utils-6z5t7vq1.js → utils-cjrz64pc.js} +3 -3
- package/package.json +1 -1
- package/src/cli/knowledge.test.ts +140 -0
- package/src/cli/knowledge.ts +146 -0
- package/src/cli/pentests.test.ts +15 -0
- package/src/cli/pentests.ts +15 -1
- package/src/cli.ts +4 -0
- package/src/core/api/index.ts +15 -0
- package/src/core/api/issues.ts +1 -0
- package/src/core/api/knowledge.ts +70 -0
- package/build/agent-6pyd6vmv.js +0 -13
- package/build/agent-9wqvzg28.js +0 -13
- package/build/pentest-wx108ypq.js +0 -22
- package/build/recordedRunClient-4yx9czwe.js +0 -11
- package/build/threatModel-cxkg9kd3.js +0 -21
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_CONCURRENCY2,
|
|
3
|
+
runPentestSwarm2,
|
|
4
|
+
runPentestWorkflow2
|
|
5
|
+
} from "./cli-d37a42dc.js";
|
|
6
|
+
import"./cli-n2en7j5b.js";
|
|
7
|
+
import"./cli-ngq9dr8n.js";
|
|
8
|
+
import"./cli-k2nwxta0.js";
|
|
9
|
+
import"./cli-xtc2t6me.js";
|
|
10
|
+
import"./cli-kb21qhvm.js";
|
|
11
|
+
import"./cli-1ve18npr.js";
|
|
12
|
+
import"./cli-qba2x69h.js";
|
|
13
|
+
import"./cli-qgz1q9g5.js";
|
|
14
|
+
import"./cli-dpsw2fe6.js";
|
|
15
|
+
import"./cli-c05y640n.js";
|
|
16
|
+
import"./cli-c2k4xxaw.js";
|
|
17
|
+
import"./cli-fy6vh2a7.js";
|
|
18
|
+
export {
|
|
19
|
+
DEFAULT_CONCURRENCY2 as DEFAULT_CONCURRENCY,
|
|
20
|
+
runPentestSwarm2 as runPentestSwarm,
|
|
21
|
+
runPentestWorkflow2 as runPentestWorkflow
|
|
22
|
+
};
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import"./cli-
|
|
3
|
-
import"./cli-
|
|
2
|
+
import"./cli-fy6vh2a7.js";
|
|
3
|
+
import"./cli-c05y640n.js";
|
|
4
4
|
import {
|
|
5
5
|
listScans2,
|
|
6
6
|
getScan2,
|
|
7
7
|
dispatchPentest2
|
|
8
|
-
} from "./cli-
|
|
9
|
-
import"./cli-
|
|
10
|
-
import"./cli-
|
|
11
|
-
import"./cli-
|
|
12
|
-
import"./cli-
|
|
13
|
-
import"./cli-
|
|
14
|
-
import"./cli-
|
|
15
|
-
import"./cli-
|
|
16
|
-
import"./cli-
|
|
8
|
+
} from "./cli-7eea4e2y.js";
|
|
9
|
+
import"./cli-qgz1q9g5.js";
|
|
10
|
+
import"./cli-k2nwxta0.js";
|
|
11
|
+
import"./cli-kb21qhvm.js";
|
|
12
|
+
import"./cli-ngq9dr8n.js";
|
|
13
|
+
import"./cli-d37a42dc.js";
|
|
14
|
+
import"./cli-3sp6nd8d.js";
|
|
15
|
+
import"./cli-xtc2t6me.js";
|
|
16
|
+
import"./cli-n2en7j5b.js";
|
|
17
17
|
import"./cli-xcy2vxj2.js";
|
|
18
18
|
import {
|
|
19
19
|
markCommandFailed
|
|
20
20
|
} from "./cli-z82n3qk1.js";
|
|
21
|
-
import"./cli-
|
|
21
|
+
import"./cli-1ve18npr.js";
|
|
22
22
|
import"./cli-qba2x69h.js";
|
|
23
|
-
import"./cli-
|
|
23
|
+
import"./cli-dpsw2fe6.js";
|
|
24
24
|
import"./cli-c2k4xxaw.js";
|
|
25
25
|
import {
|
|
26
26
|
init_zod
|
|
@@ -51,6 +51,8 @@ dispatch options:
|
|
|
51
51
|
--endpoint-id <UUIDs> Select endpoints; repeat or separate IDs with commas (full only)
|
|
52
52
|
--endpoint-ids-file <file|-> Read endpoint UUIDs, one per line; - reads stdin
|
|
53
53
|
May combine with --endpoint-id; blank lines ignored
|
|
54
|
+
--knowledge-id <UUIDs> Attach active knowledge base entries as run context;
|
|
55
|
+
repeat or separate IDs with commas (maximum 20)
|
|
54
56
|
|
|
55
57
|
Endpoint selection requires 1–1000 unique UUIDs and full depth.
|
|
56
58
|
|
|
@@ -85,6 +87,7 @@ async function main() {
|
|
|
85
87
|
level: { type: "string" },
|
|
86
88
|
"endpoint-ids-file": { type: "string" },
|
|
87
89
|
"endpoint-id": { type: "string", multiple: true },
|
|
90
|
+
"knowledge-id": { type: "string", multiple: true },
|
|
88
91
|
help: { type: "boolean", short: "h" }
|
|
89
92
|
},
|
|
90
93
|
strict: true,
|
|
@@ -117,7 +120,11 @@ async function main() {
|
|
|
117
120
|
endpointIds: array(uuid()).min(1).max(1000).parse([...new Set(ids.map((id) => id.trim().toLowerCase()))]),
|
|
118
121
|
scanLevel: scanLevel ?? "full"
|
|
119
122
|
} : { branch: values.branch, scanLevel };
|
|
120
|
-
const
|
|
123
|
+
const knowledgeIds = (values["knowledge-id"] ?? []).flatMap((value) => value.split(","));
|
|
124
|
+
const knowledgeEntryIds = knowledgeIds.length ? array(uuid()).max(20).parse([
|
|
125
|
+
...new Set(knowledgeIds.map((id) => id.trim().toLowerCase()))
|
|
126
|
+
]) : undefined;
|
|
127
|
+
const result = await dispatchPentest2({ ...input, knowledgeEntryIds });
|
|
121
128
|
console.log(JSON.stringify(result, null, 2));
|
|
122
129
|
} else if (!sub || sub === "list") {
|
|
123
130
|
const scans = await listScans2();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openRecordedRunClient2
|
|
3
|
+
} from "./cli-ae8jqxqr.js";
|
|
4
|
+
import"./cli-gx71jcke.js";
|
|
5
|
+
import"./cli-dpsw2fe6.js";
|
|
6
|
+
import"./cli-c05y640n.js";
|
|
7
|
+
import"./cli-c2k4xxaw.js";
|
|
8
|
+
import"./cli-fy6vh2a7.js";
|
|
9
|
+
export {
|
|
10
|
+
openRecordedRunClient2 as openRecordedRunClient
|
|
11
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import"./cli-
|
|
2
|
-
import"./cli-
|
|
3
|
-
import"./cli-
|
|
1
|
+
import"./cli-fy6vh2a7.js";
|
|
2
|
+
import"./cli-c05y640n.js";
|
|
3
|
+
import"./cli-qgz1q9g5.js";
|
|
4
4
|
import {
|
|
5
5
|
TargetedPentestAgent2
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-xtc2t6me.js";
|
|
7
7
|
import {
|
|
8
8
|
startAgentExecution
|
|
9
9
|
} from "./cli-g06s7edq.js";
|
|
10
|
-
import"./cli-
|
|
10
|
+
import"./cli-1ve18npr.js";
|
|
11
11
|
import"./cli-qba2x69h.js";
|
|
12
|
-
import"./cli-
|
|
12
|
+
import"./cli-dpsw2fe6.js";
|
|
13
13
|
import"./cli-c2k4xxaw.js";
|
|
14
14
|
|
|
15
15
|
// src/core/api/targetedPentest.ts
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import"./cli-
|
|
3
|
-
import"./cli-
|
|
2
|
+
import"./cli-fy6vh2a7.js";
|
|
3
|
+
import"./cli-c05y640n.js";
|
|
4
4
|
import {
|
|
5
5
|
listPentestTargets2,
|
|
6
6
|
listTargetLogs2,
|
|
7
7
|
searchTargetLogs2
|
|
8
|
-
} from "./cli-
|
|
9
|
-
import"./cli-
|
|
10
|
-
import"./cli-
|
|
11
|
-
import"./cli-
|
|
12
|
-
import"./cli-
|
|
13
|
-
import"./cli-
|
|
14
|
-
import"./cli-
|
|
15
|
-
import"./cli-
|
|
16
|
-
import"./cli-
|
|
8
|
+
} from "./cli-7eea4e2y.js";
|
|
9
|
+
import"./cli-qgz1q9g5.js";
|
|
10
|
+
import"./cli-k2nwxta0.js";
|
|
11
|
+
import"./cli-kb21qhvm.js";
|
|
12
|
+
import"./cli-ngq9dr8n.js";
|
|
13
|
+
import"./cli-d37a42dc.js";
|
|
14
|
+
import"./cli-3sp6nd8d.js";
|
|
15
|
+
import"./cli-xtc2t6me.js";
|
|
16
|
+
import"./cli-n2en7j5b.js";
|
|
17
17
|
import"./cli-xcy2vxj2.js";
|
|
18
18
|
import {
|
|
19
19
|
markCommandFailed
|
|
20
20
|
} from "./cli-z82n3qk1.js";
|
|
21
|
-
import"./cli-
|
|
21
|
+
import"./cli-1ve18npr.js";
|
|
22
22
|
import"./cli-qba2x69h.js";
|
|
23
|
-
import"./cli-
|
|
23
|
+
import"./cli-dpsw2fe6.js";
|
|
24
24
|
import"./cli-c2k4xxaw.js";
|
|
25
25
|
|
|
26
26
|
// src/cli/targets.ts
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import"./cli-qgz1q9g5.js";
|
|
2
|
+
import"./cli-fy6vh2a7.js";
|
|
3
|
+
import"./cli-c05y640n.js";
|
|
4
|
+
import {
|
|
5
|
+
runThreatModelWorkflow2
|
|
6
|
+
} from "./cli-7eea4e2y.js";
|
|
7
|
+
import"./cli-k2nwxta0.js";
|
|
8
|
+
import"./cli-kb21qhvm.js";
|
|
9
|
+
import"./cli-ngq9dr8n.js";
|
|
10
|
+
import"./cli-d37a42dc.js";
|
|
11
|
+
import"./cli-3sp6nd8d.js";
|
|
12
|
+
import"./cli-xtc2t6me.js";
|
|
13
|
+
import"./cli-n2en7j5b.js";
|
|
14
|
+
import"./cli-xcy2vxj2.js";
|
|
15
|
+
import"./cli-1ve18npr.js";
|
|
16
|
+
import"./cli-qba2x69h.js";
|
|
17
|
+
import"./cli-dpsw2fe6.js";
|
|
18
|
+
import"./cli-c2k4xxaw.js";
|
|
19
|
+
export {
|
|
20
|
+
runThreatModelWorkflow2 as runThreatModelWorkflow
|
|
21
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import"./cli-
|
|
2
|
-
import"./cli-
|
|
1
|
+
import"./cli-fy6vh2a7.js";
|
|
2
|
+
import"./cli-c05y640n.js";
|
|
3
3
|
import {
|
|
4
4
|
resolveConfig,
|
|
5
5
|
createWeaveTracer
|
|
6
|
-
} from "./cli-
|
|
7
|
-
import"./cli-
|
|
6
|
+
} from "./cli-az3xq70v.js";
|
|
7
|
+
import"./cli-dpsw2fe6.js";
|
|
8
8
|
import"./cli-c2k4xxaw.js";
|
|
9
9
|
|
|
10
10
|
// src/core/integrations/wandb/upload.ts
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import"./cli-
|
|
2
|
-
import"./cli-
|
|
1
|
+
import"./cli-fy6vh2a7.js";
|
|
2
|
+
import"./cli-c05y640n.js";
|
|
3
3
|
import {
|
|
4
4
|
init_types
|
|
5
5
|
} from "./cli-3gt761d2.js";
|
|
6
6
|
import {
|
|
7
7
|
AVAILABLE_MODELS,
|
|
8
8
|
init_ai
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-dpsw2fe6.js";
|
|
10
10
|
import"./cli-c2k4xxaw.js";
|
|
11
11
|
|
|
12
12
|
// src/core/providers/utils.ts
|
package/package.json
CHANGED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
|
|
8
|
+
const CLI = join(import.meta.dirname, "knowledge.ts");
|
|
9
|
+
const ID = "33333333-3333-4333-8333-333333333333";
|
|
10
|
+
|
|
11
|
+
function run(args: string[]) {
|
|
12
|
+
const result = spawnSync("bun", [CLI, ...args], { encoding: "utf8" });
|
|
13
|
+
return {
|
|
14
|
+
status: result.status,
|
|
15
|
+
stdout: result.stdout,
|
|
16
|
+
stderr: result.stderr,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function captureRequest(args: string[]) {
|
|
21
|
+
let request: { method?: string; url?: string; body: unknown } | undefined;
|
|
22
|
+
const server = createServer((req, res) => {
|
|
23
|
+
const chunks: Buffer[] = [];
|
|
24
|
+
req.on("data", (c: Buffer) => chunks.push(c));
|
|
25
|
+
req.on("end", () => {
|
|
26
|
+
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
27
|
+
request = {
|
|
28
|
+
method: req.method,
|
|
29
|
+
url: req.url,
|
|
30
|
+
body: raw ? JSON.parse(raw) : undefined,
|
|
31
|
+
};
|
|
32
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
33
|
+
res.end(JSON.stringify({ id: ID }));
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
37
|
+
const address = server.address();
|
|
38
|
+
if (address === null || typeof address === "string")
|
|
39
|
+
throw new Error("no port");
|
|
40
|
+
const home = mkdtempSync(join(tmpdir(), "pensar-knowledge-"));
|
|
41
|
+
try {
|
|
42
|
+
const status = await new Promise<number | null>((resolve) => {
|
|
43
|
+
const child = spawn("bun", [CLI, ...args], {
|
|
44
|
+
env: {
|
|
45
|
+
...process.env,
|
|
46
|
+
HOME: home,
|
|
47
|
+
PENSAR_API_KEY: "test-key",
|
|
48
|
+
PENSAR_API_URL: `http://127.0.0.1:${address.port}`,
|
|
49
|
+
},
|
|
50
|
+
stdio: "ignore",
|
|
51
|
+
});
|
|
52
|
+
child.on("exit", resolve);
|
|
53
|
+
});
|
|
54
|
+
expect(status).toBe(0);
|
|
55
|
+
} finally {
|
|
56
|
+
server.close();
|
|
57
|
+
rmSync(home, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
if (!request) throw new Error("CLI sent no request");
|
|
60
|
+
return request;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe("pensar knowledge CLI", () => {
|
|
64
|
+
it("documents that writes need a user login", () => {
|
|
65
|
+
const { status, stdout } = run(["--help"]);
|
|
66
|
+
expect(status).toBe(0);
|
|
67
|
+
expect(stdout).toContain("require a user login");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("lists with filters", async () => {
|
|
71
|
+
const req = await captureRequest([
|
|
72
|
+
"--category",
|
|
73
|
+
"user_note",
|
|
74
|
+
"--status",
|
|
75
|
+
"active",
|
|
76
|
+
"--tag",
|
|
77
|
+
"auth,api",
|
|
78
|
+
]);
|
|
79
|
+
expect(req.method).toBe("GET");
|
|
80
|
+
expect(req.url).toBe(
|
|
81
|
+
"/knowledge?category=user_note&status=active&tags=auth%2Capi",
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("adds an entry", async () => {
|
|
86
|
+
const req = await captureRequest([
|
|
87
|
+
"add",
|
|
88
|
+
"--title",
|
|
89
|
+
"Stack",
|
|
90
|
+
"--content",
|
|
91
|
+
"Next.js on Lambda",
|
|
92
|
+
"--category",
|
|
93
|
+
"technology_context",
|
|
94
|
+
"--tag",
|
|
95
|
+
"infra",
|
|
96
|
+
]);
|
|
97
|
+
expect(req).toMatchObject({
|
|
98
|
+
method: "POST",
|
|
99
|
+
url: "/knowledge",
|
|
100
|
+
body: {
|
|
101
|
+
title: "Stack",
|
|
102
|
+
content: "Next.js on Lambda",
|
|
103
|
+
category: "technology_context",
|
|
104
|
+
tags: ["infra"],
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("updates an entry", async () => {
|
|
110
|
+
const req = await captureRequest(["update", ID, "--status", "stale"]);
|
|
111
|
+
expect(req).toMatchObject({
|
|
112
|
+
method: "PATCH",
|
|
113
|
+
url: `/knowledge/${ID}`,
|
|
114
|
+
body: { status: "stale" },
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("archives an entry", async () => {
|
|
119
|
+
const req = await captureRequest(["archive", ID]);
|
|
120
|
+
expect(req).toMatchObject({ method: "DELETE", url: `/knowledge/${ID}` });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("requires title, content and category to add", () => {
|
|
124
|
+
const { status, stderr } = run(["add", "--title", "x"]);
|
|
125
|
+
expect(status).toBe(1);
|
|
126
|
+
expect(stderr).toContain("--title, --content and --category are required");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("rejects an unknown category before calling the API", () => {
|
|
130
|
+
const { status, stderr } = run(["add", "--category", "nope"]);
|
|
131
|
+
expect(status).toBe(1);
|
|
132
|
+
expect(stderr).toContain('invalid --category "nope"');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("requires an id for get", () => {
|
|
136
|
+
const { status, stderr } = run(["get"]);
|
|
137
|
+
expect(status).toBe(1);
|
|
138
|
+
expect(stderr).toContain("entry ID is required");
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* pensar knowledge — Read and edit the workspace knowledge base
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* pensar knowledge [filters] List entries
|
|
8
|
+
* pensar knowledge get <id> Get one entry
|
|
9
|
+
* pensar knowledge add [options] Add an entry
|
|
10
|
+
* pensar knowledge update <id> [options] Edit an entry
|
|
11
|
+
* pensar knowledge archive <id> Archive an entry
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { parseArgs } from "node:util";
|
|
15
|
+
import {
|
|
16
|
+
archiveKnowledge,
|
|
17
|
+
createKnowledge,
|
|
18
|
+
getKnowledge,
|
|
19
|
+
KNOWLEDGE_CATEGORIES,
|
|
20
|
+
KNOWLEDGE_STATUSES,
|
|
21
|
+
type KnowledgeCategory,
|
|
22
|
+
type KnowledgeInput,
|
|
23
|
+
type KnowledgeStatus,
|
|
24
|
+
listKnowledge,
|
|
25
|
+
updateKnowledge,
|
|
26
|
+
} from "../core/api";
|
|
27
|
+
import { markCommandFailed } from "./command-exit";
|
|
28
|
+
|
|
29
|
+
function showHelp(): void {
|
|
30
|
+
console.log(`pensar knowledge — Read and edit the workspace knowledge base
|
|
31
|
+
|
|
32
|
+
Entries are context that agents use during pentests. A false_positive_pattern
|
|
33
|
+
entry suppresses matching findings.
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
pensar knowledge [filters] List entries
|
|
37
|
+
pensar knowledge get <id> Get one entry
|
|
38
|
+
pensar knowledge add [options] Add an entry
|
|
39
|
+
pensar knowledge update <id> [options] Edit an entry
|
|
40
|
+
pensar knowledge archive <id> Archive an entry
|
|
41
|
+
|
|
42
|
+
Filters and options:
|
|
43
|
+
--title <text> Entry title (required for add)
|
|
44
|
+
--content <text> Entry body (required for add)
|
|
45
|
+
--category <category> ${KNOWLEDGE_CATEGORIES.join(", ")}
|
|
46
|
+
(required for add)
|
|
47
|
+
--status <status> ${KNOWLEDGE_STATUSES.join(", ")}
|
|
48
|
+
--tag <tags> Repeat or separate with commas; a list filter
|
|
49
|
+
matches entries carrying every tag
|
|
50
|
+
|
|
51
|
+
Adding, editing and archiving require a user login; a workspace API key can
|
|
52
|
+
only read.
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
-h, --help Show this help message`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseCategory(value: string | undefined) {
|
|
59
|
+
if (value === undefined) return undefined;
|
|
60
|
+
if (!(KNOWLEDGE_CATEGORIES as readonly string[]).includes(value)) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`invalid --category "${value}". Accepted: ${KNOWLEDGE_CATEGORIES.join(", ")}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return value as KnowledgeCategory;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseStatus(value: string | undefined) {
|
|
69
|
+
if (value === undefined) return undefined;
|
|
70
|
+
if (!(KNOWLEDGE_STATUSES as readonly string[]).includes(value)) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`invalid --status "${value}". Accepted: ${KNOWLEDGE_STATUSES.join(", ")}`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return value as KnowledgeStatus;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function main(): Promise<void> {
|
|
79
|
+
const args = process.argv.slice(2);
|
|
80
|
+
const sub = args[0] && !args[0].startsWith("-") ? args[0] : "list";
|
|
81
|
+
|
|
82
|
+
if (sub === "help" || args.includes("--help") || args.includes("-h")) {
|
|
83
|
+
showHelp();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const takesId = sub === "get" || sub === "update" || sub === "archive";
|
|
89
|
+
const id = takesId ? args[1] : undefined;
|
|
90
|
+
if (takesId && (!id || id.startsWith("-"))) {
|
|
91
|
+
throw new Error(`entry ID is required: pensar knowledge ${sub} <id>`);
|
|
92
|
+
}
|
|
93
|
+
const { values } = parseArgs({
|
|
94
|
+
args: args.slice(args[0] === sub ? (takesId ? 2 : 1) : 0),
|
|
95
|
+
options: {
|
|
96
|
+
title: { type: "string" },
|
|
97
|
+
content: { type: "string" },
|
|
98
|
+
category: { type: "string" },
|
|
99
|
+
status: { type: "string" },
|
|
100
|
+
tag: { type: "string", multiple: true },
|
|
101
|
+
},
|
|
102
|
+
strict: true,
|
|
103
|
+
allowPositionals: false,
|
|
104
|
+
});
|
|
105
|
+
const tags = values.tag?.flatMap((t) => t.split(",")).filter(Boolean);
|
|
106
|
+
const input: KnowledgeInput = {
|
|
107
|
+
title: values.title,
|
|
108
|
+
content: values.content,
|
|
109
|
+
category: parseCategory(values.category),
|
|
110
|
+
status: parseStatus(values.status),
|
|
111
|
+
tags,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
let result: unknown;
|
|
115
|
+
if (sub === "list") {
|
|
116
|
+
result = await listKnowledge({
|
|
117
|
+
category: input.category,
|
|
118
|
+
status: input.status,
|
|
119
|
+
tags,
|
|
120
|
+
});
|
|
121
|
+
} else if (sub === "get") {
|
|
122
|
+
result = await getKnowledge(id!);
|
|
123
|
+
} else if (sub === "add") {
|
|
124
|
+
if (!input.title || !input.content || !input.category) {
|
|
125
|
+
throw new Error("--title, --content and --category are required");
|
|
126
|
+
}
|
|
127
|
+
result = await createKnowledge(input);
|
|
128
|
+
} else if (sub === "update") {
|
|
129
|
+
result = await updateKnowledge(id!, input);
|
|
130
|
+
} else if (sub === "archive") {
|
|
131
|
+
result = await archiveKnowledge(id!);
|
|
132
|
+
} else {
|
|
133
|
+
console.error(`Error: Unknown subcommand "${sub}"`);
|
|
134
|
+
showHelp();
|
|
135
|
+
return markCommandFailed();
|
|
136
|
+
}
|
|
137
|
+
console.log(JSON.stringify(result, null, 2));
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error(
|
|
140
|
+
`\nError: ${err instanceof Error ? err.message : String(err)}`,
|
|
141
|
+
);
|
|
142
|
+
return markCommandFailed();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
await main();
|
package/src/cli/pentests.test.ts
CHANGED
|
@@ -70,6 +70,21 @@ describe("hosted pentest dispatch", () => {
|
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
it("attaches knowledge entries to a launch", async () => {
|
|
74
|
+
await run([
|
|
75
|
+
"dispatch",
|
|
76
|
+
"--knowledge-id",
|
|
77
|
+
`${endpointA.toUpperCase()},${endpointB}`,
|
|
78
|
+
"--knowledge-id",
|
|
79
|
+
endpointA,
|
|
80
|
+
]);
|
|
81
|
+
expect(api.dispatchPentest).toHaveBeenCalledWith({
|
|
82
|
+
branch: undefined,
|
|
83
|
+
scanLevel: undefined,
|
|
84
|
+
knowledgeEntryIds: [endpointA, endpointB],
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
73
88
|
it("combines repeated, comma-separated, and file IDs without duplicates", async () => {
|
|
74
89
|
const file = join(directory, "endpoints.txt");
|
|
75
90
|
await writeFile(file, `${endpointB.toUpperCase()}\n${endpointA}\n`);
|
package/src/cli/pentests.ts
CHANGED
|
@@ -33,6 +33,8 @@ dispatch options:
|
|
|
33
33
|
--endpoint-id <UUIDs> Select endpoints; repeat or separate IDs with commas (full only)
|
|
34
34
|
--endpoint-ids-file <file|-> Read endpoint UUIDs, one per line; - reads stdin
|
|
35
35
|
May combine with --endpoint-id; blank lines ignored
|
|
36
|
+
--knowledge-id <UUIDs> Attach active knowledge base entries as run context;
|
|
37
|
+
repeat or separate IDs with commas (maximum 20)
|
|
36
38
|
|
|
37
39
|
Endpoint selection requires 1–1000 unique UUIDs and full depth.
|
|
38
40
|
|
|
@@ -70,6 +72,7 @@ async function main(): Promise<void> {
|
|
|
70
72
|
level: { type: "string" },
|
|
71
73
|
"endpoint-ids-file": { type: "string" },
|
|
72
74
|
"endpoint-id": { type: "string", multiple: true },
|
|
75
|
+
"knowledge-id": { type: "string", multiple: true },
|
|
73
76
|
help: { type: "boolean", short: "h" },
|
|
74
77
|
},
|
|
75
78
|
strict: true,
|
|
@@ -124,7 +127,18 @@ async function main(): Promise<void> {
|
|
|
124
127
|
scanLevel: scanLevel ?? "full",
|
|
125
128
|
}
|
|
126
129
|
: { branch: values.branch, scanLevel };
|
|
127
|
-
const
|
|
130
|
+
const knowledgeIds = (values["knowledge-id"] ?? []).flatMap((value) =>
|
|
131
|
+
value.split(","),
|
|
132
|
+
);
|
|
133
|
+
const knowledgeEntryIds = knowledgeIds.length
|
|
134
|
+
? z
|
|
135
|
+
.array(z.uuid())
|
|
136
|
+
.max(20)
|
|
137
|
+
.parse([
|
|
138
|
+
...new Set(knowledgeIds.map((id) => id.trim().toLowerCase())),
|
|
139
|
+
])
|
|
140
|
+
: undefined;
|
|
141
|
+
const result = await dispatchPentest({ ...input, knowledgeEntryIds });
|
|
128
142
|
console.log(JSON.stringify(result, null, 2));
|
|
129
143
|
} else if (!sub || sub === "list") {
|
|
130
144
|
const scans = await listScans();
|
package/src/cli.ts
CHANGED
|
@@ -269,6 +269,7 @@ Usage:
|
|
|
269
269
|
pensar targets List pentest targets and view their agent logs
|
|
270
270
|
pensar issues List and manage security issues
|
|
271
271
|
pensar fixes View security fixes
|
|
272
|
+
pensar knowledge Read and edit the workspace knowledge base
|
|
272
273
|
pensar logs View agent execution logs
|
|
273
274
|
pensar config headers Manage global default HTTP headers
|
|
274
275
|
pensar export-trajectory Convert saved rollout evidence to ATIF
|
|
@@ -828,6 +829,9 @@ try {
|
|
|
828
829
|
} else if (command === "issues") {
|
|
829
830
|
process.argv = [process.argv[0], process.argv[1], ...args.slice(1)];
|
|
830
831
|
await import("./cli/issues");
|
|
832
|
+
} else if (command === "knowledge") {
|
|
833
|
+
process.argv = [process.argv[0], process.argv[1], ...args.slice(1)];
|
|
834
|
+
await import("./cli/knowledge");
|
|
831
835
|
} else if (command === "fixes") {
|
|
832
836
|
process.argv = [process.argv[0], process.argv[1], ...args.slice(1)];
|
|
833
837
|
await import("./cli/fixes");
|
package/src/core/api/index.ts
CHANGED
|
@@ -151,6 +151,21 @@ export {
|
|
|
151
151
|
searchTargetLogs,
|
|
152
152
|
updateIssue,
|
|
153
153
|
} from "./issues";
|
|
154
|
+
export type {
|
|
155
|
+
KnowledgeCategory,
|
|
156
|
+
KnowledgeEntry,
|
|
157
|
+
KnowledgeInput,
|
|
158
|
+
KnowledgeStatus,
|
|
159
|
+
} from "./knowledge";
|
|
160
|
+
export {
|
|
161
|
+
archiveKnowledge,
|
|
162
|
+
createKnowledge,
|
|
163
|
+
getKnowledge,
|
|
164
|
+
KNOWLEDGE_CATEGORIES,
|
|
165
|
+
KNOWLEDGE_STATUSES,
|
|
166
|
+
listKnowledge,
|
|
167
|
+
updateKnowledge,
|
|
168
|
+
} from "./knowledge";
|
|
154
169
|
export { serveLocalRunWorker } from "./localWorker";
|
|
155
170
|
export type {
|
|
156
171
|
OffensiveSecurityAgentClientInput,
|