@node9/proxy 2.38.0 → 2.40.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/index.mjs CHANGED
@@ -438,6 +438,32 @@ function ssrfFloorDecision(m, asWritten, opts) {
438
438
  }
439
439
  return "block";
440
440
  }
441
+ function isModeValue(v) {
442
+ return typeof v === "string" && MODE_VALUES.includes(v);
443
+ }
444
+ function levelOf(mode) {
445
+ if (mode === "observe") return "audit";
446
+ return LEVELS.includes(mode ?? "") ? mode : "standard";
447
+ }
448
+ function isRecordOnly(mode) {
449
+ return levelOf(mode) === "audit";
450
+ }
451
+ function reviewsEveryInline(mode) {
452
+ const level = levelOf(mode);
453
+ return level === "strict" || level === "block-all";
454
+ }
455
+ function isBlockAll(mode) {
456
+ return levelOf(mode) === "block-all";
457
+ }
458
+ function levelCheckValue(mode, id) {
459
+ return LEVEL_CHECKS[levelOf(mode)][id];
460
+ }
461
+ function levelChecks(mode) {
462
+ return LEVEL_CHECKS[levelOf(mode)];
463
+ }
464
+ function levelPackageSignals(mode) {
465
+ return levelOf(mode) === "soft" ? { newPackage: "off", installScript: "off" } : void 0;
466
+ }
441
467
  function isVerdict(v) {
442
468
  return v === "off" || v === "log" || v === "review" || v === "block";
443
469
  }
@@ -583,19 +609,21 @@ function resolveCheck(settings, id) {
583
609
  if (!def) return void 0;
584
610
  if (isLockedCheck(def)) return { id, value: "block", source: "locked" };
585
611
  const floor = def.floor ? CHECK_VERDICT_RANK[def.floor] : 0;
612
+ const levelDefault = levelCheckValue(settings.mode, id) ?? def.defaultValue;
613
+ const sourceOf = (value2) => value2 === levelDefault ? "default" : "configured";
586
614
  const explicit = settings.checks?.[id];
587
615
  if (isVerdict(explicit)) {
588
616
  const value2 = CHECK_VERDICT_RANK[explicit] < floor ? def.floor : explicit;
589
- return { id, value: value2, source: value2 === def.defaultValue ? "default" : "configured" };
617
+ return { id, value: value2, source: sourceOf(value2) };
590
618
  }
591
619
  if (def.pack) {
592
620
  const on = settings.appliedShields?.includes(def.pack) ?? false;
593
621
  return { id, value: on ? def.defaultValue : "off", source: "default" };
594
622
  }
595
623
  const read2 = LEGACY_READERS[id]?.(settings);
596
- if (read2 === void 0) return { id, value: def.defaultValue, source: "default" };
624
+ if (read2 === void 0) return { id, value: levelDefault, source: "default" };
597
625
  const value = CHECK_VERDICT_RANK[read2] < floor ? def.floor : read2;
598
- return { id, value, source: value === def.defaultValue ? "default" : "configured" };
626
+ return { id, value, source: sourceOf(value) };
599
627
  }
600
628
  function checkValue(settings, id) {
601
629
  return resolveCheck(settings, id)?.value ?? "off";
@@ -5345,6 +5373,20 @@ function extractPackageInstalls(command) {
5345
5373
  return true;
5346
5374
  });
5347
5375
  }
5376
+ function tuningFromLegacyPolicy(policy) {
5377
+ const out = {};
5378
+ const p = policy;
5379
+ if (policy.packageCheck?.registrySignals === false) {
5380
+ out["loading.malicious-package"] = { newPackage: "off", installScript: "off" };
5381
+ }
5382
+ for (const f of TUNING_FIELDS) {
5383
+ const [block, key] = f.legacy;
5384
+ const value = p[block]?.[key];
5385
+ if (value === void 0) continue;
5386
+ (out[f.checkId] ??= {})[f.name] = value;
5387
+ }
5388
+ return out;
5389
+ }
5348
5390
  function tuningToLegacyPolicy(policy, tuning) {
5349
5391
  const unknown = [];
5350
5392
  for (const [id, fields] of Object.entries(tuning)) {
@@ -5459,6 +5501,25 @@ function checkToLegacyPolicy(policy, id, v) {
5459
5501
  return false;
5460
5502
  }
5461
5503
  }
5504
+ function knobStatedChecks(policy) {
5505
+ const out = /* @__PURE__ */ new Set();
5506
+ const has = (o, key) => !!o && typeof o === "object" && o[key] !== void 0;
5507
+ const { dlp, egress, loopDetection, injectionScan, skillPinning, packageCheck } = policy;
5508
+ const uc = policy.untrustedContent;
5509
+ if (has(dlp, "enabled")) out.add("data.secrets");
5510
+ if (has(dlp, "reviewAction") || dlp?.enabled === false) out.add("data.secrets-weak");
5511
+ if (has(dlp, "pii")) out.add("data.pii");
5512
+ if (has(egress, "enabled") || has(egress, "mode")) out.add("network.unknown-host");
5513
+ if (has(egress, "ssrfStrict")) out.add("network.internal-addresses");
5514
+ if (has(loopDetection, "enabled")) out.add("behavior.loops");
5515
+ if (has(injectionScan, "enabled")) out.add("behavior.prompt-injection");
5516
+ if (has(skillPinning, "enabled") || has(skillPinning, "mode")) out.add("loading.skill-tamper");
5517
+ if (has(packageCheck, "enabled") || has(packageCheck, "onMalicious"))
5518
+ out.add("loading.malicious-package");
5519
+ if (uc && typeof uc === "object" && (uc.enabled === false || has(uc, "afterExposure")))
5520
+ out.add("behavior.untrusted-content");
5521
+ return out;
5522
+ }
5462
5523
  function isKnobGoverned(id) {
5463
5524
  return id in KNOB_GOVERNED;
5464
5525
  }
@@ -6269,7 +6330,7 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
6269
6330
  if (v?.logged) noteLogged(v);
6270
6331
  else if (v) candidates.push(v);
6271
6332
  };
6272
- const inline = config.settings.mode === "strict" ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand);
6333
+ const inline = reviewsEveryInline(config.settings.mode) ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand);
6273
6334
  if (inline !== null) {
6274
6335
  consider("commands.inline-exec", {
6275
6336
  decision: "review",
@@ -6329,21 +6390,17 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
6329
6390
  if (firstToken && firstToken.startsWith("/") && checkProvenance2) {
6330
6391
  const prov = checkProvenance2(firstToken, cwd);
6331
6392
  if (prov.trustLevel === "suspect") {
6332
- const value = cv("commands.temp-binary");
6333
- const v = applyCheckValue(
6334
- value === "review" && config.settings.mode === "strict" ? "block" : value,
6335
- {
6336
- decision: "review",
6337
- blockedByLabel: "Node9: Suspect Binary",
6338
- reason: `Binary "${firstToken}" resolved to ${prov.resolvedPath} \u2014 ${prov.reason}`,
6339
- tier: 3,
6340
- checkId: "commands.temp-binary"
6341
- }
6342
- );
6393
+ const v = applyCheckValue(cv("commands.temp-binary"), {
6394
+ decision: "review",
6395
+ blockedByLabel: "Node9: Suspect Binary",
6396
+ reason: `Binary "${firstToken}" resolved to ${prov.resolvedPath} \u2014 ${prov.reason}`,
6397
+ tier: 3,
6398
+ checkId: "commands.temp-binary"
6399
+ });
6343
6400
  if (v?.logged) noteLogged(v);
6344
6401
  else if (v) return v;
6345
6402
  }
6346
- if (prov.trustLevel === "unknown" && config.settings.mode === "strict") {
6403
+ if (prov.trustLevel === "unknown" && isBlockAll(config.settings.mode)) {
6347
6404
  return {
6348
6405
  decision: "review",
6349
6406
  blockedByLabel: "Node9: Unknown Binary (strict mode)",
@@ -6434,7 +6491,7 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
6434
6491
  if (v?.logged) noteLogged(v);
6435
6492
  else if (v) return v;
6436
6493
  }
6437
- if (config.settings.mode === "strict") {
6494
+ if (isBlockAll(config.settings.mode)) {
6438
6495
  if (activeEnvironment?.requireApproval === false) return allowed();
6439
6496
  return {
6440
6497
  decision: "review",
@@ -7365,7 +7422,7 @@ function matchCanaryArgs(args, values) {
7365
7422
  return null;
7366
7423
  }
7367
7424
  }
7368
- var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax2, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, MAX, UNTRUSTED_TOOLS, SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, syntax3, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS, MAX_NESTING, SHELL_VALUE_FLAGS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, syntax4, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS2, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
7425
+ var MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, AND_OP, OR_OP, AND_OR_OPS, MAX_CALL_DEPTH, MAX_CALL_WALKS, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, syntax2, MAX_ALTERNATIVES, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, WRITES, READS, DUP_OUT, HERE_STRING, AND, OR, DEFAULT_OPS, exempt, RANK, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, MAX, UNTRUSTED_TOOLS, SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, syntax3, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS, MAX_NESTING, SHELL_VALUE_FLAGS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, syntax4, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS2, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
7369
7426
  var init_dist = __esm({
7370
7427
  "packages/policy-engine/dist/index.mjs"() {
7371
7428
  "use strict";
@@ -8996,7 +9053,7 @@ var init_dist = __esm({
8996
9053
  "actions.money": {
8997
9054
  plain: "The agent moves money (a refund, a payout, a transfer, a charge) through an app node9 has no protection for, such as an internal billing server.",
8998
9055
  example: "refund_order on a server called acme-billing",
8999
- advice: "Keep Review. When the app is Stripe or PayPal, turn on its own protection instead: it covers the CLI, the API and scripts too, and a call from it no longer comes here."
9056
+ advice: "Standard records these and Strict asks. Set Review to be asked before every money move at any level. When the app is Stripe or PayPal, turn on its own protection instead: it covers the CLI, the API and scripts too, and a call from it no longer comes here."
9000
9057
  },
9001
9058
  "actions.access": {
9002
9059
  plain: "The agent changes a password, a key, a role or who belongs to a team, through an app node9 has no protection for.",
@@ -9173,6 +9230,54 @@ var init_dist = __esm({
9173
9230
  advice: "Keep Block for known-malicious packages; brand-new packages already stop for Review."
9174
9231
  }
9175
9232
  };
9233
+ LEVELS = ["audit", "soft", "standard", "strict", "block-all"];
9234
+ MODE_VALUES = ["observe", ...LEVELS];
9235
+ SOFT = {
9236
+ "commands.inline-exec": "log",
9237
+ "commands.eval-dynamic": "log",
9238
+ "commands.rm": "log",
9239
+ "commands.chmod": "log",
9240
+ "commands.sudo": "log",
9241
+ "commands.git-destructive": "log",
9242
+ "commands.sql-ddl": "log",
9243
+ "commands.sql-no-where": "log",
9244
+ "commands.temp-binary": "log",
9245
+ "commands.disk-destroy": "log",
9246
+ "commands.dangerous-word": "log",
9247
+ "files.system-dirs": "log",
9248
+ "files.shell-startup": "log",
9249
+ "files.password-hashes": "log",
9250
+ "data.pipe-chain": "log",
9251
+ "behavior.untrusted-content": "log"
9252
+ };
9253
+ STRICT = {
9254
+ "commands.sql-ddl": "block",
9255
+ "commands.disk-destroy": "block",
9256
+ "commands.node9-disarm": "block",
9257
+ "files.system-dirs": "block",
9258
+ "files.shell-startup": "block",
9259
+ "files.password-hashes": "block",
9260
+ "data.secrets-weak": "block",
9261
+ "data.pipe-chain": "block",
9262
+ "network.unknown-host": "review",
9263
+ "network.internal-addresses": "block",
9264
+ "behavior.prompt-injection": "log",
9265
+ "loading.skill-tamper": "block",
9266
+ // Standard records money moves (catalog default log); Strict asks.
9267
+ "actions.money": "review"
9268
+ };
9269
+ BLOCK_ALL = {
9270
+ ...STRICT,
9271
+ "commands.unknown": "review",
9272
+ "commands.temp-binary": "block"
9273
+ };
9274
+ LEVEL_CHECKS = {
9275
+ audit: {},
9276
+ soft: SOFT,
9277
+ standard: {},
9278
+ strict: STRICT,
9279
+ "block-all": BLOCK_ALL
9280
+ };
9176
9281
  VERDICTS = ["off", "log", "review", "block"];
9177
9282
  CHECK_VERDICT_RANK = { off: 0, log: 1, review: 2, block: 3 };
9178
9283
  ALL = VERDICTS;
@@ -9589,7 +9694,10 @@ var init_dist = __esm({
9589
9694
  title: "Money moves",
9590
9695
  catches: "a refund, payout, transfer, charge or withdrawal through an app with no protection of its own",
9591
9696
  values: ALL,
9592
- defaultValue: "review",
9697
+ // Founder decision 2026-10-25: a transfer the user asked for is ordinary
9698
+ // work. Standard records it; Strict asks (levels.ts); a user who wants to
9699
+ // be asked states review.
9700
+ defaultValue: "log",
9593
9701
  legacy: generalActionRuleNames("finance")
9594
9702
  },
9595
9703
  {
@@ -9629,7 +9737,7 @@ var init_dist = __esm({
9629
9737
  "commands.rm": (s) => knob(s.commandChecks?.rmAdvisory),
9630
9738
  "commands.chmod": (s) => knob(s.commandChecks?.chmod),
9631
9739
  "commands.sql-ddl": (s) => knob(s.commandChecks?.sqlDdl),
9632
- "commands.unknown": (s) => s.mode === void 0 ? void 0 : s.mode === "strict" ? "review" : "off",
9740
+ "commands.unknown": (s) => s.mode === void 0 ? void 0 : isBlockAll(s.mode) ? "review" : "off",
9633
9741
  "data.secrets": (s) => enabledOr(s.dlp?.enabled, "block"),
9634
9742
  "data.secrets-weak": (s) => {
9635
9743
  if (s.dlp?.enabled === false) return "off";
@@ -15258,7 +15366,8 @@ var SmartRuleSchema = z.object({
15258
15366
  var ConfigFileSchema = z.object({
15259
15367
  version: z.string().optional(),
15260
15368
  settings: z.object({
15261
- mode: z.enum(["standard", "strict", "audit", "observe"]).optional(),
15369
+ // The protection level (levels.ts in the engine); `observe` is Audit's older name.
15370
+ mode: z.enum(["observe", "audit", "soft", "standard", "strict", "block-all"]).optional(),
15262
15371
  autoStartDaemon: z.boolean().optional(),
15263
15372
  // enableUndo / policy.snapshot: removed with the undo feature. The
15264
15373
  // schema strips undeclared keys silently (plain zod object — no
@@ -15633,7 +15742,7 @@ function readShieldOverrides() {
15633
15742
  }
15634
15743
 
15635
15744
  // src/config/managed.ts
15636
- var MODE_ORDER = ["observe", "audit", "standard", "strict"];
15745
+ var MODE_ORDER = ["observe", "audit", "soft", "standard", "strict", "block-all"];
15637
15746
  var EGRESS_MODE_ORDER = ["off", "review", "block"];
15638
15747
  function rankIn(order, value) {
15639
15748
  return value === void 0 ? -1 : order.indexOf(value);
@@ -15896,7 +16005,7 @@ function v2ToLegacy(raw, options = {}) {
15896
16005
  continue;
15897
16006
  }
15898
16007
  if (id === "commands.unknown") {
15899
- warnings.push(`checks.${id}: set "mode": "strict" instead`);
16008
+ warnings.push(`checks.${id}: set "mode": "block-all" instead`);
15900
16009
  continue;
15901
16010
  }
15902
16011
  const allowed = configurableValues(id);
@@ -16217,7 +16326,8 @@ var DEFAULT_CONFIG = {
16217
16326
  // ── Actions in apps (node9Firewall#390) ───────────────────────────────
16218
16327
  // actions.money / actions.access / actions.publish: the action templates
16219
16328
  // on every MCP server no app shield claims, plus the shell publishing
16220
- // rules. Review by default; the check value governs them.
16329
+ // rules. Review on the rule; the check value governs them (money is
16330
+ // recorded at Standard, asked at Strict).
16221
16331
  ...GENERAL_ACTION_RULES
16222
16332
  ],
16223
16333
  dlp: { enabled: true, scanIgnoredTools: true, pii: "block" },
@@ -16435,6 +16545,11 @@ var KNOB_TO_CHECK = {
16435
16545
  evalDynamic: "commands.eval-dynamic",
16436
16546
  pipeChainHigh: "data.pipe-chain"
16437
16547
  };
16548
+ function statedSignalFields(policy) {
16549
+ return Object.keys(tuningFromLegacyPolicy(policy)["loading.malicious-package"] ?? {}).filter(
16550
+ (k) => k === "newPackage" || k === "installScript"
16551
+ );
16552
+ }
16438
16553
  function catalogSettingsFrom(settings, policy) {
16439
16554
  return catalogSettingsFromConfig(settings, policy);
16440
16555
  }
@@ -16502,6 +16617,8 @@ function getConfig(cwd) {
16502
16617
  const keyed = !!pr2Creds?.apiKey && pr2Creds.localOnly !== true;
16503
16618
  let ssrfStrictSource = "default";
16504
16619
  const workspaceChecks = {};
16620
+ const managedStatedChecks = /* @__PURE__ */ new Set();
16621
+ const managedStatedSignals = /* @__PURE__ */ new Set();
16505
16622
  const applyLayer = (source, isProject = false, isCloud = false) => {
16506
16623
  if (!source) return;
16507
16624
  const s = source.settings || {};
@@ -16709,9 +16826,11 @@ function getConfig(cwd) {
16709
16826
  if (raw.managedConfig && typeof raw.managedConfig === "object") {
16710
16827
  const mc = raw.managedConfig;
16711
16828
  const locked = Array.isArray(mc.locked) ? mc.locked.filter((f) => typeof f === "string") : [];
16829
+ for (const id of knobStatedChecks(mc)) managedStatedChecks.add(id);
16830
+ for (const k of statedSignalFields(mc)) managedStatedSignals.add(k);
16712
16831
  if (typeof mc.mode === "string") {
16713
16832
  if (keyed) {
16714
- if (["observe", "audit", "standard", "strict"].includes(mc.mode)) {
16833
+ if (isModeValue(mc.mode)) {
16715
16834
  mergedSettings.mode = mc.mode;
16716
16835
  }
16717
16836
  } else {
@@ -16993,14 +17112,15 @@ function getConfig(cwd) {
16993
17112
  const envMode = process.env.NODE9_MODE;
16994
17113
  if (envMode && !modeCloudControlled && // PR-2: one listening point includes the env var — a keyed machine's
16995
17114
  // mode comes from the workspace (or the shipped default), never the shell.
16996
- !keyed && ["observe", "audit", "standard", "strict"].includes(envMode)) {
17115
+ !keyed && isModeValue(envMode)) {
16997
17116
  mergedSettings.mode = envMode;
16998
17117
  }
16999
- if ((cloudManagedShields.length > 0 || cloudMandatesEnforcement) && !modeCloudControlled && !modeCloudStaged && (mergedSettings.mode === "observe" || mergedSettings.mode === "audit")) {
17118
+ if ((cloudManagedShields.length > 0 || cloudMandatesEnforcement) && !modeCloudControlled && !modeCloudStaged && isRecordOnly(mergedSettings.mode)) {
17000
17119
  mergedSettings.mode = "standard";
17001
17120
  }
17002
- const managedFloorActive = cloudManagedShields.length > 0 || cloudMandatesEnforcement || modeCloudControlled && mergedSettings.mode === "strict";
17003
- if (modeCloudControlled && mergedSettings.mode === "strict") {
17121
+ const cloudStrictLevel = levelOf(mergedSettings.mode) === "strict" || levelOf(mergedSettings.mode) === "block-all";
17122
+ const managedFloorActive = cloudManagedShields.length > 0 || cloudMandatesEnforcement || modeCloudControlled && cloudStrictLevel;
17123
+ if (modeCloudControlled && cloudStrictLevel) {
17004
17124
  for (const name of Object.keys(mergedEnvironments)) {
17005
17125
  if (mergedEnvironments[name]?.requireApproval === false) {
17006
17126
  const cleaned = { ...mergedEnvironments[name] };
@@ -17018,6 +17138,35 @@ function getConfig(cwd) {
17018
17138
  mergedPolicy.ignoredTools = [...new Set(mergedPolicy.ignoredTools)];
17019
17139
  mergedPolicy.skillPinning.roots = [...new Set(mergedPolicy.skillPinning.roots)];
17020
17140
  const resolvedSsrfStrictSource = keyed && ssrfStrictSource === "local" ? "default" : ssrfStrictSource;
17141
+ const level = levelOf(mergedSettings.mode);
17142
+ const levelKnobChecks = Object.entries(levelChecks(level)).filter(([id]) => isKnobGoverned(id));
17143
+ const signals = levelPackageSignals(level);
17144
+ if (levelKnobChecks.length > 0 || signals) {
17145
+ const policyOf = (layer) => layer?.policy ?? {};
17146
+ const trusted = /* @__PURE__ */ new Set([...managedStatedChecks, ...Object.keys(workspaceChecks)]);
17147
+ const trustedSignals = new Set(managedStatedSignals);
17148
+ const project = /* @__PURE__ */ new Set();
17149
+ const projectSignals = /* @__PURE__ */ new Set();
17150
+ if (!keyed) {
17151
+ for (const id of knobStatedChecks(policyOf(globalConfig))) trusted.add(id);
17152
+ for (const k of statedSignalFields(policyOf(globalConfig))) trustedSignals.add(k);
17153
+ for (const id of knobStatedChecks(policyOf(projectConfig))) project.add(id);
17154
+ for (const k of statedSignalFields(policyOf(projectConfig))) projectSignals.add(k);
17155
+ }
17156
+ const before = resolveCheckMap(catalogSettingsFromConfig({}, mergedPolicy));
17157
+ for (const [id, v] of levelKnobChecks) {
17158
+ if (trusted.has(id)) continue;
17159
+ if (project.has(id) && CHECK_VERDICT_RANK[v] <= CHECK_VERDICT_RANK[before[id] ?? "off"])
17160
+ continue;
17161
+ checkToLegacyPolicy(mergedPolicy, id, v);
17162
+ }
17163
+ if (signals) {
17164
+ for (const key of ["newPackage", "installScript"]) {
17165
+ if (trustedSignals.has(key) || projectSignals.has(key)) continue;
17166
+ mergedPolicy.packageCheck[key] = signals[key];
17167
+ }
17168
+ }
17169
+ }
17021
17170
  const explicit = {};
17022
17171
  const checkSources = {};
17023
17172
  if (keyed) {
@@ -17189,6 +17338,9 @@ function applyUntrustedContent(cur, raw, replaceLists = false, isProject = false
17189
17338
  // src/utils/regex.ts
17190
17339
  init_dist();
17191
17340
 
17341
+ // src/policy/index.ts
17342
+ init_dist();
17343
+
17192
17344
  // src/dlp.ts
17193
17345
  init_dist();
17194
17346
  init_dist();
@@ -20117,11 +20269,11 @@ async function checkOne(p, cfg, misses, networkCapped, cwd) {
20117
20269
  }
20118
20270
  return findings;
20119
20271
  }
20120
- var SOFT = /* @__PURE__ */ new Set(["new", "install-script"]);
20272
+ var SOFT2 = /* @__PURE__ */ new Set(["new", "install-script"]);
20121
20273
  async function byHistory(p, version, info, findings, misses) {
20122
20274
  let out = findings;
20123
20275
  let h = info.history;
20124
- if (!h && p.ecosystem === "PyPI" && out.some((f) => SOFT.has(f.kind))) {
20276
+ if (!h && p.ecosystem === "PyPI" && out.some((f) => SOFT2.has(f.kind))) {
20125
20277
  try {
20126
20278
  h = await pypiHistory(p.name, version) ?? void 0;
20127
20279
  } catch (err) {
@@ -20141,7 +20293,7 @@ async function byHistory(p, version, info, findings, misses) {
20141
20293
  });
20142
20294
  if (p.ecosystem === "npm") {
20143
20295
  if (h.previousProvenance && h.provenance === false) return [...out, drop()];
20144
- if (!out.some((f) => SOFT.has(f.kind)) || !h.provenance || !h.previousProvenance) return out;
20296
+ if (!out.some((f) => SOFT2.has(f.kind)) || !h.provenance || !h.previousProvenance) return out;
20145
20297
  const [now, before] = await Promise.all([
20146
20298
  npmSourceRepo(p.name, version),
20147
20299
  npmSourceRepo(p.name, previous)
@@ -20149,7 +20301,7 @@ async function byHistory(p, version, info, findings, misses) {
20149
20301
  return vouched(p, version, now, before, out, misses);
20150
20302
  }
20151
20303
  if (p.ecosystem === "PyPI") {
20152
- if (!out.some((f) => SOFT.has(f.kind)) || !info.file || !h.previousFile) return out;
20304
+ if (!out.some((f) => SOFT2.has(f.kind)) || !info.file || !h.previousFile) return out;
20153
20305
  const [now, before] = await Promise.all([
20154
20306
  pypiSourceRepo(p.name, version, info.file),
20155
20307
  pypiSourceRepo(p.name, previous, h.previousFile)
@@ -20165,7 +20317,7 @@ function vouched(p, version, now, before, findings, misses) {
20165
20317
  return findings;
20166
20318
  }
20167
20319
  if (now === "none" || before === "none" || now !== before) return findings;
20168
- return findings.filter((f) => !SOFT.has(f.kind));
20320
+ return findings.filter((f) => !SOFT2.has(f.kind));
20169
20321
  }
20170
20322
  async function runPackageCheck(toolName, args, cfg, cwd) {
20171
20323
  if (!cfg.enabled) return ALLOW;
@@ -20485,7 +20637,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
20485
20637
  appendHookDebug(toolName, args, meta, hashAuditArgs);
20486
20638
  }
20487
20639
  const isManual = meta?.agent === "Terminal";
20488
- const isObserveMode = config.settings.mode === "observe";
20640
+ const isObserveMode = isRecordOnly(config.settings.mode);
20489
20641
  let explainableLabel = "Local Config";
20490
20642
  let dlpReviewFlagged = false;
20491
20643
  let packageReview = null;
@@ -20543,7 +20695,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
20543
20695
  explainableLabel = "Shell inspection incomplete";
20544
20696
  policyRuleDescription = "The executable command could not be inspected. Approve this call explicitly.";
20545
20697
  }
20546
- const fileReview = !isObserveMode && config.settings.mode !== "audit" && fileFinding?.decision === "review";
20698
+ const fileReview = !isObserveMode && fileFinding?.decision === "review";
20547
20699
  const evaluateCurrentPolicy = async (skipIgnoredFastPath = false) => {
20548
20700
  const own = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd, {
20549
20701
  fileAccess,
@@ -20570,7 +20722,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
20570
20722
  if (fileFinding) {
20571
20723
  meta = { ...meta, ruleName: fileFinding.ruleName };
20572
20724
  hashAuditArgs = true;
20573
- const observing = isObserveMode || config.settings.mode === "audit";
20725
+ const observing = isObserveMode;
20574
20726
  const blocked = !observing && (fileFinding.decision === "block" || fileReview && config.settings.panicMode);
20575
20727
  appendLocalAudit(
20576
20728
  toolName,
@@ -21052,15 +21204,6 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
21052
21204
  }
21053
21205
  return { approved: true, checkedBy: "audit" };
21054
21206
  }
21055
- if (config.settings.mode === "audit") {
21056
- if (judge) {
21057
- const policyResult = await evaluateCurrentPolicy();
21058
- if (policyResult.decision === "review") {
21059
- appendLocalAudit(toolName, args, "allow", "audit-mode", ownRowMeta(true), hashAuditArgs);
21060
- }
21061
- }
21062
- return { approved: true, checkedBy: "audit" };
21063
- }
21064
21207
  let appPermReview = null;
21065
21208
  let appPermReviewTool = null;
21066
21209
  const callSpecificReview = () => fileReview || shellReview || dlpReviewFlagged || !!appPermReview || !!taintWarning || !!exposureReview || !!packageReview;
package/dist/scan-ink.mjs CHANGED
@@ -102,7 +102,8 @@ var SmartRuleSchema = z.object({
102
102
  var ConfigFileSchema = z.object({
103
103
  version: z.string().optional(),
104
104
  settings: z.object({
105
- mode: z.enum(["standard", "strict", "audit", "observe"]).optional(),
105
+ // The protection level (levels.ts in the engine); `observe` is Audit's older name.
106
+ mode: z.enum(["observe", "audit", "soft", "standard", "strict", "block-all"]).optional(),
106
107
  autoStartDaemon: z.boolean().optional(),
107
108
  // enableUndo / policy.snapshot: removed with the undo feature. The
108
109
  // schema strips undeclared keys silently (plain zod object — no
@@ -1944,7 +1945,7 @@ var CHECK_TEXT = {
1944
1945
  "actions.money": {
1945
1946
  plain: "The agent moves money (a refund, a payout, a transfer, a charge) through an app node9 has no protection for, such as an internal billing server.",
1946
1947
  example: "refund_order on a server called acme-billing",
1947
- advice: "Keep Review. When the app is Stripe or PayPal, turn on its own protection instead: it covers the CLI, the API and scripts too, and a call from it no longer comes here."
1948
+ advice: "Standard records these and Strict asks. Set Review to be asked before every money move at any level. When the app is Stripe or PayPal, turn on its own protection instead: it covers the CLI, the API and scripts too, and a call from it no longer comes here."
1948
1949
  },
1949
1950
  "actions.access": {
1950
1951
  plain: "The agent changes a password, a key, a role or who belongs to a team, through an app node9 has no protection for.",
@@ -2121,6 +2122,29 @@ var CHECK_TEXT = {
2121
2122
  advice: "Keep Block for known-malicious packages; brand-new packages already stop for Review."
2122
2123
  }
2123
2124
  };
2125
+ var LEVELS = ["audit", "soft", "standard", "strict", "block-all"];
2126
+ var MODE_VALUES = ["observe", ...LEVELS];
2127
+ var STRICT = {
2128
+ "commands.sql-ddl": "block",
2129
+ "commands.disk-destroy": "block",
2130
+ "commands.node9-disarm": "block",
2131
+ "files.system-dirs": "block",
2132
+ "files.shell-startup": "block",
2133
+ "files.password-hashes": "block",
2134
+ "data.secrets-weak": "block",
2135
+ "data.pipe-chain": "block",
2136
+ "network.unknown-host": "review",
2137
+ "network.internal-addresses": "block",
2138
+ "behavior.prompt-injection": "log",
2139
+ "loading.skill-tamper": "block",
2140
+ // Standard records money moves (catalog default log); Strict asks.
2141
+ "actions.money": "review"
2142
+ };
2143
+ var BLOCK_ALL = {
2144
+ ...STRICT,
2145
+ "commands.unknown": "review",
2146
+ "commands.temp-binary": "block"
2147
+ };
2124
2148
  var VERDICTS = ["off", "log", "review", "block"];
2125
2149
  var ALL = VERDICTS;
2126
2150
  var BUILTIN_DANGEROUS_WORDS = ["mkfs", "shred"];
@@ -2536,7 +2560,10 @@ var PRODUCT_CHECKS = [
2536
2560
  title: "Money moves",
2537
2561
  catches: "a refund, payout, transfer, charge or withdrawal through an app with no protection of its own",
2538
2562
  values: ALL,
2539
- defaultValue: "review",
2563
+ // Founder decision 2026-10-25: a transfer the user asked for is ordinary
2564
+ // work. Standard records it; Strict asks (levels.ts); a user who wants to
2565
+ // be asked states review.
2566
+ defaultValue: "log",
2540
2567
  legacy: generalActionRuleNames("finance")
2541
2568
  },
2542
2569
  {
@@ -6917,7 +6944,8 @@ var DEFAULT_CONFIG = {
6917
6944
  // ── Actions in apps (node9Firewall#390) ───────────────────────────────
6918
6945
  // actions.money / actions.access / actions.publish: the action templates
6919
6946
  // on every MCP server no app shield claims, plus the shell publishing
6920
- // rules. Review by default; the check value governs them.
6947
+ // rules. Review on the rule; the check value governs them (money is
6948
+ // recorded at Standard, asked at Strict).
6921
6949
  ...GENERAL_ACTION_RULES
6922
6950
  ],
6923
6951
  dlp: { enabled: true, scanIgnoredTools: true, pii: "block" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "2.38.0",
3
+ "version": "2.40.0",
4
4
  "description": "Access control for AI agents. Set what Claude Code, Codex, Gemini, Cursor and any MCP server are allowed to do, review risky actions before they run, and keep every action on the record.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",