@wrongstack/tools 0.8.2 → 0.8.5
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/dist/builtin.js +100 -23
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +14 -6
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/exec.js +14 -2
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +48 -3
- package/dist/fetch.js.map +1 -1
- package/dist/index.js +100 -23
- package/dist/index.js.map +1 -1
- package/dist/logs.js +22 -11
- package/dist/logs.js.map +1 -1
- package/dist/pack.js +100 -23
- package/dist/pack.js.map +1 -1
- package/dist/replace.js +2 -1
- package/dist/replace.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -3,10 +3,11 @@ import { stat } from 'node:fs/promises';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { dirname } from 'node:path';
|
|
5
5
|
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, buildChildEnv, stripAnsi, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan } from '@wrongstack/core';
|
|
6
|
-
import { spawn,
|
|
6
|
+
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
7
7
|
import * as os from 'node:os';
|
|
8
8
|
import * as dns from 'node:dns/promises';
|
|
9
9
|
import * as net from 'node:net';
|
|
10
|
+
import { Agent } from 'undici';
|
|
10
11
|
import * as fs13 from 'node:fs';
|
|
11
12
|
import { statSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
12
13
|
import { createRequire } from 'node:module';
|
|
@@ -371,6 +372,7 @@ var replaceTool = {
|
|
|
371
372
|
const dryRun = input.dry_run ?? false;
|
|
372
373
|
const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
|
|
373
374
|
const fileList = await resolveFiles(filesInput, ctx, globRe);
|
|
375
|
+
const realRoot = await fs4.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
374
376
|
const results = [];
|
|
375
377
|
let totalReplacements = 0;
|
|
376
378
|
for (const absPath of fileList) {
|
|
@@ -386,7 +388,7 @@ var replaceTool = {
|
|
|
386
388
|
} catch {
|
|
387
389
|
continue;
|
|
388
390
|
}
|
|
389
|
-
const rel = path.relative(
|
|
391
|
+
const rel = path.relative(realRoot, realPath);
|
|
390
392
|
if (rel.startsWith("..") || path.isAbsolute(rel)) continue;
|
|
391
393
|
const stat11 = await fs4.stat(realPath).catch(() => null);
|
|
392
394
|
if (!stat11 || !stat11.isFile()) continue;
|
|
@@ -1488,8 +1490,20 @@ var BLOCKED_ARG_PATTERNS = {
|
|
|
1488
1490
|
// python -c/--command executes arbitrary code; python -m runs modules
|
|
1489
1491
|
python: [/-c$/, /^--command$/, /^-m$/, /^--module$/],
|
|
1490
1492
|
// git --exec=<cmd> runs arbitrary commands via upload-pack/receive-pack;
|
|
1491
|
-
// -C <dir> changes working directory, bypassing cwd sandbox
|
|
1492
|
-
|
|
1493
|
+
// -C <dir> changes working directory, bypassing cwd sandbox;
|
|
1494
|
+
// -c/--config <k>=<v> injects config that runs commands
|
|
1495
|
+
// (e.g. core.sshCommand, core.pager, http.proxy, alias.x=!cmd).
|
|
1496
|
+
git: [
|
|
1497
|
+
/^--exec=/,
|
|
1498
|
+
/^--upload-pack=/,
|
|
1499
|
+
/^--receive-pack=/,
|
|
1500
|
+
/^-C$/,
|
|
1501
|
+
/^-c$/,
|
|
1502
|
+
/^--config$/,
|
|
1503
|
+
/^-c=/,
|
|
1504
|
+
/^--config=/,
|
|
1505
|
+
/^--config-env=/
|
|
1506
|
+
],
|
|
1493
1507
|
// node -r/--require preloads arbitrary modules; --eval executes code
|
|
1494
1508
|
node: [/^-r$/, /^--require$/, /^-e$/, /^--eval$/, /^--prof-process$/],
|
|
1495
1509
|
// go run could execute arbitrary .go files; -ldflags could inject build-time code
|
|
@@ -1675,6 +1689,48 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1675
1689
|
var MAX_BYTES2 = 131072;
|
|
1676
1690
|
var TIMEOUT_MS2 = 2e4;
|
|
1677
1691
|
var ALLOW_PRIVATE = process.env["WRONGSTACK_FETCH_ALLOW_PRIVATE"] === "1";
|
|
1692
|
+
function guardedLookup(hostname, options, callback) {
|
|
1693
|
+
dns.lookup(hostname, { all: true }).then((records) => {
|
|
1694
|
+
const family = options?.family;
|
|
1695
|
+
const byFamily = family === 4 || family === 6 ? records.filter((r) => r.family === family) : records;
|
|
1696
|
+
const list = byFamily.length > 0 ? byFamily : records;
|
|
1697
|
+
if (!ALLOW_PRIVATE) {
|
|
1698
|
+
for (const r of list) {
|
|
1699
|
+
const bad = r.family === 4 ? isPrivateIPv4(r.address) : isPrivateIPv6(r.address);
|
|
1700
|
+
if (bad) {
|
|
1701
|
+
callback(
|
|
1702
|
+
Object.assign(new Error(`fetch: resolved to private address ${r.address}`), {
|
|
1703
|
+
code: "EAI_FAIL"
|
|
1704
|
+
})
|
|
1705
|
+
);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
if (options?.all) {
|
|
1711
|
+
callback(
|
|
1712
|
+
null,
|
|
1713
|
+
list.map((r) => ({ address: r.address, family: r.family }))
|
|
1714
|
+
);
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
const first = list[0];
|
|
1718
|
+
if (!first) {
|
|
1719
|
+
callback(
|
|
1720
|
+
Object.assign(new Error(`fetch: no address for ${hostname}`), { code: "ENOTFOUND" })
|
|
1721
|
+
);
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
callback(null, first.address, first.family);
|
|
1725
|
+
}).catch((err) => callback(err));
|
|
1726
|
+
}
|
|
1727
|
+
var pinnedAgent;
|
|
1728
|
+
function getPinnedDispatcher() {
|
|
1729
|
+
if (!pinnedAgent) {
|
|
1730
|
+
pinnedAgent = new Agent({ connect: { lookup: guardedLookup } });
|
|
1731
|
+
}
|
|
1732
|
+
return pinnedAgent;
|
|
1733
|
+
}
|
|
1678
1734
|
async function fetchWithRedirectLimit(url, maxRedirects, signal) {
|
|
1679
1735
|
const headers = {
|
|
1680
1736
|
"user-agent": "WrongStack/1.0 (+https://wrongstack.com)",
|
|
@@ -1691,11 +1747,13 @@ async function fetchWithRedirectLimit(url, maxRedirects, signal) {
|
|
|
1691
1747
|
throw new Error("fetch: redirect to http:// blocked (HTTPS required by default)");
|
|
1692
1748
|
}
|
|
1693
1749
|
await assertNotPrivate(parsed.hostname);
|
|
1694
|
-
const
|
|
1750
|
+
const init = {
|
|
1695
1751
|
redirect: "manual",
|
|
1696
1752
|
signal,
|
|
1697
|
-
headers
|
|
1698
|
-
|
|
1753
|
+
headers,
|
|
1754
|
+
dispatcher: getPinnedDispatcher()
|
|
1755
|
+
};
|
|
1756
|
+
const res = await fetch(currentUrl, init);
|
|
1699
1757
|
if (res.status < 300 || res.status > 399) {
|
|
1700
1758
|
return res;
|
|
1701
1759
|
}
|
|
@@ -4006,17 +4064,35 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4006
4064
|
let stdout = "";
|
|
4007
4065
|
let stderr = "";
|
|
4008
4066
|
const MAX = 2e5;
|
|
4067
|
+
let settled = false;
|
|
4068
|
+
const empty = () => ({
|
|
4069
|
+
source: `docker:${service}`,
|
|
4070
|
+
entries: [],
|
|
4071
|
+
total: 0,
|
|
4072
|
+
truncated: false,
|
|
4073
|
+
stream_mode: false
|
|
4074
|
+
});
|
|
4075
|
+
const finish = (result) => {
|
|
4076
|
+
if (settled) return;
|
|
4077
|
+
settled = true;
|
|
4078
|
+
clearTimeout(timer);
|
|
4079
|
+
resolve6(result);
|
|
4080
|
+
};
|
|
4009
4081
|
const child = spawn("docker", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"] });
|
|
4082
|
+
const timer = setTimeout(() => {
|
|
4083
|
+
child.kill("SIGTERM");
|
|
4084
|
+
finish(empty());
|
|
4085
|
+
}, DOCKER_LOGS_TIMEOUT_MS);
|
|
4010
4086
|
child.stdout?.on("data", (c) => {
|
|
4011
4087
|
if (stdout.length < MAX) stdout += c.toString();
|
|
4012
4088
|
});
|
|
4013
4089
|
child.stderr?.on("data", (c) => {
|
|
4014
4090
|
if (stderr.length < MAX) stderr += c.toString();
|
|
4015
4091
|
});
|
|
4016
|
-
child.on("close", (
|
|
4092
|
+
child.on("close", () => {
|
|
4017
4093
|
const output = stdout + stderr;
|
|
4018
4094
|
const entries = parseLogLines(output, filterRe);
|
|
4019
|
-
|
|
4095
|
+
finish({
|
|
4020
4096
|
source: `docker:${service}`,
|
|
4021
4097
|
entries,
|
|
4022
4098
|
total: entries.length,
|
|
@@ -4024,17 +4100,10 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4024
4100
|
stream_mode: false
|
|
4025
4101
|
});
|
|
4026
4102
|
});
|
|
4027
|
-
child.on("error", (
|
|
4028
|
-
resolve6({
|
|
4029
|
-
source: `docker:${service}`,
|
|
4030
|
-
entries: [],
|
|
4031
|
-
total: 0,
|
|
4032
|
-
truncated: false,
|
|
4033
|
-
stream_mode: false
|
|
4034
|
-
});
|
|
4035
|
-
});
|
|
4103
|
+
child.on("error", () => finish(empty()));
|
|
4036
4104
|
});
|
|
4037
4105
|
}
|
|
4106
|
+
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
4038
4107
|
var MAX_TAIL_LINES = 1e5;
|
|
4039
4108
|
async function fileLogs(path18, lines, filterRe, stream) {
|
|
4040
4109
|
const { createInterface } = await import('node:readline');
|
|
@@ -5747,7 +5816,7 @@ function syncGoParse(filePath, content, lang) {
|
|
|
5747
5816
|
mkdirSync(tmpDir, { recursive: true });
|
|
5748
5817
|
const scriptPath = path.join(tmpDir, "parse.go");
|
|
5749
5818
|
writeFileSync(scriptPath, GO_PARSE_SCRIPT, "utf8");
|
|
5750
|
-
const stdout =
|
|
5819
|
+
const stdout = execFileSync("go", ["run", scriptPath], {
|
|
5751
5820
|
input: content,
|
|
5752
5821
|
timeout: 15e3,
|
|
5753
5822
|
encoding: "utf8",
|
|
@@ -5993,7 +6062,7 @@ function syncPyParse(filePath, lang) {
|
|
|
5993
6062
|
mkdirSync(tmpDir, { recursive: true });
|
|
5994
6063
|
const scriptPath = path.join(tmpDir, "parse.py");
|
|
5995
6064
|
writeFileSync(scriptPath, PY_PARSE_SCRIPT, "utf8");
|
|
5996
|
-
const stdout =
|
|
6065
|
+
const stdout = execFileSync("python", [scriptPath, filePath], {
|
|
5997
6066
|
timeout: 15e3,
|
|
5998
6067
|
encoding: "utf8",
|
|
5999
6068
|
windowsHide: true
|
|
@@ -6031,11 +6100,19 @@ function parseSymbols4(opts) {
|
|
|
6031
6100
|
}
|
|
6032
6101
|
function checkNativeParser() {
|
|
6033
6102
|
try {
|
|
6034
|
-
|
|
6103
|
+
execFileSync("rustc", ["--version"], { stdio: "pipe" });
|
|
6035
6104
|
const toolsDir = path.join(process.cwd(), "tools");
|
|
6036
6105
|
try {
|
|
6037
|
-
|
|
6038
|
-
"cargo
|
|
6106
|
+
execFileSync(
|
|
6107
|
+
"cargo",
|
|
6108
|
+
[
|
|
6109
|
+
"metadata",
|
|
6110
|
+
"--no-deps",
|
|
6111
|
+
"--format-version",
|
|
6112
|
+
"1",
|
|
6113
|
+
"--manifest-path",
|
|
6114
|
+
path.join(toolsDir, "Cargo.toml")
|
|
6115
|
+
],
|
|
6039
6116
|
{ stdio: "pipe" }
|
|
6040
6117
|
);
|
|
6041
6118
|
return true;
|