tamperward 2.29.6 → 2.29.8

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +143 -44
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -3478,7 +3478,7 @@ function skipRegexLiteral(line, start) {
3478
3478
  }
3479
3479
  return line.length - 1;
3480
3480
  }
3481
- var CODE, EXT, COMMON, IMPORTS, HASH_COMMENT, DEBUG_ONLY, SLASH_COMMENT, HASH_COMMENT_LANGS, REGEX_KEYWORDS;
3481
+ var CODE, EXT, COMMON, IMPORTS, HASH_COMMENT, DEBUG_ONLY, SLASH_COMMENT, HASH_COMMENT_LANGS, CommentStringMasker, REGEX_KEYWORDS;
3482
3482
  var init_files = __esm({
3483
3483
  "src/detectors/files.ts"() {
3484
3484
  "use strict";
@@ -3510,6 +3510,90 @@ var init_files = __esm({
3510
3510
  DEBUG_ONLY = /^(?:console\.\w+\(.*\)\s*;?|debugger\s*;?)$/;
3511
3511
  SLASH_COMMENT = /^(?:\/\/|\/\*|\*(?:\s|\/|$))/;
3512
3512
  HASH_COMMENT_LANGS = /* @__PURE__ */ new Set(["py", "rb", "php"]);
3513
+ CommentStringMasker = class {
3514
+ constructor(maskStrings = true) {
3515
+ this.maskStrings = maskStrings;
3516
+ }
3517
+ maskStrings;
3518
+ stack = [];
3519
+ mask(line) {
3520
+ const out3 = line.split("");
3521
+ for (const f of this.stack) if (f.kind === "string" || f.kind === "template") f.carried = true;
3522
+ let i = 0;
3523
+ while (i < line.length) {
3524
+ const top = this.stack[this.stack.length - 1];
3525
+ const ch = line[i];
3526
+ const next = line[i + 1];
3527
+ if (top?.kind === "block") {
3528
+ out3[i] = " ";
3529
+ if (ch === "*" && next === "/") {
3530
+ out3[i + 1] = " ";
3531
+ this.stack.pop();
3532
+ i += 2;
3533
+ continue;
3534
+ }
3535
+ i++;
3536
+ continue;
3537
+ }
3538
+ if (top?.kind === "string" || top?.kind === "template") {
3539
+ const blank = this.maskStrings || top.carried;
3540
+ if (ch === "\\") {
3541
+ if (blank) {
3542
+ out3[i] = " ";
3543
+ if (i + 1 < line.length) out3[i + 1] = " ";
3544
+ }
3545
+ i += 2;
3546
+ continue;
3547
+ }
3548
+ if (top.kind === "string" ? ch === top.quote : ch === "`") {
3549
+ this.stack.pop();
3550
+ i++;
3551
+ continue;
3552
+ }
3553
+ if (top.kind === "template" && ch === "$" && next === "{") {
3554
+ this.stack.push({ kind: "subst", depth: 1 });
3555
+ i += 2;
3556
+ continue;
3557
+ }
3558
+ if (blank) out3[i] = " ";
3559
+ i++;
3560
+ continue;
3561
+ }
3562
+ if (ch === "/" && next === "/") {
3563
+ for (let j = i; j < line.length; j++) out3[j] = " ";
3564
+ i = line.length;
3565
+ continue;
3566
+ }
3567
+ if (ch === "/" && next === "*") {
3568
+ out3[i] = " ";
3569
+ out3[i + 1] = " ";
3570
+ this.stack.push({ kind: "block" });
3571
+ i += 2;
3572
+ continue;
3573
+ }
3574
+ if (ch === "`") {
3575
+ this.stack.push({ kind: "template", carried: false });
3576
+ i++;
3577
+ continue;
3578
+ }
3579
+ if (ch === '"' || ch === "'") {
3580
+ this.stack.push({ kind: "string", quote: ch, carried: false });
3581
+ i++;
3582
+ continue;
3583
+ }
3584
+ if (ch === "/" && regexPosition(line.slice(0, i))) {
3585
+ i = skipRegexLiteral(line, i) + 1;
3586
+ continue;
3587
+ }
3588
+ if (top?.kind === "subst") {
3589
+ if (ch === "{") top.depth++;
3590
+ else if (ch === "}" && --top.depth === 0) this.stack.pop();
3591
+ }
3592
+ i++;
3593
+ }
3594
+ return out3.join("");
3595
+ }
3596
+ };
3513
3597
  REGEX_KEYWORDS = /* @__PURE__ */ new Set([
3514
3598
  "return",
3515
3599
  "throw",
@@ -3885,29 +3969,35 @@ var init_ts_any_cast = __esm({
3885
3969
  }
3886
3970
  const jsdocCast = JS_FILE.test(c.path) ? new RegExp(JSDOC_ANY_CAST.source) : null;
3887
3971
  const aliasMap = aliasMapForAddedLines(c);
3888
- for (const l of addedLines(c)) {
3889
- if (NARROW_LINE.test(l.content) || lineHasRow4Cast(l.content, aliasMap) || lineHasLiveDirective(l.content) || jsdocCast && jsdocCast.test(l.content)) {
3890
- out3.push(
3891
- makeFinding(inTest ? WARN_RULE : BLOCK_RULE, policy, {
3892
- file: c.path,
3893
- line: l.newLine ?? void 0,
3894
- message: inTest ? "Type-checker escape in a test file (test infrastructure \u2014 flagged, not blocked)." : "Type safety discarded: an explicit cast/suppression was added.",
3895
- evidence: l.content.trim(),
3896
- remediation: inTest ? WARN_REMEDIATION : BLOCK_REMEDIATION,
3897
- defaultSeverity: inTest ? "warn" : "block"
3898
- })
3899
- );
3900
- } else if (BROAD_LINE.test(l.content)) {
3901
- out3.push(
3902
- makeFinding(WARN_RULE, policy, {
3903
- file: c.path,
3904
- line: l.newLine ?? void 0,
3905
- message: "Type laundered to `any` in a type/generic position.",
3906
- evidence: l.content.trim(),
3907
- remediation: WARN_REMEDIATION,
3908
- defaultSeverity: "warn"
3909
- })
3910
- );
3972
+ for (const h of c.hunks) {
3973
+ const masker = new CommentStringMasker();
3974
+ for (const l of h.lines) {
3975
+ if (l.type === "del") continue;
3976
+ const code2 = masker.mask(l.content);
3977
+ if (l.type !== "add") continue;
3978
+ if (NARROW_LINE.test(code2) || lineHasRow4Cast(code2, aliasMap) || lineHasLiveDirective(l.content) || jsdocCast && jsdocCast.test(l.content)) {
3979
+ out3.push(
3980
+ makeFinding(inTest ? WARN_RULE : BLOCK_RULE, policy, {
3981
+ file: c.path,
3982
+ line: l.newLine ?? void 0,
3983
+ message: inTest ? "Type-checker escape in a test file (test infrastructure \u2014 flagged, not blocked)." : "Type safety discarded: an explicit cast/suppression was added.",
3984
+ evidence: l.content.trim(),
3985
+ remediation: inTest ? WARN_REMEDIATION : BLOCK_REMEDIATION,
3986
+ defaultSeverity: inTest ? "warn" : "block"
3987
+ })
3988
+ );
3989
+ } else if (BROAD_LINE.test(code2)) {
3990
+ out3.push(
3991
+ makeFinding(WARN_RULE, policy, {
3992
+ file: c.path,
3993
+ line: l.newLine ?? void 0,
3994
+ message: "Type laundered to `any` in a type/generic position.",
3995
+ evidence: l.content.trim(),
3996
+ remediation: WARN_REMEDIATION,
3997
+ defaultSeverity: "warn"
3998
+ })
3999
+ );
4000
+ }
3911
4001
  }
3912
4002
  }
3913
4003
  }
@@ -4940,23 +5030,30 @@ var init_test_skip = __esm({
4940
5030
  );
4941
5031
  }
4942
5032
  }
4943
- for (const l of addedLines(c)) {
4944
- if (l.newLine != null && astHitLines.has(l.newLine)) continue;
4945
- const comment = isCommentLine(l.content.trim(), lang);
4946
- for (const p of patterns) {
4947
- if (astAuthoritative && p.astOwned && !(l.newLine != null && unowned.has(l.newLine))) continue;
4948
- if (comment && !p.comment) continue;
4949
- if (matchesOutsideString(p, l.content, lang)) {
4950
- out3.push(
4951
- makeFinding(RULE4, policy, {
4952
- file: c.path,
4953
- line: l.newLine ?? void 0,
4954
- message: `Test skipped or narrowed: ${p.why}.`,
4955
- evidence: l.content.trim(),
4956
- remediation: "Make the test pass rather than skipping it. If it is genuinely obsolete, a human must sign off."
4957
- })
4958
- );
4959
- break;
5033
+ const maskJs = lang === "js" || lang == null;
5034
+ for (const h of c.hunks) {
5035
+ const masker = maskJs ? new CommentStringMasker(false) : null;
5036
+ for (const l of h.lines) {
5037
+ if (l.type === "del") continue;
5038
+ const code2 = masker ? masker.mask(l.content) : l.content;
5039
+ if (l.type !== "add") continue;
5040
+ if (l.newLine != null && astHitLines.has(l.newLine)) continue;
5041
+ const comment = isCommentLine(code2.trim(), lang);
5042
+ for (const p of patterns) {
5043
+ if (astAuthoritative && p.astOwned && !(l.newLine != null && unowned.has(l.newLine))) continue;
5044
+ if (comment && !p.comment) continue;
5045
+ if (matchesOutsideString(p, p.comment ? l.content : code2, lang)) {
5046
+ out3.push(
5047
+ makeFinding(RULE4, policy, {
5048
+ file: c.path,
5049
+ line: l.newLine ?? void 0,
5050
+ message: `Test skipped or narrowed: ${p.why}.`,
5051
+ evidence: l.content.trim(),
5052
+ remediation: "Make the test pass rather than skipping it. If it is genuinely obsolete, a human must sign off."
5053
+ })
5054
+ );
5055
+ break;
5056
+ }
4960
5057
  }
4961
5058
  }
4962
5059
  }
@@ -9914,7 +10011,7 @@ function namesProtectedSnapshot(seg, policy) {
9914
10011
  }
9915
10012
  return null;
9916
10013
  }
9917
- var RULE12, RUNNER3, PM_TEST_SCRIPT, UPDATE_ANY, UPDATE_WITH_RUNNER, INSTA_ACCEPT, UPDATE_EXPECT, REGEN_SCRIPT, MUTATE, snapshotRewrite;
10014
+ var RULE12, RUNNER3, PM_TEST_SCRIPT, UPDATE_ANY, UPDATE_WITH_RUNNER, INSTA_ACCEPT, UPDATE_EXPECT, TAP_SNAPSHOT, REGEN_SCRIPT, MUTATE, snapshotRewrite;
9918
10015
  var init_snapshot_rewrite = __esm({
9919
10016
  "src/detectors/snapshot-rewrite.ts"() {
9920
10017
  "use strict";
@@ -9922,12 +10019,13 @@ var init_snapshot_rewrite = __esm({
9922
10019
  init_finding();
9923
10020
  init_command();
9924
10021
  RULE12 = "snapshot-rewrite";
9925
- RUNNER3 = /\b(?:jest|vitest|playwright|ava)\b/;
10022
+ RUNNER3 = /\b(?:jest|vitest|playwright|ava|tap)\b/;
9926
10023
  PM_TEST_SCRIPT = /(?:^|\s)(?:npm|pnpm|yarn|bun)\s+(?:t|tst|test|run(?:-script)?\s+\S*test\S*)(?:\s|$)/;
9927
10024
  UPDATE_ANY = /--(?:update-?[sS]napshots?|test-update-snapshots|snapshot-update)\b/;
9928
- UPDATE_WITH_RUNNER = /(?:^|\s)(?:-u|--update)(?:\s|$)/;
10025
+ UPDATE_WITH_RUNNER = /(?:^|\s)(?:-u|--update|--snapshot)(?:=(?:1|true))?(?:\s|$)/;
9929
10026
  INSTA_ACCEPT = /\bcargo\s+insta\s+(?:accept\b|.*\s--accept\b)/;
9930
10027
  UPDATE_EXPECT = /(?:^|\s)UPDATE_EXPECT=\S+/;
10028
+ TAP_SNAPSHOT = /(?:^|\s)TAP_SNAPSHOT=1(?:\s|$)/;
9931
10029
  REGEN_SCRIPT = /\b(?:update|regen(?:erate)?|re?bless)[-_.]?(?:golden|snapshots?|baselines?|expected)\b/i;
9932
10030
  MUTATE = /(?:^|\s)(?:rm|cp|mv|tee|truncate|dd)(?:\s|$)|sed\s+-i|>{1,2}|\bfind\b.*\s-(?:delete\b|exec\s+rm\b)|\bgit\s+(?:checkout|restore)\b/;
9933
10031
  snapshotRewrite = {
@@ -9945,6 +10043,7 @@ var init_snapshot_rewrite = __esm({
9945
10043
  else if ((RUNNER3.test(seg) || PM_TEST_SCRIPT.test(seg)) && UPDATE_WITH_RUNNER.test(seg)) why = "running the test runner in update mode rewrites failing snapshots to match current output";
9946
10044
  else if (INSTA_ACCEPT.test(seg)) why = "cargo insta accept rewrites every pending snapshot to match current output";
9947
10045
  else if (UPDATE_EXPECT.test(seg)) why = "UPDATE_EXPECT=1 rewrites every expect-test expectation to match current output";
10046
+ else if (TAP_SNAPSHOT.test(seg)) why = "TAP_SNAPSHOT=1 rewrites every node-tap snapshot to match current output";
9948
10047
  else if (REGEN_SCRIPT.test(seg)) why = "a regeneration script rewrites the recorded expected output from current output";
9949
10048
  else {
9950
10049
  const path = MUTATE.test(seg) ? namesProtectedSnapshot(seg, policy) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.29.6",
3
+ "version": "2.29.8",
4
4
  "description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "hexrift",