@pensar/apex 2.6.1 → 2.7.0-canary.1572d9a4
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-ayreaj6z.js → agent-3g1b578v.js} +6 -5
- package/build/{agent-yby11zaq.js → agent-p8cezgbb.js} +7 -6
- package/build/{agent-runs-g37vkrjr.js → agent-runs-f86emmgg.js} +23 -20
- package/build/agent-vaq31je6.js +14 -0
- package/build/agent-vvdqga09.js +14 -0
- package/build/{apps-xn6km9yn.js → apps-3stwnmen.js} +16 -13
- package/build/{auth-d105wc64.js → auth-7md9kwda.js} +16 -13
- package/build/blackboxAgent-ct8bejef.js +14 -0
- package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-w2nr4md3.js} +21 -15
- package/build/{cli-c05y640n.js → cli-1j28cbhy.js} +1 -1
- package/build/{cli-d37a42dc.js → cli-2jz2jz06.js} +206 -90
- package/build/{cli-az3xq70v.js → cli-4a8dsz2k.js} +4 -4
- package/build/{cli-qgz1q9g5.js → cli-58781vcf.js} +1192 -1473
- package/build/{cli-gx71jcke.js → cli-7067zzeb.js} +1 -1
- package/build/{cli-3sp6nd8d.js → cli-81smmd5w.js} +5 -5
- package/build/{cli-k2nwxta0.js → cli-8b25dhky.js} +2 -2
- package/build/{cli-fy6vh2a7.js → cli-8sw5zpqz.js} +1 -1
- package/build/{cli-709rvekb.js → cli-cg3ypx5n.js} +14 -7
- package/build/{cli-dpsw2fe6.js → cli-e9v6zg6h.js} +40941 -40172
- package/build/cli-fjxmphg1.js +36 -0
- package/build/{cli-7eea4e2y.js → cli-gzb6qrzh.js} +31 -60
- package/build/{cli-65g6rcat.js → cli-khnf5xrf.js} +2 -1
- package/build/{cli-1ve18npr.js → cli-mdzt2e8j.js} +4 -2
- package/build/{cli-n2en7j5b.js → cli-n8mmw4c4.js} +1 -1
- package/build/cli-pndb7mh9.js +1193 -0
- package/build/cli-px6ehzqx.js +54 -0
- package/build/{cli-xtc2t6me.js → cli-qs4msn6x.js} +111 -47
- package/build/{cli-kb21qhvm.js → cli-rvybdhgn.js} +4 -3
- package/build/{cli-ae8jqxqr.js → cli-v739h7hb.js} +2 -2
- package/build/{cli-ngq9dr8n.js → cli-wm8ech0x.js} +3 -3
- package/build/cli.js +170 -51
- package/build/{config-zpqkd5cz.js → config-e5v1bkh1.js} +1 -1
- package/build/{fastStrike-mcjdvwez.js → fastStrike-efp0rjs3.js} +74 -17
- package/build/{fixes-kytx5dmj.js → fixes-926cw1ej.js} +16 -13
- package/build/{index-n65z6v7b.js → index-3t41p258.js} +7 -6
- package/build/{index-qv4cc65p.js → index-bv09af6g.js} +19 -15
- package/build/{index-je6hcsqr.js → index-bv6dtwse.js} +1 -1
- package/build/{index-4vqdgb42.js → index-jt52ffgn.js} +1657 -1400
- package/build/{index-ns4m4s01.js → index-np405b9e.js} +11 -7
- package/build/{index-r9yjkfrv.js → index-qys178kp.js} +5 -4
- package/build/{index-wqetp6gq.js → index-tpyzq2wq.js} +42 -11
- package/build/{index-fv64eb32.js → index-vrcdyebh.js} +2 -2
- package/build/{index-dr3tg1w3.js → index-z1g8vbtm.js} +1 -1
- package/build/{issues-eb3q9d3a.js → issues-sncyqh14.js} +16 -13
- package/build/{knowledge-fqsvtx0f.js → knowledge-esgvy5ws.js} +16 -13
- package/build/lance-sacfgs1z.js +232 -0
- package/build/lib/{chunk-9yksqgzr.js → chunk-4aevegnc.js} +77 -45
- package/build/lib/{chunk-9tt2021m.js → chunk-4kf4a15q.js} +13 -13
- package/build/lib/{chunk-fy3bbbqy.js → chunk-5avnedwm.js} +7 -1
- package/build/lib/{chunk-bb0ekhkw.js → chunk-5nz5tk3p.js} +76 -22
- package/build/lib/{chunk-4hwzqthr.js → chunk-7s8e5wrd.js} +3 -2
- package/build/lib/{chunk-yrnrbjes.js → chunk-85kpxwzs.js} +4 -2
- package/build/lib/{chunk-mg03jdmt.js → chunk-9jkzk9nc.js} +1 -1
- package/build/lib/{chunk-r4j8ybn9.js → chunk-9wwts6r6.js} +824 -77
- package/build/lib/{chunk-nhfax4gb.js → chunk-bxznzxdy.js} +5 -1
- package/build/lib/{chunk-r2dkp4tb.js → chunk-cqxm95md.js} +1 -1
- package/build/lib/{chunk-w66ce82a.js → chunk-e3agqspc.js} +12 -4
- package/build/lib/{chunk-ba41jh41.js → chunk-eh5yw385.js} +1137 -333
- package/build/lib/{chunk-1azdancq.js → chunk-ewc9r84m.js} +5 -1
- package/build/lib/{chunk-2njv7wz3.js → chunk-hbyxyxdc.js} +4 -0
- package/build/lib/{chunk-e8yy2k73.js → chunk-jhhwts6w.js} +28 -2
- package/build/lib/{chunk-1jvwqnem.js → chunk-kbxbd1kn.js} +108 -44
- package/build/lib/{chunk-7pwa92rn.js → chunk-mph5fvk7.js} +1 -1
- package/build/lib/chunk-psc23epq.js +107 -0
- package/build/lib/{chunk-acgbyf5h.js → chunk-qxad7qjd.js} +4 -2
- package/build/lib/{chunk-3c00n0cy.js → chunk-r0v3vvgm.js} +54 -33
- package/build/lib/{chunk-1yct6cra.js → chunk-rt13120a.js} +1 -1
- package/build/lib/{chunk-v3dk9j7k.js → chunk-sgya016v.js} +93 -22
- package/build/lib/{chunk-1fy8azee.js → chunk-txef92hq.js} +1 -1
- package/build/lib/{chunk-2qsq76xq.js → chunk-vcd90qrn.js} +189 -90
- package/build/lib/{chunk-7gjdygcx.js → chunk-vwr9w3ab.js} +2 -0
- package/build/lib/{chunk-z137x08b.js → chunk-wf6ak0m3.js} +92 -70
- package/build/lib/{chunk-xhdpgpkm.js → chunk-xft0ms9j.js} +2 -2
- package/build/lib/core/agents/agentRuntime.d.ts +3 -1
- package/build/lib/core/agents/defineAgent.d.ts +3 -2
- package/build/lib/core/agents/lance.d.ts +153 -0
- package/build/lib/core/agents/lanceJudge.d.ts +3 -0
- package/build/lib/core/agents/offSecAgent/index.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/index.js +16 -14
- package/build/lib/core/agents/offSecAgent/offensiveSecurityAgent.d.ts +4 -0
- package/build/lib/core/agents/offSecAgent/prompt.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/subagentSpawner.d.ts +18 -2
- package/build/lib/core/agents/offSecAgent/subagentSpawner.js +10 -8
- package/build/lib/core/agents/offSecAgent/toolExecutionContext.d.ts +3 -0
- package/build/lib/core/agents/offSecAgent/toolLifecycle.d.ts +1 -0
- package/build/lib/core/agents/offSecAgent/tools/index.js +10 -6
- package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
- package/build/lib/core/agents/offSecAgent/tools/reportError.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/tools/runPentestWorkflow.d.ts +20 -1
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestAgent.d.ts +4 -7
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestSwarm.d.ts +7 -1
- package/build/lib/core/agents/offSecAgent/tools/types.d.ts +6 -3
- package/build/lib/core/agents/offSecAgent/tools/whiteboxCandidates.d.ts +2 -2
- package/build/lib/core/agents/offSecAgent/types.d.ts +19 -3
- package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +13 -13
- package/build/lib/core/agents/specialized/attackSurface/schemas.js +12 -12
- package/build/lib/core/agents/specialized/authenticationAgent/index.js +14 -14
- package/build/lib/core/agents/specialized/codeAgent/agent.js +13 -13
- package/build/lib/core/agents/specialized/codeAgent/prompts.d.ts +1 -0
- package/build/lib/core/agents/specialized/cvssScorer/index.d.ts +2 -1
- package/build/lib/core/agents/specialized/findingJudge/agent.js +11 -11
- package/build/lib/core/agents/specialized/findingJudge/index.d.ts +2 -1
- package/build/lib/core/agents/specialized/findingJudge/index.js +4 -4
- package/build/lib/core/agents/specialized/patching/index.js +14 -14
- package/build/lib/core/agents/specialized/pentest/agent.d.ts +18 -4
- package/build/lib/core/agents/specialized/pentest/agent.js +15 -13
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.d.ts +2 -1
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +13 -13
- package/build/lib/core/ai/ai.d.ts +29 -70
- package/build/lib/core/ai/ai.js +5 -3
- package/build/lib/core/ai/index.d.ts +1 -0
- package/build/lib/core/ai/index.js +16 -4
- package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
- package/build/lib/core/ai/models/concentrate.d.ts +1 -0
- package/build/lib/core/ai/models/index.d.ts +1 -1
- package/build/lib/core/ai/providers/concentrate.d.ts +1 -0
- package/build/lib/core/ai/reasoning.d.ts +44 -0
- package/build/lib/core/ai/utils.d.ts +2 -0
- package/build/lib/core/ai/utils.js +5 -3
- package/build/lib/core/api/index.d.ts +6 -0
- package/build/lib/core/api/index.js +32 -23
- package/build/lib/core/api/lance.d.ts +6 -0
- package/build/lib/core/api/offesecAgent.d.ts +1 -0
- package/build/lib/core/api/reasoning.d.ts +12 -0
- package/build/lib/core/api/targetedPentest.d.ts +1 -0
- package/build/lib/core/api/targetedPentest.js +14 -14
- package/build/lib/core/cli/reasoning.d.ts +4 -0
- package/build/lib/core/config/config.d.ts +10 -2
- package/build/lib/core/config/customProviders.d.ts +11 -0
- package/build/lib/core/config/index.js +1 -1
- package/build/lib/core/eventBus.js +1 -1
- package/build/lib/core/findings/registry.d.ts +3 -1
- package/build/lib/core/findings/registry.js +4 -4
- package/build/lib/core/observability/index.js +1 -1
- package/build/lib/core/observability/telemetry.d.ts +4 -0
- package/build/lib/core/session/index.d.ts +47 -0
- package/build/lib/core/session/index.js +6 -4
- package/build/lib/core/session/persistence.d.ts +7 -0
- package/build/lib/core/session/persistence.js +8 -4
- package/build/lib/core/tools/backends/index.js +1 -1
- package/build/lib/core/tools/backends/resolve.d.ts +1 -0
- package/build/lib/core/workflows/fastStrike.d.ts +3 -1
- package/build/lib/core/workflows/pentest.d.ts +12 -2
- package/build/lib/core/workflows/pentest.js +19 -19
- package/build/lib/core/workflows/seams.js +5 -5
- package/build/lib/core/workflows/threatModel.d.ts +1 -0
- package/build/lib/core/workflows/whiteboxAttackSurface.d.ts +6 -4
- package/build/lib/core/workflows/whiteboxAttackSurface.js +15 -15
- package/build/lib/index.js +25 -25
- package/build/{logs-x62b7hk1.js → logs-bcbjpjp6.js} +16 -13
- package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-rph1774m.js} +5 -5
- package/build/offesecAgent-81h1p6ee.js +32 -0
- package/build/pentest-2q20q6n1.js +23 -0
- package/build/{pentests-e0f32aqx.js → pentests-jgw031mc.js} +16 -13
- package/build/recordedRunClient-6axj6fba.js +11 -0
- package/build/subagentSpawner-a861gvt0.js +12 -0
- package/build/targetedPentest-6yxznt7s.js +91 -0
- package/build/{targets-xj9g3q0z.js → targets-bjah19dp.js} +16 -13
- package/build/threatModel-739kpexm.js +24 -0
- package/build/{uninstall-7s784q4a.js → uninstall-yxrn9edt.js} +1 -1
- package/build/{upload-4gvhwmvr.js → upload-34ewrjp5.js} +4 -4
- package/build/{utils-cjrz64pc.js → utils-fzm66efw.js} +5 -5
- package/package.json +2 -1
- package/src/cli/issues.test.ts +17 -1
- package/src/cli/lance-verifier.test.ts +57 -0
- package/src/cli/lance-verifier.ts +73 -0
- package/src/cli/lance.test.ts +71 -0
- package/src/cli/lance.ts +48 -0
- package/src/cli.ts +109 -19
- package/src/core/agents/agentRuntime.test.ts +42 -0
- package/src/core/agents/agentRuntime.ts +7 -2
- package/src/core/agents/defineAgent.ts +3 -1
- package/src/core/agents/lance.test.ts +421 -0
- package/src/core/agents/lance.ts +701 -0
- package/src/core/agents/lanceJudge.test.ts +166 -0
- package/src/core/agents/lanceJudge.ts +115 -0
- package/src/core/agents/offSecAgent/index.ts +3 -0
- package/src/core/agents/offSecAgent/interruptedStepFinalization.test.ts +51 -0
- package/src/core/agents/offSecAgent/lance.test.ts +188 -0
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +244 -41
- package/src/core/agents/offSecAgent/prompt.test.ts +46 -0
- package/src/core/agents/offSecAgent/prompt.ts +52 -8
- package/src/core/agents/offSecAgent/selectiveConstruction.publicPath.test.ts +38 -0
- package/src/core/agents/offSecAgent/selectiveConstruction.test.ts +64 -0
- package/src/core/agents/offSecAgent/subagentSpawner.hooks.test.ts +11 -3
- package/src/core/agents/offSecAgent/subagentSpawner.reasoning.test.ts +167 -0
- package/src/core/agents/offSecAgent/subagentSpawner.ts +82 -28
- package/src/core/agents/offSecAgent/toolExecutionContext.test.ts +230 -0
- package/src/core/agents/offSecAgent/toolExecutionContext.ts +56 -0
- package/src/core/agents/offSecAgent/toolLifecycle.ts +2 -0
- package/src/core/agents/offSecAgent/tools/delegateAuth.ts +4 -2
- package/src/core/agents/offSecAgent/tools/documentFinding.test.ts +9 -4
- package/src/core/agents/offSecAgent/tools/documentFinding.ts +10 -9
- package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
- package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
- package/src/core/agents/offSecAgent/tools/reportError.test.ts +6 -0
- package/src/core/agents/offSecAgent/tools/reportError.ts +10 -2
- package/src/core/agents/offSecAgent/tools/runAttackSurface.ts +7 -4
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.test.ts +57 -0
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.ts +21 -1
- package/src/core/agents/offSecAgent/tools/runWhiteboxScan.ts +5 -2
- package/src/core/agents/offSecAgent/tools/spawnCodingAgent.ts +50 -67
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.test.ts +79 -3
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.ts +36 -16
- package/src/core/agents/offSecAgent/tools/spawnPentestSwarm.ts +28 -5
- package/src/core/agents/offSecAgent/tools/threatModelGenerator.ts +4 -3
- package/src/core/agents/offSecAgent/tools/types.ts +12 -2
- package/src/core/agents/offSecAgent/tools/updateTask.ts +5 -1
- package/src/core/agents/offSecAgent/tools/whiteboxCandidates.ts +11 -4
- package/src/core/agents/offSecAgent/types.ts +22 -1
- package/src/core/agents/specialized/codeAgent/agent.test.ts +7 -0
- package/src/core/agents/specialized/codeAgent/agent.ts +9 -2
- package/src/core/agents/specialized/codeAgent/prompts.ts +6 -0
- package/src/core/agents/specialized/cvssScorer/index.test.ts +2 -1
- package/src/core/agents/specialized/cvssScorer/index.ts +3 -0
- package/src/core/agents/specialized/findingJudge/index.ts +6 -0
- package/src/core/agents/specialized/pentest/agent.test.ts +155 -0
- package/src/core/agents/specialized/pentest/agent.ts +181 -52
- package/src/core/agents/specialized/pentest/results.test.ts +59 -4
- package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.concurrency.test.ts +59 -2
- package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.hooks.test.ts +127 -0
- package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.ts +74 -68
- package/src/core/ai/ai.durability-hooks.test.ts +25 -7
- package/src/core/ai/ai.lance.test.ts +581 -0
- package/src/core/ai/ai.operator-context.bench.test.ts +1390 -0
- package/src/core/ai/ai.recorded-context.test.ts +89 -8
- package/src/core/ai/ai.test.ts +81 -59
- package/src/core/ai/ai.ts +453 -327
- package/src/core/ai/compactionTelemetry.test.ts +69 -17
- package/src/core/ai/index.ts +11 -0
- package/src/core/ai/models/anthropic.ts +6 -0
- package/src/core/ai/models/bedrock.ts +18 -0
- package/src/core/ai/models/claude-capabilities.ts +29 -8
- package/src/core/ai/models/concentrate.ts +52 -0
- package/src/core/ai/models/index.ts +25 -4
- package/src/core/ai/models/models.test.ts +179 -7
- package/src/core/ai/models/openrouter-reasoning.json +219 -0
- package/src/core/ai/models/openrouter.ts +43 -1
- package/src/core/ai/providers/anthropic-models.test.ts +60 -1
- package/src/core/ai/providers/bedrock-models.test.ts +81 -0
- package/src/core/ai/providers/concentrate.test.ts +31 -0
- package/src/core/ai/providers/concentrate.ts +11 -0
- package/src/core/ai/providers/custom.test.ts +74 -0
- package/src/core/ai/providers/custom.ts +3 -1
- package/src/core/ai/providers/gateway-models.test.ts +16 -6
- package/src/core/ai/providers/pensarFormatters.ts +8 -1
- package/src/core/ai/reasoning.test.ts +313 -0
- package/src/core/ai/reasoning.ts +500 -0
- package/src/core/ai/streamIdleTimeout.test.ts +21 -0
- package/src/core/ai/utils.native-rollout-evidence.test.ts +21 -8
- package/src/core/ai/utils.ts +269 -163
- package/src/core/api/attackSurface.ts +1 -0
- package/src/core/api/blackboxPentest.ts +9 -1
- package/src/core/api/index.ts +17 -0
- package/src/core/api/lance.ts +23 -0
- package/src/core/api/offesecAgent.test.ts +51 -0
- package/src/core/api/offesecAgent.ts +15 -1
- package/src/core/api/reasoning.test.ts +213 -0
- package/src/core/api/reasoning.ts +44 -0
- package/src/core/api/recordedRun.loop.test.ts +5 -1
- package/src/core/api/targetedPentest.test.ts +14 -2
- package/src/core/api/targetedPentest.ts +52 -5
- package/src/core/cli/reasoning.test.ts +149 -0
- package/src/core/cli/reasoning.ts +95 -0
- package/src/core/config/config.test.ts +35 -0
- package/src/core/config/config.ts +11 -0
- package/src/core/config/customProviders.ts +21 -2
- package/src/core/eventBus.ts +1 -0
- package/src/core/findings/registry.test.ts +9 -1
- package/src/core/findings/registry.ts +6 -0
- package/src/core/observability/telemetry.test.ts +131 -79
- package/src/core/observability/telemetry.ts +5 -0
- package/src/core/runtime/sqliteRunObservation.test.ts +1 -1
- package/src/core/session/index.ts +38 -0
- package/src/core/session/persistence.test.ts +62 -0
- package/src/core/session/persistence.ts +56 -0
- package/src/core/tools/backends/resolve.ts +7 -0
- package/src/core/tools/backends/whiteboxJobs.test.ts +9 -8
- package/src/core/workflows/fastStrike.seams.test.ts +149 -0
- package/src/core/workflows/fastStrike.test.ts +18 -1
- package/src/core/workflows/fastStrike.ts +106 -11
- package/src/core/workflows/pentest.test.ts +104 -0
- package/src/core/workflows/pentest.ts +128 -7
- package/src/core/workflows/seams.test.ts +13 -0
- package/src/core/workflows/seams.ts +5 -1
- package/src/core/workflows/threatModel.ts +2 -0
- package/src/core/workflows/whiteboxAttackSurface.test.ts +74 -2
- package/src/core/workflows/whiteboxAttackSurface.ts +102 -73
- package/src/tui/command-registry.test.ts +12 -0
- package/src/tui/command-registry.ts +10 -0
- package/src/tui/components/chat/config-view.tsx +6 -10
- package/src/tui/components/chat/home-view.tsx +2 -2
- package/src/tui/components/chat/input-area.tsx +2 -2
- package/src/tui/components/chat/loading-indicator.tsx +20 -4
- package/src/tui/components/chat/message-list.tsx +1 -0
- package/src/tui/components/commands/__tests__/advanced-settings-lifecycle.tsx +164 -0
- package/src/tui/components/commands/advanced-settings.test.ts +34 -0
- package/src/tui/components/commands/advanced-settings.tsx +220 -31
- package/src/tui/components/commands/models-display.tsx +7 -1
- package/src/tui/components/model-picker/ModelPicker.tsx +65 -103
- package/src/tui/components/model-picker/ModelPickerDialog.tsx +8 -14
- package/src/tui/components/model-picker/__tests__/reasoning-control.tsx +162 -0
- package/src/tui/components/model-picker/reasoning-control.test.ts +15 -0
- package/src/tui/components/operator-dashboard/index.tsx +166 -50
- package/src/tui/components/operator-dashboard/logic.test.ts +144 -2
- package/src/tui/components/operator-dashboard/logic.ts +54 -3
- package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
- package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
- package/src/tui/components/shared/action-label.test.ts +9 -0
- package/src/tui/components/shared/compacting-icon.tsx +18 -0
- package/src/tui/components/shared/index.ts +1 -0
- package/src/tui/components/shared/tool-registry.ts +1 -0
- package/src/tui/components/shared/tool-renderer.tsx +21 -7
- package/src/tui/context/agent.tsx +32 -79
- package/src/tui/context/route.tsx +2 -0
- package/src/tui/index.tsx +1 -0
- package/src/tui/keybindings/registry.ts +2 -0
- package/build/agent-6w7egcf1.js +0 -13
- package/build/agent-9zx75feh.js +0 -13
- package/build/blackboxAgent-s56sgx9b.js +0 -13
- package/build/cli-g06s7edq.js +0 -11
- package/build/lib/chunk-z96pbjhd.js +0 -56
- package/build/offesecAgent-5whnpeta.js +0 -22
- package/build/pentest-e61hc38s.js +0 -22
- package/build/recordedRunClient-dp032c32.js +0 -11
- package/build/targetedPentest-rcbs4nvp.js +0 -57
- package/build/threatModel-jkxfa40s.js +0 -21
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { tool } from "ai";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { getModelSettings } from "../../../ai";
|
|
3
4
|
import type { AssetRecord } from "../../../findings/attackSurfaceRegistry";
|
|
4
5
|
import {
|
|
5
6
|
resolvePathWithinCodebaseRoot,
|
|
6
7
|
resolveWhiteboxCodebaseRoot,
|
|
7
8
|
} from "../../../whitebox";
|
|
8
|
-
import type
|
|
9
|
+
import { type SpawnOptions, spawnBatch } from "../subagentSpawner";
|
|
9
10
|
import type { ToolContext } from "./types";
|
|
10
11
|
|
|
11
12
|
/** Default max concurrent coding agents */
|
|
@@ -100,49 +101,46 @@ Returns an array of results with the text output from each agent.`,
|
|
|
100
101
|
|
|
101
102
|
const spawner = ctx.subagentSpawner;
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
);
|
|
119
|
-
return {
|
|
120
|
-
codebasePath: item.codebasePath,
|
|
121
|
-
objective: item.objective,
|
|
122
|
-
output,
|
|
123
|
-
};
|
|
124
|
-
} catch (err) {
|
|
125
|
-
return {
|
|
126
|
-
codebasePath: item.codebasePath,
|
|
127
|
-
objective: item.objective,
|
|
128
|
-
output: "",
|
|
129
|
-
error: err instanceof Error ? err.message : String(err),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
},
|
|
104
|
+
const textOutputs = validatedTasks.map(() => "");
|
|
105
|
+
const settled = await spawnBatch(
|
|
106
|
+
spawner,
|
|
107
|
+
validatedTasks.map((item, index) =>
|
|
108
|
+
codingSpawnOptions(
|
|
109
|
+
ctx,
|
|
110
|
+
item.codebasePath,
|
|
111
|
+
item.objective,
|
|
112
|
+
item.name,
|
|
113
|
+
toolCallId,
|
|
114
|
+
(text) => {
|
|
115
|
+
textOutputs[index] += text;
|
|
116
|
+
},
|
|
117
|
+
),
|
|
118
|
+
),
|
|
133
119
|
{ concurrency: DEFAULT_CONCURRENCY },
|
|
134
120
|
);
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
121
|
+
const results = [];
|
|
122
|
+
for (const [index, item] of validatedTasks.entries()) {
|
|
123
|
+
const result = settled[index]!;
|
|
124
|
+
try {
|
|
125
|
+
if (result.status === "rejected") throw result.reason;
|
|
126
|
+
if (result.value?.surface?.length && ctx.attackSurfaceRegistry) {
|
|
127
|
+
for (const asset of result.value.surface) {
|
|
128
|
+
await ctx.attackSurfaceRegistry.register(asset);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
results.push({
|
|
132
|
+
...item,
|
|
133
|
+
output: result.value?.text ?? textOutputs[index]!,
|
|
134
|
+
error: undefined,
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
results.push({
|
|
138
|
+
...item,
|
|
139
|
+
output: "",
|
|
140
|
+
error: error instanceof Error ? error.message : String(error),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
146
144
|
|
|
147
145
|
const failedTasks = results.filter((r) => r.error);
|
|
148
146
|
|
|
@@ -165,7 +163,7 @@ Returns an array of results with the text output from each agent.`,
|
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
// ---------------------------------------------------------------------------
|
|
168
|
-
//
|
|
166
|
+
// Child request
|
|
169
167
|
// ---------------------------------------------------------------------------
|
|
170
168
|
|
|
171
169
|
/** The slice of a durable CodeAgent child's returned value the parent folds. */
|
|
@@ -174,33 +172,28 @@ interface CodingChildResult {
|
|
|
174
172
|
text?: string;
|
|
175
173
|
}
|
|
176
174
|
|
|
177
|
-
|
|
175
|
+
function codingSpawnOptions(
|
|
178
176
|
ctx: ToolContext,
|
|
179
|
-
spawner: SubagentSpawner,
|
|
180
177
|
codebasePath: string,
|
|
181
178
|
objective: string,
|
|
182
|
-
_agentIndex: number,
|
|
183
179
|
name: string,
|
|
184
180
|
parentToolCallId: string,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const result = await spawner.spawn<CodingChildResult | undefined>({
|
|
181
|
+
onText: (text: string) => void,
|
|
182
|
+
): SpawnOptions<CodingChildResult | undefined> {
|
|
183
|
+
return {
|
|
189
184
|
spec: { type: "code", codebasePath, objective },
|
|
190
185
|
runtime: {
|
|
186
|
+
findingPolicy: ctx.findingPolicy,
|
|
191
187
|
session: ctx.session,
|
|
192
|
-
|
|
193
|
-
authConfig: ctx.authConfig,
|
|
188
|
+
...getModelSettings(ctx),
|
|
194
189
|
abortSignal: ctx.abortSignal,
|
|
195
190
|
sandbox: ctx.sandbox,
|
|
196
191
|
backends: ctx.backends,
|
|
197
192
|
environmentVariables: ctx.environmentVariables,
|
|
198
193
|
secretValues: ctx.secretValues,
|
|
199
|
-
enableThinking: ctx.enableThinking,
|
|
200
|
-
thinkingEffort: ctx.thinkingEffort,
|
|
201
|
-
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
202
194
|
languageModelMiddleware: ctx.languageModelMiddleware,
|
|
203
195
|
usageRecorder: ctx.usageRecorder,
|
|
196
|
+
toolExecutionContext: ctx.toolExecutionContext,
|
|
204
197
|
streamIdFactory: ctx.streamIdFactory,
|
|
205
198
|
},
|
|
206
199
|
parentBus: ctx.eventBus,
|
|
@@ -212,18 +205,8 @@ async function runSingleCodingAgent(
|
|
|
212
205
|
stampChildSessionId: true,
|
|
213
206
|
beforeConsume: (childBus) => {
|
|
214
207
|
childBus.on("text-delta", (d) => {
|
|
215
|
-
|
|
208
|
+
onText(d.text);
|
|
216
209
|
});
|
|
217
210
|
},
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Durable children return their surface by value (in-process children return
|
|
221
|
-
// void); fold it into the parent registry so dedup-in-parent closes.
|
|
222
|
-
if (result?.surface?.length && ctx.attackSurfaceRegistry) {
|
|
223
|
-
for (const asset of result.surface) {
|
|
224
|
-
await ctx.attackSurfaceRegistry.register(asset);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return result?.text ?? textOutput;
|
|
211
|
+
};
|
|
229
212
|
}
|
|
@@ -23,6 +23,9 @@ const registryCalls: Array<{
|
|
|
23
23
|
path: string;
|
|
24
24
|
options: Record<string, unknown>;
|
|
25
25
|
}> = [];
|
|
26
|
+
const swarmMock = vi.hoisted(() => ({
|
|
27
|
+
results: [] as Array<Record<string, unknown>>,
|
|
28
|
+
}));
|
|
26
29
|
|
|
27
30
|
vi.mock("../../specialized/pentest/agent", () => ({
|
|
28
31
|
TargetedPentestAgent: class {
|
|
@@ -46,7 +49,7 @@ vi.mock("../../../findings/registry", () => ({
|
|
|
46
49
|
|
|
47
50
|
vi.mock("../../../workflows/pentest", () => ({
|
|
48
51
|
DEFAULT_CONCURRENCY: 10,
|
|
49
|
-
runPentestSwarm: async () =>
|
|
52
|
+
runPentestSwarm: async () => swarmMock.results,
|
|
50
53
|
}));
|
|
51
54
|
|
|
52
55
|
import type { AIModel } from "../../../ai";
|
|
@@ -94,7 +97,12 @@ function makeParentSession(): {
|
|
|
94
97
|
async function runSpawn(
|
|
95
98
|
ctx: ToolContext,
|
|
96
99
|
inputOverrides: Record<string, unknown> = {},
|
|
97
|
-
): Promise<{
|
|
100
|
+
): Promise<{
|
|
101
|
+
success?: boolean;
|
|
102
|
+
message?: string;
|
|
103
|
+
findingsCount?: number;
|
|
104
|
+
reportedFindings?: string[];
|
|
105
|
+
}> {
|
|
98
106
|
const tool = spawnPentestAgent(ctx);
|
|
99
107
|
// biome-ignore lint/suspicious/noExplicitAny: ai-sdk tool execute receives an opaque ExecuteContext we don't need to narrow for this test.
|
|
100
108
|
return await (tool as any).execute(
|
|
@@ -110,6 +118,31 @@ async function runSpawn(
|
|
|
110
118
|
);
|
|
111
119
|
}
|
|
112
120
|
|
|
121
|
+
it("passes external grading to a worker and returns its findings without native documentation", async () => {
|
|
122
|
+
const spawn = vi.fn().mockResolvedValue({
|
|
123
|
+
findings: [],
|
|
124
|
+
reportedFindings: ["Cross-tenant read at GET /private"],
|
|
125
|
+
objectiveResults: [],
|
|
126
|
+
});
|
|
127
|
+
const ctx = buildCtx({
|
|
128
|
+
findingPolicy: "external",
|
|
129
|
+
subagentSpawner: { spawn, spawnMany: vi.fn() },
|
|
130
|
+
});
|
|
131
|
+
const result = await runSpawn(ctx);
|
|
132
|
+
expect(spawn).toHaveBeenCalledWith(
|
|
133
|
+
expect.objectContaining({
|
|
134
|
+
runtime: expect.objectContaining({ findingPolicy: "external" }),
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
expect(result).toMatchObject({
|
|
138
|
+
findingsCount: 1,
|
|
139
|
+
reportedFindings: ["Cross-tenant read at GET /private"],
|
|
140
|
+
});
|
|
141
|
+
const description = spawnPentestAgent(ctx).description;
|
|
142
|
+
expect(description).not.toContain("document_vulnerability");
|
|
143
|
+
expect(description).not.toContain("ONE MORE TIME");
|
|
144
|
+
});
|
|
145
|
+
|
|
113
146
|
function makeEventBus(): {
|
|
114
147
|
bus: ToolContext["eventBus"];
|
|
115
148
|
emit: ReturnType<typeof vi.fn>;
|
|
@@ -121,6 +154,7 @@ function makeEventBus(): {
|
|
|
121
154
|
afterEach(() => {
|
|
122
155
|
constructorCalls.length = 0;
|
|
123
156
|
registryCalls.length = 0;
|
|
157
|
+
swarmMock.results = [];
|
|
124
158
|
vi.restoreAllMocks();
|
|
125
159
|
});
|
|
126
160
|
|
|
@@ -154,16 +188,58 @@ describe("spawn_pentest_agent — usage callbacks", () => {
|
|
|
154
188
|
it("forwards usage callbacks to the worker", async () => {
|
|
155
189
|
const onStepFinish = vi.fn();
|
|
156
190
|
const onCacheMetrics = vi.fn();
|
|
157
|
-
const ctx = buildCtx({
|
|
191
|
+
const ctx = buildCtx({
|
|
192
|
+
model: "gpt-6.1-sol",
|
|
193
|
+
onStepFinish,
|
|
194
|
+
onCacheMetrics,
|
|
195
|
+
reasoning: "low",
|
|
196
|
+
});
|
|
158
197
|
|
|
159
198
|
await runSpawn(ctx);
|
|
160
199
|
|
|
161
200
|
expect(constructorCalls[0]?.onStepFinish).toBe(onStepFinish);
|
|
162
201
|
expect(constructorCalls[0]?.onCacheMetrics).toBe(onCacheMetrics);
|
|
202
|
+
expect(constructorCalls[0]?.reasoning).toBe("low");
|
|
163
203
|
});
|
|
164
204
|
});
|
|
165
205
|
|
|
166
206
|
describe("spawn tools — findings session attribution", () => {
|
|
207
|
+
it("returns each external swarm objective outcome to the parent", async () => {
|
|
208
|
+
swarmMock.results = [
|
|
209
|
+
{
|
|
210
|
+
findings: [],
|
|
211
|
+
reportedFindings: ["Cross-tenant read"],
|
|
212
|
+
objectiveResults: [
|
|
213
|
+
{
|
|
214
|
+
objective: "Extract the assigned flag",
|
|
215
|
+
completed: true,
|
|
216
|
+
result: "Extracted FLAG{example}",
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
];
|
|
221
|
+
const tool = spawnPentestSwarm(buildCtx({ findingPolicy: "external" }));
|
|
222
|
+
// biome-ignore lint/suspicious/noExplicitAny: ai-sdk tool execute receives an opaque ExecuteContext we don't need to narrow for this test.
|
|
223
|
+
const output = await (tool as any).execute(
|
|
224
|
+
{
|
|
225
|
+
targets: [{ target: "https://example.com/api", objectives: ["Test"] }],
|
|
226
|
+
toolCallDescription: "spawn swarm",
|
|
227
|
+
},
|
|
228
|
+
{ toolCallId: "tc_external", messages: [], abortSignal: undefined },
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
expect(output.results[0]).toMatchObject({
|
|
232
|
+
reportedFindings: ["Cross-tenant read"],
|
|
233
|
+
objectiveResults: [
|
|
234
|
+
{
|
|
235
|
+
objective: "Extract the assigned flag",
|
|
236
|
+
completed: true,
|
|
237
|
+
result: "Extracted FLAG{example}",
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
167
243
|
it("attributes the single-agent fallback registry to the root session", async () => {
|
|
168
244
|
await runSpawn(buildCtx());
|
|
169
245
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { tool } from "ai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { parseTargetUrl } from "../../../../util/url";
|
|
4
|
+
import { getModelSettings } from "../../../ai";
|
|
4
5
|
import { FindingsRegistry } from "../../../findings/registry";
|
|
5
6
|
// Type-only (erased) — the value is constructed inside the spawner registry.
|
|
6
7
|
import type { GrpcPentestContext } from "../../specialized/attackSurface/grpcSchema";
|
|
@@ -35,6 +36,22 @@ const ORIGIN_AUTH_FAILURE_GUIDANCE = `A 401/403 from one resource does not by it
|
|
|
35
36
|
* directly on the parent bus
|
|
36
37
|
*/
|
|
37
38
|
export function spawnPentestAgent(ctx: ToolContext) {
|
|
39
|
+
const externalFindings = ctx.findingPolicy === "external";
|
|
40
|
+
const findingSteps = externalFindings
|
|
41
|
+
? "2. Reports concise evidence-backed findings in its response\n3. Leaves acceptance to the caller's external evaluator"
|
|
42
|
+
: "2. Confirms vulnerabilities with POC scripts\n3. Documents findings to the shared findings registry only when the exploit path and material security impact are proven";
|
|
43
|
+
const findingGuidance = externalFindings
|
|
44
|
+
? "False-positive discipline: report a security weakness only when observations support a material abuse path. Include the affected target, evidence, and impact; do not add a separate in-run finding review."
|
|
45
|
+
: "False-positive discipline: workers should not call document_vulnerability for public/unauthenticated behavior, missing best-practice controls, generic errors, local HTTP deployment context, or other low-signal observations unless they prove a material abuse path such as non-public data access, credentialed cross-origin abuse, state change, denial of service, account takeover, or another concrete exploit chain.";
|
|
46
|
+
const returnGuidance = externalFindings
|
|
47
|
+
? "Returns the worker's summary, objective results, and reported findings so the parent can investigate chains."
|
|
48
|
+
: "Returns the worker's summary, objective results, and finding count — but NOT the findings themselves (those land in the shared registry).";
|
|
49
|
+
const exploratoryGuidance = externalFindings
|
|
50
|
+
? "Spawn a follow-up exploratory worker only when the assigned objective requires broader coverage or a credible untested lead remains. For detection-only work, finish once the requested evidence is sufficient."
|
|
51
|
+
: 'After fanning out one worker per objective, call this tool ONE MORE TIME for a final "exploratory" worker. Pass it the URLs of any suspicious behaviors discovered by earlier workers and ask it to chain findings together and probe for additional, unspecified vulnerabilities.';
|
|
52
|
+
const objectiveGuidance = externalFindings
|
|
53
|
+
? "Pass one focused objective per worker. A follow-up objective may cover a concrete chain or untested lead when the assignment calls for it."
|
|
54
|
+
: "For per-objective fan-out, pass exactly one objective. For the final exploratory pass, pass a single composite objective describing chaining + exploration.";
|
|
38
55
|
const targetScopeGuidance =
|
|
39
56
|
ctx.systemScope && ctx.systemScope.memberHosts.length > 0
|
|
40
57
|
? `For a cross-service follow-up, you may instead use a full URL on one of these authorized System Scope members: ${ctx.systemScope.memberHosts.join(", ")}.`
|
|
@@ -51,18 +68,17 @@ Authentication state is origin-specific. Before spawning a cross-service worker
|
|
|
51
68
|
|
|
52
69
|
Each spawn produces an independent TargetedPentestAgent that:
|
|
53
70
|
1. Tests the assigned objective(s) deeply (execute_command, http_request, browser tools)
|
|
54
|
-
|
|
55
|
-
3. Documents findings to the shared findings registry only when the exploit path and material security impact are proven
|
|
71
|
+
${findingSteps}
|
|
56
72
|
|
|
57
73
|
Cloned browser session — the worker gets its OWN isolated Chromium instance, but it is seeded at spawn time with a snapshot of your current cookies and localStorage. If you've already authenticated in your browser (or recon set up useful state), the worker starts already authenticated for the same origins. Critically, the worker's browser is a COPY: its navigations, form fills, \`localStorage.setItem\`, alerts, and any other browser-side mutations stay inside the worker's own browser and do NOT leak back to you or to sibling workers. If you want state to be visible to the next worker, set it up in YOUR browser before spawning.
|
|
58
74
|
|
|
59
75
|
The worker has no further spawn capability — it cannot recursively spawn other pentest agents.
|
|
60
76
|
|
|
61
|
-
|
|
77
|
+
${exploratoryGuidance}
|
|
62
78
|
|
|
63
|
-
|
|
79
|
+
${findingGuidance}
|
|
64
80
|
|
|
65
|
-
|
|
81
|
+
${returnGuidance}`,
|
|
66
82
|
inputSchema: z.object({
|
|
67
83
|
name: z
|
|
68
84
|
.string()
|
|
@@ -77,9 +93,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
77
93
|
objectives: z
|
|
78
94
|
.array(z.string())
|
|
79
95
|
.min(1)
|
|
80
|
-
.describe(
|
|
81
|
-
"Testing objectives for this worker. For per-objective fan-out, pass exactly one objective. For the final exploratory pass, pass a single composite objective describing chaining + exploration.",
|
|
82
|
-
),
|
|
96
|
+
.describe(`Testing objectives for this worker. ${objectiveGuidance}`),
|
|
83
97
|
context: z
|
|
84
98
|
.string()
|
|
85
99
|
.optional()
|
|
@@ -130,6 +144,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
130
144
|
const findingsRegistry =
|
|
131
145
|
ctx.findingsRegistry ??
|
|
132
146
|
FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
|
|
147
|
+
reasoning: ctx.reasoning,
|
|
133
148
|
model: ctx.model,
|
|
134
149
|
authConfig: ctx.authConfig,
|
|
135
150
|
abortSignal: ctx.abortSignal,
|
|
@@ -151,7 +166,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
151
166
|
const spawner = ctx.subagentSpawner;
|
|
152
167
|
let subagentId = "";
|
|
153
168
|
try {
|
|
154
|
-
const { findings, objectiveResults } =
|
|
169
|
+
const { findings, reportedFindings, objectiveResults } =
|
|
155
170
|
await spawner.spawn<PentestResult>({
|
|
156
171
|
spec: {
|
|
157
172
|
type: "pentest",
|
|
@@ -170,9 +185,9 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
170
185
|
browserSession: sharedBrowserSession,
|
|
171
186
|
},
|
|
172
187
|
runtime: {
|
|
188
|
+
findingPolicy: ctx.findingPolicy,
|
|
173
189
|
session: ctx.session,
|
|
174
|
-
|
|
175
|
-
authConfig: ctx.authConfig,
|
|
190
|
+
...getModelSettings(ctx),
|
|
176
191
|
abortSignal: ctx.abortSignal,
|
|
177
192
|
onStepFinish: ctx.onStepFinish,
|
|
178
193
|
onCacheMetrics: ctx.onCacheMetrics,
|
|
@@ -180,11 +195,9 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
180
195
|
backends: ctx.backends,
|
|
181
196
|
display: ctx.display,
|
|
182
197
|
secretValues: ctx.secretValues,
|
|
183
|
-
enableThinking: ctx.enableThinking,
|
|
184
|
-
thinkingEffort: ctx.thinkingEffort,
|
|
185
|
-
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
186
198
|
languageModelMiddleware: ctx.languageModelMiddleware,
|
|
187
199
|
usageRecorder: ctx.usageRecorder,
|
|
200
|
+
toolExecutionContext: ctx.toolExecutionContext,
|
|
188
201
|
streamIdFactory: ctx.streamIdFactory,
|
|
189
202
|
},
|
|
190
203
|
parentBus: ctx.eventBus,
|
|
@@ -203,9 +216,16 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
203
216
|
return {
|
|
204
217
|
success: true,
|
|
205
218
|
subagentId,
|
|
206
|
-
findingsCount:
|
|
219
|
+
findingsCount: externalFindings
|
|
220
|
+
? (reportedFindings?.length ?? 0)
|
|
221
|
+
: findings.length,
|
|
222
|
+
...(externalFindings
|
|
223
|
+
? { reportedFindings: reportedFindings ?? [] }
|
|
224
|
+
: {}),
|
|
207
225
|
objectiveResults,
|
|
208
|
-
message:
|
|
226
|
+
message: externalFindings
|
|
227
|
+
? `Worker '${name}' complete. Reported ${reportedFindings?.length ?? 0} finding(s) for external evaluation.`
|
|
228
|
+
: `Worker '${name}' complete. Documented ${findings.length} finding(s).`,
|
|
209
229
|
};
|
|
210
230
|
} catch (error) {
|
|
211
231
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -21,15 +21,21 @@ const log = scopedLogger(() => createLogger("spawn-pentest-swarm"));
|
|
|
21
21
|
* after recon, it calls this tool to fan-out testing to sub-agents.
|
|
22
22
|
*/
|
|
23
23
|
export function spawnPentestSwarm(ctx: ToolContext) {
|
|
24
|
+
const externalFindings = ctx.findingPolicy === "external";
|
|
25
|
+
const findingSteps = externalFindings
|
|
26
|
+
? "2. Surface concise evidence-backed findings in its response\n3. Leave finding acceptance to the caller's evaluator"
|
|
27
|
+
: "2. Create POC scripts for confirmed vulnerabilities\n3. Document findings with evidence and remediation";
|
|
28
|
+
const findingDestination = externalFindings
|
|
29
|
+
? "Reported findings are returned to this caller; no native finding review runs."
|
|
30
|
+
: "All findings are written to the shared session directory.";
|
|
24
31
|
return tool({
|
|
25
32
|
description: `Launch a swarm of targeted pentest sub-agents to test multiple targets in parallel.
|
|
26
33
|
|
|
27
34
|
Call this AFTER completing attack surface discovery. Each entry in 'targets' spawns an independent TargetedPentestAgent that will:
|
|
28
35
|
1. Test the specified target for the given objectives
|
|
29
|
-
|
|
30
|
-
3. Document findings with evidence and remediation
|
|
36
|
+
${findingSteps}
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
${findingDestination}
|
|
33
39
|
|
|
34
40
|
Pass every target you want tested — the swarm handles concurrency automatically.`,
|
|
35
41
|
inputSchema: z.object({
|
|
@@ -79,6 +85,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
79
85
|
const findingsRegistry =
|
|
80
86
|
ctx.findingsRegistry ??
|
|
81
87
|
FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
|
|
88
|
+
reasoning: ctx.reasoning,
|
|
82
89
|
model: ctx.model!,
|
|
83
90
|
authConfig: ctx.authConfig,
|
|
84
91
|
abortSignal: ctx.abortSignal,
|
|
@@ -92,6 +99,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
92
99
|
);
|
|
93
100
|
|
|
94
101
|
const swarmResults = await runPentestSwarm({
|
|
102
|
+
findingPolicy: ctx.findingPolicy,
|
|
95
103
|
targets,
|
|
96
104
|
model: ctx.model!,
|
|
97
105
|
session: ctx.session,
|
|
@@ -105,12 +113,15 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
105
113
|
enableThinking: ctx.enableThinking,
|
|
106
114
|
thinkingEffort: ctx.thinkingEffort,
|
|
107
115
|
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
116
|
+
reasoning: ctx.reasoning,
|
|
108
117
|
display: ctx.display,
|
|
109
118
|
hooks: {
|
|
119
|
+
findingPolicy: ctx.findingPolicy,
|
|
110
120
|
backends: ctx.backends,
|
|
111
121
|
subagentSpawner: ctx.subagentSpawner,
|
|
112
122
|
languageModelMiddleware: ctx.languageModelMiddleware,
|
|
113
123
|
usageRecorder: ctx.usageRecorder,
|
|
124
|
+
toolExecutionContext: ctx.toolExecutionContext,
|
|
114
125
|
streamIdFactory: ctx.streamIdFactory,
|
|
115
126
|
smsInbox: ctx.smsInbox,
|
|
116
127
|
emailAdapterFor: ctx.emailAdapterFor,
|
|
@@ -120,7 +131,11 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
120
131
|
|
|
121
132
|
// Aggregate
|
|
122
133
|
const totalFindings = swarmResults.reduce(
|
|
123
|
-
(sum, r) =>
|
|
134
|
+
(sum, r) =>
|
|
135
|
+
sum +
|
|
136
|
+
(externalFindings
|
|
137
|
+
? (r?.reportedFindings?.length ?? 0)
|
|
138
|
+
: (r?.findings.length ?? 0)),
|
|
124
139
|
0,
|
|
125
140
|
);
|
|
126
141
|
const failedCount = swarmResults.filter((r) => r == null).length;
|
|
@@ -132,7 +147,15 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
132
147
|
failedTargets: failedCount,
|
|
133
148
|
results: targets.map((t, i) => ({
|
|
134
149
|
target: t.target,
|
|
135
|
-
findingsCount:
|
|
150
|
+
findingsCount: externalFindings
|
|
151
|
+
? (swarmResults[i]?.reportedFindings?.length ?? 0)
|
|
152
|
+
: (swarmResults[i]?.findings.length ?? 0),
|
|
153
|
+
...(externalFindings
|
|
154
|
+
? {
|
|
155
|
+
reportedFindings: swarmResults[i]?.reportedFindings ?? [],
|
|
156
|
+
objectiveResults: swarmResults[i]?.objectiveResults ?? [],
|
|
157
|
+
}
|
|
158
|
+
: {}),
|
|
136
159
|
error: swarmResults[i] == null ? "Agent failed" : undefined,
|
|
137
160
|
})),
|
|
138
161
|
message: `Swarm complete. ${totalFindings} findings across ${total} targets. ${
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stepCountIs } from "ai";
|
|
2
2
|
import pLimit from "p-limit";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { getModelSettings } from "../../../ai";
|
|
4
5
|
import { createLogger } from "../../../logger/structured";
|
|
5
6
|
import { scopedLogger } from "../../../util/lazyLogger";
|
|
6
7
|
import type {
|
|
@@ -314,7 +315,6 @@ export async function generateThreatModelForEndpoint(
|
|
|
314
315
|
input: GenerateThreatModelInput,
|
|
315
316
|
): Promise<ThreatModelOutput | null> {
|
|
316
317
|
if (!ctx.model) return null;
|
|
317
|
-
const model = ctx.model;
|
|
318
318
|
|
|
319
319
|
return threatModelLimiter(async () => {
|
|
320
320
|
if (ctx.abortSignal?.aborted) return null;
|
|
@@ -373,13 +373,14 @@ export async function generateThreatModelForEndpoint(
|
|
|
373
373
|
excludeTools: ["document_endpoint", "document_app"],
|
|
374
374
|
},
|
|
375
375
|
runtime: {
|
|
376
|
+
findingPolicy: ctx.findingPolicy,
|
|
376
377
|
session: ctx.session,
|
|
377
|
-
|
|
378
|
-
authConfig: ctx.authConfig,
|
|
378
|
+
...getModelSettings(ctx),
|
|
379
379
|
abortSignal: childAbort.signal,
|
|
380
380
|
backends: ctx.backends,
|
|
381
381
|
languageModelMiddleware: ctx.languageModelMiddleware,
|
|
382
382
|
usageRecorder: ctx.usageRecorder,
|
|
383
|
+
toolExecutionContext: ctx.toolExecutionContext,
|
|
383
384
|
streamIdFactory: ctx.streamIdFactory,
|
|
384
385
|
},
|
|
385
386
|
parentBus: ctx.eventBus,
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
AIModel,
|
|
9
9
|
CacheMetrics,
|
|
10
10
|
OpenAIReasoningEffort,
|
|
11
|
+
ReasoningSetting,
|
|
11
12
|
ThinkingEffort,
|
|
12
13
|
UsageRecorder,
|
|
13
14
|
} from "../../../ai";
|
|
@@ -22,7 +23,12 @@ import type { ToolBackends } from "../../../tools/backends/types";
|
|
|
22
23
|
import type { GrpcPentestContext } from "../../specialized/attackSurface/grpcSchema";
|
|
23
24
|
import type { SubagentSpawner } from "../subagentSpawner";
|
|
24
25
|
import type { StepTraceWriter } from "../trace";
|
|
25
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
AgentHooks,
|
|
28
|
+
FindingPolicy,
|
|
29
|
+
StreamIdFactory,
|
|
30
|
+
SystemPentestScope,
|
|
31
|
+
} from "../types";
|
|
26
32
|
import type { CallbackListenerRegistry } from "./callbackListener";
|
|
27
33
|
import type { EmailAdapterResolver } from "./email/adapters";
|
|
28
34
|
import type { PerCommandShell } from "./perCommandShell";
|
|
@@ -38,6 +44,7 @@ import type { SmsInbox } from "./smsInbox";
|
|
|
38
44
|
* session or agent internals directly.
|
|
39
45
|
*/
|
|
40
46
|
export type ToolContext = {
|
|
47
|
+
findingPolicy?: FindingPolicy;
|
|
41
48
|
attackSurfaceArtifactsPath?: string;
|
|
42
49
|
|
|
43
50
|
/** Session providing paths for findings, POCs, logs, scratchpad, etc. */
|
|
@@ -172,6 +179,7 @@ export type ToolContext = {
|
|
|
172
179
|
|
|
173
180
|
/** OpenAI reasoning effort for GPT/o-series sub-agents. */
|
|
174
181
|
openAIReasoningEffort?: OpenAIReasoningEffort | null;
|
|
182
|
+
reasoning?: ReasoningSetting;
|
|
175
183
|
|
|
176
184
|
/**
|
|
177
185
|
* Whitebox attack surface flag. Forwarded into `runPentestWorkflow` so the
|
|
@@ -229,7 +237,7 @@ export type ToolContext = {
|
|
|
229
237
|
* the agent builds its tools (`OffensiveSecurityAgentInput.subagentSpawner` ??
|
|
230
238
|
* the in-process spawner), so it is always present here and tools never
|
|
231
239
|
* re-default it; a durable runtime injects one that spawns child workflows
|
|
232
|
-
* instead. The
|
|
240
|
+
* instead. The durable hooks below are inherited by every child the
|
|
233
241
|
* spawner constructs.
|
|
234
242
|
*/
|
|
235
243
|
subagentSpawner: SubagentSpawner;
|
|
@@ -256,6 +264,8 @@ export type ToolContext = {
|
|
|
256
264
|
*/
|
|
257
265
|
emailAdapterFor?: EmailAdapterResolver;
|
|
258
266
|
|
|
267
|
+
toolExecutionContext?: AgentHooks["toolExecutionContext"];
|
|
268
|
+
|
|
259
269
|
/** Provider middleware inherited by spawned children. Unset → raw model. */
|
|
260
270
|
languageModelMiddleware?: LanguageModelMiddleware | LanguageModelMiddleware[];
|
|
261
271
|
|
|
@@ -34,12 +34,16 @@ type UpdateTaskResult = {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export function updateTask(ctx: ToolContext) {
|
|
37
|
+
const completedGuidance =
|
|
38
|
+
ctx.findingPolicy === "external"
|
|
39
|
+
? "vulnerability identified with supporting evidence, OR conclusively determined the endpoint is not vulnerable / materiality is not met for this technique."
|
|
40
|
+
: "vulnerability found and documented via document_vulnerability, OR conclusively determined the endpoint is not vulnerable / materiality is not met for this technique. Documentation is NOT required to complete a non-vulnerable task.";
|
|
37
41
|
return tool({
|
|
38
42
|
description: `Update a task's status and record results.
|
|
39
43
|
|
|
40
44
|
Status transitions:
|
|
41
45
|
- "in_progress" — Set when you START testing a task. Pick one pending task at a time.
|
|
42
|
-
- "completed" — Set when testing is done:
|
|
46
|
+
- "completed" — Set when testing is done: ${completedGuidance}
|
|
43
47
|
- "failed" — Set when the technique didn't work: rate limited, blocked by WAF, dead end, or approach not applicable. Then create a NEW task with an alternative technique.
|
|
44
48
|
|
|
45
49
|
Always include a result or observation explaining the outcome.`,
|
|
@@ -47,12 +47,15 @@ const CandidateStateSchema = z.enum([
|
|
|
47
47
|
]);
|
|
48
48
|
|
|
49
49
|
export function createWhiteboxCandidate(ctx: ToolContext) {
|
|
50
|
+
const candidateGuidance =
|
|
51
|
+
ctx.findingPolicy === "external"
|
|
52
|
+
? "for the caller's final evaluation. Candidates keep hypotheses, source-to-sink traces, scanner artifacts, fuzzing logs, and verification status separate from reported findings."
|
|
53
|
+
: "for document_vulnerability. Candidates keep hypotheses, source-to-sink traces,\nscanner artifacts, fuzzing logs, and verification status out of official findings.";
|
|
50
54
|
return tool({
|
|
51
55
|
description: `Create a whitebox vulnerability candidate.
|
|
52
56
|
|
|
53
57
|
Use this for plausible source-code findings that are not yet confirmed enough
|
|
54
|
-
|
|
55
|
-
scanner artifacts, fuzzing logs, and verification status out of official findings.`,
|
|
58
|
+
${candidateGuidance}`,
|
|
56
59
|
inputSchema: z.object({
|
|
57
60
|
title: z.string(),
|
|
58
61
|
vulnerabilityClass: z.string(),
|
|
@@ -81,7 +84,9 @@ scanner artifacts, fuzzing logs, and verification status out of official finding
|
|
|
81
84
|
artifactPaths: candidate.artifacts.map((artifact) => artifact.path),
|
|
82
85
|
nextActions: [
|
|
83
86
|
"Move candidate to investigating after reading source context.",
|
|
84
|
-
|
|
87
|
+
ctx.findingPolicy === "external"
|
|
88
|
+
? "Gather the evidence required by the caller before reporting this candidate."
|
|
89
|
+
: "Attempt a reproducer or dynamic verification before document_vulnerability.",
|
|
85
90
|
],
|
|
86
91
|
truncated: false,
|
|
87
92
|
};
|
|
@@ -132,7 +137,9 @@ State machine: hypothesis -> investigating -> repro_attempted -> confirmed (requ
|
|
|
132
137
|
nextActions:
|
|
133
138
|
candidate.state === "confirmed"
|
|
134
139
|
? [
|
|
135
|
-
|
|
140
|
+
ctx.findingPolicy === "external"
|
|
141
|
+
? "Report only the evidence-backed conclusion to the caller."
|
|
142
|
+
: "Use document_vulnerability only if the proof demonstrates exploitability.",
|
|
136
143
|
]
|
|
137
144
|
: [
|
|
138
145
|
"Continue tracing or verification based on the candidate state.",
|