@node9/proxy 1.19.4 → 1.20.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 +57 -102
- package/dist/cli.js +1660 -925
- package/dist/cli.mjs +1660 -924
- package/dist/dashboard.mjs +3503 -1343
- package/dist/index.js +127 -13
- package/dist/index.mjs +127 -13
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -118,12 +118,14 @@ function appendHookDebug(toolName, args, meta, auditHashArgsEnabled) {
|
|
|
118
118
|
function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashArgsEnabled) {
|
|
119
119
|
const argsField = auditHashArgsEnabled ? { argsHash: hashArgs(args) } : { args: args ? JSON.parse(redactSecrets(JSON.stringify(args))) : {} };
|
|
120
120
|
const testRun = isTestCall(toolName, args) || process.env.NODE9_TESTING === "1" ? { testRun: true } : {};
|
|
121
|
+
const ruleNameField = meta?.ruleName ? { ruleName: meta.ruleName } : {};
|
|
121
122
|
appendToLog(LOCAL_AUDIT_LOG, {
|
|
122
123
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
123
124
|
tool: toolName,
|
|
124
125
|
...argsField,
|
|
125
126
|
decision,
|
|
126
127
|
checkedBy,
|
|
128
|
+
...ruleNameField,
|
|
127
129
|
...testRun,
|
|
128
130
|
agent: meta?.agent,
|
|
129
131
|
mcpServer: meta?.mcpServer,
|
|
@@ -1089,15 +1091,50 @@ var SENSITIVE_PATH_RULES = [
|
|
|
1089
1091
|
match: (p) => /(^|[\\/])\.aws[\\/]/i.test(p)
|
|
1090
1092
|
},
|
|
1091
1093
|
{
|
|
1094
|
+
// Mirrors the JSON shield's `.env` pattern (project-jail.json's
|
|
1095
|
+
// review-read-env-any-tool) so the AST FS-op path catches the
|
|
1096
|
+
// same set the regex shield does — including Next.js / Vite's
|
|
1097
|
+
// `.env.<env>.local` double-suffix overrides which are commonly
|
|
1098
|
+
// gitignored AND commonly contain real secrets.
|
|
1099
|
+
//
|
|
1100
|
+
// Intentional non-matches (dev fixtures): .env.example, .env.sample,
|
|
1101
|
+
// .env.template, .env.test, .envrc. See shields.test.ts:983-995
|
|
1102
|
+
// for the canonical test-asserted contract.
|
|
1092
1103
|
rule: "shield:project-jail:block-read-env",
|
|
1093
1104
|
reason: "Reading .env files is blocked by project-jail shield",
|
|
1094
|
-
match: (p) => /(?:^|[\\/])\.env(?:\.local
|
|
1105
|
+
match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
|
|
1106
|
+
p
|
|
1107
|
+
)
|
|
1095
1108
|
},
|
|
1096
1109
|
{
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1110
|
+
// verdict: 'review' (not 'block') is a deliberate design choice
|
|
1111
|
+
// documented in commit 29327a8. SSH keys and AWS credentials are
|
|
1112
|
+
// cryptographic material with no legitimate read use-case for
|
|
1113
|
+
// an AI agent → hard `block`. But .netrc / .npmrc / .docker /
|
|
1114
|
+
// .kube / gcloud are CONFIG files that hold tokens AND have
|
|
1115
|
+
// legitimate diagnostic reads ("which registry am I configured
|
|
1116
|
+
// for", "what cluster am I on"). Hard-blocking those creates
|
|
1117
|
+
// friction without much safety win because the review gate
|
|
1118
|
+
// still catches genuine exfiltration attempts.
|
|
1119
|
+
//
|
|
1120
|
+
// The review gate FAILS CLOSED on timeout (daemon.approvalTimeoutMs
|
|
1121
|
+
// returns a deny verdict via the orchestrator's timeout branch),
|
|
1122
|
+
// so a stuck or unattended approval does NOT silently grant
|
|
1123
|
+
// credential access. If the threat model demands strict block,
|
|
1124
|
+
// a future per-shield strict-mode toggle is the right fix —
|
|
1125
|
+
// not a regex-level upgrade here.
|
|
1126
|
+
rule: "shield:project-jail:review-read-credentials",
|
|
1127
|
+
reason: "Reading credential files requires approval (project-jail shield)",
|
|
1128
|
+
verdict: "review",
|
|
1129
|
+
match: (p) => (
|
|
1130
|
+
// .kube/config holds Kubernetes cluster credentials and was
|
|
1131
|
+
// flagged as missing by the node9-pr-agent review (the comment
|
|
1132
|
+
// above mentioned .kube but the regex didn't include it — a
|
|
1133
|
+
// textbook code-comment vs code drift). The JSON shield's
|
|
1134
|
+
// review-read-credentials-any-tool already had it. Now aligned.
|
|
1135
|
+
/(?:credentials\.json|\.netrc|\.npmrc|\.docker[\\/]config\.json|gcloud[\\/]credentials|\.kube[\\/]config)$/i.test(
|
|
1136
|
+
p
|
|
1137
|
+
)
|
|
1101
1138
|
)
|
|
1102
1139
|
}
|
|
1103
1140
|
];
|
|
@@ -1116,7 +1153,7 @@ var AST_FS_REGEX_RULES = /* @__PURE__ */ new Set([
|
|
|
1116
1153
|
"shield:project-jail:block-read-ssh",
|
|
1117
1154
|
"shield:project-jail:block-read-aws",
|
|
1118
1155
|
"shield:project-jail:block-read-env",
|
|
1119
|
-
"shield:project-jail:
|
|
1156
|
+
"shield:project-jail:review-read-credentials"
|
|
1120
1157
|
]);
|
|
1121
1158
|
function isProtectedHomePath(rawPath) {
|
|
1122
1159
|
let p = rawPath.replace(/^\$HOME[\\/]?|^\$\{HOME\}[\\/]?/, "~/");
|
|
@@ -1228,7 +1265,12 @@ function analyzeFsOperationImpl(command) {
|
|
|
1228
1265
|
for (const p of paths) {
|
|
1229
1266
|
for (const sp of SENSITIVE_PATH_RULES) {
|
|
1230
1267
|
if (sp.match(p)) {
|
|
1231
|
-
result = {
|
|
1268
|
+
result = {
|
|
1269
|
+
ruleName: sp.rule,
|
|
1270
|
+
verdict: sp.verdict ?? "block",
|
|
1271
|
+
reason: sp.reason,
|
|
1272
|
+
path: p
|
|
1273
|
+
};
|
|
1232
1274
|
return false;
|
|
1233
1275
|
}
|
|
1234
1276
|
}
|
|
@@ -2512,7 +2554,7 @@ var project_jail_default = {
|
|
|
2512
2554
|
{
|
|
2513
2555
|
field: "command",
|
|
2514
2556
|
op: "matches",
|
|
2515
|
-
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s
|
|
2557
|
+
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s+.*?\\.ssh[\\/\\\\]",
|
|
2516
2558
|
flags: "i"
|
|
2517
2559
|
}
|
|
2518
2560
|
],
|
|
@@ -2526,7 +2568,7 @@ var project_jail_default = {
|
|
|
2526
2568
|
{
|
|
2527
2569
|
field: "command",
|
|
2528
2570
|
op: "matches",
|
|
2529
|
-
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s
|
|
2571
|
+
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s+.*?\\.aws[\\/\\\\]",
|
|
2530
2572
|
flags: "i"
|
|
2531
2573
|
}
|
|
2532
2574
|
],
|
|
@@ -2548,7 +2590,7 @@ var project_jail_default = {
|
|
|
2548
2590
|
reason: "Reading .env files is blocked by project-jail shield"
|
|
2549
2591
|
},
|
|
2550
2592
|
{
|
|
2551
|
-
name: "shield:project-jail:
|
|
2593
|
+
name: "shield:project-jail:review-read-credentials",
|
|
2552
2594
|
tool: "bash",
|
|
2553
2595
|
conditions: [
|
|
2554
2596
|
{
|
|
@@ -2558,8 +2600,64 @@ var project_jail_default = {
|
|
|
2558
2600
|
flags: "i"
|
|
2559
2601
|
}
|
|
2560
2602
|
],
|
|
2603
|
+
verdict: "review",
|
|
2604
|
+
reason: "Reading credential files requires approval (project-jail shield)"
|
|
2605
|
+
},
|
|
2606
|
+
{
|
|
2607
|
+
name: "shield:project-jail:block-read-ssh-any-tool",
|
|
2608
|
+
tool: "*",
|
|
2609
|
+
conditions: [
|
|
2610
|
+
{
|
|
2611
|
+
field: "file_path",
|
|
2612
|
+
op: "matches",
|
|
2613
|
+
value: "(^|[\\/\\\\])\\.ssh[\\/\\\\]",
|
|
2614
|
+
flags: "i"
|
|
2615
|
+
}
|
|
2616
|
+
],
|
|
2617
|
+
verdict: "block",
|
|
2618
|
+
reason: "Reading SSH private keys is blocked by project-jail shield"
|
|
2619
|
+
},
|
|
2620
|
+
{
|
|
2621
|
+
name: "shield:project-jail:block-read-aws-any-tool",
|
|
2622
|
+
tool: "*",
|
|
2623
|
+
conditions: [
|
|
2624
|
+
{
|
|
2625
|
+
field: "file_path",
|
|
2626
|
+
op: "matches",
|
|
2627
|
+
value: "(^|[\\/\\\\])\\.aws[\\/\\\\]",
|
|
2628
|
+
flags: "i"
|
|
2629
|
+
}
|
|
2630
|
+
],
|
|
2561
2631
|
verdict: "block",
|
|
2562
|
-
reason: "Reading
|
|
2632
|
+
reason: "Reading AWS credentials is blocked by project-jail shield"
|
|
2633
|
+
},
|
|
2634
|
+
{
|
|
2635
|
+
name: "shield:project-jail:review-read-env-any-tool",
|
|
2636
|
+
tool: "*",
|
|
2637
|
+
conditions: [
|
|
2638
|
+
{
|
|
2639
|
+
field: "file_path",
|
|
2640
|
+
op: "matches",
|
|
2641
|
+
value: "(^|[\\/\\\\])\\.env(\\.(local|production|staging|development|production\\.local|staging\\.local|development\\.local))?$",
|
|
2642
|
+
flags: "i"
|
|
2643
|
+
}
|
|
2644
|
+
],
|
|
2645
|
+
verdict: "review",
|
|
2646
|
+
reason: "Reading .env files requires approval (project-jail shield)"
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
name: "shield:project-jail:review-read-credentials-any-tool",
|
|
2650
|
+
tool: "*",
|
|
2651
|
+
conditions: [
|
|
2652
|
+
{
|
|
2653
|
+
field: "file_path",
|
|
2654
|
+
op: "matches",
|
|
2655
|
+
value: ".*(credentials\\.json|\\.netrc|\\.npmrc|\\.docker[\\/\\\\]config\\.json|gcloud[\\/\\\\]credentials|\\.kube[\\/\\\\]config)",
|
|
2656
|
+
flags: "i"
|
|
2657
|
+
}
|
|
2658
|
+
],
|
|
2659
|
+
verdict: "review",
|
|
2660
|
+
reason: "Reading credential files requires approval (project-jail shield)"
|
|
2563
2661
|
}
|
|
2564
2662
|
],
|
|
2565
2663
|
dangerousWords: []
|
|
@@ -4664,7 +4762,10 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4664
4762
|
args,
|
|
4665
4763
|
"deny",
|
|
4666
4764
|
"smart-rule-block-override",
|
|
4667
|
-
|
|
4765
|
+
// Same rationale as the smart-rule-block path above —
|
|
4766
|
+
// pass the specific rule name so [2] SHIELDS can
|
|
4767
|
+
// attribute this override-block to its owning shield.
|
|
4768
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
4668
4769
|
hashAuditArgs
|
|
4669
4770
|
);
|
|
4670
4771
|
if (approvers.cloud && creds?.apiKey)
|
|
@@ -4694,7 +4795,20 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4694
4795
|
}
|
|
4695
4796
|
} else {
|
|
4696
4797
|
if (!isManual)
|
|
4697
|
-
appendLocalAudit(
|
|
4798
|
+
appendLocalAudit(
|
|
4799
|
+
toolName,
|
|
4800
|
+
args,
|
|
4801
|
+
"deny",
|
|
4802
|
+
"smart-rule-block",
|
|
4803
|
+
// Include policyResult.ruleName so the [2] Report SHIELDS
|
|
4804
|
+
// panel can attribute this block to its specific shield
|
|
4805
|
+
// (e.g. `shield:project-jail:block-read-ssh`) via the
|
|
4806
|
+
// rule→shield map. checkedBy stays as the generic
|
|
4807
|
+
// `smart-rule-block` for backward compat with existing
|
|
4808
|
+
// log readers.
|
|
4809
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
4810
|
+
hashAuditArgs
|
|
4811
|
+
);
|
|
4698
4812
|
if (approvers.cloud && creds?.apiKey)
|
|
4699
4813
|
auditLocalAllow(toolName, args, "smart-rule-block", creds, meta, void 0, false, {
|
|
4700
4814
|
ruleName: policyResult.ruleName,
|
package/dist/index.mjs
CHANGED
|
@@ -98,12 +98,14 @@ function appendHookDebug(toolName, args, meta, auditHashArgsEnabled) {
|
|
|
98
98
|
function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashArgsEnabled) {
|
|
99
99
|
const argsField = auditHashArgsEnabled ? { argsHash: hashArgs(args) } : { args: args ? JSON.parse(redactSecrets(JSON.stringify(args))) : {} };
|
|
100
100
|
const testRun = isTestCall(toolName, args) || process.env.NODE9_TESTING === "1" ? { testRun: true } : {};
|
|
101
|
+
const ruleNameField = meta?.ruleName ? { ruleName: meta.ruleName } : {};
|
|
101
102
|
appendToLog(LOCAL_AUDIT_LOG, {
|
|
102
103
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
103
104
|
tool: toolName,
|
|
104
105
|
...argsField,
|
|
105
106
|
decision,
|
|
106
107
|
checkedBy,
|
|
108
|
+
...ruleNameField,
|
|
107
109
|
...testRun,
|
|
108
110
|
agent: meta?.agent,
|
|
109
111
|
mcpServer: meta?.mcpServer,
|
|
@@ -1059,15 +1061,50 @@ var SENSITIVE_PATH_RULES = [
|
|
|
1059
1061
|
match: (p) => /(^|[\\/])\.aws[\\/]/i.test(p)
|
|
1060
1062
|
},
|
|
1061
1063
|
{
|
|
1064
|
+
// Mirrors the JSON shield's `.env` pattern (project-jail.json's
|
|
1065
|
+
// review-read-env-any-tool) so the AST FS-op path catches the
|
|
1066
|
+
// same set the regex shield does — including Next.js / Vite's
|
|
1067
|
+
// `.env.<env>.local` double-suffix overrides which are commonly
|
|
1068
|
+
// gitignored AND commonly contain real secrets.
|
|
1069
|
+
//
|
|
1070
|
+
// Intentional non-matches (dev fixtures): .env.example, .env.sample,
|
|
1071
|
+
// .env.template, .env.test, .envrc. See shields.test.ts:983-995
|
|
1072
|
+
// for the canonical test-asserted contract.
|
|
1062
1073
|
rule: "shield:project-jail:block-read-env",
|
|
1063
1074
|
reason: "Reading .env files is blocked by project-jail shield",
|
|
1064
|
-
match: (p) => /(?:^|[\\/])\.env(?:\.local
|
|
1075
|
+
match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
|
|
1076
|
+
p
|
|
1077
|
+
)
|
|
1065
1078
|
},
|
|
1066
1079
|
{
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1080
|
+
// verdict: 'review' (not 'block') is a deliberate design choice
|
|
1081
|
+
// documented in commit 29327a8. SSH keys and AWS credentials are
|
|
1082
|
+
// cryptographic material with no legitimate read use-case for
|
|
1083
|
+
// an AI agent → hard `block`. But .netrc / .npmrc / .docker /
|
|
1084
|
+
// .kube / gcloud are CONFIG files that hold tokens AND have
|
|
1085
|
+
// legitimate diagnostic reads ("which registry am I configured
|
|
1086
|
+
// for", "what cluster am I on"). Hard-blocking those creates
|
|
1087
|
+
// friction without much safety win because the review gate
|
|
1088
|
+
// still catches genuine exfiltration attempts.
|
|
1089
|
+
//
|
|
1090
|
+
// The review gate FAILS CLOSED on timeout (daemon.approvalTimeoutMs
|
|
1091
|
+
// returns a deny verdict via the orchestrator's timeout branch),
|
|
1092
|
+
// so a stuck or unattended approval does NOT silently grant
|
|
1093
|
+
// credential access. If the threat model demands strict block,
|
|
1094
|
+
// a future per-shield strict-mode toggle is the right fix —
|
|
1095
|
+
// not a regex-level upgrade here.
|
|
1096
|
+
rule: "shield:project-jail:review-read-credentials",
|
|
1097
|
+
reason: "Reading credential files requires approval (project-jail shield)",
|
|
1098
|
+
verdict: "review",
|
|
1099
|
+
match: (p) => (
|
|
1100
|
+
// .kube/config holds Kubernetes cluster credentials and was
|
|
1101
|
+
// flagged as missing by the node9-pr-agent review (the comment
|
|
1102
|
+
// above mentioned .kube but the regex didn't include it — a
|
|
1103
|
+
// textbook code-comment vs code drift). The JSON shield's
|
|
1104
|
+
// review-read-credentials-any-tool already had it. Now aligned.
|
|
1105
|
+
/(?:credentials\.json|\.netrc|\.npmrc|\.docker[\\/]config\.json|gcloud[\\/]credentials|\.kube[\\/]config)$/i.test(
|
|
1106
|
+
p
|
|
1107
|
+
)
|
|
1071
1108
|
)
|
|
1072
1109
|
}
|
|
1073
1110
|
];
|
|
@@ -1086,7 +1123,7 @@ var AST_FS_REGEX_RULES = /* @__PURE__ */ new Set([
|
|
|
1086
1123
|
"shield:project-jail:block-read-ssh",
|
|
1087
1124
|
"shield:project-jail:block-read-aws",
|
|
1088
1125
|
"shield:project-jail:block-read-env",
|
|
1089
|
-
"shield:project-jail:
|
|
1126
|
+
"shield:project-jail:review-read-credentials"
|
|
1090
1127
|
]);
|
|
1091
1128
|
function isProtectedHomePath(rawPath) {
|
|
1092
1129
|
let p = rawPath.replace(/^\$HOME[\\/]?|^\$\{HOME\}[\\/]?/, "~/");
|
|
@@ -1198,7 +1235,12 @@ function analyzeFsOperationImpl(command) {
|
|
|
1198
1235
|
for (const p of paths) {
|
|
1199
1236
|
for (const sp of SENSITIVE_PATH_RULES) {
|
|
1200
1237
|
if (sp.match(p)) {
|
|
1201
|
-
result = {
|
|
1238
|
+
result = {
|
|
1239
|
+
ruleName: sp.rule,
|
|
1240
|
+
verdict: sp.verdict ?? "block",
|
|
1241
|
+
reason: sp.reason,
|
|
1242
|
+
path: p
|
|
1243
|
+
};
|
|
1202
1244
|
return false;
|
|
1203
1245
|
}
|
|
1204
1246
|
}
|
|
@@ -2482,7 +2524,7 @@ var project_jail_default = {
|
|
|
2482
2524
|
{
|
|
2483
2525
|
field: "command",
|
|
2484
2526
|
op: "matches",
|
|
2485
|
-
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s
|
|
2527
|
+
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s+.*?\\.ssh[\\/\\\\]",
|
|
2486
2528
|
flags: "i"
|
|
2487
2529
|
}
|
|
2488
2530
|
],
|
|
@@ -2496,7 +2538,7 @@ var project_jail_default = {
|
|
|
2496
2538
|
{
|
|
2497
2539
|
field: "command",
|
|
2498
2540
|
op: "matches",
|
|
2499
|
-
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s
|
|
2541
|
+
value: "(cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\\s+.*?\\.aws[\\/\\\\]",
|
|
2500
2542
|
flags: "i"
|
|
2501
2543
|
}
|
|
2502
2544
|
],
|
|
@@ -2518,7 +2560,7 @@ var project_jail_default = {
|
|
|
2518
2560
|
reason: "Reading .env files is blocked by project-jail shield"
|
|
2519
2561
|
},
|
|
2520
2562
|
{
|
|
2521
|
-
name: "shield:project-jail:
|
|
2563
|
+
name: "shield:project-jail:review-read-credentials",
|
|
2522
2564
|
tool: "bash",
|
|
2523
2565
|
conditions: [
|
|
2524
2566
|
{
|
|
@@ -2528,8 +2570,64 @@ var project_jail_default = {
|
|
|
2528
2570
|
flags: "i"
|
|
2529
2571
|
}
|
|
2530
2572
|
],
|
|
2573
|
+
verdict: "review",
|
|
2574
|
+
reason: "Reading credential files requires approval (project-jail shield)"
|
|
2575
|
+
},
|
|
2576
|
+
{
|
|
2577
|
+
name: "shield:project-jail:block-read-ssh-any-tool",
|
|
2578
|
+
tool: "*",
|
|
2579
|
+
conditions: [
|
|
2580
|
+
{
|
|
2581
|
+
field: "file_path",
|
|
2582
|
+
op: "matches",
|
|
2583
|
+
value: "(^|[\\/\\\\])\\.ssh[\\/\\\\]",
|
|
2584
|
+
flags: "i"
|
|
2585
|
+
}
|
|
2586
|
+
],
|
|
2587
|
+
verdict: "block",
|
|
2588
|
+
reason: "Reading SSH private keys is blocked by project-jail shield"
|
|
2589
|
+
},
|
|
2590
|
+
{
|
|
2591
|
+
name: "shield:project-jail:block-read-aws-any-tool",
|
|
2592
|
+
tool: "*",
|
|
2593
|
+
conditions: [
|
|
2594
|
+
{
|
|
2595
|
+
field: "file_path",
|
|
2596
|
+
op: "matches",
|
|
2597
|
+
value: "(^|[\\/\\\\])\\.aws[\\/\\\\]",
|
|
2598
|
+
flags: "i"
|
|
2599
|
+
}
|
|
2600
|
+
],
|
|
2531
2601
|
verdict: "block",
|
|
2532
|
-
reason: "Reading
|
|
2602
|
+
reason: "Reading AWS credentials is blocked by project-jail shield"
|
|
2603
|
+
},
|
|
2604
|
+
{
|
|
2605
|
+
name: "shield:project-jail:review-read-env-any-tool",
|
|
2606
|
+
tool: "*",
|
|
2607
|
+
conditions: [
|
|
2608
|
+
{
|
|
2609
|
+
field: "file_path",
|
|
2610
|
+
op: "matches",
|
|
2611
|
+
value: "(^|[\\/\\\\])\\.env(\\.(local|production|staging|development|production\\.local|staging\\.local|development\\.local))?$",
|
|
2612
|
+
flags: "i"
|
|
2613
|
+
}
|
|
2614
|
+
],
|
|
2615
|
+
verdict: "review",
|
|
2616
|
+
reason: "Reading .env files requires approval (project-jail shield)"
|
|
2617
|
+
},
|
|
2618
|
+
{
|
|
2619
|
+
name: "shield:project-jail:review-read-credentials-any-tool",
|
|
2620
|
+
tool: "*",
|
|
2621
|
+
conditions: [
|
|
2622
|
+
{
|
|
2623
|
+
field: "file_path",
|
|
2624
|
+
op: "matches",
|
|
2625
|
+
value: ".*(credentials\\.json|\\.netrc|\\.npmrc|\\.docker[\\/\\\\]config\\.json|gcloud[\\/\\\\]credentials|\\.kube[\\/\\\\]config)",
|
|
2626
|
+
flags: "i"
|
|
2627
|
+
}
|
|
2628
|
+
],
|
|
2629
|
+
verdict: "review",
|
|
2630
|
+
reason: "Reading credential files requires approval (project-jail shield)"
|
|
2533
2631
|
}
|
|
2534
2632
|
],
|
|
2535
2633
|
dangerousWords: []
|
|
@@ -4634,7 +4732,10 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4634
4732
|
args,
|
|
4635
4733
|
"deny",
|
|
4636
4734
|
"smart-rule-block-override",
|
|
4637
|
-
|
|
4735
|
+
// Same rationale as the smart-rule-block path above —
|
|
4736
|
+
// pass the specific rule name so [2] SHIELDS can
|
|
4737
|
+
// attribute this override-block to its owning shield.
|
|
4738
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
4638
4739
|
hashAuditArgs
|
|
4639
4740
|
);
|
|
4640
4741
|
if (approvers.cloud && creds?.apiKey)
|
|
@@ -4664,7 +4765,20 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4664
4765
|
}
|
|
4665
4766
|
} else {
|
|
4666
4767
|
if (!isManual)
|
|
4667
|
-
appendLocalAudit(
|
|
4768
|
+
appendLocalAudit(
|
|
4769
|
+
toolName,
|
|
4770
|
+
args,
|
|
4771
|
+
"deny",
|
|
4772
|
+
"smart-rule-block",
|
|
4773
|
+
// Include policyResult.ruleName so the [2] Report SHIELDS
|
|
4774
|
+
// panel can attribute this block to its specific shield
|
|
4775
|
+
// (e.g. `shield:project-jail:block-read-ssh`) via the
|
|
4776
|
+
// rule→shield map. checkedBy stays as the generic
|
|
4777
|
+
// `smart-rule-block` for backward compat with existing
|
|
4778
|
+
// log readers.
|
|
4779
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
4780
|
+
hashAuditArgs
|
|
4781
|
+
);
|
|
4668
4782
|
if (approvers.cloud && creds?.apiKey)
|
|
4669
4783
|
auditLocalAllow(toolName, args, "smart-rule-block", creds, meta, void 0, false, {
|
|
4670
4784
|
ruleName: policyResult.ruleName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.1",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code & MCP.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"react": "^19.2.6",
|
|
84
84
|
"safe-regex2": "^5.1.0",
|
|
85
85
|
"smol-toml": "^1.6.1",
|
|
86
|
+
"string-width": "^4.2.3",
|
|
86
87
|
"zod": "^3.25.76"
|
|
87
88
|
},
|
|
88
89
|
"bundleDependencies": [
|
|
@@ -101,6 +102,7 @@
|
|
|
101
102
|
"@types/react": "^19.2.14",
|
|
102
103
|
"@vitest/coverage-v8": "4.1.2",
|
|
103
104
|
"cross-env": "^10.1.0",
|
|
105
|
+
"ink-testing-library": "^4.0.0",
|
|
104
106
|
"prettier": "^3.4.2",
|
|
105
107
|
"semantic-release": "^25.0.3",
|
|
106
108
|
"tsup": "^8.5.1",
|