pentesting 0.73.14 → 0.90.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/README.md +120 -49
- package/bin/pentesting.mjs +32 -0
- package/lib/runtime.mjs +419 -0
- package/package.json +17 -46
- package/scripts/postinstall.mjs +30 -0
- package/scripts/preflight-local.sh +24 -0
- package/dist/ad/prompt.md +0 -60
- package/dist/agent-tool-MMDCBQ74.js +0 -989
- package/dist/api/prompt.md +0 -63
- package/dist/chunk-4KLVUP3C.js +0 -11458
- package/dist/chunk-AEQNELCQ.js +0 -5930
- package/dist/chunk-YZNPWDNS.js +0 -1166
- package/dist/cloud/prompt.md +0 -49
- package/dist/container/prompt.md +0 -58
- package/dist/database/prompt.md +0 -58
- package/dist/email/prompt.md +0 -44
- package/dist/file-sharing/prompt.md +0 -56
- package/dist/ics/prompt.md +0 -76
- package/dist/main.d.ts +0 -1
- package/dist/main.js +0 -9737
- package/dist/network/prompt.md +0 -49
- package/dist/persistence-IGAKJZJ3.js +0 -13
- package/dist/process-registry-DNEZX4S5.js +0 -30
- package/dist/prompts/base.md +0 -436
- package/dist/prompts/ctf-crypto.md +0 -168
- package/dist/prompts/ctf-forensics.md +0 -182
- package/dist/prompts/ctf-pwn.md +0 -137
- package/dist/prompts/evasion.md +0 -215
- package/dist/prompts/exploit.md +0 -416
- package/dist/prompts/infra.md +0 -114
- package/dist/prompts/llm/analyst-system.md +0 -76
- package/dist/prompts/llm/context-extractor-system.md +0 -19
- package/dist/prompts/llm/input-processor-system.md +0 -64
- package/dist/prompts/llm/memory-synth-system.md +0 -14
- package/dist/prompts/llm/playbook-synthesizer-system.md +0 -10
- package/dist/prompts/llm/reflector-system.md +0 -16
- package/dist/prompts/llm/report-generator-system.md +0 -21
- package/dist/prompts/llm/strategist-fallback.md +0 -9
- package/dist/prompts/llm/triage-system.md +0 -47
- package/dist/prompts/main-agent.md +0 -193
- package/dist/prompts/offensive-playbook.md +0 -250
- package/dist/prompts/payload-craft.md +0 -181
- package/dist/prompts/post.md +0 -185
- package/dist/prompts/recon.md +0 -296
- package/dist/prompts/report.md +0 -98
- package/dist/prompts/strategist-system.md +0 -472
- package/dist/prompts/strategy.md +0 -163
- package/dist/prompts/techniques/README.md +0 -40
- package/dist/prompts/techniques/ad-attack.md +0 -261
- package/dist/prompts/techniques/auth-access.md +0 -256
- package/dist/prompts/techniques/container-escape.md +0 -103
- package/dist/prompts/techniques/crypto.md +0 -296
- package/dist/prompts/techniques/enterprise-pentest.md +0 -175
- package/dist/prompts/techniques/file-attacks.md +0 -144
- package/dist/prompts/techniques/forensics.md +0 -313
- package/dist/prompts/techniques/injection.md +0 -217
- package/dist/prompts/techniques/lateral.md +0 -128
- package/dist/prompts/techniques/network-svc.md +0 -229
- package/dist/prompts/techniques/pivoting.md +0 -205
- package/dist/prompts/techniques/privesc.md +0 -190
- package/dist/prompts/techniques/pwn.md +0 -595
- package/dist/prompts/techniques/reversing.md +0 -183
- package/dist/prompts/techniques/sandbox-escape.md +0 -73
- package/dist/prompts/techniques/shells.md +0 -194
- package/dist/prompts/vuln.md +0 -190
- package/dist/prompts/web.md +0 -318
- package/dist/prompts/zero-day.md +0 -298
- package/dist/remote-access/prompt.md +0 -52
- package/dist/web/prompt.md +0 -59
- package/dist/wireless/prompt.md +0 -62
package/README.md
CHANGED
|
@@ -1,79 +1,150 @@
|
|
|
1
|
-
|
|
1
|
+
# pentesting
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<img src="https://api.iconify.design/game-icons:fizzing-flask.svg?color=%232496ED" width="80" height="80" alt="Pentesting Agent" />
|
|
5
|
-
</a>
|
|
3
|
+
`pentesting` is the public npm facade for the Builder runtime.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
- Installs the `pentesting` CLI.
|
|
6
|
+
- Keeps `builder` as a temporary compatibility alias.
|
|
7
|
+
- Downloads the matching Builder binary from `agnusdei1207/builder` releases for the current OS/CPU.
|
|
8
|
+
- Performs only minimal wrapping before delegating execution to the Rust Builder binary.
|
|
9
|
+
- Does not ship a second JavaScript or TypeScript runtime.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
[](https://hub.docker.com/r/agnusdei1207/pentesting)
|
|
12
|
-
[](https://agnusdei1207.github.io/brainscience/pentesting/)
|
|
11
|
+
## Install
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g pentesting
|
|
15
|
+
pentesting
|
|
16
|
+
builder --version
|
|
17
|
+
```
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
## Quick commands
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
```bash
|
|
22
|
+
pentesting
|
|
23
|
+
pentesting run "Enumerate the target web application and summarize the next actions."
|
|
24
|
+
pentesting scan 10.10.10.10
|
|
25
|
+
builder --version
|
|
26
|
+
```
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
Inside the interactive TUI:
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
```text
|
|
31
|
+
/goal harden the npm release flow and verify Docker startup
|
|
32
|
+
/auto
|
|
33
|
+
```
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
- `/goal <objective>` sets the active goal only.
|
|
36
|
+
- `/goal` with no text clears the goal and disables auto mode.
|
|
37
|
+
- `/auto` toggles auto mode for the current goal.
|
|
38
|
+
- `/auto` requires an existing goal and will not infer one from the transcript.
|
|
39
|
+
- `/auto <text>` is rejected with usage guidance; use `/goal <objective>` first, then `/auto`.
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|---------|-----------------|
|
|
30
|
-
|  |  |
|
|
41
|
+
## What npm installs
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
`npm install -g pentesting` installs a thin wrapper package and then runs `postinstall`:
|
|
44
|
+
|
|
45
|
+
- if `BUILDER_BIN` is already set, the wrapper reuses that Builder executable
|
|
46
|
+
- if `BUILDER_SKIP_DOWNLOAD=true`, the wrapper skips managed download entirely
|
|
47
|
+
- otherwise it downloads the matching public Builder release asset into the package-local managed binary directory and executes that binary on launch
|
|
48
|
+
|
|
49
|
+
This means the outside package name is `pentesting`, but the actual runtime engine is Builder.
|
|
50
|
+
|
|
51
|
+
## Thin-wrapper design
|
|
52
|
+
|
|
53
|
+
The npm package is intentionally narrow.
|
|
54
|
+
|
|
55
|
+
- it installs a launcher, not a second agent runtime
|
|
56
|
+
- it resolves or downloads the correct Builder release asset
|
|
57
|
+
- it forwards execution into the Rust Builder binary
|
|
58
|
+
- it keeps only minimal compatibility translation for legacy `interactive`, `run`, and `scan` entrypoints
|
|
33
59
|
|
|
34
|
-
|
|
60
|
+
If a change would add orchestration, memory, monitoring, or prompt-management logic directly into the npm layer, that change belongs upstream in Builder instead.
|
|
35
61
|
|
|
36
|
-
|
|
62
|
+
## Runtime strengths exposed through pentesting
|
|
37
63
|
|
|
38
|
-
|
|
64
|
+
Because `pentesting` delegates to the Rust Builder runtime, it inherits the same core capabilities:
|
|
39
65
|
|
|
40
|
-
|
|
66
|
+
- goal-aware TUI sessions through `/goal`
|
|
67
|
+
- explicit auto-mode toggling through `/auto`
|
|
68
|
+
- post-turn self-review and persistent local memory files
|
|
69
|
+
- context compression for long-running sessions
|
|
70
|
+
- workflow status, budget, proof, and verification signals in the TUI
|
|
71
|
+
- Docker and npm entrypoints that share one runtime instead of diverging implementations
|
|
72
|
+
|
|
73
|
+
## Docker and compose alternative
|
|
74
|
+
|
|
75
|
+
If you do not want a managed local binary, use Builder directly through Docker:
|
|
41
76
|
|
|
42
77
|
```bash
|
|
43
78
|
docker run -it --rm \
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
-v pentesting-data:/tmp/.pentesting \
|
|
48
|
-
agnusdei1207/pentesting
|
|
79
|
+
-v "$(pwd):/workspace" \
|
|
80
|
+
-w /workspace \
|
|
81
|
+
agnusdei1207/builder:latest
|
|
49
82
|
```
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
The entrypoint resets that directory on each fresh container start to avoid mixing stale state into a new run.
|
|
53
|
-
Mount that path if you want access to `.pentesting/turns`, `.pentesting/sessions`, `.pentesting/memory`, and workspace artifacts after an OOM or while the same container is still alive.
|
|
54
|
-
|
|
55
|
-
### 🐉 Kali Linux (Native)
|
|
84
|
+
For a PostgreSQL-backed compose path, use the public `compose.yaml` facade from the public repo or mirrored docs:
|
|
56
85
|
|
|
57
86
|
```bash
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
pentesting
|
|
87
|
+
docker compose up -d postgres
|
|
88
|
+
PENTESTING_PROJECT_DIR=/path/to/project docker compose run pentesting
|
|
61
89
|
```
|
|
62
90
|
|
|
63
|
-
|
|
91
|
+
## Supported runtime targets
|
|
64
92
|
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
93
|
+
| OS | CPU | Release asset |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| Linux | x64 | `builder-x86_64-unknown-linux-musl` |
|
|
96
|
+
| Linux | arm64 | `builder-aarch64-unknown-linux-musl` |
|
|
97
|
+
| macOS | x64 | `builder-x86_64-apple-darwin` |
|
|
98
|
+
| macOS | arm64 | `builder-aarch64-apple-darwin` |
|
|
99
|
+
| Windows | x64 | `builder-x86_64-pc-windows-msvc.exe` |
|
|
100
|
+
| Windows | arm64 | `builder-aarch64-pc-windows-msvc.exe` |
|
|
101
|
+
| Android | arm64 | `builder-aarch64-linux-android` |
|
|
102
|
+
|
|
103
|
+
## Environment variables
|
|
104
|
+
|
|
105
|
+
| Variable | Description |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `BUILDER_BIN` | Use an already-installed Builder binary instead of the managed download. |
|
|
108
|
+
| `BUILDER_REPO` | Override the public release repo used for binary downloads. Defaults to `agnusdei1207/builder`. |
|
|
109
|
+
| `BUILDER_SKIP_DOWNLOAD` | Skip the postinstall binary download. Useful in CI or when `BUILDER_BIN` will be provided later. |
|
|
110
|
+
|
|
111
|
+
## Compatibility wrappers
|
|
112
|
+
|
|
113
|
+
- `pentesting` / `pentesting interactive` starts Builder interactive mode.
|
|
114
|
+
- `pentesting run "<objective>"` becomes a Builder prompt tailored for the objective.
|
|
115
|
+
- `pentesting scan <target>` becomes a Builder prompt tailored for recon and pentest scanning.
|
|
116
|
+
- `builder` remains available as a compatibility alias during the naming transition.
|
|
117
|
+
|
|
118
|
+
## Runtime behavior notes
|
|
119
|
+
|
|
120
|
+
- `pentesting` with no extra arguments starts the Builder interactive/default flow.
|
|
121
|
+
- `builder` and `pentesting` share the same wrapper entrypoint in the public package.
|
|
122
|
+
- Docker and npm both end up delegating to the same upstream Builder runtime, so differences are usually install/configuration problems rather than different products.
|
|
123
|
+
|
|
124
|
+
## Runtime cautions
|
|
125
|
+
|
|
126
|
+
- `BUILDER_SKIP_DOWNLOAD=true` is only safe when you intentionally plan to provide `BUILDER_BIN` later or reinstall after provisioning access to the Builder release asset.
|
|
127
|
+
- The npm package does not publish Docker images itself. Docker users should treat `agnusdei1207/builder:latest` as the runtime image and `pentesting` as the public command/package facade.
|
|
128
|
+
- Unsupported OS/CPU pairs fail during release asset resolution before download.
|
|
129
|
+
- If the managed binary is missing at runtime, reinstall the package or set `BUILDER_BIN` explicitly.
|
|
130
|
+
|
|
131
|
+
## Development and release from source
|
|
132
|
+
|
|
133
|
+
If you maintain this npm facade from the private source repository, use the root `builder-private` commands rather than adding more logic inside this package:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm run pentesting:status
|
|
137
|
+
npm run pentesting:verify
|
|
138
|
+
npm run pentesting:pack:dry-run
|
|
139
|
+
npm run pentesting:release:patch:dry-run
|
|
140
|
+
NPM_TOKEN=... npm run pentesting:publish -- 0.90.1
|
|
141
|
+
```
|
|
73
142
|
|
|
74
|
-
##
|
|
143
|
+
## Further reading
|
|
75
144
|
|
|
76
|
-
|
|
145
|
+
- public Builder runtime docs and Docker guidance
|
|
146
|
+
- the mirrored public `compose.yaml` facade for PostgreSQL-backed sessions
|
|
147
|
+
- the Builder release asset matching your OS/CPU target
|
|
77
148
|
|
|
78
149
|
---
|
|
79
150
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
import { resolveBuilderBinary, translateBuilderInvocation } from "../lib/runtime.mjs";
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
const invocation = translateBuilderInvocation(process.argv.slice(2));
|
|
9
|
+
for (const warning of invocation.warnings) {
|
|
10
|
+
console.warn(`[pentesting] ${warning}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const builderBinary = await resolveBuilderBinary({ downloadIfMissing: true });
|
|
14
|
+
const result = spawnSync(builderBinary, invocation.builderArgs, {
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
env: process.env,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (result.error) {
|
|
20
|
+
console.error(
|
|
21
|
+
`pentesting could not start Builder (${result.error.message}). Set BUILDER_BIN or reinstall the pentesting package.`,
|
|
22
|
+
);
|
|
23
|
+
process.exit(127);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
process.exit(result.status ?? 1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
main().catch((error) => {
|
|
30
|
+
console.error(`[pentesting] ${error instanceof Error ? error.message : String(error)}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
package/lib/runtime.mjs
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { createWriteStream, readFileSync } from "node:fs";
|
|
2
|
+
import { chmod, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { pipeline } from "node:stream/promises";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
const PACKAGE_JSON = JSON.parse(
|
|
11
|
+
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
12
|
+
);
|
|
13
|
+
const MANAGED_BINARY_DIR = path.join(PACKAGE_ROOT, "vendor");
|
|
14
|
+
const MANAGED_BINARY_MANIFEST = path.join(MANAGED_BINARY_DIR, "builder-manifest.json");
|
|
15
|
+
const BUILDER_COMMANDS = new Set([
|
|
16
|
+
"agent",
|
|
17
|
+
"banner",
|
|
18
|
+
"cmd",
|
|
19
|
+
"commit",
|
|
20
|
+
"config",
|
|
21
|
+
"conversation",
|
|
22
|
+
"data",
|
|
23
|
+
"doctor",
|
|
24
|
+
"info",
|
|
25
|
+
"list",
|
|
26
|
+
"mcp",
|
|
27
|
+
"provider",
|
|
28
|
+
"setup",
|
|
29
|
+
"suggest",
|
|
30
|
+
"update",
|
|
31
|
+
"vscode",
|
|
32
|
+
"workspace",
|
|
33
|
+
"zsh",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const RELEASE_TARGETS = {
|
|
37
|
+
"android:arm64": {
|
|
38
|
+
assetName: "builder-aarch64-linux-android",
|
|
39
|
+
binaryFileName: "builder",
|
|
40
|
+
label: "android-arm64",
|
|
41
|
+
},
|
|
42
|
+
"darwin:arm64": {
|
|
43
|
+
assetName: "builder-aarch64-apple-darwin",
|
|
44
|
+
binaryFileName: "builder",
|
|
45
|
+
label: "macos-arm64",
|
|
46
|
+
},
|
|
47
|
+
"darwin:x64": {
|
|
48
|
+
assetName: "builder-x86_64-apple-darwin",
|
|
49
|
+
binaryFileName: "builder",
|
|
50
|
+
label: "macos-x64",
|
|
51
|
+
},
|
|
52
|
+
"linux:arm64": {
|
|
53
|
+
assetName: "builder-aarch64-unknown-linux-musl",
|
|
54
|
+
binaryFileName: "builder",
|
|
55
|
+
label: "linux-arm64",
|
|
56
|
+
},
|
|
57
|
+
"linux:x64": {
|
|
58
|
+
assetName: "builder-x86_64-unknown-linux-musl",
|
|
59
|
+
binaryFileName: "builder",
|
|
60
|
+
label: "linux-x64",
|
|
61
|
+
},
|
|
62
|
+
"win32:arm64": {
|
|
63
|
+
assetName: "builder-aarch64-pc-windows-msvc.exe",
|
|
64
|
+
binaryFileName: "builder.exe",
|
|
65
|
+
label: "windows-arm64",
|
|
66
|
+
},
|
|
67
|
+
"win32:x64": {
|
|
68
|
+
assetName: "builder-x86_64-pc-windows-msvc.exe",
|
|
69
|
+
binaryFileName: "builder.exe",
|
|
70
|
+
label: "windows-x64",
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function parseLegacyFlags(argv) {
|
|
75
|
+
const passthrough = [];
|
|
76
|
+
const warnings = [];
|
|
77
|
+
|
|
78
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
79
|
+
const current = argv[index];
|
|
80
|
+
|
|
81
|
+
if (current === "--dangerously-skip-permissions") {
|
|
82
|
+
warnings.push(
|
|
83
|
+
"Legacy '--dangerously-skip-permissions' is ignored. Builder owns approval handling inside its runtime.",
|
|
84
|
+
);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (current === "--target" || current === "-t") {
|
|
89
|
+
const target = argv[index + 1];
|
|
90
|
+
if (target) {
|
|
91
|
+
warnings.push(
|
|
92
|
+
`Legacy target '${target}' is not auto-injected into Builder interactive mode. Paste it as your first prompt after startup.`,
|
|
93
|
+
);
|
|
94
|
+
index += 1;
|
|
95
|
+
} else {
|
|
96
|
+
warnings.push("Legacy '--target' was provided without a value and was ignored.");
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
passthrough.push(current);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { passthrough, warnings };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseOptionValue(argv, index, option) {
|
|
108
|
+
if (index + 1 >= argv.length) {
|
|
109
|
+
throw new Error(`Missing value for ${option}.`);
|
|
110
|
+
}
|
|
111
|
+
return argv[index + 1];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildRunPrompt(objective, options) {
|
|
115
|
+
const lines = [`Objective: ${objective}`];
|
|
116
|
+
|
|
117
|
+
if (options.target) {
|
|
118
|
+
lines.push(`Primary target: ${options.target}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push("Use Builder to execute the task.");
|
|
123
|
+
|
|
124
|
+
if (options.maxSteps) {
|
|
125
|
+
lines.push(
|
|
126
|
+
`Keep the workflow within roughly ${options.maxSteps} meaningful tool steps when it does not reduce quality.`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (options.output) {
|
|
131
|
+
lines.push(`Write the final deliverable to ${options.output}.`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function buildScanPrompt(target, options) {
|
|
138
|
+
const lines = [`Perform a reconnaissance scan against ${target}.`];
|
|
139
|
+
lines.push(`Focus mode: ${options.scanType}.`);
|
|
140
|
+
|
|
141
|
+
if (options.ports) {
|
|
142
|
+
lines.push(`Prioritize ports: ${options.ports}.`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (options.output) {
|
|
146
|
+
lines.push(`Write the final deliverable to ${options.output}.`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
lines.push("Prefer Builder-native tool selection and summarize the most actionable findings first.");
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function translateRun(argv) {
|
|
154
|
+
const warnings = [];
|
|
155
|
+
const options = {};
|
|
156
|
+
const objectiveParts = [];
|
|
157
|
+
|
|
158
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
159
|
+
const current = argv[index];
|
|
160
|
+
|
|
161
|
+
if (current === "--output" || current === "-o") {
|
|
162
|
+
options.output = parseOptionValue(argv, index, current);
|
|
163
|
+
index += 1;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (current === "--max-steps") {
|
|
168
|
+
options.maxSteps = parseOptionValue(argv, index, current);
|
|
169
|
+
index += 1;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (current === "--target" || current === "-t") {
|
|
174
|
+
options.target = parseOptionValue(argv, index, current);
|
|
175
|
+
index += 1;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (current === "--dangerously-skip-permissions") {
|
|
180
|
+
warnings.push(
|
|
181
|
+
"Legacy '--dangerously-skip-permissions' is ignored. Builder owns approval handling inside its runtime.",
|
|
182
|
+
);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
objectiveParts.push(current);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const objective = objectiveParts.join(" ").trim();
|
|
190
|
+
if (!objective) {
|
|
191
|
+
throw new Error("pentesting run requires an objective.");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
builderArgs: ["--prompt", buildRunPrompt(objective, options)],
|
|
196
|
+
warnings,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function translateScan(argv) {
|
|
201
|
+
const warnings = [];
|
|
202
|
+
const options = { scanType: "service" };
|
|
203
|
+
let target = "";
|
|
204
|
+
|
|
205
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
206
|
+
const current = argv[index];
|
|
207
|
+
|
|
208
|
+
if (current === "--scan-type" || current === "-s") {
|
|
209
|
+
options.scanType = parseOptionValue(argv, index, current);
|
|
210
|
+
index += 1;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (current === "--ports" || current === "-p") {
|
|
215
|
+
options.ports = parseOptionValue(argv, index, current);
|
|
216
|
+
index += 1;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (current === "--output" || current === "-o") {
|
|
221
|
+
options.output = parseOptionValue(argv, index, current);
|
|
222
|
+
index += 1;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (current === "--dangerously-skip-permissions") {
|
|
227
|
+
warnings.push(
|
|
228
|
+
"Legacy '--dangerously-skip-permissions' is ignored. Builder owns approval handling inside its runtime.",
|
|
229
|
+
);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (!target) {
|
|
234
|
+
target = current;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
warnings.push(`Extra scan argument '${current}' was folded into the Builder prompt.`);
|
|
239
|
+
target = `${target} ${current}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!target) {
|
|
243
|
+
throw new Error("pentesting scan requires a target.");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
builderArgs: ["--prompt", buildScanPrompt(target, options)],
|
|
248
|
+
warnings,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function packageVersion() {
|
|
253
|
+
return PACKAGE_JSON.version;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function releaseRepository() {
|
|
257
|
+
return process.env.BUILDER_REPO || "agnusdei1207/builder";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function defaultReleaseTag(version = packageVersion()) {
|
|
261
|
+
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(version) ? `v${version}` : "latest";
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function resolveReleaseAsset(platform = process.platform, arch = process.arch) {
|
|
265
|
+
const target = RELEASE_TARGETS[`${platform}:${arch}`];
|
|
266
|
+
if (!target) {
|
|
267
|
+
const supported = Object.keys(RELEASE_TARGETS).join(", ");
|
|
268
|
+
throw new Error(
|
|
269
|
+
`Unsupported platform '${platform}/${arch}'. Supported builder targets: ${supported}.`,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
return target;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function releaseAssetUrl(assetName, options = {}) {
|
|
276
|
+
const repo = options.repo || releaseRepository();
|
|
277
|
+
const releaseTag = options.releaseTag || defaultReleaseTag();
|
|
278
|
+
if (releaseTag === "latest") {
|
|
279
|
+
return `https://github.com/${repo}/releases/latest/download/${assetName}`;
|
|
280
|
+
}
|
|
281
|
+
return `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function pathExists(filePath) {
|
|
285
|
+
try {
|
|
286
|
+
await stat(filePath);
|
|
287
|
+
return true;
|
|
288
|
+
} catch {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function manifestMatches(expected) {
|
|
294
|
+
try {
|
|
295
|
+
const raw = JSON.parse(await readFile(MANAGED_BINARY_MANIFEST, "utf8"));
|
|
296
|
+
return (
|
|
297
|
+
raw.assetName === expected.assetName &&
|
|
298
|
+
raw.releaseTag === expected.releaseTag &&
|
|
299
|
+
raw.repo === expected.repo
|
|
300
|
+
);
|
|
301
|
+
} catch {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export async function installManagedBuilder(options = {}) {
|
|
307
|
+
if (process.env.BUILDER_BIN) {
|
|
308
|
+
return { binaryPath: process.env.BUILDER_BIN, source: "external" };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const target = resolveReleaseAsset();
|
|
312
|
+
const repo = options.repo || releaseRepository();
|
|
313
|
+
const releaseTag = options.releaseTag || defaultReleaseTag();
|
|
314
|
+
const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
|
|
315
|
+
const manifest = { assetName: target.assetName, releaseTag, repo };
|
|
316
|
+
|
|
317
|
+
if (!options.force && (await pathExists(binaryPath)) && (await manifestMatches(manifest))) {
|
|
318
|
+
return { binaryPath, source: "cached", ...manifest };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (process.env.BUILDER_SKIP_DOWNLOAD === "true") {
|
|
322
|
+
return { binaryPath, source: "skipped", ...manifest };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
await mkdir(MANAGED_BINARY_DIR, { recursive: true });
|
|
326
|
+
const downloadUrl = releaseAssetUrl(target.assetName, { repo, releaseTag });
|
|
327
|
+
const response = await fetch(downloadUrl, {
|
|
328
|
+
headers: {
|
|
329
|
+
"user-agent": `pentesting-npm/${packageVersion()}`,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
if (!response.ok || !response.body) {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`Failed to download ${target.assetName} from ${downloadUrl} (${response.status} ${response.statusText}).`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const tempPath = path.join(MANAGED_BINARY_DIR, `${target.binaryFileName}.download`);
|
|
340
|
+
await rm(tempPath, { force: true });
|
|
341
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(tempPath));
|
|
342
|
+
if (process.platform !== "win32") {
|
|
343
|
+
await chmod(tempPath, 0o755);
|
|
344
|
+
}
|
|
345
|
+
await rm(binaryPath, { force: true });
|
|
346
|
+
await rename(tempPath, binaryPath);
|
|
347
|
+
await writeFile(
|
|
348
|
+
MANAGED_BINARY_MANIFEST,
|
|
349
|
+
JSON.stringify(
|
|
350
|
+
{
|
|
351
|
+
...manifest,
|
|
352
|
+
downloadedAt: new Date().toISOString(),
|
|
353
|
+
},
|
|
354
|
+
null,
|
|
355
|
+
2,
|
|
356
|
+
),
|
|
357
|
+
"utf8",
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
return { binaryPath, source: "downloaded", ...manifest };
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export async function resolveBuilderBinary(options = {}) {
|
|
364
|
+
if (process.env.BUILDER_BIN) {
|
|
365
|
+
return process.env.BUILDER_BIN;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const target = resolveReleaseAsset();
|
|
369
|
+
const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
|
|
370
|
+
if (await pathExists(binaryPath)) {
|
|
371
|
+
return binaryPath;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (options.downloadIfMissing) {
|
|
375
|
+
const install = await installManagedBuilder();
|
|
376
|
+
if (install.source === "skipped") {
|
|
377
|
+
throw new Error(
|
|
378
|
+
"Managed Builder download was skipped and no BUILDER_BIN override was provided.",
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
return install.binaryPath;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
throw new Error(
|
|
385
|
+
"No managed Builder binary is available. Reinstall the pentesting package or set BUILDER_BIN.",
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function translateBuilderInvocation(argv) {
|
|
390
|
+
if (argv.length === 0) {
|
|
391
|
+
return { builderArgs: [], warnings: [] };
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const [command, ...rest] = argv;
|
|
395
|
+
|
|
396
|
+
if (command === "interactive" || command === "i") {
|
|
397
|
+
const parsed = parseLegacyFlags(rest);
|
|
398
|
+
return { builderArgs: parsed.passthrough, warnings: parsed.warnings };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (command === "run" || command === "r") {
|
|
402
|
+
return translateRun(rest);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (command === "scan") {
|
|
406
|
+
return translateScan(rest);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (command.startsWith("-")) {
|
|
410
|
+
const parsed = parseLegacyFlags(argv);
|
|
411
|
+
return { builderArgs: parsed.passthrough, warnings: parsed.warnings };
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (BUILDER_COMMANDS.has(command)) {
|
|
415
|
+
return { builderArgs: argv, warnings: [] };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return { builderArgs: argv, warnings: [] };
|
|
419
|
+
}
|