tamperward 2.24.2 → 2.24.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/cli/index.js +109 -13
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -3713,6 +3713,83 @@ var init_lint_suppression = __esm({
|
|
|
3713
3713
|
}
|
|
3714
3714
|
});
|
|
3715
3715
|
|
|
3716
|
+
// src/detectors/runner-chain.ts
|
|
3717
|
+
function readRunnerChain(root, props) {
|
|
3718
|
+
let runner = root;
|
|
3719
|
+
const modifiers = [];
|
|
3720
|
+
let table = null;
|
|
3721
|
+
let skipMarker = null;
|
|
3722
|
+
let skipIndex = -1;
|
|
3723
|
+
for (let i = 0; i < props.length; i++) {
|
|
3724
|
+
const p = props[i];
|
|
3725
|
+
if (table) return null;
|
|
3726
|
+
if (RUNNER_NAMES.has(p) && modifiers.length === 0) {
|
|
3727
|
+
runner = p;
|
|
3728
|
+
continue;
|
|
3729
|
+
}
|
|
3730
|
+
if (CHAIN_MODIFIERS.has(p)) {
|
|
3731
|
+
modifiers.push(p);
|
|
3732
|
+
const marker = skipMarkerOf(p);
|
|
3733
|
+
if (marker && !skipMarker) {
|
|
3734
|
+
skipMarker = marker;
|
|
3735
|
+
skipIndex = i;
|
|
3736
|
+
}
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
const t = tableOf(p);
|
|
3740
|
+
if (t) {
|
|
3741
|
+
table = t;
|
|
3742
|
+
continue;
|
|
3743
|
+
}
|
|
3744
|
+
return null;
|
|
3745
|
+
}
|
|
3746
|
+
return { runner, modifiers, table, skipMarker, skipIndex };
|
|
3747
|
+
}
|
|
3748
|
+
function readCallee(expr) {
|
|
3749
|
+
const props = [];
|
|
3750
|
+
let cur = expr;
|
|
3751
|
+
while (ts.isPropertyAccessExpression(cur) || ts.isElementAccessExpression(cur)) {
|
|
3752
|
+
if (ts.isPropertyAccessExpression(cur)) {
|
|
3753
|
+
props.unshift(cur.name.text);
|
|
3754
|
+
} else {
|
|
3755
|
+
const arg = cur.argumentExpression;
|
|
3756
|
+
if (!ts.isStringLiteralLike(arg)) return null;
|
|
3757
|
+
props.unshift(arg.text);
|
|
3758
|
+
}
|
|
3759
|
+
cur = cur.expression;
|
|
3760
|
+
}
|
|
3761
|
+
if (!ts.isIdentifier(cur)) return null;
|
|
3762
|
+
return readRunnerChain(cur.text, props);
|
|
3763
|
+
}
|
|
3764
|
+
function readTableCallee(expr) {
|
|
3765
|
+
const head = ts.isCallExpression(expr) ? expr.expression : ts.isTaggedTemplateExpression(expr) ? expr.tag : null;
|
|
3766
|
+
if (!head) return null;
|
|
3767
|
+
const chain = readCallee(head);
|
|
3768
|
+
return chain?.table ? chain : null;
|
|
3769
|
+
}
|
|
3770
|
+
var RUNNER_NAMES, CHAIN_MODIFIERS, skipMarkerOf, tableOf;
|
|
3771
|
+
var init_runner_chain = __esm({
|
|
3772
|
+
"src/detectors/runner-chain.ts"() {
|
|
3773
|
+
"use strict";
|
|
3774
|
+
init_ts_lazy();
|
|
3775
|
+
RUNNER_NAMES = /* @__PURE__ */ new Set(["it", "test", "describe", "suite"]);
|
|
3776
|
+
CHAIN_MODIFIERS = /* @__PURE__ */ new Set([
|
|
3777
|
+
"concurrent",
|
|
3778
|
+
"sequential",
|
|
3779
|
+
"shuffle",
|
|
3780
|
+
"serial",
|
|
3781
|
+
"parallel",
|
|
3782
|
+
"skip",
|
|
3783
|
+
"only",
|
|
3784
|
+
"todo",
|
|
3785
|
+
"fails",
|
|
3786
|
+
"failing"
|
|
3787
|
+
]);
|
|
3788
|
+
skipMarkerOf = (name) => name === "skip" || name === "only" || name === "todo" ? name : null;
|
|
3789
|
+
tableOf = (name) => name === "each" || name === "for" ? name : null;
|
|
3790
|
+
}
|
|
3791
|
+
});
|
|
3792
|
+
|
|
3716
3793
|
// src/detectors/test-skip.ts
|
|
3717
3794
|
import { posix as posix2 } from "node:path";
|
|
3718
3795
|
function pyMarkAliases(source) {
|
|
@@ -3886,12 +3963,14 @@ function staticPropertyName(expr, ctx, strings) {
|
|
|
3886
3963
|
}
|
|
3887
3964
|
function runnerChain(expr, ctx, binder, strings) {
|
|
3888
3965
|
const props = [];
|
|
3966
|
+
const propNodes = [];
|
|
3889
3967
|
const causes = [];
|
|
3890
3968
|
let cur = expr;
|
|
3891
3969
|
let terminalNode = expr;
|
|
3892
3970
|
while (ts.isPropertyAccessExpression(cur) || ts.isElementAccessExpression(cur)) {
|
|
3893
3971
|
if (ts.isPropertyAccessExpression(cur)) {
|
|
3894
3972
|
props.unshift(cur.name.text);
|
|
3973
|
+
propNodes.unshift(cur.name);
|
|
3895
3974
|
if (props.length === 1) terminalNode = cur.name;
|
|
3896
3975
|
cur = cur.expression;
|
|
3897
3976
|
continue;
|
|
@@ -3900,6 +3979,7 @@ function runnerChain(expr, ctx, binder, strings) {
|
|
|
3900
3979
|
const property = staticPropertyName(cur.argumentExpression, ctx, strings);
|
|
3901
3980
|
if (!property) return null;
|
|
3902
3981
|
props.unshift(property.name);
|
|
3982
|
+
propNodes.unshift(cur.argumentExpression);
|
|
3903
3983
|
causes.push(...property.causes);
|
|
3904
3984
|
if (props.length === 1) terminalNode = cur.argumentExpression;
|
|
3905
3985
|
cur = cur.expression;
|
|
@@ -3916,17 +3996,21 @@ function runnerChain(expr, ctx, binder, strings) {
|
|
|
3916
3996
|
}
|
|
3917
3997
|
} else {
|
|
3918
3998
|
namespace = requiredModule(cur);
|
|
3999
|
+
if (namespace == null && readTableCallee(cur)) return null;
|
|
3919
4000
|
verdict2 = namespace == null ? UNKNOWN : NON_RUNNER;
|
|
3920
4001
|
}
|
|
3921
4002
|
let root = ts.isIdentifier(cur) ? cur.text : "";
|
|
3922
4003
|
if (namespace != null && props.length > 0) {
|
|
3923
4004
|
verdict2 = withCause(binder.memberOf(namespace, props[0]), cur);
|
|
3924
|
-
if (verdict2.kind === "runner")
|
|
4005
|
+
if (verdict2.kind === "runner") {
|
|
4006
|
+
root = props.shift() ?? root;
|
|
4007
|
+
propNodes.shift();
|
|
4008
|
+
}
|
|
3925
4009
|
}
|
|
3926
4010
|
if (verdict2.kind === "unknown") return "unknown";
|
|
3927
4011
|
if (verdict2.kind === "non-runner") return null;
|
|
3928
4012
|
causes.push(...verdict2.causes);
|
|
3929
|
-
return { root, props, terminalNode, causes };
|
|
4013
|
+
return { root, props, propNodes, terminalNode, causes };
|
|
3930
4014
|
}
|
|
3931
4015
|
function optionDisables(value) {
|
|
3932
4016
|
return !(value.kind === ts.SyntaxKind.FalseKeyword || ts.isNumericLiteral(value) && Number(value.text) === 0);
|
|
@@ -3965,8 +4049,9 @@ function semanticSkipHits(ctx, binder) {
|
|
|
3965
4049
|
const last = lineOf(callee.getEnd());
|
|
3966
4050
|
for (let line = first; line <= last; line++) unowned.add(line);
|
|
3967
4051
|
} else if (chain) {
|
|
3968
|
-
const { props, terminalNode, causes } = chain;
|
|
4052
|
+
const { root, props, propNodes, terminalNode, causes } = chain;
|
|
3969
4053
|
const terminal = props.at(-1);
|
|
4054
|
+
const shape = readRunnerChain(root, props);
|
|
3970
4055
|
const push = (target, extraCauses, why) => {
|
|
3971
4056
|
hits.push({
|
|
3972
4057
|
semanticKey: `${callKey}\0${why}`,
|
|
@@ -3976,13 +4061,13 @@ function semanticSkipHits(ctx, binder) {
|
|
|
3976
4061
|
evidence: callText
|
|
3977
4062
|
});
|
|
3978
4063
|
};
|
|
3979
|
-
if (
|
|
3980
|
-
push(terminalNode, [], "a .skip/.only/.todo marker");
|
|
4064
|
+
if (shape?.skipMarker) {
|
|
4065
|
+
push(propNodes[shape.skipIndex] ?? terminalNode, [], "a .skip/.only/.todo marker");
|
|
3981
4066
|
} else if (terminal && ["skipIf", "runIf"].includes(terminal) && props.length === 1) {
|
|
3982
4067
|
push(terminalNode, [], "a .skipIf()/.runIf() condition (the test runs only when the condition allows)");
|
|
3983
4068
|
} else if (terminal && ["fails", "failing"].includes(terminal) && props.length === 1) {
|
|
3984
4069
|
push(terminalNode, [], "a .fails/.failing marker (the test now passes by failing)");
|
|
3985
|
-
} else if (
|
|
4070
|
+
} else if (shape?.table === "each" && node.arguments.length > 0 && ts.isArrayLiteralExpression(node.arguments[0]) && node.arguments[0].elements.length === 0) {
|
|
3986
4071
|
push(terminalNode, [], "an empty .each table (no case ever runs)");
|
|
3987
4072
|
}
|
|
3988
4073
|
if (props.length === 0) {
|
|
@@ -4062,11 +4147,12 @@ function astSkipHits(c, resolvers) {
|
|
|
4062
4147
|
}
|
|
4063
4148
|
return { hits, authoritative: true, unowned: analysis.unowned };
|
|
4064
4149
|
}
|
|
4065
|
-
var RULE4, acc, JS_RUNNER, JS_MOD, GO_SKIP_PATTERNS, PY_MARK, PY_CONFTEST_PATTERNS, PY_MARK_ALIAS, PY_DECORATOR, PATTERNS2, JS_RUNNERS,
|
|
4150
|
+
var RULE4, acc, JS_RUNNER, JS_MOD, GO_SKIP_PATTERNS, PY_MARK, PY_CONFTEST_PATTERNS, PY_MARK_ALIAS, PY_DECORATOR, PATTERNS2, JS_RUNNERS, JS_DEFAULT_RUNNER_MODULES, JS_TEST_MODULES, RUNNER2, NON_RUNNER, UNKNOWN, withCause, MODULE_EXTENSIONS, RunnerResolver, ModuleBinder, NO_AST, testSkip;
|
|
4066
4151
|
var init_test_skip = __esm({
|
|
4067
4152
|
"src/detectors/test-skip.ts"() {
|
|
4068
4153
|
"use strict";
|
|
4069
4154
|
init_ts_lazy();
|
|
4155
|
+
init_runner_chain();
|
|
4070
4156
|
init_select();
|
|
4071
4157
|
init_policy();
|
|
4072
4158
|
init_repo();
|
|
@@ -4172,7 +4258,6 @@ var init_test_skip = __esm({
|
|
|
4172
4258
|
]
|
|
4173
4259
|
};
|
|
4174
4260
|
JS_RUNNERS = /* @__PURE__ */ new Set(["it", "test", "describe", "suite"]);
|
|
4175
|
-
JS_CHAIN_MODIFIERS = /* @__PURE__ */ new Set(["concurrent", "sequential", "shuffle", "serial", "parallel"]);
|
|
4176
4261
|
JS_DEFAULT_RUNNER_MODULES = /* @__PURE__ */ new Set(["node:test", "node:test/promises", "@playwright/test"]);
|
|
4177
4262
|
JS_TEST_MODULES = /* @__PURE__ */ new Set([
|
|
4178
4263
|
"vitest",
|
|
@@ -7878,6 +7963,8 @@ function calleeName(expr) {
|
|
|
7878
7963
|
if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.expression)) {
|
|
7879
7964
|
return expr.expression.text;
|
|
7880
7965
|
}
|
|
7966
|
+
const chain = readCallee(expr);
|
|
7967
|
+
if (chain && !chain.table) return chain.runner;
|
|
7881
7968
|
return null;
|
|
7882
7969
|
}
|
|
7883
7970
|
function loopRows(iterable) {
|
|
@@ -8098,7 +8185,7 @@ function pytestPrecedenceFindings(changes, policy, ctx) {
|
|
|
8098
8185
|
})
|
|
8099
8186
|
);
|
|
8100
8187
|
}
|
|
8101
|
-
var RULE9, JVM_TEST, TEST_DEFS,
|
|
8188
|
+
var RULE9, JVM_TEST, TEST_DEFS, isTableOf, isEachOf, isDescribeEach, OTHER_RUNNER_DIR, WHOLE_SUITE_SCRIPT, SLICE_SCRIPT, SED_INPLACE, testDeletion;
|
|
8102
8189
|
var init_test_deletion = __esm({
|
|
8103
8190
|
"src/detectors/test-deletion.ts"() {
|
|
8104
8191
|
"use strict";
|
|
@@ -8111,6 +8198,7 @@ var init_test_deletion = __esm({
|
|
|
8111
8198
|
init_suite_config();
|
|
8112
8199
|
init_invocation();
|
|
8113
8200
|
init_narrow();
|
|
8201
|
+
init_runner_chain();
|
|
8114
8202
|
RULE9 = "test-deletion";
|
|
8115
8203
|
JVM_TEST = /^\s*(?:@\w+(?:\([^)]*\))?\s+)*@(?:Test|ParameterizedTest|RepeatedTest|TestFactory|TestTemplate)\b/;
|
|
8116
8204
|
TEST_DEFS = {
|
|
@@ -8123,9 +8211,12 @@ var init_test_deletion = __esm({
|
|
|
8123
8211
|
php: /^\s*(?:(?:public\s+)?function\s+test\w*\s*\(|#\[Test\]|\*\s*@test\b)/,
|
|
8124
8212
|
cs: /^\s*\[(?:Fact|Theory|Test|TestMethod|TestCase|DataTestMethod)\b/
|
|
8125
8213
|
};
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8214
|
+
isTableOf = (expr, runners) => {
|
|
8215
|
+
const chain = readCallee(expr);
|
|
8216
|
+
return chain != null && chain.table != null && runners.includes(chain.runner);
|
|
8217
|
+
};
|
|
8218
|
+
isEachOf = (expr) => isTableOf(expr, ["it", "test"]);
|
|
8219
|
+
isDescribeEach = (expr) => isTableOf(expr, ["describe"]);
|
|
8129
8220
|
OTHER_RUNNER_DIR = /(?:^|\/)(?:e2e|cypress|playwright|fixtures|__fixtures__|__mocks__)\//;
|
|
8130
8221
|
WHOLE_SUITE_SCRIPT = /^(?:test|test:ci|check|pretest)$/;
|
|
8131
8222
|
SLICE_SCRIPT = /^test:(?:unit|integration)$/;
|
|
@@ -8635,7 +8726,11 @@ function expectAssertion(node, sf) {
|
|
|
8635
8726
|
};
|
|
8636
8727
|
}
|
|
8637
8728
|
function simpleCallName(node) {
|
|
8638
|
-
|
|
8729
|
+
if (ts.isIdentifier(node.expression)) return node.expression.text;
|
|
8730
|
+
const chain = readCallee(node.expression) ?? readTableCallee(node.expression);
|
|
8731
|
+
if (!chain) return null;
|
|
8732
|
+
if (chain.table && !ts.isCallExpression(node.expression) && !ts.isTaggedTemplateExpression(node.expression)) return null;
|
|
8733
|
+
return chain.runner;
|
|
8639
8734
|
}
|
|
8640
8735
|
function callbackFor(node) {
|
|
8641
8736
|
const cb = node.arguments[1];
|
|
@@ -8755,6 +8850,7 @@ var init_assertion_weakening = __esm({
|
|
|
8755
8850
|
init_policy();
|
|
8756
8851
|
init_finding();
|
|
8757
8852
|
init_files();
|
|
8853
|
+
init_runner_chain();
|
|
8758
8854
|
RULE13 = "assertion-weakening";
|
|
8759
8855
|
TEST_CALLS = /* @__PURE__ */ new Set(["it", "test"]);
|
|
8760
8856
|
SUITE_CALLS = /* @__PURE__ */ new Set(["describe", "suite", "context"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.24.
|
|
3
|
+
"version": "2.24.3",
|
|
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",
|