slopbrick 0.34.8 → 0.34.10

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.
@@ -37142,7 +37142,7 @@ var javaHardcodedCredentialRule = createRule({
37142
37142
  // src/rules/java/sql-string-concat.ts
37143
37143
  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
37144
  var UNSAFE_REGEX = /\+/;
37145
- var SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?\s*,)/;
37145
+ var SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?)/;
37146
37146
  var javaSqlStringConcatRule = createRule({
37147
37147
  id: "java/sql-string-concat",
37148
37148
  category: "security",
@@ -37160,7 +37160,14 @@ var javaSqlStringConcatRule = createRule({
37160
37160
  const lines = source.split("\n");
37161
37161
  for (let i = 0; i < lines.length; i++) {
37162
37162
  const line = lines[i];
37163
- if (!SQL_KEYWORD_REGEX.test(line)) continue;
37163
+ const keywordMatch = SQL_KEYWORD_REGEX.exec(line);
37164
+ if (!keywordMatch) continue;
37165
+ const keywordIdx = keywordMatch.index;
37166
+ let j = keywordIdx - 1;
37167
+ while (j >= 0 && /\s/.test(line[j])) j--;
37168
+ if (j < 0) continue;
37169
+ const prevChar = line[j];
37170
+ if (prevChar !== '"' && prevChar !== "'" && prevChar !== "=") continue;
37164
37171
  if (!UNSAFE_REGEX.test(line)) continue;
37165
37172
  if (SAFE_REGEX.test(line)) continue;
37166
37173
  issues.push({
@@ -37171,7 +37178,7 @@ var javaSqlStringConcatRule = createRule({
37171
37178
  message: `SQL query built via string concat at line ${i + 1}`,
37172
37179
  line: i + 1,
37173
37180
  column: 1,
37174
- advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.30 (OWASP A03:2021).'
37181
+ advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.34.9 (refined: require SQL keyword to start a string literal; tightened SAFE_REGEX).'
37175
37182
  });
37176
37183
  }
37177
37184
  return issues;
@@ -40561,7 +40568,7 @@ var swiftFatalErrorThrownRule = createRule({
40561
40568
 
40562
40569
  // src/rules/swift/force-unwrap.ts
40563
40570
  var AS_FORCE_REGEX = /\bas!\s+/g;
40564
- var ACCESS_FORCE_REGEX = /(?:\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
40571
+ var ACCESS_FORCE_REGEX = /(?<![=!])(\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
40565
40572
  var TRY_FORCE_REGEX = /\btry!\s+/g;
40566
40573
  var swiftForceUnwrapRule = createRule({
40567
40574
  id: "swift/force-unwrap",
@@ -40588,7 +40595,7 @@ var swiftForceUnwrapRule = createRule({
40588
40595
  message: `force-unwrap (${label}) at line ${line} \u2014 crashes if the value is nil`,
40589
40596
  line,
40590
40597
  column: 1,
40591
- advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.24.'
40598
+ advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.34.10 (refined: exclude `!` in `!==`/`!=` operators via negative lookbehind).'
40592
40599
  });
40593
40600
  };
40594
40601
  let m;
@@ -40597,7 +40604,10 @@ var swiftForceUnwrapRule = createRule({
40597
40604
  TRY_FORCE_REGEX.lastIndex = 0;
40598
40605
  while ((m = TRY_FORCE_REGEX.exec(source)) !== null) emit(m.index, "try!");
40599
40606
  ACCESS_FORCE_REGEX.lastIndex = 0;
40600
- while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) emit(m.index, "!.");
40607
+ while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) {
40608
+ const bangOffset = m.index + (m[1]?.length ?? 1);
40609
+ emit(bangOffset, "!.");
40610
+ }
40601
40611
  return issues;
40602
40612
  }
40603
40613
  });
@@ -45627,7 +45637,7 @@ var signal_strength_default = {
45627
45637
  precision: 0.0691,
45628
45638
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45629
45639
  verdict: "DORMANT",
45630
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.59 \u2014 fires 1.7x more on pre-2022 (neg) than post-2024 (pos). Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. Same direction as kotlin/sql-string-concat. 1664 total fires \u2014 Java uses ORMs (Hibernate) heavily so SQL concat is rare in both arms. defaultOff.",
45640
+ _calibrationNote: 'v0.34.9: REFINED \u2014 rule now requires the SQL keyword to be the start of a string literal (preceded by `"`, `\'`, or `=`), and tightened the SAFE_REGEX. Per-file unique v9 Java calibration (81891 neg, 10305 pos): 115 TP files, 1549 FP files, ratio=0.59 (DORMANT). 1664 total fires. The refinement is expected to push precision from 6.9% to 25%+ by removing lines where SELECT/INSERT appears in string values (e.g. `String msg = "Selected 1 row: " + count`). Also tightened SAFE_REGEX from `:??` to `:?` (the original was over-broad). The full v9 re-calibration is part of the broader v0.34.8/v0.34.9 pipeline (same pattern applied to kotlin/sql-string-concat and java/sql-string-concat). INSUFFICIENT_DATA: pos arm 10305 files, below the 10k floor. Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. defaultOff.',
45631
45641
  aiSpecific: false,
45632
45642
  _v9Verdict: "DORMANT",
45633
45643
  _v9Lift: 0.59,
@@ -45707,7 +45717,7 @@ var signal_strength_default = {
45707
45717
  precision: 0.1721,
45708
45718
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45709
45719
  verdict: "DORMANT",
45710
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique measurement: 58 TP files, 279 FP files, ratio=0.48. Era-confounded: pre-2022 Swift used ! freely (the only way to unwrap); modern Swift uses guard let / if let / try?. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45720
+ _calibrationNote: "v0.34.10: REFINED \u2014 the access-force regex now uses a negative lookbehind to exclude `!` in `!=` and `!==` comparison operators. Per-file unique v9 Swift calibration (1300 neg, 568 pos): 58 TP files, 279 FP files, ratio=0.48 (DORMANT). The previous regex incorrectly fired on `!` in `a != b` and `a !== b` patterns, which are common in control flow. The refinement is expected to push precision from 17.2% to 25%+ by removing these false positives. Era-confounded: pre-2022 Swift used `!` freely (the only way to unwrap); modern Swift uses `guard let` / `if let` / `try?`. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45711
45721
  aiSpecific: true,
45712
45722
  _v7Verdict: "DORMANT",
45713
45723
  _v7Lift: 1,
@@ -37113,7 +37113,7 @@ var javaHardcodedCredentialRule = createRule({
37113
37113
  // src/rules/java/sql-string-concat.ts
37114
37114
  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
37115
  var UNSAFE_REGEX = /\+/;
37116
- var SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?\s*,)/;
37116
+ var SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?)/;
37117
37117
  var javaSqlStringConcatRule = createRule({
37118
37118
  id: "java/sql-string-concat",
37119
37119
  category: "security",
@@ -37131,7 +37131,14 @@ var javaSqlStringConcatRule = createRule({
37131
37131
  const lines = source.split("\n");
37132
37132
  for (let i = 0; i < lines.length; i++) {
37133
37133
  const line = lines[i];
37134
- if (!SQL_KEYWORD_REGEX.test(line)) continue;
37134
+ const keywordMatch = SQL_KEYWORD_REGEX.exec(line);
37135
+ if (!keywordMatch) continue;
37136
+ const keywordIdx = keywordMatch.index;
37137
+ let j = keywordIdx - 1;
37138
+ while (j >= 0 && /\s/.test(line[j])) j--;
37139
+ if (j < 0) continue;
37140
+ const prevChar = line[j];
37141
+ if (prevChar !== '"' && prevChar !== "'" && prevChar !== "=") continue;
37135
37142
  if (!UNSAFE_REGEX.test(line)) continue;
37136
37143
  if (SAFE_REGEX.test(line)) continue;
37137
37144
  issues.push({
@@ -37142,7 +37149,7 @@ var javaSqlStringConcatRule = createRule({
37142
37149
  message: `SQL query built via string concat at line ${i + 1}`,
37143
37150
  line: i + 1,
37144
37151
  column: 1,
37145
- advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.30 (OWASP A03:2021).'
37152
+ advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.34.9 (refined: require SQL keyword to start a string literal; tightened SAFE_REGEX).'
37146
37153
  });
37147
37154
  }
37148
37155
  return issues;
@@ -40532,7 +40539,7 @@ var swiftFatalErrorThrownRule = createRule({
40532
40539
 
40533
40540
  // src/rules/swift/force-unwrap.ts
40534
40541
  var AS_FORCE_REGEX = /\bas!\s+/g;
40535
- var ACCESS_FORCE_REGEX = /(?:\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
40542
+ var ACCESS_FORCE_REGEX = /(?<![=!])(\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
40536
40543
  var TRY_FORCE_REGEX = /\btry!\s+/g;
40537
40544
  var swiftForceUnwrapRule = createRule({
40538
40545
  id: "swift/force-unwrap",
@@ -40559,7 +40566,7 @@ var swiftForceUnwrapRule = createRule({
40559
40566
  message: `force-unwrap (${label}) at line ${line} \u2014 crashes if the value is nil`,
40560
40567
  line,
40561
40568
  column: 1,
40562
- advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.24.'
40569
+ advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.34.10 (refined: exclude `!` in `!==`/`!=` operators via negative lookbehind).'
40563
40570
  });
40564
40571
  };
40565
40572
  let m;
@@ -40568,7 +40575,10 @@ var swiftForceUnwrapRule = createRule({
40568
40575
  TRY_FORCE_REGEX.lastIndex = 0;
40569
40576
  while ((m = TRY_FORCE_REGEX.exec(source)) !== null) emit(m.index, "try!");
40570
40577
  ACCESS_FORCE_REGEX.lastIndex = 0;
40571
- while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) emit(m.index, "!.");
40578
+ while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) {
40579
+ const bangOffset = m.index + (m[1]?.length ?? 1);
40580
+ emit(bangOffset, "!.");
40581
+ }
40572
40582
  return issues;
40573
40583
  }
40574
40584
  });
@@ -45598,7 +45608,7 @@ var signal_strength_default = {
45598
45608
  precision: 0.0691,
45599
45609
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45600
45610
  verdict: "DORMANT",
45601
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.59 \u2014 fires 1.7x more on pre-2022 (neg) than post-2024 (pos). Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. Same direction as kotlin/sql-string-concat. 1664 total fires \u2014 Java uses ORMs (Hibernate) heavily so SQL concat is rare in both arms. defaultOff.",
45611
+ _calibrationNote: 'v0.34.9: REFINED \u2014 rule now requires the SQL keyword to be the start of a string literal (preceded by `"`, `\'`, or `=`), and tightened the SAFE_REGEX. Per-file unique v9 Java calibration (81891 neg, 10305 pos): 115 TP files, 1549 FP files, ratio=0.59 (DORMANT). 1664 total fires. The refinement is expected to push precision from 6.9% to 25%+ by removing lines where SELECT/INSERT appears in string values (e.g. `String msg = "Selected 1 row: " + count`). Also tightened SAFE_REGEX from `:??` to `:?` (the original was over-broad). The full v9 re-calibration is part of the broader v0.34.8/v0.34.9 pipeline (same pattern applied to kotlin/sql-string-concat and java/sql-string-concat). INSUFFICIENT_DATA: pos arm 10305 files, below the 10k floor. Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. defaultOff.',
45602
45612
  aiSpecific: false,
45603
45613
  _v9Verdict: "DORMANT",
45604
45614
  _v9Lift: 0.59,
@@ -45678,7 +45688,7 @@ var signal_strength_default = {
45678
45688
  precision: 0.1721,
45679
45689
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45680
45690
  verdict: "DORMANT",
45681
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique measurement: 58 TP files, 279 FP files, ratio=0.48. Era-confounded: pre-2022 Swift used ! freely (the only way to unwrap); modern Swift uses guard let / if let / try?. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45691
+ _calibrationNote: "v0.34.10: REFINED \u2014 the access-force regex now uses a negative lookbehind to exclude `!` in `!=` and `!==` comparison operators. Per-file unique v9 Swift calibration (1300 neg, 568 pos): 58 TP files, 279 FP files, ratio=0.48 (DORMANT). The previous regex incorrectly fired on `!` in `a != b` and `a !== b` patterns, which are common in control flow. The refinement is expected to push precision from 17.2% to 25%+ by removing these false positives. Era-confounded: pre-2022 Swift used `!` freely (the only way to unwrap); modern Swift uses `guard let` / `if let` / `try?`. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45682
45692
  aiSpecific: true,
45683
45693
  _v7Verdict: "DORMANT",
45684
45694
  _v7Lift: 1,
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.34.8";
39
+ VERSION = "0.34.10";
40
40
  }
41
41
  });
42
42
 
@@ -30805,7 +30805,7 @@ var init_sql_string_concat = __esm({
30805
30805
  init_rule();
30806
30806
  SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
30807
30807
  UNSAFE_REGEX = /\+/;
30808
- SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?\s*,)/;
30808
+ SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?)/;
30809
30809
  javaSqlStringConcatRule = createRule({
30810
30810
  id: "java/sql-string-concat",
30811
30811
  category: "security",
@@ -30823,7 +30823,14 @@ var init_sql_string_concat = __esm({
30823
30823
  const lines = source.split("\n");
30824
30824
  for (let i = 0; i < lines.length; i++) {
30825
30825
  const line = lines[i];
30826
- if (!SQL_KEYWORD_REGEX.test(line)) continue;
30826
+ const keywordMatch = SQL_KEYWORD_REGEX.exec(line);
30827
+ if (!keywordMatch) continue;
30828
+ const keywordIdx = keywordMatch.index;
30829
+ let j = keywordIdx - 1;
30830
+ while (j >= 0 && /\s/.test(line[j])) j--;
30831
+ if (j < 0) continue;
30832
+ const prevChar = line[j];
30833
+ if (prevChar !== '"' && prevChar !== "'" && prevChar !== "=") continue;
30827
30834
  if (!UNSAFE_REGEX.test(line)) continue;
30828
30835
  if (SAFE_REGEX.test(line)) continue;
30829
30836
  issues.push({
@@ -30834,7 +30841,7 @@ var init_sql_string_concat = __esm({
30834
30841
  message: `SQL query built via string concat at line ${i + 1}`,
30835
30842
  line: i + 1,
30836
30843
  column: 1,
30837
- advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.30 (OWASP A03:2021).'
30844
+ advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.34.9 (refined: require SQL keyword to start a string literal; tightened SAFE_REGEX).'
30838
30845
  });
30839
30846
  }
30840
30847
  return issues;
@@ -41095,7 +41102,7 @@ var init_force_unwrap2 = __esm({
41095
41102
  "use strict";
41096
41103
  init_rule();
41097
41104
  AS_FORCE_REGEX = /\bas!\s+/g;
41098
- ACCESS_FORCE_REGEX = /(?:\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
41105
+ ACCESS_FORCE_REGEX = /(?<![=!])(\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
41099
41106
  TRY_FORCE_REGEX = /\btry!\s+/g;
41100
41107
  swiftForceUnwrapRule = createRule({
41101
41108
  id: "swift/force-unwrap",
@@ -41122,7 +41129,7 @@ var init_force_unwrap2 = __esm({
41122
41129
  message: `force-unwrap (${label}) at line ${line} \u2014 crashes if the value is nil`,
41123
41130
  line,
41124
41131
  column: 1,
41125
- advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.24.'
41132
+ advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.34.10 (refined: exclude `!` in `!==`/`!=` operators via negative lookbehind).'
41126
41133
  });
41127
41134
  };
41128
41135
  let m;
@@ -41131,7 +41138,10 @@ var init_force_unwrap2 = __esm({
41131
41138
  TRY_FORCE_REGEX.lastIndex = 0;
41132
41139
  while ((m = TRY_FORCE_REGEX.exec(source)) !== null) emit(m.index, "try!");
41133
41140
  ACCESS_FORCE_REGEX.lastIndex = 0;
41134
- while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) emit(m.index, "!.");
41141
+ while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) {
41142
+ const bangOffset = m.index + (m[1]?.length ?? 1);
41143
+ emit(bangOffset, "!.");
41144
+ }
41135
41145
  return issues;
41136
41146
  }
41137
41147
  });
@@ -51714,7 +51724,7 @@ var init_signal_strength = __esm({
51714
51724
  precision: 0.0691,
51715
51725
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51716
51726
  verdict: "DORMANT",
51717
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.59 \u2014 fires 1.7x more on pre-2022 (neg) than post-2024 (pos). Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. Same direction as kotlin/sql-string-concat. 1664 total fires \u2014 Java uses ORMs (Hibernate) heavily so SQL concat is rare in both arms. defaultOff.",
51727
+ _calibrationNote: 'v0.34.9: REFINED \u2014 rule now requires the SQL keyword to be the start of a string literal (preceded by `"`, `\'`, or `=`), and tightened the SAFE_REGEX. Per-file unique v9 Java calibration (81891 neg, 10305 pos): 115 TP files, 1549 FP files, ratio=0.59 (DORMANT). 1664 total fires. The refinement is expected to push precision from 6.9% to 25%+ by removing lines where SELECT/INSERT appears in string values (e.g. `String msg = "Selected 1 row: " + count`). Also tightened SAFE_REGEX from `:??` to `:?` (the original was over-broad). The full v9 re-calibration is part of the broader v0.34.8/v0.34.9 pipeline (same pattern applied to kotlin/sql-string-concat and java/sql-string-concat). INSUFFICIENT_DATA: pos arm 10305 files, below the 10k floor. Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. defaultOff.',
51718
51728
  aiSpecific: false,
51719
51729
  _v9Verdict: "DORMANT",
51720
51730
  _v9Lift: 0.59,
@@ -51794,7 +51804,7 @@ var init_signal_strength = __esm({
51794
51804
  precision: 0.1721,
51795
51805
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51796
51806
  verdict: "DORMANT",
51797
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique measurement: 58 TP files, 279 FP files, ratio=0.48. Era-confounded: pre-2022 Swift used ! freely (the only way to unwrap); modern Swift uses guard let / if let / try?. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51807
+ _calibrationNote: "v0.34.10: REFINED \u2014 the access-force regex now uses a negative lookbehind to exclude `!` in `!=` and `!==` comparison operators. Per-file unique v9 Swift calibration (1300 neg, 568 pos): 58 TP files, 279 FP files, ratio=0.48 (DORMANT). The previous regex incorrectly fired on `!` in `a != b` and `a !== b` patterns, which are common in control flow. The refinement is expected to push precision from 17.2% to 25%+ by removing these false positives. Era-confounded: pre-2022 Swift used `!` freely (the only way to unwrap); modern Swift uses `guard let` / `if let` / `try?`. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51798
51808
  aiSpecific: true,
51799
51809
  _v7Verdict: "DORMANT",
51800
51810
  _v7Lift: 1,
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.34.8";
22
+ VERSION = "0.34.10";
23
23
  }
24
24
  });
25
25
 
@@ -30786,7 +30786,7 @@ var init_sql_string_concat = __esm({
30786
30786
  init_rule();
30787
30787
  SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
30788
30788
  UNSAFE_REGEX = /\+/;
30789
- SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?\s*,)/;
30789
+ SAFE_REGEX = /(?:PreparedStatement|setParameter|setString|setInt|setLong|createQuery.*:.*\b(?:set|bind)|:name\b|\?)/;
30790
30790
  javaSqlStringConcatRule = createRule({
30791
30791
  id: "java/sql-string-concat",
30792
30792
  category: "security",
@@ -30804,7 +30804,14 @@ var init_sql_string_concat = __esm({
30804
30804
  const lines = source.split("\n");
30805
30805
  for (let i = 0; i < lines.length; i++) {
30806
30806
  const line = lines[i];
30807
- if (!SQL_KEYWORD_REGEX.test(line)) continue;
30807
+ const keywordMatch = SQL_KEYWORD_REGEX.exec(line);
30808
+ if (!keywordMatch) continue;
30809
+ const keywordIdx = keywordMatch.index;
30810
+ let j = keywordIdx - 1;
30811
+ while (j >= 0 && /\s/.test(line[j])) j--;
30812
+ if (j < 0) continue;
30813
+ const prevChar = line[j];
30814
+ if (prevChar !== '"' && prevChar !== "'" && prevChar !== "=") continue;
30808
30815
  if (!UNSAFE_REGEX.test(line)) continue;
30809
30816
  if (SAFE_REGEX.test(line)) continue;
30810
30817
  issues.push({
@@ -30815,7 +30822,7 @@ var init_sql_string_concat = __esm({
30815
30822
  message: `SQL query built via string concat at line ${i + 1}`,
30816
30823
  line: i + 1,
30817
30824
  column: 1,
30818
- advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.30 (OWASP A03:2021).'
30825
+ advice: 'Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{} binding). String concatenation into a SQL query is the canonical SQL-injection pattern \u2014 even "trusted" inputs (signed JWT, internal config) can be influenced by an attacker. Reference: java/sql-string-concat v0.34.9 (refined: require SQL keyword to start a string literal; tightened SAFE_REGEX).'
30819
30826
  });
30820
30827
  }
30821
30828
  return issues;
@@ -41076,7 +41083,7 @@ var init_force_unwrap2 = __esm({
41076
41083
  "use strict";
41077
41084
  init_rule();
41078
41085
  AS_FORCE_REGEX = /\bas!\s+/g;
41079
- ACCESS_FORCE_REGEX = /(?:\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
41086
+ ACCESS_FORCE_REGEX = /(?<![=!])(\w|\])\!\s*(?:\.|\(|;|,|\s*$)/gm;
41080
41087
  TRY_FORCE_REGEX = /\btry!\s+/g;
41081
41088
  swiftForceUnwrapRule = createRule({
41082
41089
  id: "swift/force-unwrap",
@@ -41103,7 +41110,7 @@ var init_force_unwrap2 = __esm({
41103
41110
  message: `force-unwrap (${label}) at line ${line} \u2014 crashes if the value is nil`,
41104
41111
  line,
41105
41112
  column: 1,
41106
- advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.24.'
41113
+ advice: 'Replace with the safe form: `as?` + guard/if let, `try?` + nil-check, or `guard let x = optional else { return }` instead of `x!`. A force-unwrap converts "the value might be nil" into "the program crashes if the value is nil" \u2014 in production that is a customer-facing crash log. AI agents reach for `!` because their training-data snippets "just make it compile" without modelling the nil case. Apple SwiftLint flags every shape (force_cast / force_try / force_unwrapping). Reference: swift/force-unwrap v0.34.10 (refined: exclude `!` in `!==`/`!=` operators via negative lookbehind).'
41107
41114
  });
41108
41115
  };
41109
41116
  let m;
@@ -41112,7 +41119,10 @@ var init_force_unwrap2 = __esm({
41112
41119
  TRY_FORCE_REGEX.lastIndex = 0;
41113
41120
  while ((m = TRY_FORCE_REGEX.exec(source)) !== null) emit(m.index, "try!");
41114
41121
  ACCESS_FORCE_REGEX.lastIndex = 0;
41115
- while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) emit(m.index, "!.");
41122
+ while ((m = ACCESS_FORCE_REGEX.exec(source)) !== null) {
41123
+ const bangOffset = m.index + (m[1]?.length ?? 1);
41124
+ emit(bangOffset, "!.");
41125
+ }
41116
41126
  return issues;
41117
41127
  }
41118
41128
  });
@@ -51692,7 +51702,7 @@ var init_signal_strength = __esm({
51692
51702
  precision: 0.0691,
51693
51703
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51694
51704
  verdict: "DORMANT",
51695
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.59 \u2014 fires 1.7x more on pre-2022 (neg) than post-2024 (pos). Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. Same direction as kotlin/sql-string-concat. 1664 total fires \u2014 Java uses ORMs (Hibernate) heavily so SQL concat is rare in both arms. defaultOff.",
51705
+ _calibrationNote: 'v0.34.9: REFINED \u2014 rule now requires the SQL keyword to be the start of a string literal (preceded by `"`, `\'`, or `=`), and tightened the SAFE_REGEX. Per-file unique v9 Java calibration (81891 neg, 10305 pos): 115 TP files, 1549 FP files, ratio=0.59 (DORMANT). 1664 total fires. The refinement is expected to push precision from 6.9% to 25%+ by removing lines where SELECT/INSERT appears in string values (e.g. `String msg = "Selected 1 row: " + count`). Also tightened SAFE_REGEX from `:??` to `:?` (the original was over-broad). The full v9 re-calibration is part of the broader v0.34.8/v0.34.9 pipeline (same pattern applied to kotlin/sql-string-concat and java/sql-string-concat). INSUFFICIENT_DATA: pos arm 10305 files, below the 10k floor. Era-confounded: pre-2022 Java used JDBC string concat more; modern Java uses PreparedStatement. defaultOff.',
51696
51706
  aiSpecific: false,
51697
51707
  _v9Verdict: "DORMANT",
51698
51708
  _v9Lift: 0.59,
@@ -51772,7 +51782,7 @@ var init_signal_strength = __esm({
51772
51782
  precision: 0.1721,
51773
51783
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51774
51784
  verdict: "DORMANT",
51775
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique measurement: 58 TP files, 279 FP files, ratio=0.48. Era-confounded: pre-2022 Swift used ! freely (the only way to unwrap); modern Swift uses guard let / if let / try?. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51785
+ _calibrationNote: "v0.34.10: REFINED \u2014 the access-force regex now uses a negative lookbehind to exclude `!` in `!=` and `!==` comparison operators. Per-file unique v9 Swift calibration (1300 neg, 568 pos): 58 TP files, 279 FP files, ratio=0.48 (DORMANT). The previous regex incorrectly fired on `!` in `a != b` and `a !== b` patterns, which are common in control flow. The refinement is expected to push precision from 17.2% to 25%+ by removing these false positives. Era-confounded: pre-2022 Swift used `!` freely (the only way to unwrap); modern Swift uses `guard let` / `if let` / `try?`. Same direction as kotlin/force-unwrap (0.35) and kotlin/runblocking-misuse (0.50). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51776
51786
  aiSpecific: true,
51777
51787
  _v7Verdict: "DORMANT",
51778
51788
  _v7Lift: 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slopbrick",
3
- "version": "0.34.8",
3
+ "version": "0.34.10",
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": {