@node9/proxy 1.62.0 → 1.63.0
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/cli.js +56 -5
- package/dist/cli.mjs +56 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17451,7 +17451,7 @@ var init_ship = __esm({
|
|
|
17451
17451
|
});
|
|
17452
17452
|
|
|
17453
17453
|
// src/policy-snapshot/build.ts
|
|
17454
|
-
function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, statusEntries = []) {
|
|
17454
|
+
function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, statusEntries = [], syncHealth) {
|
|
17455
17455
|
const p = config.policy;
|
|
17456
17456
|
const statusByKey = /* @__PURE__ */ new Map();
|
|
17457
17457
|
for (const s of statusEntries) {
|
|
@@ -17510,7 +17510,17 @@ function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, st
|
|
|
17510
17510
|
dlpEnabled: p.dlp.enabled,
|
|
17511
17511
|
engineVersion: ENGINE_VERSION,
|
|
17512
17512
|
// Connected rows first so they win the cap; non-connected SEE rows fill the rest.
|
|
17513
|
-
mcpServers: [...connectedRows, ...extraRows].slice(0, MAX_MCP_SERVERS)
|
|
17513
|
+
mcpServers: [...connectedRows, ...extraRows].slice(0, MAX_MCP_SERVERS),
|
|
17514
|
+
// fleet-ship Step 2: ship the proxy's own sync health so the dashboard can
|
|
17515
|
+
// derive a "sync failing" badge. Only included when the caller passes it.
|
|
17516
|
+
...syncHealth && {
|
|
17517
|
+
syncHealth: {
|
|
17518
|
+
lastCheckedAt: syncHealth.lastCheckedAt,
|
|
17519
|
+
lastChangedAt: syncHealth.lastChangedAt,
|
|
17520
|
+
lastError: syncHealth.lastError,
|
|
17521
|
+
consecutiveFailures: syncHealth.consecutiveFailures
|
|
17522
|
+
}
|
|
17523
|
+
}
|
|
17514
17524
|
};
|
|
17515
17525
|
}
|
|
17516
17526
|
var MAX_RULES, MAX_EGRESS, MAX_MCP_SERVERS, MAX_MCP_TOOLS;
|
|
@@ -18285,7 +18295,10 @@ async function pushPolicySnapshot(creds) {
|
|
|
18285
18295
|
// Merged config-vs-connected status. resolveMcpStatus reads process.env to
|
|
18286
18296
|
// resolve ${VAR} placeholders — so this push reflects THIS process's env
|
|
18287
18297
|
// (daemon here, user shell in runPolicyPush); see the P2 design's two-env note.
|
|
18288
|
-
resolveMcpStatus()
|
|
18298
|
+
resolveMcpStatus(),
|
|
18299
|
+
// fleet-ship Step 2: ship this machine's sync health so the dashboard can
|
|
18300
|
+
// show "sync failing" badges. readSyncHealth is local (same module, no circular).
|
|
18301
|
+
readSyncHealth()
|
|
18289
18302
|
);
|
|
18290
18303
|
await shipPolicySnapshot(body, creds);
|
|
18291
18304
|
} catch {
|
|
@@ -18308,7 +18321,8 @@ async function runPolicyPush() {
|
|
|
18308
18321
|
// Merged config-vs-connected status. resolveMcpStatus reads process.env to
|
|
18309
18322
|
// resolve ${VAR} placeholders — so this push reflects THIS process's env
|
|
18310
18323
|
// (daemon here, user shell in runPolicyPush); see the P2 design's two-env note.
|
|
18311
|
-
resolveMcpStatus()
|
|
18324
|
+
resolveMcpStatus(),
|
|
18325
|
+
readSyncHealth()
|
|
18312
18326
|
);
|
|
18313
18327
|
const sent = await shipPolicySnapshot(body, creds);
|
|
18314
18328
|
return sent ? { ok: true } : { ok: false, reason: "Push failed (network or server error)" };
|
|
@@ -53772,6 +53786,38 @@ function collectTools(steps) {
|
|
|
53772
53786
|
}
|
|
53773
53787
|
return s;
|
|
53774
53788
|
}
|
|
53789
|
+
function toolTokens(blob) {
|
|
53790
|
+
const out = [];
|
|
53791
|
+
let buf = "";
|
|
53792
|
+
let inParen = false;
|
|
53793
|
+
const flush = () => {
|
|
53794
|
+
const t = buf.replace(/[[\]"'`\r\n]/g, "").trim();
|
|
53795
|
+
if (t) out.push(t);
|
|
53796
|
+
buf = "";
|
|
53797
|
+
};
|
|
53798
|
+
for (const ch of blob) {
|
|
53799
|
+
if (ch === "(") inParen = true;
|
|
53800
|
+
else if (ch === ")") inParen = false;
|
|
53801
|
+
if (!inParen && (ch === "," || /\s/.test(ch))) {
|
|
53802
|
+
flush();
|
|
53803
|
+
continue;
|
|
53804
|
+
}
|
|
53805
|
+
buf += ch;
|
|
53806
|
+
}
|
|
53807
|
+
flush();
|
|
53808
|
+
return out;
|
|
53809
|
+
}
|
|
53810
|
+
function matchedBroadTools(blob) {
|
|
53811
|
+
const seen = /* @__PURE__ */ new Set();
|
|
53812
|
+
const out = [];
|
|
53813
|
+
for (const tok of toolTokens(blob)) {
|
|
53814
|
+
if (!BROAD_TOOL_RE.test(`,${tok},`)) continue;
|
|
53815
|
+
if (seen.has(tok)) continue;
|
|
53816
|
+
seen.add(tok);
|
|
53817
|
+
out.push(tok.length > 40 ? tok.slice(0, 40) + "\u2026" : tok);
|
|
53818
|
+
}
|
|
53819
|
+
return out;
|
|
53820
|
+
}
|
|
53775
53821
|
function untrustedHeadCheckout(steps) {
|
|
53776
53822
|
for (const step of steps) {
|
|
53777
53823
|
if (!step.uses || !/actions\/checkout/.test(step.uses)) continue;
|
|
@@ -53998,7 +54044,12 @@ function analyzeWorkflow(path71, content) {
|
|
|
53998
54044
|
if (head === "root") signals.push("checks out the untrusted PR head into the workspace root");
|
|
53999
54045
|
if (head === "subdir") signals.push("checks out the untrusted PR head into an isolated subdir");
|
|
54000
54046
|
if (promptUntrusted) signals.push("feeds untrusted PR/issue text to the agent");
|
|
54001
|
-
if (broadTools)
|
|
54047
|
+
if (broadTools) {
|
|
54048
|
+
const names = matchedBroadTools(toolsBlob);
|
|
54049
|
+
signals.push(
|
|
54050
|
+
names.length ? `agent has broad/write-capable tools: ${names.map((n) => `\`${n}\``).join(", ")}` : "agent has broad/write-capable tool grants"
|
|
54051
|
+
);
|
|
54052
|
+
}
|
|
54002
54053
|
if (bypassActive) signals.push('allowed_non_write_users: "*" \u2014 any user can trigger the agent');
|
|
54003
54054
|
if (elevated) signals.push("elevated permissions (contents/id-token: write)");
|
|
54004
54055
|
if (pat) signals.push("a static PAT is exposed to the agent (recoverable via injection)");
|
package/dist/cli.mjs
CHANGED
|
@@ -17448,7 +17448,7 @@ var init_ship = __esm({
|
|
|
17448
17448
|
});
|
|
17449
17449
|
|
|
17450
17450
|
// src/policy-snapshot/build.ts
|
|
17451
|
-
function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, statusEntries = []) {
|
|
17451
|
+
function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, statusEntries = [], syncHealth) {
|
|
17452
17452
|
const p = config.policy;
|
|
17453
17453
|
const statusByKey = /* @__PURE__ */ new Map();
|
|
17454
17454
|
for (const s of statusEntries) {
|
|
@@ -17507,7 +17507,17 @@ function buildPolicySnapshot(config, activeShields, overrides, mcpTools = {}, st
|
|
|
17507
17507
|
dlpEnabled: p.dlp.enabled,
|
|
17508
17508
|
engineVersion: ENGINE_VERSION,
|
|
17509
17509
|
// Connected rows first so they win the cap; non-connected SEE rows fill the rest.
|
|
17510
|
-
mcpServers: [...connectedRows, ...extraRows].slice(0, MAX_MCP_SERVERS)
|
|
17510
|
+
mcpServers: [...connectedRows, ...extraRows].slice(0, MAX_MCP_SERVERS),
|
|
17511
|
+
// fleet-ship Step 2: ship the proxy's own sync health so the dashboard can
|
|
17512
|
+
// derive a "sync failing" badge. Only included when the caller passes it.
|
|
17513
|
+
...syncHealth && {
|
|
17514
|
+
syncHealth: {
|
|
17515
|
+
lastCheckedAt: syncHealth.lastCheckedAt,
|
|
17516
|
+
lastChangedAt: syncHealth.lastChangedAt,
|
|
17517
|
+
lastError: syncHealth.lastError,
|
|
17518
|
+
consecutiveFailures: syncHealth.consecutiveFailures
|
|
17519
|
+
}
|
|
17520
|
+
}
|
|
17511
17521
|
};
|
|
17512
17522
|
}
|
|
17513
17523
|
var MAX_RULES, MAX_EGRESS, MAX_MCP_SERVERS, MAX_MCP_TOOLS;
|
|
@@ -18283,7 +18293,10 @@ async function pushPolicySnapshot(creds) {
|
|
|
18283
18293
|
// Merged config-vs-connected status. resolveMcpStatus reads process.env to
|
|
18284
18294
|
// resolve ${VAR} placeholders — so this push reflects THIS process's env
|
|
18285
18295
|
// (daemon here, user shell in runPolicyPush); see the P2 design's two-env note.
|
|
18286
|
-
resolveMcpStatus()
|
|
18296
|
+
resolveMcpStatus(),
|
|
18297
|
+
// fleet-ship Step 2: ship this machine's sync health so the dashboard can
|
|
18298
|
+
// show "sync failing" badges. readSyncHealth is local (same module, no circular).
|
|
18299
|
+
readSyncHealth()
|
|
18287
18300
|
);
|
|
18288
18301
|
await shipPolicySnapshot(body, creds);
|
|
18289
18302
|
} catch {
|
|
@@ -18306,7 +18319,8 @@ async function runPolicyPush() {
|
|
|
18306
18319
|
// Merged config-vs-connected status. resolveMcpStatus reads process.env to
|
|
18307
18320
|
// resolve ${VAR} placeholders — so this push reflects THIS process's env
|
|
18308
18321
|
// (daemon here, user shell in runPolicyPush); see the P2 design's two-env note.
|
|
18309
|
-
resolveMcpStatus()
|
|
18322
|
+
resolveMcpStatus(),
|
|
18323
|
+
readSyncHealth()
|
|
18310
18324
|
);
|
|
18311
18325
|
const sent = await shipPolicySnapshot(body, creds);
|
|
18312
18326
|
return sent ? { ok: true } : { ok: false, reason: "Push failed (network or server error)" };
|
|
@@ -53765,6 +53779,38 @@ function collectTools(steps) {
|
|
|
53765
53779
|
}
|
|
53766
53780
|
return s;
|
|
53767
53781
|
}
|
|
53782
|
+
function toolTokens(blob) {
|
|
53783
|
+
const out = [];
|
|
53784
|
+
let buf = "";
|
|
53785
|
+
let inParen = false;
|
|
53786
|
+
const flush = () => {
|
|
53787
|
+
const t = buf.replace(/[[\]"'`\r\n]/g, "").trim();
|
|
53788
|
+
if (t) out.push(t);
|
|
53789
|
+
buf = "";
|
|
53790
|
+
};
|
|
53791
|
+
for (const ch of blob) {
|
|
53792
|
+
if (ch === "(") inParen = true;
|
|
53793
|
+
else if (ch === ")") inParen = false;
|
|
53794
|
+
if (!inParen && (ch === "," || /\s/.test(ch))) {
|
|
53795
|
+
flush();
|
|
53796
|
+
continue;
|
|
53797
|
+
}
|
|
53798
|
+
buf += ch;
|
|
53799
|
+
}
|
|
53800
|
+
flush();
|
|
53801
|
+
return out;
|
|
53802
|
+
}
|
|
53803
|
+
function matchedBroadTools(blob) {
|
|
53804
|
+
const seen = /* @__PURE__ */ new Set();
|
|
53805
|
+
const out = [];
|
|
53806
|
+
for (const tok of toolTokens(blob)) {
|
|
53807
|
+
if (!BROAD_TOOL_RE.test(`,${tok},`)) continue;
|
|
53808
|
+
if (seen.has(tok)) continue;
|
|
53809
|
+
seen.add(tok);
|
|
53810
|
+
out.push(tok.length > 40 ? tok.slice(0, 40) + "\u2026" : tok);
|
|
53811
|
+
}
|
|
53812
|
+
return out;
|
|
53813
|
+
}
|
|
53768
53814
|
function untrustedHeadCheckout(steps) {
|
|
53769
53815
|
for (const step of steps) {
|
|
53770
53816
|
if (!step.uses || !/actions\/checkout/.test(step.uses)) continue;
|
|
@@ -53991,7 +54037,12 @@ function analyzeWorkflow(path71, content) {
|
|
|
53991
54037
|
if (head === "root") signals.push("checks out the untrusted PR head into the workspace root");
|
|
53992
54038
|
if (head === "subdir") signals.push("checks out the untrusted PR head into an isolated subdir");
|
|
53993
54039
|
if (promptUntrusted) signals.push("feeds untrusted PR/issue text to the agent");
|
|
53994
|
-
if (broadTools)
|
|
54040
|
+
if (broadTools) {
|
|
54041
|
+
const names = matchedBroadTools(toolsBlob);
|
|
54042
|
+
signals.push(
|
|
54043
|
+
names.length ? `agent has broad/write-capable tools: ${names.map((n) => `\`${n}\``).join(", ")}` : "agent has broad/write-capable tool grants"
|
|
54044
|
+
);
|
|
54045
|
+
}
|
|
53995
54046
|
if (bypassActive) signals.push('allowed_non_write_users: "*" \u2014 any user can trigger the agent');
|
|
53996
54047
|
if (elevated) signals.push("elevated permissions (contents/id-token: write)");
|
|
53997
54048
|
if (pat) signals.push("a static PAT is exposed to the agent (recoverable via injection)");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.63.0",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|