@node9/proxy 1.0.14 → 1.0.15
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 +78 -7
- package/dist/cli.js +2037 -1175
- package/dist/cli.mjs +2021 -1157
- package/dist/index.js +60 -3
- package/dist/index.mjs +60 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -40,6 +40,8 @@ var import_prompts = require("@inquirer/prompts");
|
|
|
40
40
|
var import_fs2 = __toESM(require("fs"));
|
|
41
41
|
var import_path4 = __toESM(require("path"));
|
|
42
42
|
var import_os2 = __toESM(require("os"));
|
|
43
|
+
var import_net = __toESM(require("net"));
|
|
44
|
+
var import_crypto = require("crypto");
|
|
43
45
|
var import_picomatch = __toESM(require("picomatch"));
|
|
44
46
|
var import_sh_syntax = require("sh-syntax");
|
|
45
47
|
|
|
@@ -1335,7 +1337,7 @@ function getPersistentDecision(toolName) {
|
|
|
1335
1337
|
}
|
|
1336
1338
|
return null;
|
|
1337
1339
|
}
|
|
1338
|
-
async function askDaemon(toolName, args, meta, signal, riskMetadata) {
|
|
1340
|
+
async function askDaemon(toolName, args, meta, signal, riskMetadata, activityId) {
|
|
1339
1341
|
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
1340
1342
|
const checkCtrl = new AbortController();
|
|
1341
1343
|
const checkTimer = setTimeout(() => checkCtrl.abort(), 5e3);
|
|
@@ -1350,6 +1352,12 @@ async function askDaemon(toolName, args, meta, signal, riskMetadata) {
|
|
|
1350
1352
|
args,
|
|
1351
1353
|
agent: meta?.agent,
|
|
1352
1354
|
mcpServer: meta?.mcpServer,
|
|
1355
|
+
fromCLI: true,
|
|
1356
|
+
// Pass the flight-recorder ID so the daemon uses the same UUID for
|
|
1357
|
+
// activity-result as the CLI used for the pending activity event.
|
|
1358
|
+
// Without this, the two UUIDs never match and tail.ts never resolves
|
|
1359
|
+
// the pending item.
|
|
1360
|
+
activityId,
|
|
1353
1361
|
...riskMetadata && { riskMetadata }
|
|
1354
1362
|
}),
|
|
1355
1363
|
signal: checkCtrl.signal
|
|
@@ -1404,7 +1412,45 @@ async function resolveViaDaemon(id, decision, internalToken) {
|
|
|
1404
1412
|
signal: AbortSignal.timeout(3e3)
|
|
1405
1413
|
});
|
|
1406
1414
|
}
|
|
1415
|
+
var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path4.default.join(import_os2.default.tmpdir(), "node9-activity.sock");
|
|
1416
|
+
function notifyActivity(data) {
|
|
1417
|
+
return new Promise((resolve) => {
|
|
1418
|
+
try {
|
|
1419
|
+
const payload = JSON.stringify(data);
|
|
1420
|
+
const sock = import_net.default.createConnection(ACTIVITY_SOCKET_PATH);
|
|
1421
|
+
sock.on("connect", () => {
|
|
1422
|
+
sock.on("close", resolve);
|
|
1423
|
+
sock.end(payload);
|
|
1424
|
+
});
|
|
1425
|
+
sock.on("error", resolve);
|
|
1426
|
+
} catch {
|
|
1427
|
+
resolve();
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1407
1431
|
async function authorizeHeadless(toolName, args, allowTerminalFallback = false, meta, options) {
|
|
1432
|
+
if (!options?.calledFromDaemon) {
|
|
1433
|
+
const actId = (0, import_crypto.randomUUID)();
|
|
1434
|
+
const actTs = Date.now();
|
|
1435
|
+
await notifyActivity({ id: actId, ts: actTs, tool: toolName, args, status: "pending" });
|
|
1436
|
+
const result = await _authorizeHeadlessCore(toolName, args, allowTerminalFallback, meta, {
|
|
1437
|
+
...options,
|
|
1438
|
+
activityId: actId
|
|
1439
|
+
});
|
|
1440
|
+
if (!result.noApprovalMechanism) {
|
|
1441
|
+
await notifyActivity({
|
|
1442
|
+
id: actId,
|
|
1443
|
+
tool: toolName,
|
|
1444
|
+
ts: actTs,
|
|
1445
|
+
status: result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : "block",
|
|
1446
|
+
label: result.blockedByLabel
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
return result;
|
|
1450
|
+
}
|
|
1451
|
+
return _authorizeHeadlessCore(toolName, args, allowTerminalFallback, meta, options);
|
|
1452
|
+
}
|
|
1453
|
+
async function _authorizeHeadlessCore(toolName, args, allowTerminalFallback = false, meta, options) {
|
|
1408
1454
|
if (process.env.NODE9_PAUSED === "1") return { approved: true, checkedBy: "paused" };
|
|
1409
1455
|
const pauseState = checkPause();
|
|
1410
1456
|
if (pauseState.paused) return { approved: true, checkedBy: "paused" };
|
|
@@ -1440,6 +1486,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
1440
1486
|
blockedByLabel: "\u{1F6A8} Node9 DLP (Secret Detected)"
|
|
1441
1487
|
};
|
|
1442
1488
|
}
|
|
1489
|
+
if (!isManual) appendLocalAudit(toolName, args, "allow", "dlp-review-flagged", meta);
|
|
1443
1490
|
explainableLabel = "\u{1F6A8} Node9 DLP (Credential Review)";
|
|
1444
1491
|
}
|
|
1445
1492
|
}
|
|
@@ -1662,7 +1709,14 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
1662
1709
|
console.error(import_chalk2.default.cyan(` URL \u2192 http://${DAEMON_HOST}:${DAEMON_PORT}/
|
|
1663
1710
|
`));
|
|
1664
1711
|
}
|
|
1665
|
-
const daemonDecision = await askDaemon(
|
|
1712
|
+
const daemonDecision = await askDaemon(
|
|
1713
|
+
toolName,
|
|
1714
|
+
args,
|
|
1715
|
+
meta,
|
|
1716
|
+
signal,
|
|
1717
|
+
riskMetadata,
|
|
1718
|
+
options?.activityId
|
|
1719
|
+
);
|
|
1666
1720
|
if (daemonDecision === "abandoned") throw new Error("Abandoned");
|
|
1667
1721
|
const isApproved = daemonDecision === "allow";
|
|
1668
1722
|
return {
|
|
@@ -1866,7 +1920,10 @@ function getConfig() {
|
|
|
1866
1920
|
for (const rule of shield.smartRules) {
|
|
1867
1921
|
if (!existingRuleNames.has(rule.name)) mergedPolicy.smartRules.push(rule);
|
|
1868
1922
|
}
|
|
1869
|
-
|
|
1923
|
+
const existingWords = new Set(mergedPolicy.dangerousWords);
|
|
1924
|
+
for (const word of shield.dangerousWords) {
|
|
1925
|
+
if (!existingWords.has(word)) mergedPolicy.dangerousWords.push(word);
|
|
1926
|
+
}
|
|
1870
1927
|
}
|
|
1871
1928
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
1872
1929
|
for (const rule of ADVISORY_SMART_RULES) {
|
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,8 @@ import { confirm } from "@inquirer/prompts";
|
|
|
4
4
|
import fs2 from "fs";
|
|
5
5
|
import path4 from "path";
|
|
6
6
|
import os2 from "os";
|
|
7
|
+
import net from "net";
|
|
8
|
+
import { randomUUID } from "crypto";
|
|
7
9
|
import pm from "picomatch";
|
|
8
10
|
import { parse } from "sh-syntax";
|
|
9
11
|
|
|
@@ -1299,7 +1301,7 @@ function getPersistentDecision(toolName) {
|
|
|
1299
1301
|
}
|
|
1300
1302
|
return null;
|
|
1301
1303
|
}
|
|
1302
|
-
async function askDaemon(toolName, args, meta, signal, riskMetadata) {
|
|
1304
|
+
async function askDaemon(toolName, args, meta, signal, riskMetadata, activityId) {
|
|
1303
1305
|
const base = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
1304
1306
|
const checkCtrl = new AbortController();
|
|
1305
1307
|
const checkTimer = setTimeout(() => checkCtrl.abort(), 5e3);
|
|
@@ -1314,6 +1316,12 @@ async function askDaemon(toolName, args, meta, signal, riskMetadata) {
|
|
|
1314
1316
|
args,
|
|
1315
1317
|
agent: meta?.agent,
|
|
1316
1318
|
mcpServer: meta?.mcpServer,
|
|
1319
|
+
fromCLI: true,
|
|
1320
|
+
// Pass the flight-recorder ID so the daemon uses the same UUID for
|
|
1321
|
+
// activity-result as the CLI used for the pending activity event.
|
|
1322
|
+
// Without this, the two UUIDs never match and tail.ts never resolves
|
|
1323
|
+
// the pending item.
|
|
1324
|
+
activityId,
|
|
1317
1325
|
...riskMetadata && { riskMetadata }
|
|
1318
1326
|
}),
|
|
1319
1327
|
signal: checkCtrl.signal
|
|
@@ -1368,7 +1376,45 @@ async function resolveViaDaemon(id, decision, internalToken) {
|
|
|
1368
1376
|
signal: AbortSignal.timeout(3e3)
|
|
1369
1377
|
});
|
|
1370
1378
|
}
|
|
1379
|
+
var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path4.join(os2.tmpdir(), "node9-activity.sock");
|
|
1380
|
+
function notifyActivity(data) {
|
|
1381
|
+
return new Promise((resolve) => {
|
|
1382
|
+
try {
|
|
1383
|
+
const payload = JSON.stringify(data);
|
|
1384
|
+
const sock = net.createConnection(ACTIVITY_SOCKET_PATH);
|
|
1385
|
+
sock.on("connect", () => {
|
|
1386
|
+
sock.on("close", resolve);
|
|
1387
|
+
sock.end(payload);
|
|
1388
|
+
});
|
|
1389
|
+
sock.on("error", resolve);
|
|
1390
|
+
} catch {
|
|
1391
|
+
resolve();
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1371
1395
|
async function authorizeHeadless(toolName, args, allowTerminalFallback = false, meta, options) {
|
|
1396
|
+
if (!options?.calledFromDaemon) {
|
|
1397
|
+
const actId = randomUUID();
|
|
1398
|
+
const actTs = Date.now();
|
|
1399
|
+
await notifyActivity({ id: actId, ts: actTs, tool: toolName, args, status: "pending" });
|
|
1400
|
+
const result = await _authorizeHeadlessCore(toolName, args, allowTerminalFallback, meta, {
|
|
1401
|
+
...options,
|
|
1402
|
+
activityId: actId
|
|
1403
|
+
});
|
|
1404
|
+
if (!result.noApprovalMechanism) {
|
|
1405
|
+
await notifyActivity({
|
|
1406
|
+
id: actId,
|
|
1407
|
+
tool: toolName,
|
|
1408
|
+
ts: actTs,
|
|
1409
|
+
status: result.approved ? "allow" : result.blockedByLabel?.includes("DLP") ? "dlp" : "block",
|
|
1410
|
+
label: result.blockedByLabel
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
return result;
|
|
1414
|
+
}
|
|
1415
|
+
return _authorizeHeadlessCore(toolName, args, allowTerminalFallback, meta, options);
|
|
1416
|
+
}
|
|
1417
|
+
async function _authorizeHeadlessCore(toolName, args, allowTerminalFallback = false, meta, options) {
|
|
1372
1418
|
if (process.env.NODE9_PAUSED === "1") return { approved: true, checkedBy: "paused" };
|
|
1373
1419
|
const pauseState = checkPause();
|
|
1374
1420
|
if (pauseState.paused) return { approved: true, checkedBy: "paused" };
|
|
@@ -1404,6 +1450,7 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
1404
1450
|
blockedByLabel: "\u{1F6A8} Node9 DLP (Secret Detected)"
|
|
1405
1451
|
};
|
|
1406
1452
|
}
|
|
1453
|
+
if (!isManual) appendLocalAudit(toolName, args, "allow", "dlp-review-flagged", meta);
|
|
1407
1454
|
explainableLabel = "\u{1F6A8} Node9 DLP (Credential Review)";
|
|
1408
1455
|
}
|
|
1409
1456
|
}
|
|
@@ -1626,7 +1673,14 @@ async function authorizeHeadless(toolName, args, allowTerminalFallback = false,
|
|
|
1626
1673
|
console.error(chalk2.cyan(` URL \u2192 http://${DAEMON_HOST}:${DAEMON_PORT}/
|
|
1627
1674
|
`));
|
|
1628
1675
|
}
|
|
1629
|
-
const daemonDecision = await askDaemon(
|
|
1676
|
+
const daemonDecision = await askDaemon(
|
|
1677
|
+
toolName,
|
|
1678
|
+
args,
|
|
1679
|
+
meta,
|
|
1680
|
+
signal,
|
|
1681
|
+
riskMetadata,
|
|
1682
|
+
options?.activityId
|
|
1683
|
+
);
|
|
1630
1684
|
if (daemonDecision === "abandoned") throw new Error("Abandoned");
|
|
1631
1685
|
const isApproved = daemonDecision === "allow";
|
|
1632
1686
|
return {
|
|
@@ -1830,7 +1884,10 @@ function getConfig() {
|
|
|
1830
1884
|
for (const rule of shield.smartRules) {
|
|
1831
1885
|
if (!existingRuleNames.has(rule.name)) mergedPolicy.smartRules.push(rule);
|
|
1832
1886
|
}
|
|
1833
|
-
|
|
1887
|
+
const existingWords = new Set(mergedPolicy.dangerousWords);
|
|
1888
|
+
for (const word of shield.dangerousWords) {
|
|
1889
|
+
if (!existingWords.has(word)) mergedPolicy.dangerousWords.push(word);
|
|
1890
|
+
}
|
|
1834
1891
|
}
|
|
1835
1892
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
1836
1893
|
for (const rule of ADVISORY_SMART_RULES) {
|