slopbrick 0.35.0 → 0.35.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/dist/engine/worker.cjs +78 -0
- package/dist/engine/worker.js +78 -0
- package/dist/index.cjs +89 -1
- package/dist/index.js +89 -1
- package/package.json +1 -1
package/dist/engine/worker.cjs
CHANGED
|
@@ -37139,6 +37139,67 @@ var javaHardcodedCredentialRule = createRule({
|
|
|
37139
37139
|
}
|
|
37140
37140
|
});
|
|
37141
37141
|
|
|
37142
|
+
// src/rules/java/lost-stack-trace.ts
|
|
37143
|
+
var THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
|
|
37144
|
+
var CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
|
|
37145
|
+
var javaLostStackTraceRule = createRule({
|
|
37146
|
+
id: "java/lost-stack-trace",
|
|
37147
|
+
category: "logic",
|
|
37148
|
+
severity: "medium",
|
|
37149
|
+
aiSpecific: false,
|
|
37150
|
+
description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
|
|
37151
|
+
create(_context) {
|
|
37152
|
+
return {};
|
|
37153
|
+
},
|
|
37154
|
+
analyze(_context, facts) {
|
|
37155
|
+
const issues = [];
|
|
37156
|
+
const source = facts.v2?._source;
|
|
37157
|
+
if (!source) return issues;
|
|
37158
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
37159
|
+
if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
|
|
37160
|
+
const catchBlocks = [];
|
|
37161
|
+
let cm;
|
|
37162
|
+
CATCH_REGEX.lastIndex = 0;
|
|
37163
|
+
while ((cm = CATCH_REGEX.exec(source)) !== null) {
|
|
37164
|
+
const catchStart = cm.index;
|
|
37165
|
+
const exVar = cm[1];
|
|
37166
|
+
let depth = 1;
|
|
37167
|
+
let i = cm.index + cm[0].length;
|
|
37168
|
+
while (i < source.length && depth > 0) {
|
|
37169
|
+
const ch = source[i];
|
|
37170
|
+
if (ch === "{") depth++;
|
|
37171
|
+
else if (ch === "}") depth--;
|
|
37172
|
+
i++;
|
|
37173
|
+
}
|
|
37174
|
+
catchBlocks.push({ start: catchStart, end: i, exVar });
|
|
37175
|
+
}
|
|
37176
|
+
let m;
|
|
37177
|
+
THROW_NEW_REGEX.lastIndex = 0;
|
|
37178
|
+
while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
|
|
37179
|
+
const throwPos = m.index;
|
|
37180
|
+
const args = m[2].trim();
|
|
37181
|
+
const enclosing = catchBlocks.find(
|
|
37182
|
+
(cb) => cb.start < throwPos && throwPos < cb.end
|
|
37183
|
+
);
|
|
37184
|
+
if (!enclosing) continue;
|
|
37185
|
+
const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
|
|
37186
|
+
if (exVarPattern.test(args)) continue;
|
|
37187
|
+
const line = source.slice(0, throwPos).split("\n").length;
|
|
37188
|
+
issues.push({
|
|
37189
|
+
ruleId: "java/lost-stack-trace",
|
|
37190
|
+
category: "logic",
|
|
37191
|
+
severity: "medium",
|
|
37192
|
+
aiSpecific: false,
|
|
37193
|
+
message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
|
|
37194
|
+
line,
|
|
37195
|
+
column: 1,
|
|
37196
|
+
advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
|
|
37197
|
+
});
|
|
37198
|
+
}
|
|
37199
|
+
return issues;
|
|
37200
|
+
}
|
|
37201
|
+
});
|
|
37202
|
+
|
|
37142
37203
|
// src/rules/java/sql-string-concat.ts
|
|
37143
37204
|
var SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
|
|
37144
37205
|
var UNSAFE_REGEX = /\+/;
|
|
@@ -43375,6 +43436,7 @@ var builtinRules = [
|
|
|
43375
43436
|
goStructTagInconsistencyRule,
|
|
43376
43437
|
javaCommandInjectionRule,
|
|
43377
43438
|
javaHardcodedCredentialRule,
|
|
43439
|
+
javaLostStackTraceRule,
|
|
43378
43440
|
javaSqlStringConcatRule,
|
|
43379
43441
|
javaSuspiciousImplementationRule,
|
|
43380
43442
|
javaSystemOutPrintlnRule,
|
|
@@ -45782,6 +45844,22 @@ var signal_strength_default = {
|
|
|
45782
45844
|
_v9Precision: 0,
|
|
45783
45845
|
defaultOff: false
|
|
45784
45846
|
},
|
|
45847
|
+
"java/lost-stack-trace": {
|
|
45848
|
+
recall: 0,
|
|
45849
|
+
fpRate: 0,
|
|
45850
|
+
ratio: 0,
|
|
45851
|
+
precision: 0,
|
|
45852
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
45853
|
+
verdict: "OK",
|
|
45854
|
+
_calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
|
|
45855
|
+
aiSpecific: false,
|
|
45856
|
+
_v9Verdict: "OK",
|
|
45857
|
+
_v9Lift: 0,
|
|
45858
|
+
_v9Recall: 0,
|
|
45859
|
+
_v9FpRate: 0,
|
|
45860
|
+
_v9Precision: 0,
|
|
45861
|
+
defaultOff: false
|
|
45862
|
+
},
|
|
45785
45863
|
"swift/force-unwrap": {
|
|
45786
45864
|
recall: 0.10211,
|
|
45787
45865
|
fpRate: 0.21462,
|
package/dist/engine/worker.js
CHANGED
|
@@ -37110,6 +37110,67 @@ var javaHardcodedCredentialRule = createRule({
|
|
|
37110
37110
|
}
|
|
37111
37111
|
});
|
|
37112
37112
|
|
|
37113
|
+
// src/rules/java/lost-stack-trace.ts
|
|
37114
|
+
var THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
|
|
37115
|
+
var CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
|
|
37116
|
+
var javaLostStackTraceRule = createRule({
|
|
37117
|
+
id: "java/lost-stack-trace",
|
|
37118
|
+
category: "logic",
|
|
37119
|
+
severity: "medium",
|
|
37120
|
+
aiSpecific: false,
|
|
37121
|
+
description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
|
|
37122
|
+
create(_context) {
|
|
37123
|
+
return {};
|
|
37124
|
+
},
|
|
37125
|
+
analyze(_context, facts) {
|
|
37126
|
+
const issues = [];
|
|
37127
|
+
const source = facts.v2?._source;
|
|
37128
|
+
if (!source) return issues;
|
|
37129
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
37130
|
+
if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
|
|
37131
|
+
const catchBlocks = [];
|
|
37132
|
+
let cm;
|
|
37133
|
+
CATCH_REGEX.lastIndex = 0;
|
|
37134
|
+
while ((cm = CATCH_REGEX.exec(source)) !== null) {
|
|
37135
|
+
const catchStart = cm.index;
|
|
37136
|
+
const exVar = cm[1];
|
|
37137
|
+
let depth = 1;
|
|
37138
|
+
let i = cm.index + cm[0].length;
|
|
37139
|
+
while (i < source.length && depth > 0) {
|
|
37140
|
+
const ch = source[i];
|
|
37141
|
+
if (ch === "{") depth++;
|
|
37142
|
+
else if (ch === "}") depth--;
|
|
37143
|
+
i++;
|
|
37144
|
+
}
|
|
37145
|
+
catchBlocks.push({ start: catchStart, end: i, exVar });
|
|
37146
|
+
}
|
|
37147
|
+
let m;
|
|
37148
|
+
THROW_NEW_REGEX.lastIndex = 0;
|
|
37149
|
+
while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
|
|
37150
|
+
const throwPos = m.index;
|
|
37151
|
+
const args = m[2].trim();
|
|
37152
|
+
const enclosing = catchBlocks.find(
|
|
37153
|
+
(cb) => cb.start < throwPos && throwPos < cb.end
|
|
37154
|
+
);
|
|
37155
|
+
if (!enclosing) continue;
|
|
37156
|
+
const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
|
|
37157
|
+
if (exVarPattern.test(args)) continue;
|
|
37158
|
+
const line = source.slice(0, throwPos).split("\n").length;
|
|
37159
|
+
issues.push({
|
|
37160
|
+
ruleId: "java/lost-stack-trace",
|
|
37161
|
+
category: "logic",
|
|
37162
|
+
severity: "medium",
|
|
37163
|
+
aiSpecific: false,
|
|
37164
|
+
message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
|
|
37165
|
+
line,
|
|
37166
|
+
column: 1,
|
|
37167
|
+
advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
|
|
37168
|
+
});
|
|
37169
|
+
}
|
|
37170
|
+
return issues;
|
|
37171
|
+
}
|
|
37172
|
+
});
|
|
37173
|
+
|
|
37113
37174
|
// src/rules/java/sql-string-concat.ts
|
|
37114
37175
|
var SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
|
|
37115
37176
|
var UNSAFE_REGEX = /\+/;
|
|
@@ -43346,6 +43407,7 @@ var builtinRules = [
|
|
|
43346
43407
|
goStructTagInconsistencyRule,
|
|
43347
43408
|
javaCommandInjectionRule,
|
|
43348
43409
|
javaHardcodedCredentialRule,
|
|
43410
|
+
javaLostStackTraceRule,
|
|
43349
43411
|
javaSqlStringConcatRule,
|
|
43350
43412
|
javaSuspiciousImplementationRule,
|
|
43351
43413
|
javaSystemOutPrintlnRule,
|
|
@@ -45753,6 +45815,22 @@ var signal_strength_default = {
|
|
|
45753
45815
|
_v9Precision: 0,
|
|
45754
45816
|
defaultOff: false
|
|
45755
45817
|
},
|
|
45818
|
+
"java/lost-stack-trace": {
|
|
45819
|
+
recall: 0,
|
|
45820
|
+
fpRate: 0,
|
|
45821
|
+
ratio: 0,
|
|
45822
|
+
precision: 0,
|
|
45823
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
45824
|
+
verdict: "OK",
|
|
45825
|
+
_calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
|
|
45826
|
+
aiSpecific: false,
|
|
45827
|
+
_v9Verdict: "OK",
|
|
45828
|
+
_v9Lift: 0,
|
|
45829
|
+
_v9Recall: 0,
|
|
45830
|
+
_v9FpRate: 0,
|
|
45831
|
+
_v9Precision: 0,
|
|
45832
|
+
defaultOff: false
|
|
45833
|
+
},
|
|
45756
45834
|
"swift/force-unwrap": {
|
|
45757
45835
|
recall: 0.10211,
|
|
45758
45836
|
fpRate: 0.21462,
|
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ var VERSION;
|
|
|
36
36
|
var init_header = __esm({
|
|
37
37
|
"src/types/_header.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
VERSION = "0.35.
|
|
39
|
+
VERSION = "0.35.1";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -30797,6 +30797,74 @@ var init_hardcoded_credential = __esm({
|
|
|
30797
30797
|
}
|
|
30798
30798
|
});
|
|
30799
30799
|
|
|
30800
|
+
// src/rules/java/lost-stack-trace.ts
|
|
30801
|
+
var THROW_NEW_REGEX, CATCH_REGEX, javaLostStackTraceRule;
|
|
30802
|
+
var init_lost_stack_trace = __esm({
|
|
30803
|
+
"src/rules/java/lost-stack-trace.ts"() {
|
|
30804
|
+
"use strict";
|
|
30805
|
+
init_rule();
|
|
30806
|
+
THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
|
|
30807
|
+
CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
|
|
30808
|
+
javaLostStackTraceRule = createRule({
|
|
30809
|
+
id: "java/lost-stack-trace",
|
|
30810
|
+
category: "logic",
|
|
30811
|
+
severity: "medium",
|
|
30812
|
+
aiSpecific: false,
|
|
30813
|
+
description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
|
|
30814
|
+
create(_context) {
|
|
30815
|
+
return {};
|
|
30816
|
+
},
|
|
30817
|
+
analyze(_context, facts) {
|
|
30818
|
+
const issues = [];
|
|
30819
|
+
const source = facts.v2?._source;
|
|
30820
|
+
if (!source) return issues;
|
|
30821
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30822
|
+
if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
|
|
30823
|
+
const catchBlocks = [];
|
|
30824
|
+
let cm;
|
|
30825
|
+
CATCH_REGEX.lastIndex = 0;
|
|
30826
|
+
while ((cm = CATCH_REGEX.exec(source)) !== null) {
|
|
30827
|
+
const catchStart = cm.index;
|
|
30828
|
+
const exVar = cm[1];
|
|
30829
|
+
let depth = 1;
|
|
30830
|
+
let i = cm.index + cm[0].length;
|
|
30831
|
+
while (i < source.length && depth > 0) {
|
|
30832
|
+
const ch = source[i];
|
|
30833
|
+
if (ch === "{") depth++;
|
|
30834
|
+
else if (ch === "}") depth--;
|
|
30835
|
+
i++;
|
|
30836
|
+
}
|
|
30837
|
+
catchBlocks.push({ start: catchStart, end: i, exVar });
|
|
30838
|
+
}
|
|
30839
|
+
let m;
|
|
30840
|
+
THROW_NEW_REGEX.lastIndex = 0;
|
|
30841
|
+
while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
|
|
30842
|
+
const throwPos = m.index;
|
|
30843
|
+
const args = m[2].trim();
|
|
30844
|
+
const enclosing = catchBlocks.find(
|
|
30845
|
+
(cb) => cb.start < throwPos && throwPos < cb.end
|
|
30846
|
+
);
|
|
30847
|
+
if (!enclosing) continue;
|
|
30848
|
+
const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
|
|
30849
|
+
if (exVarPattern.test(args)) continue;
|
|
30850
|
+
const line = source.slice(0, throwPos).split("\n").length;
|
|
30851
|
+
issues.push({
|
|
30852
|
+
ruleId: "java/lost-stack-trace",
|
|
30853
|
+
category: "logic",
|
|
30854
|
+
severity: "medium",
|
|
30855
|
+
aiSpecific: false,
|
|
30856
|
+
message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
|
|
30857
|
+
line,
|
|
30858
|
+
column: 1,
|
|
30859
|
+
advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
|
|
30860
|
+
});
|
|
30861
|
+
}
|
|
30862
|
+
return issues;
|
|
30863
|
+
}
|
|
30864
|
+
});
|
|
30865
|
+
}
|
|
30866
|
+
});
|
|
30867
|
+
|
|
30800
30868
|
// src/rules/java/sql-string-concat.ts
|
|
30801
30869
|
var SQL_KEYWORD_REGEX, UNSAFE_REGEX, SAFE_REGEX, javaSqlStringConcatRule;
|
|
30802
30870
|
var init_sql_string_concat = __esm({
|
|
@@ -47025,6 +47093,7 @@ var init_builtins = __esm({
|
|
|
47025
47093
|
init_struct_tag_inconsistency();
|
|
47026
47094
|
init_command_injection();
|
|
47027
47095
|
init_hardcoded_credential();
|
|
47096
|
+
init_lost_stack_trace();
|
|
47028
47097
|
init_sql_string_concat();
|
|
47029
47098
|
init_suspicious_implementation();
|
|
47030
47099
|
init_system_out_println();
|
|
@@ -47165,6 +47234,7 @@ var init_builtins = __esm({
|
|
|
47165
47234
|
goStructTagInconsistencyRule,
|
|
47166
47235
|
javaCommandInjectionRule,
|
|
47167
47236
|
javaHardcodedCredentialRule,
|
|
47237
|
+
javaLostStackTraceRule,
|
|
47168
47238
|
javaSqlStringConcatRule,
|
|
47169
47239
|
javaSuspiciousImplementationRule,
|
|
47170
47240
|
javaSystemOutPrintlnRule,
|
|
@@ -51877,6 +51947,22 @@ var init_signal_strength = __esm({
|
|
|
51877
51947
|
_v9Precision: 0,
|
|
51878
51948
|
defaultOff: false
|
|
51879
51949
|
},
|
|
51950
|
+
"java/lost-stack-trace": {
|
|
51951
|
+
recall: 0,
|
|
51952
|
+
fpRate: 0,
|
|
51953
|
+
ratio: 0,
|
|
51954
|
+
precision: 0,
|
|
51955
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51956
|
+
verdict: "OK",
|
|
51957
|
+
_calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
|
|
51958
|
+
aiSpecific: false,
|
|
51959
|
+
_v9Verdict: "OK",
|
|
51960
|
+
_v9Lift: 0,
|
|
51961
|
+
_v9Recall: 0,
|
|
51962
|
+
_v9FpRate: 0,
|
|
51963
|
+
_v9Precision: 0,
|
|
51964
|
+
defaultOff: false
|
|
51965
|
+
},
|
|
51880
51966
|
"swift/force-unwrap": {
|
|
51881
51967
|
recall: 0.10211,
|
|
51882
51968
|
fpRate: 0.21462,
|
|
@@ -60145,6 +60231,8 @@ var RULE_HINTS = {
|
|
|
60145
60231
|
"java/command-injection": "Use ProcessBuilder with a List<String> of args (no shell parsing) and validate each arg. Runtime.exec() with concat is the canonical command-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT.)",
|
|
60146
60232
|
// v0.35.0 — content-based detection (CoCoNUTS-inspired)
|
|
60147
60233
|
"java/suspicious-implementation": "Function name claims validate/encrypt/hash/sanitize but body is empty, returns null/true, or returns the input. This is a content mismatch \u2014 the function's claimed behavior doesn't match its actual behavior. OWASP A04:2021.",
|
|
60234
|
+
// v0.35.1 — Raidar-inspired content-based detection
|
|
60235
|
+
"java/lost-stack-trace": 'catch block throws a new exception without the original cause \u2014 stack trace is lost. Pass the original exception as the second arg to the new exception\'s constructor: `throw new XxxException("msg", e)`.',
|
|
60148
60236
|
// v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
|
|
60149
60237
|
"swift/force-unwrap": "Replace with the safe form: `as?` + guard/if let, `try?`, or `guard let x = optional else { return }`. `!` crashes unconditionally in release. (v0.24.0 \u2014 DORMANT.)",
|
|
60150
60238
|
"swift/print-debug": "Replace with `Logger(subsystem:..., category:...).info(...)` (os.log). `print` writes to stdout with no level and no redaction. (v0.24.0 \u2014 DORMANT.)",
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ var VERSION;
|
|
|
19
19
|
var init_header = __esm({
|
|
20
20
|
"src/types/_header.ts"() {
|
|
21
21
|
"use strict";
|
|
22
|
-
VERSION = "0.35.
|
|
22
|
+
VERSION = "0.35.1";
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -30778,6 +30778,74 @@ var init_hardcoded_credential = __esm({
|
|
|
30778
30778
|
}
|
|
30779
30779
|
});
|
|
30780
30780
|
|
|
30781
|
+
// src/rules/java/lost-stack-trace.ts
|
|
30782
|
+
var THROW_NEW_REGEX, CATCH_REGEX, javaLostStackTraceRule;
|
|
30783
|
+
var init_lost_stack_trace = __esm({
|
|
30784
|
+
"src/rules/java/lost-stack-trace.ts"() {
|
|
30785
|
+
"use strict";
|
|
30786
|
+
init_rule();
|
|
30787
|
+
THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
|
|
30788
|
+
CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
|
|
30789
|
+
javaLostStackTraceRule = createRule({
|
|
30790
|
+
id: "java/lost-stack-trace",
|
|
30791
|
+
category: "logic",
|
|
30792
|
+
severity: "medium",
|
|
30793
|
+
aiSpecific: false,
|
|
30794
|
+
description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
|
|
30795
|
+
create(_context) {
|
|
30796
|
+
return {};
|
|
30797
|
+
},
|
|
30798
|
+
analyze(_context, facts) {
|
|
30799
|
+
const issues = [];
|
|
30800
|
+
const source = facts.v2?._source;
|
|
30801
|
+
if (!source) return issues;
|
|
30802
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30803
|
+
if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
|
|
30804
|
+
const catchBlocks = [];
|
|
30805
|
+
let cm;
|
|
30806
|
+
CATCH_REGEX.lastIndex = 0;
|
|
30807
|
+
while ((cm = CATCH_REGEX.exec(source)) !== null) {
|
|
30808
|
+
const catchStart = cm.index;
|
|
30809
|
+
const exVar = cm[1];
|
|
30810
|
+
let depth = 1;
|
|
30811
|
+
let i = cm.index + cm[0].length;
|
|
30812
|
+
while (i < source.length && depth > 0) {
|
|
30813
|
+
const ch = source[i];
|
|
30814
|
+
if (ch === "{") depth++;
|
|
30815
|
+
else if (ch === "}") depth--;
|
|
30816
|
+
i++;
|
|
30817
|
+
}
|
|
30818
|
+
catchBlocks.push({ start: catchStart, end: i, exVar });
|
|
30819
|
+
}
|
|
30820
|
+
let m;
|
|
30821
|
+
THROW_NEW_REGEX.lastIndex = 0;
|
|
30822
|
+
while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
|
|
30823
|
+
const throwPos = m.index;
|
|
30824
|
+
const args = m[2].trim();
|
|
30825
|
+
const enclosing = catchBlocks.find(
|
|
30826
|
+
(cb) => cb.start < throwPos && throwPos < cb.end
|
|
30827
|
+
);
|
|
30828
|
+
if (!enclosing) continue;
|
|
30829
|
+
const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
|
|
30830
|
+
if (exVarPattern.test(args)) continue;
|
|
30831
|
+
const line = source.slice(0, throwPos).split("\n").length;
|
|
30832
|
+
issues.push({
|
|
30833
|
+
ruleId: "java/lost-stack-trace",
|
|
30834
|
+
category: "logic",
|
|
30835
|
+
severity: "medium",
|
|
30836
|
+
aiSpecific: false,
|
|
30837
|
+
message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
|
|
30838
|
+
line,
|
|
30839
|
+
column: 1,
|
|
30840
|
+
advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
|
|
30841
|
+
});
|
|
30842
|
+
}
|
|
30843
|
+
return issues;
|
|
30844
|
+
}
|
|
30845
|
+
});
|
|
30846
|
+
}
|
|
30847
|
+
});
|
|
30848
|
+
|
|
30781
30849
|
// src/rules/java/sql-string-concat.ts
|
|
30782
30850
|
var SQL_KEYWORD_REGEX, UNSAFE_REGEX, SAFE_REGEX, javaSqlStringConcatRule;
|
|
30783
30851
|
var init_sql_string_concat = __esm({
|
|
@@ -47006,6 +47074,7 @@ var init_builtins = __esm({
|
|
|
47006
47074
|
init_struct_tag_inconsistency();
|
|
47007
47075
|
init_command_injection();
|
|
47008
47076
|
init_hardcoded_credential();
|
|
47077
|
+
init_lost_stack_trace();
|
|
47009
47078
|
init_sql_string_concat();
|
|
47010
47079
|
init_suspicious_implementation();
|
|
47011
47080
|
init_system_out_println();
|
|
@@ -47146,6 +47215,7 @@ var init_builtins = __esm({
|
|
|
47146
47215
|
goStructTagInconsistencyRule,
|
|
47147
47216
|
javaCommandInjectionRule,
|
|
47148
47217
|
javaHardcodedCredentialRule,
|
|
47218
|
+
javaLostStackTraceRule,
|
|
47149
47219
|
javaSqlStringConcatRule,
|
|
47150
47220
|
javaSuspiciousImplementationRule,
|
|
47151
47221
|
javaSystemOutPrintlnRule,
|
|
@@ -51855,6 +51925,22 @@ var init_signal_strength = __esm({
|
|
|
51855
51925
|
_v9Precision: 0,
|
|
51856
51926
|
defaultOff: false
|
|
51857
51927
|
},
|
|
51928
|
+
"java/lost-stack-trace": {
|
|
51929
|
+
recall: 0,
|
|
51930
|
+
fpRate: 0,
|
|
51931
|
+
ratio: 0,
|
|
51932
|
+
precision: 0,
|
|
51933
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51934
|
+
verdict: "OK",
|
|
51935
|
+
_calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
|
|
51936
|
+
aiSpecific: false,
|
|
51937
|
+
_v9Verdict: "OK",
|
|
51938
|
+
_v9Lift: 0,
|
|
51939
|
+
_v9Recall: 0,
|
|
51940
|
+
_v9FpRate: 0,
|
|
51941
|
+
_v9Precision: 0,
|
|
51942
|
+
defaultOff: false
|
|
51943
|
+
},
|
|
51858
51944
|
"swift/force-unwrap": {
|
|
51859
51945
|
recall: 0.10211,
|
|
51860
51946
|
fpRate: 0.21462,
|
|
@@ -60044,6 +60130,8 @@ var RULE_HINTS = {
|
|
|
60044
60130
|
"java/command-injection": "Use ProcessBuilder with a List<String> of args (no shell parsing) and validate each arg. Runtime.exec() with concat is the canonical command-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT.)",
|
|
60045
60131
|
// v0.35.0 — content-based detection (CoCoNUTS-inspired)
|
|
60046
60132
|
"java/suspicious-implementation": "Function name claims validate/encrypt/hash/sanitize but body is empty, returns null/true, or returns the input. This is a content mismatch \u2014 the function's claimed behavior doesn't match its actual behavior. OWASP A04:2021.",
|
|
60133
|
+
// v0.35.1 — Raidar-inspired content-based detection
|
|
60134
|
+
"java/lost-stack-trace": 'catch block throws a new exception without the original cause \u2014 stack trace is lost. Pass the original exception as the second arg to the new exception\'s constructor: `throw new XxxException("msg", e)`.',
|
|
60047
60135
|
// v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
|
|
60048
60136
|
"swift/force-unwrap": "Replace with the safe form: `as?` + guard/if let, `try?`, or `guard let x = optional else { return }`. `!` crashes unconditionally in release. (v0.24.0 \u2014 DORMANT.)",
|
|
60049
60137
|
"swift/print-debug": "Replace with `Logger(subsystem:..., category:...).info(...)` (os.log). `print` writes to stdout with no level and no redaction. (v0.24.0 \u2014 DORMANT.)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopbrick",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"description": "Discovered, modeled, and governed repository structure. SlopBrick scans source code, classifies it against 95+ rules in 15 categories, computes 4 scores (aiSlopScore: lower=cleaner, engineeringHygiene, security, repositoryHealth composite), and persists the structure for AI agents and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|