pentesting 0.100.4 → 0.100.7

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/lib/runtime.mjs CHANGED
@@ -1,189 +1,182 @@
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, "pentesting-manifest.json");
15
-
16
- const RELEASE_TARGETS = {
17
- // Native binaries published as release assets. Linux uses musl (static, covers
18
- // x64/arm64); android is the cross-built target. macOS/Windows are not
19
- // cross-buildable from the Linux release host, so they are served by the
20
- // Docker image (see the Unsupported-platform error below).
21
- "android:arm64": {
22
- assetName: "pentesting-aarch64-linux-android",
23
- binaryFileName: "builder",
24
- label: "android-arm64",
25
- },
26
- "linux:x64": {
27
- assetName: "pentesting-x86_64-unknown-linux-musl",
28
- binaryFileName: "builder",
29
- label: "linux-x64",
30
- },
31
- };
32
-
33
- export function packageVersion() {
34
- return PACKAGE_JSON.version;
35
- }
36
-
37
- export function configuredBuilderReleaseTag() {
38
- const releaseTag = PACKAGE_JSON.builderReleaseTag;
39
- return typeof releaseTag === "string" && releaseTag.trim() ? releaseTag.trim() : undefined;
40
- }
41
-
42
- export function releaseRepository() {
43
- return process.env.PENTESTING_REPO || "agnusdei1207/pentesting-public";
44
- }
45
-
46
- export function defaultReleaseTag(version = undefined) {
47
- const resolvedVersion = version ?? configuredBuilderReleaseTag() ?? packageVersion();
48
- if (resolvedVersion.startsWith("v")) {
49
- return resolvedVersion;
50
- }
51
- return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(resolvedVersion)
52
- ? `v${resolvedVersion}`
53
- : "latest";
54
- }
55
-
56
- export function resolveReleaseAsset(platform = process.platform, arch = process.arch) {
57
- const target = RELEASE_TARGETS[`${platform}:${arch}`];
58
- if (!target) {
59
- const supported = Object.keys(RELEASE_TARGETS).join(", ");
60
- throw new Error(
61
- `No native pentesting binary for '${platform}/${arch}'. ` +
62
- `Native targets: ${supported}. ` +
63
- `On macOS/Windows run it via Docker instead: ` +
64
- `docker run -it --rm -v "$(pwd):/workspace" -v pentesting-config:/root/.pentesting -w /workspace -e OPENAI_API_KEY -e OPENAI_BASE_URL -e OPENAI_MODEL -e OPENAI_MAX_TOKENS agnusdei1207/pentesting`,
65
- );
66
- }
67
- return target;
68
- }
69
-
70
- export function releaseAssetUrl(assetName, options = {}) {
71
- const repo = options.repo || releaseRepository();
72
- const releaseTag = options.releaseTag || defaultReleaseTag();
73
- if (releaseTag === "latest") {
74
- return `https://github.com/${repo}/releases/latest/download/${assetName}`;
75
- }
76
- return `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`;
77
- }
78
-
79
- async function pathExists(filePath) {
80
- try {
81
- await stat(filePath);
82
- return true;
83
- } catch {
84
- return false;
85
- }
86
- }
87
-
88
- async function manifestMatches(expected) {
89
- try {
90
- const raw = JSON.parse(await readFile(MANAGED_BINARY_MANIFEST, "utf8"));
91
- return (
92
- raw.assetName === expected.assetName &&
93
- raw.releaseTag === expected.releaseTag &&
94
- raw.repo === expected.repo
95
- );
96
- } catch {
97
- return false;
98
- }
99
- }
100
-
101
- export async function installManagedBuilder(options = {}) {
102
- if (process.env.PENTESTING_BIN) {
103
- return { binaryPath: process.env.PENTESTING_BIN, source: "external" };
104
- }
105
-
106
- const target = resolveReleaseAsset();
107
- const repo = options.repo || releaseRepository();
108
- const releaseTag = options.releaseTag || defaultReleaseTag();
109
- const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
110
- const manifest = { assetName: target.assetName, releaseTag, repo };
111
-
112
- if (!options.force && (await pathExists(binaryPath)) && (await manifestMatches(manifest))) {
113
- return { binaryPath, source: "cached", ...manifest };
114
- }
115
-
116
- if (process.env.PENTESTING_SKIP_DOWNLOAD === "true") {
117
- return { binaryPath, source: "skipped", ...manifest };
118
- }
119
-
120
- await mkdir(MANAGED_BINARY_DIR, { recursive: true });
121
- const downloadUrl = releaseAssetUrl(target.assetName, { repo, releaseTag });
122
- const response = await fetch(downloadUrl);
123
-
124
- if (!response.ok || !response.body) {
125
- throw new Error(
126
- `Failed to download ${target.assetName} from ${downloadUrl} (${response.status} ${response.statusText}).`,
127
- );
128
- }
129
-
130
- const tempPath = path.join(MANAGED_BINARY_DIR, `${target.binaryFileName}.download`);
131
- await rm(tempPath, { force: true });
132
- await pipeline(Readable.fromWeb(response.body), createWriteStream(tempPath));
133
- if (process.platform !== "win32") {
134
- await chmod(tempPath, 0o755);
135
- }
136
- await rm(binaryPath, { force: true });
137
- await rename(tempPath, binaryPath);
138
- await writeFile(
139
- MANAGED_BINARY_MANIFEST,
140
- JSON.stringify(
141
- {
142
- ...manifest,
143
- downloadedAt: new Date().toISOString(),
144
- },
145
- null,
146
- 2,
147
- ),
148
- "utf8",
149
- );
150
-
151
- return { binaryPath, source: "downloaded", ...manifest };
152
- }
153
-
154
- export async function resolveBuilderBinary(options = {}) {
155
- if (process.env.PENTESTING_BIN) {
156
- return process.env.PENTESTING_BIN;
157
- }
158
-
159
- const target = resolveReleaseAsset();
160
- const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
161
- if (await pathExists(binaryPath)) {
162
- return binaryPath;
163
- }
164
-
165
- if (options.downloadIfMissing) {
166
- const install = await installManagedBuilder();
167
- if (install.source === "skipped") {
168
- throw new Error(
169
- "Managed Builder download was skipped and no PENTESTING_BIN override was provided.",
170
- );
171
- }
172
- return install.binaryPath;
173
- }
174
-
175
- throw new Error(
176
- "No managed Builder binary is available. Reinstall the pentesting package or set PENTESTING_BIN.",
177
- );
178
- }
179
-
180
- export function translateBuilderInvocation(argv) {
181
- return { builderArgs: argv, warnings: [] };
182
- }
183
-
184
- export function pentestingEnvironment(baseEnv = process.env) {
185
- return {
186
- ...baseEnv,
187
- PENTESTING_PRODUCT_NAME: "pentesting",
188
- };
189
- }
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, "pentesting-manifest.json");
15
+
16
+ const RELEASE_TARGETS = {
17
+ // Native binaries published as release assets. Linux x64 uses musl (static).
18
+ // Other platforms use the published linux/amd64 image through Docker.
19
+ "linux:x64": {
20
+ assetName: "pentesting-x86_64-unknown-linux-musl",
21
+ binaryFileName: "builder",
22
+ label: "linux-x64",
23
+ },
24
+ };
25
+
26
+ export function packageVersion() {
27
+ return PACKAGE_JSON.version;
28
+ }
29
+
30
+ export function configuredBuilderReleaseTag() {
31
+ const releaseTag = PACKAGE_JSON.builderReleaseTag;
32
+ return typeof releaseTag === "string" && releaseTag.trim() ? releaseTag.trim() : undefined;
33
+ }
34
+
35
+ export function releaseRepository() {
36
+ return process.env.PENTESTING_REPO || "agnusdei1207/pentesting-public";
37
+ }
38
+
39
+ export function defaultReleaseTag(version = undefined) {
40
+ const resolvedVersion = version ?? configuredBuilderReleaseTag() ?? packageVersion();
41
+ if (resolvedVersion.startsWith("v")) {
42
+ return resolvedVersion;
43
+ }
44
+ return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(resolvedVersion)
45
+ ? `v${resolvedVersion}`
46
+ : "latest";
47
+ }
48
+
49
+ export function resolveReleaseAsset(platform = process.platform, arch = process.arch) {
50
+ const target = RELEASE_TARGETS[`${platform}:${arch}`];
51
+ if (!target) {
52
+ const supported = Object.keys(RELEASE_TARGETS).join(", ");
53
+ throw new Error(
54
+ `No native pentesting binary for '${platform}/${arch}'. ` +
55
+ `Native targets: ${supported}. ` +
56
+ `On macOS or Windows, or on a non-amd64 host, use the linux/amd64 Docker image instead: ` +
57
+ `docker run -it --rm -v "$(pwd):/workspace" -v pentesting-config:/root/.pentesting -w /workspace -e OPENAI_API_KEY -e OPENAI_BASE_URL -e OPENAI_MODEL -e OPENAI_MAX_TOKENS agnusdei1207/pentesting`,
58
+ );
59
+ }
60
+ return target;
61
+ }
62
+
63
+ export function releaseAssetUrl(assetName, options = {}) {
64
+ const repo = options.repo || releaseRepository();
65
+ const releaseTag = options.releaseTag || defaultReleaseTag();
66
+ if (releaseTag === "latest") {
67
+ return `https://github.com/${repo}/releases/latest/download/${assetName}`;
68
+ }
69
+ return `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`;
70
+ }
71
+
72
+ async function pathExists(filePath) {
73
+ try {
74
+ await stat(filePath);
75
+ return true;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ async function manifestMatches(expected) {
82
+ try {
83
+ const raw = JSON.parse(await readFile(MANAGED_BINARY_MANIFEST, "utf8"));
84
+ return (
85
+ raw.assetName === expected.assetName &&
86
+ raw.releaseTag === expected.releaseTag &&
87
+ raw.repo === expected.repo
88
+ );
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
94
+ export async function installManagedBuilder(options = {}) {
95
+ if (process.env.PENTESTING_BIN) {
96
+ return { binaryPath: process.env.PENTESTING_BIN, source: "external" };
97
+ }
98
+
99
+ const target = resolveReleaseAsset();
100
+ const repo = options.repo || releaseRepository();
101
+ const releaseTag = options.releaseTag || defaultReleaseTag();
102
+ const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
103
+ const manifest = { assetName: target.assetName, releaseTag, repo };
104
+
105
+ if (!options.force && (await pathExists(binaryPath)) && (await manifestMatches(manifest))) {
106
+ return { binaryPath, source: "cached", ...manifest };
107
+ }
108
+
109
+ if (process.env.PENTESTING_SKIP_DOWNLOAD === "true") {
110
+ return { binaryPath, source: "skipped", ...manifest };
111
+ }
112
+
113
+ await mkdir(MANAGED_BINARY_DIR, { recursive: true });
114
+ const downloadUrl = releaseAssetUrl(target.assetName, { repo, releaseTag });
115
+ const response = await fetch(downloadUrl);
116
+
117
+ if (!response.ok || !response.body) {
118
+ throw new Error(
119
+ `Failed to download ${target.assetName} from ${downloadUrl} (${response.status} ${response.statusText}).`,
120
+ );
121
+ }
122
+
123
+ const tempPath = path.join(MANAGED_BINARY_DIR, `${target.binaryFileName}.download`);
124
+ await rm(tempPath, { force: true });
125
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(tempPath));
126
+ if (process.platform !== "win32") {
127
+ await chmod(tempPath, 0o755);
128
+ }
129
+ await rm(binaryPath, { force: true });
130
+ await rename(tempPath, binaryPath);
131
+ await writeFile(
132
+ MANAGED_BINARY_MANIFEST,
133
+ JSON.stringify(
134
+ {
135
+ ...manifest,
136
+ downloadedAt: new Date().toISOString(),
137
+ },
138
+ null,
139
+ 2,
140
+ ),
141
+ "utf8",
142
+ );
143
+
144
+ return { binaryPath, source: "downloaded", ...manifest };
145
+ }
146
+
147
+ export async function resolveBuilderBinary(options = {}) {
148
+ if (process.env.PENTESTING_BIN) {
149
+ return process.env.PENTESTING_BIN;
150
+ }
151
+
152
+ const target = resolveReleaseAsset();
153
+ const binaryPath = path.join(MANAGED_BINARY_DIR, target.binaryFileName);
154
+ if (await pathExists(binaryPath)) {
155
+ return binaryPath;
156
+ }
157
+
158
+ if (options.downloadIfMissing) {
159
+ const install = await installManagedBuilder();
160
+ if (install.source === "skipped") {
161
+ throw new Error(
162
+ "Managed Builder download was skipped and no PENTESTING_BIN override was provided.",
163
+ );
164
+ }
165
+ return install.binaryPath;
166
+ }
167
+
168
+ throw new Error(
169
+ "No managed Builder binary is available. Reinstall the pentesting package or set PENTESTING_BIN.",
170
+ );
171
+ }
172
+
173
+ export function translateBuilderInvocation(argv) {
174
+ return { builderArgs: argv, warnings: [] };
175
+ }
176
+
177
+ export function pentestingEnvironment(baseEnv = process.env) {
178
+ return {
179
+ ...baseEnv,
180
+ PENTESTING_PRODUCT_NAME: "pentesting",
181
+ };
182
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.100.4",
4
- "builderReleaseTag": "v0.100.1",
3
+ "version": "0.100.7",
4
+ "builderReleaseTag": "v0.100.7",
5
5
  "description": "pentesting — coding agent runtime with audited reverse-shell capture, verified PTY session upgrades, pivot control, evidence transcripts, and safe session reclamation.",
6
6
  "license": "MIT",
7
7
  "author": "agnusdei1207",
@@ -72,9 +72,9 @@
72
72
  "public:sync": "bash scripts/sync-public-repo.sh",
73
73
  "public:mirror-release": "bash scripts/mirror-public-release.sh",
74
74
  "release:backfill": "bash scripts/backfill-release-local.sh",
75
- "check:docker": "sh -c ': \"${OPENAI_API_KEY:?Set OPENAI_API_KEY}\"; : \"${OPENAI_BASE_URL:?Set OPENAI_BASE_URL}\"; : \"${OPENAI_MODEL:?Set OPENAI_MODEL}\"; : \"${OPENAI_MAX_TOKENS:?Set OPENAI_MAX_TOKENS}\"; npm run docker:build && docker run -it --rm -v builder-workspace:/workspace -v pentesting-config:/root/.pentesting -e OPENAI_API_KEY -e OPENAI_BASE_URL -e OPENAI_MODEL -e OPENAI_MAX_TOKENS agnusdei1207/pentesting:latest'",
76
- "docker:build": "(docker image inspect agnusdei1207/pentesting-build-base:1.96 >/dev/null 2>&1 && docker image inspect agnusdei1207/pentesting-runtime-base:26.04 >/dev/null 2>&1 || npm run docker:base:build) && docker build --build-arg APP_VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo dev) -t agnusdei1207/pentesting:latest .",
77
- "docker:base:build": "docker build -t agnusdei1207/pentesting-build-base:1.96 -f docker/build-base.Dockerfile . && docker build -t agnusdei1207/pentesting-runtime-base:26.04 -f docker/runtime-base.Dockerfile .",
75
+ "check:docker": "npm run docker:build && docker run -it --rm --memory 2g --memory-swap 2g --cpus 2 --pids-limit 512 -v builder-workspace:/workspace -v pentesting-config:/root/.pentesting -e OPENAI_API_KEY -e OPENAI_BASE_URL -e OPENAI_MODEL -e OPENAI_MAX_TOKENS agnusdei1207/pentesting:latest",
76
+ "docker:build": "bash scripts/dbuild-image.sh app",
77
+ "docker:base:build": "bash scripts/dbuild-image.sh bases",
78
78
  "release:patch": "./scripts/release-all.sh patch",
79
79
  "release:minor": "./scripts/release-all.sh minor",
80
80
  "release:major": "./scripts/release-all.sh major"
@@ -1,13 +1,13 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
2
- <g
3
- fill="none"
4
- stroke="#00d4aa"
5
- stroke-linecap="round"
6
- stroke-linejoin="round"
7
- stroke-width="1.5"
8
- >
9
- <path d="m7 7l1.227 1.057C8.742 8.502 9 8.724 9 9s-.258.498-.773.943L7 11" />
10
- <path d="M11 11h3" />
11
- <path d="M12 21c3.75 0 5.625 0 6.939-.955a5 5 0 0 0 1.106-1.106C21 17.625 21 15.749 21 12s0-5.625-.955-6.939a5 5 0 0 0-1.106-1.106C17.625 3 15.749 3 12 3s-5.625 0-6.939.955A5 5 0 0 0 3.955 5.06C3 6.375 3 8.251 3 12s0 5.625.955 6.939a5 5 0 0 0 1.106 1.106C6.375 21 8.251 21 12 21" />
12
- </g>
13
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
2
+ <g
3
+ fill="none"
4
+ stroke="#00d4aa"
5
+ stroke-linecap="round"
6
+ stroke-linejoin="round"
7
+ stroke-width="1.5"
8
+ >
9
+ <path d="m7 7l1.227 1.057C8.742 8.502 9 8.724 9 9s-.258.498-.773.943L7 11" />
10
+ <path d="M11 11h3" />
11
+ <path d="M12 21c3.75 0 5.625 0 6.939-.955a5 5 0 0 0 1.106-1.106C21 17.625 21 15.749 21 12s0-5.625-.955-6.939a5 5 0 0 0-1.106-1.106C17.625 3 15.749 3 12 3s-5.625 0-6.939.955A5 5 0 0 0 3.955 5.06C3 6.375 3 8.251 3 12s0 5.625.955 6.939a5 5 0 0 0 1.106 1.106C6.375 21 8.251 21 12 21" />
12
+ </g>
13
+ </svg>
@@ -1,33 +1,33 @@
1
- import { installManagedBuilder } from "../lib/runtime.mjs";
2
-
3
- if (process.env.PENTESTING_BIN) {
4
- console.log("[pentesting] PENTESTING_BIN is set; skipping managed Builder download.");
5
- process.exit(0);
6
- }
7
-
8
- if (process.env.PENTESTING_SKIP_DOWNLOAD === "true") {
9
- console.log("[pentesting] Skipping managed Builder download.");
10
- process.exit(0);
11
- }
12
-
13
- try {
14
- const result = await installManagedBuilder({
15
- force: process.env.PENTESTING_FORCE_DOWNLOAD === "true",
16
- });
17
-
18
- if (result.source === "cached") {
19
- console.log("[pentesting] Runtime already installed.");
20
- } else if (result.source === "downloaded") {
21
- console.log("[pentesting] Runtime downloaded successfully.");
22
- }
23
- } catch (error) {
24
- // Non-fatal: never break `npm i pentesting`. The runtime is fetched on first
25
- // run (resolveBuilderBinary downloads if missing), so a failed/offline
26
- // postinstall just defers the download instead of failing the install.
27
- console.warn(
28
- `[pentesting] Runtime not pre-downloaded (${
29
- error instanceof Error ? error.message : String(error)
30
- }). It will be fetched automatically on first run.`,
31
- );
32
- process.exit(0);
33
- }
1
+ import { installManagedBuilder } from "../lib/runtime.mjs";
2
+
3
+ if (process.env.PENTESTING_BIN) {
4
+ console.log("[pentesting] PENTESTING_BIN is set; skipping managed Builder download.");
5
+ process.exit(0);
6
+ }
7
+
8
+ if (process.env.PENTESTING_SKIP_DOWNLOAD === "true") {
9
+ console.log("[pentesting] Skipping managed Builder download.");
10
+ process.exit(0);
11
+ }
12
+
13
+ try {
14
+ const result = await installManagedBuilder({
15
+ force: process.env.PENTESTING_FORCE_DOWNLOAD === "true",
16
+ });
17
+
18
+ if (result.source === "cached") {
19
+ console.log("[pentesting] Runtime already installed.");
20
+ } else if (result.source === "downloaded") {
21
+ console.log("[pentesting] Runtime downloaded successfully.");
22
+ }
23
+ } catch (error) {
24
+ // Non-fatal: never break `npm i pentesting`. The runtime is fetched on first
25
+ // run (resolveBuilderBinary downloads if missing), so a failed/offline
26
+ // postinstall just defers the download instead of failing the install.
27
+ console.warn(
28
+ `[pentesting] Runtime not pre-downloaded (${
29
+ error instanceof Error ? error.message : String(error)
30
+ }). It will be fetched automatically on first run.`,
31
+ );
32
+ process.exit(0);
33
+ }