@node9/policy-engine 1.67.2 → 1.67.3

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/index.d.mts CHANGED
@@ -1117,7 +1117,7 @@ declare const LONG_OUTPUT_THRESHOLD_BYTES: number;
1117
1117
  * and fails CI when the hash drifts without a version bump — forgetting
1118
1118
  * is loud, not silent.
1119
1119
  */
1120
- declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
1120
+ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
1121
1121
  /**
1122
1122
  * SHA-256 prefix of the detector-source files
1123
1123
  * (canonical.ts + pii.ts + destructive-regex.ts).
@@ -1128,7 +1128,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
1128
1128
  * files changed, this hash must change too, and you must consciously
1129
1129
  * decide whether to bump CANONICAL_EXTRACTOR_VERSION."
1130
1130
  */
1131
- declare const CANONICAL_EXTRACTOR_HASH = "80f40f974263b281";
1131
+ declare const CANONICAL_EXTRACTOR_HASH = "4ebf40dfe1d7c0a1";
1132
1132
  declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
1133
1133
  declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
1134
1134
  /**
package/dist/index.d.ts CHANGED
@@ -1117,7 +1117,7 @@ declare const LONG_OUTPUT_THRESHOLD_BYTES: number;
1117
1117
  * and fails CI when the hash drifts without a version bump — forgetting
1118
1118
  * is loud, not silent.
1119
1119
  */
1120
- declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
1120
+ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
1121
1121
  /**
1122
1122
  * SHA-256 prefix of the detector-source files
1123
1123
  * (canonical.ts + pii.ts + destructive-regex.ts).
@@ -1128,7 +1128,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
1128
1128
  * files changed, this hash must change too, and you must consciously
1129
1129
  * decide whether to bump CANONICAL_EXTRACTOR_VERSION."
1130
1130
  */
1131
- declare const CANONICAL_EXTRACTOR_HASH = "80f40f974263b281";
1131
+ declare const CANONICAL_EXTRACTOR_HASH = "4ebf40dfe1d7c0a1";
1132
1132
  declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
1133
1133
  declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
1134
1134
  /**
package/dist/index.js CHANGED
@@ -1160,9 +1160,34 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
1160
1160
  "vi",
1161
1161
  "emacs",
1162
1162
  "code",
1163
- "type"
1163
+ "type",
1164
+ // — the 22 that were missing —
1165
+ "grep",
1166
+ "egrep",
1167
+ "fgrep",
1168
+ "rg",
1169
+ "ag",
1170
+ "ack",
1171
+ "awk",
1172
+ "gawk",
1173
+ "sed",
1174
+ "cut",
1175
+ "tr",
1176
+ "jq",
1177
+ "yq",
1178
+ "od",
1179
+ "xxd",
1180
+ "hexdump",
1181
+ "strings",
1182
+ "sort",
1183
+ "uniq",
1184
+ "tac",
1185
+ "nl",
1186
+ "dd"
1164
1187
  ]);
1165
- var FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
1188
+ var FS_OP_PRESCREEN_RE = new RegExp(
1189
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
1190
+ );
1166
1191
  var HOME_CACHE_ALLOWLIST = [
1167
1192
  ".cache",
1168
1193
  ".npm/_npx",
@@ -1201,9 +1226,37 @@ var SENSITIVE_PATH_RULES = [
1201
1226
  // for the canonical test-asserted contract.
1202
1227
  rule: "shield:project-jail:block-read-env",
1203
1228
  reason: "Reading .env files is blocked by project-jail shield",
1204
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
1205
- p
1206
- )
1229
+ // Structural, not a list. The previous form enumerated seven suffixes and
1230
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
1231
+ // gitignored, all routinely holding real secrets — were never covered. A
1232
+ // hand-written list of what to protect is only ever as complete as the day
1233
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
1234
+ // exceptions, which is the direction that fails safe.
1235
+ //
1236
+ // \.env the segment itself
1237
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1238
+ // files. Without it a flat suffix class swallows both.
1239
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1240
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
1241
+ // `(\.[\w-]+)*` reads the same but is rejected by
1242
+ // safe-regex2, and this pattern runs on the hook hot path.
1243
+ //
1244
+ // The two exclusions are NOT the same shape, because the words do not mean
1245
+ // the same thing:
1246
+ //
1247
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
1248
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
1249
+ // These are checked into git by convention: already public, so blocking
1250
+ // them buys nothing and costs the most common legitimate agent read.
1251
+ //
1252
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
1253
+ // fixture. `.env.test` is the committed template and stays allowed, but
1254
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
1255
+ // holds real values, so it must block. Using `\b` here — the obvious
1256
+ // symmetry — silently exempts every `.env.test.*` file.
1257
+ //
1258
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
1259
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
1207
1260
  },
1208
1261
  {
1209
1262
  // verdict: 'review' (not 'block') is a deliberate design choice
@@ -3917,8 +3970,8 @@ function detectArgsPii(args) {
3917
3970
 
3918
3971
  // src/scan/canonical.ts
3919
3972
  var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
3920
- var CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
3921
- var CANONICAL_EXTRACTOR_HASH = "80f40f974263b281";
3973
+ var CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
3974
+ var CANONICAL_EXTRACTOR_HASH = "4ebf40dfe1d7c0a1";
3922
3975
  var DEDUPE_PREVIEW_LEN = 120;
3923
3976
  function extractCanonicalFindings(call, ctx) {
3924
3977
  const out = [];
package/dist/index.mjs CHANGED
@@ -1047,9 +1047,34 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
1047
1047
  "vi",
1048
1048
  "emacs",
1049
1049
  "code",
1050
- "type"
1050
+ "type",
1051
+ // — the 22 that were missing —
1052
+ "grep",
1053
+ "egrep",
1054
+ "fgrep",
1055
+ "rg",
1056
+ "ag",
1057
+ "ack",
1058
+ "awk",
1059
+ "gawk",
1060
+ "sed",
1061
+ "cut",
1062
+ "tr",
1063
+ "jq",
1064
+ "yq",
1065
+ "od",
1066
+ "xxd",
1067
+ "hexdump",
1068
+ "strings",
1069
+ "sort",
1070
+ "uniq",
1071
+ "tac",
1072
+ "nl",
1073
+ "dd"
1051
1074
  ]);
1052
- var FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
1075
+ var FS_OP_PRESCREEN_RE = new RegExp(
1076
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
1077
+ );
1053
1078
  var HOME_CACHE_ALLOWLIST = [
1054
1079
  ".cache",
1055
1080
  ".npm/_npx",
@@ -1088,9 +1113,37 @@ var SENSITIVE_PATH_RULES = [
1088
1113
  // for the canonical test-asserted contract.
1089
1114
  rule: "shield:project-jail:block-read-env",
1090
1115
  reason: "Reading .env files is blocked by project-jail shield",
1091
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
1092
- p
1093
- )
1116
+ // Structural, not a list. The previous form enumerated seven suffixes and
1117
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
1118
+ // gitignored, all routinely holding real secrets — were never covered. A
1119
+ // hand-written list of what to protect is only ever as complete as the day
1120
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
1121
+ // exceptions, which is the direction that fails safe.
1122
+ //
1123
+ // \.env the segment itself
1124
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1125
+ // files. Without it a flat suffix class swallows both.
1126
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1127
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
1128
+ // `(\.[\w-]+)*` reads the same but is rejected by
1129
+ // safe-regex2, and this pattern runs on the hook hot path.
1130
+ //
1131
+ // The two exclusions are NOT the same shape, because the words do not mean
1132
+ // the same thing:
1133
+ //
1134
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
1135
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
1136
+ // These are checked into git by convention: already public, so blocking
1137
+ // them buys nothing and costs the most common legitimate agent read.
1138
+ //
1139
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
1140
+ // fixture. `.env.test` is the committed template and stays allowed, but
1141
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
1142
+ // holds real values, so it must block. Using `\b` here — the obvious
1143
+ // symmetry — silently exempts every `.env.test.*` file.
1144
+ //
1145
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
1146
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
1094
1147
  },
1095
1148
  {
1096
1149
  // verdict: 'review' (not 'block') is a deliberate design choice
@@ -3804,8 +3857,8 @@ function detectArgsPii(args) {
3804
3857
 
3805
3858
  // src/scan/canonical.ts
3806
3859
  var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
3807
- var CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
3808
- var CANONICAL_EXTRACTOR_HASH = "80f40f974263b281";
3860
+ var CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
3861
+ var CANONICAL_EXTRACTOR_HASH = "4ebf40dfe1d7c0a1";
3809
3862
  var DEDUPE_PREVIEW_LEN = 120;
3810
3863
  function extractCanonicalFindings(call, ctx) {
3811
3864
  const out = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/policy-engine",
3
- "version": "1.67.2",
3
+ "version": "1.67.3",
4
4
  "description": "Shared policy evaluation engine for node9 — DLP, smart rules, AST shell parsing, shields, loop detection. Pure functions, no I/O. Used by both node9-proxy and the node9 SaaS firewall.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://node9.ai",