diff --git a/.tool_version b/.tool_version
index bbb75a1..f21c0ae 100644
--- a/.tool_version
+++ b/.tool_version
@@ -1 +1 @@
-1.16.1
\ No newline at end of file
+1.16.2
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 0b5831b..6f9e19a 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-ARG OPENGREP_VERSION=v1.16.1
+ARG OPENGREP_VERSION=v1.16.2
# Build codacy-opengrep wrapper
FROM golang:1.23-alpine3.21 as builder
diff --git a/docs/codacy-rules-exotic.yaml b/docs/codacy-rules-exotic.yaml
new file mode 100644
index 0000000..7a7dc1b
--- /dev/null
+++ b/docs/codacy-rules-exotic.yaml
@@ -0,0 +1,28 @@
+rules:
+ - id: codacy.generic.sql.exotic.hardcoded-sql-values
+ severity: WARNING
+ languages:
+ - generic
+ patterns:
+ - pattern-either:
+ # Complete SQL queries with hardcoded values
+ - pattern-regex: "(?i)^[^\n]*(?:SELECT|INSERT|UPDATE|DELETE|FROM)[^\n]*\\b(?:85|4322385|86|4323386|1628302)\\b"
+ - pattern-regex: "(?i)^[^\n]*(?:SELECT|INSERT|UPDATE|DELETE|FROM)[^\n]*['\"](?:IMO|CVO|SMO|US|FRC)['\"]"
+ # SQL fragments with WHERE/AND/OR and hardcoded values
+ - pattern-regex: "(?i)^[^\n]*(?:WHERE|AND|OR|SET|VALUES|IN)\\s+[^\n]*\\b(?:85|4322385|86|4323386|1628302)\\b"
+ - pattern-regex: "(?i)^[^\n]*(?:WHERE|AND|OR|SET|VALUES|IN)\\s+[^\n]*['\"](?:IMO|CVO|SMO|US|FRC)['\"]"
+ # Column assignments with hardcoded values
+ - pattern-regex: "(?i)^[^\n]*(?:org_id|organization_id|language|currency|mode)\\s*=\\s*(?:85|4322385|86|4323386|1628302)\\b"
+ - pattern-regex: "(?i)^[^\n]*(?:org_id|organization_id|language|currency|mode)\\s*=\\s*['\"](?:IMO|CVO|SMO|US|FRC)['\"]"
+ - pattern-not-regex: '^\s*(?://|--|/\*|\*)'
+ message: >-
+ Hardcoded Language, Currency, or Org_Id values detected in SQL. Avoid hardcoding such values; use parameters or configuration instead.
+ metadata:
+ category: security
+ subcategory: sql
+ description: Flags hardcoded Language, Currency, or Org_Id values in SQL queries that should be parameterized
+ technology:
+ - sql
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
\ No newline at end of file
diff --git a/docs/codacy-rules-i18n.yaml b/docs/codacy-rules-i18n.yaml
index cba4477..7d36c36 100644
--- a/docs/codacy-rules-i18n.yaml
+++ b/docs/codacy-rules-i18n.yaml
@@ -106,6 +106,242 @@ rules:
confidence: LOW
likelihood: HIGH
+ - id: codacy.js.i18n.no-hardcoded-confirm-prompt
+ severity: WARNING
+ languages:
+ - js
+ - ts
+ patterns:
+ - pattern-either:
+ - pattern: confirm("...")
+ - pattern: window.confirm("...")
+ - pattern: prompt("...")
+ - pattern: window.prompt("...")
+ - pattern-not: confirm(t(...))
+ - pattern-not: prompt(t(...))
+ message: >-
+ Avoid hardcoded strings in confirm/prompt dialogs. Use an i18n translation function (e.g., t("key")) with interpolation.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded strings in confirm/prompt dialogs to enforce localization
+ technology:
+ - javascript
+ - typescript
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.js.i18n.no-hardcoded-jsx-user-props
+ severity: WARNING
+ languages:
+ - js
+ - ts
+ patterns:
+ - pattern-either:
+ - pattern: <$EL placeholder="$STR" ... />
+ - pattern: <$EL alt="$STR" ... />
+ - pattern: <$EL aria-label="$STR" ... />
+ - pattern: <$EL label="$STR" ... />
+ - pattern: <$EL title="$STR" ... />
+ - metavariable-regex:
+ metavariable: $STR
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ message: >-
+ Avoid hardcoded strings in JSX user-facing props. Use an i18n translation function (e.g., t("key")).
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded strings in JSX props like placeholder, alt, aria-label, label, and title
+ technology:
+ - javascript
+ - typescript
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.js.i18n.no-hardcoded-console-error
+ severity: WARNING
+ languages:
+ - js
+ - ts
+ patterns:
+ - pattern: console.error("$MSG")
+ - metavariable-regex:
+ metavariable: $MSG
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ message: >-
+ Avoid hardcoded strings in console.error. Use an i18n translation function (e.g., t("key")).
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in console.error calls
+ technology:
+ - javascript
+ - typescript
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: MEDIUM
+
+ - id: codacy.js.i18n.no-hardcoded-throw-error
+ severity: WARNING
+ languages:
+ - js
+ - ts
+ patterns:
+ - pattern: throw new Error("$MSG")
+ - metavariable-regex:
+ metavariable: $MSG
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ message: >-
+ Avoid hardcoded strings in Error constructors. Use an i18n translation function (e.g., t("key")).
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in Error constructor calls
+ technology:
+ - javascript
+ - typescript
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: MEDIUM
+
+ - id: codacy.java.i18n.no-hardcoded-date-format
+ severity: WARNING
+ languages:
+ - java
+ pattern-either:
+ - pattern: new SimpleDateFormat("...")
+ - pattern: DateTimeFormatter.ofPattern("...")
+ message: >-
+ Avoid hardcoded date format patterns. Use DateTimeFormatter.ofLocalizedDate() or DateTimeFormatter.ofLocalizedDateTime() for locale-aware formatting.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded date format patterns that are not locale-aware
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: HIGH
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-decimal-format
+ severity: WARNING
+ languages:
+ - java
+ pattern-either:
+ - pattern: new DecimalFormat("...")
+ - patterns:
+ - pattern: String.format("$FMT", ...)
+ - metavariable-regex:
+ metavariable: $FMT
+ regex: '%[0-9.]*[fd]'
+ message: >-
+ Avoid hardcoded number format patterns. Use NumberFormat.getInstance(locale) or locale-aware formatting for user-visible numbers.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded decimal format patterns and String.format with numeric format specifiers
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: MEDIUM
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-exception-message
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern: throw new $EX("$MSG");
+ - metavariable-regex:
+ metavariable: $MSG
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ - pattern-not: throw new $EX($BUNDLE.getString(...));
+ message: >-
+ Avoid hardcoded strings in exception messages. Use ResourceBundle.getString() or a localization key.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in exception constructors
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-return-string
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern: return "$STR";
+ - metavariable-regex:
+ metavariable: $STR
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ - pattern-not: return $BUNDLE.getString(...);
+ message: >-
+ Avoid returning hardcoded natural language strings. Use ResourceBundle.getString() or a localization key.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings returned from methods
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-string-concat
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern-either:
+ - patterns:
+ - pattern: return "$LIT" + ...;
+ - metavariable-regex:
+ metavariable: $LIT
+ regex: '^[A-Z](?![a-z]+\[)[a-z].*'
+ - patterns:
+ - pattern: return ... + "$LIT";
+ - metavariable-regex:
+ metavariable: $LIT
+ regex: '^\s(?!.*\b(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN)\b).*[a-z]{2}'
+ - pattern-not: return $BUNDLE.getString(...) + ...;
+ message: >-
+ Avoid hardcoded strings in string concatenation for user-facing output. Use ResourceBundle.getString() with MessageFormat.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in return concatenation
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-stringbuilder-append
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern: $SB.append("$STR");
+ - metavariable-regex:
+ metavariable: $STR
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|ORDER)[^.]*\s[^.]*'
+ message: >-
+ Avoid hardcoded natural language strings in StringBuilder.append. Use ResourceBundle.getString() or MessageFormat.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in StringBuilder.append calls
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
- id: codacy.js.i18n.no-raw-jsx-text
severity: WARNING
languages:
@@ -124,4 +360,75 @@ rules:
impact: MEDIUM
confidence: LOW
likelihood: MEDIUM
-
\ No newline at end of file
+
+ - id: codacy.java.i18n.no-hardcoded-map-put
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern: $MAP.put("$KEY", "$VALUE");
+ - metavariable-regex:
+ metavariable: $VALUE
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ - pattern-not: $MAP.put("$KEY", $BUNDLE.getString(...));
+ message: >-
+ Avoid hardcoded strings in Map.put(). Use ResourceBundle.getString() or a localization key for user-facing messages.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in Map.put() calls that should be localized
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-map-of
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern-either:
+ - pattern: Map.of(..., "$VALUE", ...)
+ - pattern: Map.of("$KEY", "$VALUE")
+ - metavariable-regex:
+ metavariable: $VALUE
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ - pattern-not: Map.of(..., $BUNDLE.getString(...), ...)
+ message: >-
+ Avoid hardcoded strings in Map.of(). Use ResourceBundle.getString() or a localization key for user-facing messages.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in Map.of() calls that should be localized
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
+
+ - id: codacy.java.i18n.no-hardcoded-response-body
+ severity: WARNING
+ languages:
+ - java
+ patterns:
+ - pattern-either:
+ - pattern: ResponseEntity.ok(Map.of(..., "$VALUE", ...))
+ - pattern: ResponseEntity.status(...).body(Map.of(..., "$VALUE", ...))
+ - pattern: ResponseEntity.$METHOD(Map.of(..., "$VALUE", ...))
+ - metavariable-regex:
+ metavariable: $VALUE
+ regex: '^(?!SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|ERR)[^.]*\s[^.]*'
+ - pattern-not: ResponseEntity.ok(Map.of(..., $BUNDLE.getString(...), ...))
+ - pattern-not: ResponseEntity.status(...).body(Map.of(..., $BUNDLE.getString(...), ...))
+ message: >-
+ Avoid hardcoded strings in ResponseEntity body maps. Use ResourceBundle.getString() or a localization key for user-facing messages.
+ metadata:
+ category: codestyle
+ subcategory: i18n
+ description: Flags hardcoded natural language strings in Spring ResponseEntity responses that should be localized
+ technology:
+ - java
+ impact: MEDIUM
+ confidence: LOW
+ likelihood: HIGH
diff --git a/docs/codacy-rules.yaml b/docs/codacy-rules.yaml
index 187a6f2..e983a00 100644
--- a/docs/codacy-rules.yaml
+++ b/docs/codacy-rules.yaml
@@ -182,7 +182,7 @@ rules:
GRANT SELECT privileges should only be given to role-based accounts
(ending in '_role'). Direct grants to users or non-role accounts violate
security best practices.
- pattern-regex: GRANT\s+(DELETE|INSERT|SELECT|UPDATE)(\s*,\s*(DELETE|INSERT|SELECT|UPDATE))*\s+ON\s+[a-zA-Z0-9_]+(\.[a-zA-Z0-9_*]+)?\s+TO\s+(?![a-zA-Z0-9_]*_role\b)[a-zA-Z0-9_]+
+ pattern-regex: GRANT\s+(?:DELETE|INSERT|SELECT|UPDATE)(?:\s*,\s*(?:DELETE|INSERT|SELECT|UPDATE))*\s+ON\s+[\w.*]+\s+TO\s+(?!\w*_[Rr][Oo][Ll][Ee]\b)\b\w+
paths:
include:
- "*.sql"
@@ -303,9 +303,9 @@ rules:
- generic
patterns:
- pattern-either:
- - pattern-regex: "(?i)\\b\\w*language\\w*\\b\\s*(=|:=)\\s*'?\\b[A-Z]{2}\\b'?"
- - pattern-regex: "(?i)\\b\\w*currency\\w*\\b\\s*(=|:=)\\s*'?\\b[A-Z]{3}\\b'?"
- - pattern-regex: "(?i)\\b(\\w*\\.)?org_id\\b\\s*(=|:=|IN|!=|<>)\\s*(\\(?\\s*'?\\d+'?(,\\s*'?\\d+'?)*\\s*\\)?)?"
+ - pattern-regex: "(?i)^(?:(?!--).)*\\b\\w*language\\w*\\b\\s*(=|:=)\\s*'?\\b[A-Z]{2}\\b'?"
+ - pattern-regex: "(?i)^(?:(?!--).)*\\b\\w*currency\\w*\\b\\s*(=|:=)\\s*'?\\b[A-Z]{3}\\b'?"
+ - pattern-regex: "(?i)^(?:(?!--).)*\\b(\\w*\\.)?org_id\\b\\s*(=|:=|IN|!=|<>)\\s*(\\(?\\s*'?\\d+'?(,\\s*'?\\d+'?)*\\s*\\)?)?"
paths:
include:
- "*.sql"
diff --git a/docs/multiple-tests/exotic/patterns.xml b/docs/multiple-tests/exotic/patterns.xml
new file mode 100644
index 0000000..6b5fcb5
--- /dev/null
+++ b/docs/multiple-tests/exotic/patterns.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/docs/multiple-tests/exotic/results.xml b/docs/multiple-tests/exotic/results.xml
new file mode 100644
index 0000000..1b739b9
--- /dev/null
+++ b/docs/multiple-tests/exotic/results.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/multiple-tests/exotic/src/ExoticCode01.java b/docs/multiple-tests/exotic/src/ExoticCode01.java
new file mode 100644
index 0000000..750f0f7
--- /dev/null
+++ b/docs/multiple-tests/exotic/src/ExoticCode01.java
@@ -0,0 +1,30 @@
+public class ExoticCode01 {
+ public void example() {
+ // This is an exotic code snippet with a unique pattern
+ }
+
+
+ public String buildUserQuery(String tableName, String username) {
+ // Initialize StringBuilder with a starting capacity or initial string
+ StringBuilder query = new StringBuilder("SELECT * FROM ");
+
+ // Dynamically append parts of the query
+ query.append(tableName);
+ query.append(" WHERE status = 'ACTIVE'");
+
+ // ❌ org_id should not be hardcoded
+ query.append(" AND org_id = 85");
+ // query.append(" AND org_id = 85");
+ query.append(" AND language = 'FRC'");
+
+ if (username != null && !username.isEmpty()) {
+ query.append(" AND username = '");
+ query.append(username);
+ query.append("'");
+ }
+
+ query.append(";");
+
+ return query.toString();
+ }
+}
\ No newline at end of file
diff --git a/docs/multiple-tests/i18n/patterns.xml b/docs/multiple-tests/i18n/patterns.xml
index 823ff8c..3f7d685 100644
--- a/docs/multiple-tests/i18n/patterns.xml
+++ b/docs/multiple-tests/i18n/patterns.xml
@@ -1,7 +1,19 @@
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
diff --git a/docs/multiple-tests/i18n/results.xml b/docs/multiple-tests/i18n/results.xml
index a1bdcb0..194728d 100644
--- a/docs/multiple-tests/i18n/results.xml
+++ b/docs/multiple-tests/i18n/results.xml
@@ -45,5 +45,274 @@
message="Avoid using toFixed for user-visible number formatting."
severity="warning" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/docs/multiple-tests/i18n/src/FalsePositive.jsx b/docs/multiple-tests/i18n/src/FalsePositive.jsx
new file mode 100644
index 0000000..e25feb3
--- /dev/null
+++ b/docs/multiple-tests/i18n/src/FalsePositive.jsx
@@ -0,0 +1,280 @@
+import React from 'react';
+
+// ============================================
+// 1. JSX ELEMENT CONTENT - Should BE flagged
+// ============================================
+
+function WelcomeComponent() {
+ return (
+
+
Welcome to our application
+
Please enter your information.
+
+
Loading data from server...
+
+ );
+}
+
+// ============================================
+// 2. JSX ELEMENT CONTENT - Should NOT be flagged
+// ============================================
+
+function CorrectComponent({ userName, t }) {
+ return (
+
+
{userName}
+
{t('welcome.message')}
+
{count}
+
ID
{/* Very short technical text */}
+
+ );
+}
+
+// ============================================
+// 3. JSX USER PROPS - Should BE flagged
+// ============================================
+
+function FormComponent() {
+ return (
+
+
+
+

+
+
+
+
+
+
+ );
+}
+
+// ============================================
+// 4. JSX USER PROPS - Should NOT be flagged
+// ============================================
+
+function CorrectFormComponent({ t }) {
+ return (
+
+
+

+
+
{/* Very short */}
+
+ );
+}
+
+// ============================================
+// 5. ALERT/CONFIRM/PROMPT - Should BE flagged
+// ============================================
+
+function AlertComponent() {
+ function handleDelete() {
+ alert("Error: File not found");
+
+ if (confirm("Are you sure you want to delete?")) {
+ // delete logic
+ }
+
+ const name = prompt("Please enter your name");
+ }
+
+ return ;
+}
+
+// ============================================
+// 6. ALERT/CONFIRM/PROMPT - Should NOT be flagged
+// ============================================
+
+function CorrectAlertComponent({ t }) {
+ function handleDelete() {
+ alert(t('error.fileNotFound'));
+
+ if (confirm(t('confirm.delete'))) {
+ // delete logic
+ }
+
+ const name = prompt(t('prompt.enterName'));
+ }
+
+ return ;
+}
+
+// ============================================
+// 7. CONDITIONAL TEXT - Should BE flagged
+// ============================================
+
+function ConditionalComponent({ isOnline, count }) {
+ return (
+
+
{isOnline ? "User is online" : "User is offline"}
+
{count > 0 ? "Items available" : "Out of stock"}
+
{hasError ? "An error occurred" : "Success"}
+
+ );
+}
+
+// ============================================
+// 8. CONDITIONAL TEXT - Should NOT be flagged (technical values)
+// ============================================
+
+function ConditionalTechnicalComponent({ variant, type, position }) {
+ return (
+
+
+
+
+
+
{userId ? userId : "default_id"}
+
+
+ );
+}
+
+// ============================================
+// 9. CONSOLE.ERROR - Should BE flagged
+// ============================================
+
+function DataLoadingComponent() {
+ async function loadData() {
+ try {
+ const data = await fetch('/api/users');
+ } catch (error) {
+ console.error("Failed to load user data");
+ console.error("Authentication error occurred");
+ console.error("Network connection timeout");
+ }
+ }
+
+ return ;
+}
+
+// ============================================
+// 10. CONSOLE.ERROR - Should NOT be flagged
+// ============================================
+
+function CorrectDataLoadingComponent({ t }) {
+ async function loadData() {
+ try {
+ const data = await fetch('/api/users');
+ } catch (error) {
+ console.error(t('error.dataLoad'));
+ console.error(error); // Variable
+ console.error("ERR"); // Very short
+ }
+ }
+
+ return ;
+}
+
+// ============================================
+// 11. ERROR CONSTRUCTOR - Should BE flagged
+// ============================================
+
+function ValidationComponent() {
+ function validateUser(user) {
+ if (!user.email) {
+ throw new Error("Invalid user credentials");
+ }
+
+ if (!user.password) {
+ throw new Error("Password is required");
+ }
+
+ try {
+ // some logic
+ } catch (e) {
+ throw new Error("Network request failed");
+ }
+ }
+
+ return ;
+}
+
+// ============================================
+// 12. ERROR CONSTRUCTOR - Should NOT be flagged
+// ============================================
+
+function CorrectValidationComponent({ t }) {
+ function validateUser(user) {
+ if (!user.email) {
+ throw new Error(t('error.invalidCredentials'));
+ }
+
+ if (!user.password) {
+ throw new Error(t('error.passwordRequired'));
+ }
+
+ // Very short technical error
+ throw new Error("ERR01");
+ }
+
+ return ;
+}
+
+// ============================================
+// 13. NUMBER FORMATTING - Should BE flagged
+// ============================================
+
+function PriceComponent({ price, quantity }) {
+ return (
+
+
Price: ${price.toFixed(2)}
+
Quantity: {quantity.toLocaleString()}
+
Total: ${(price * quantity).toFixed(2)}
+
{Number(price).toLocaleString()}
+
+ );
+}
+
+// ============================================
+// 14. NUMBER FORMATTING - Should NOT be flagged
+// ============================================
+
+function CorrectPriceComponent({ price, t }) {
+ const formatter = new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ });
+
+ return (
+
+
{formatter.format(price)}
+
{t('price', { value: price })}
+
{price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}
+
+ );
+}
+
+// ============================================
+// 15. MIXED EXAMPLES - Should BE flagged
+// ============================================
+
+function ComplexComponent({ user, count }) {
+ const handleSave = () => {
+ if (count === 0) {
+ alert("No items to save");
+ return;
+ }
+
+ try {
+ // save logic
+ console.log("Saved successfully");
+ } catch (error) {
+ console.error("Failed to save data");
+ throw new Error("Save operation failed");
+ }
+ };
+
+ return (
+
+
Welcome back, {user.name}!
+
{count > 0 ? "You have items" : "Cart is empty"}
+
+
+
Total: ${user.balance.toFixed(2)}
+
+ );
+}
+
+export default ComplexComponent;
diff --git a/docs/multiple-tests/i18n/src/Javai18nPotentialsIssues.java b/docs/multiple-tests/i18n/src/Javai18nPotentialsIssues.java
new file mode 100644
index 0000000..e89c90a
--- /dev/null
+++ b/docs/multiple-tests/i18n/src/Javai18nPotentialsIssues.java
@@ -0,0 +1,554 @@
+package examples;
+
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.time.format.DateTimeFormatter;
+import java.util.ResourceBundle;
+
+/**
+ * Test file for Java i18n Semgrep rules
+ * Each section tests a specific rule with both positive (should flag)
+ * and negative (should NOT flag) test cases
+ */
+public class JavaI18nTest {
+
+ private ResourceBundle bundle = ResourceBundle.getBundle("messages");
+
+ // ============================================
+ // 1. HARDCODED RETURN STRING - Should BE flagged
+ // ============================================
+
+ public String getUserStatus() {
+ return "Invalid username or password";
+ }
+
+ public String getEmailError() {
+ return "Please enter a valid email";
+ }
+
+ public String getSuccessMessage() {
+ return "Your account has been created successfully.";
+ }
+
+ public String getWelcomeText() {
+ return "Welcome to our platform!";
+ }
+
+ // ============================================
+ // 2. HARDCODED RETURN STRING - Should NOT be flagged
+ // ============================================
+
+ public String getI18nMessage() {
+ return bundle.getString("error.login.invalid");
+ }
+
+ public String getPropertyKey() {
+ return "user.email.validation";
+ }
+
+ public String getSqlQuery() {
+ return "SELECT * FROM users WHERE email = ?";
+ }
+
+ public String getToString() {
+ return "User[id=" + id + ", name=" + name + "]";
+ }
+
+ public String getTechnicalId() {
+ return "user_session_id";
+ }
+
+ public String getEmptyString() {
+ return "";
+ }
+
+ // ============================================
+ // 3. STRING CONCATENATION - Should BE flagged
+ // ============================================
+
+ public String getUserGreeting(String userName) {
+ return "Hello, " + userName;
+ }
+
+ public String getItemCount(int count) {
+ return count + " items selected";
+ }
+
+ public String getWelcomeMessage(String name) {
+ return "Welcome back, " + name + "!";
+ }
+
+ public String getErrorWithDetails(String detail) {
+ return "Error occurred: " + detail;
+ }
+
+ // ============================================
+ // 4. STRING CONCATENATION - Should NOT be flagged
+ // ============================================
+
+ public String getI18nConcatenation(String userName) {
+ return bundle.getString("greeting.hello") + userName;
+ }
+
+ public String getSqlWithParam(String table) {
+ return "SELECT * FROM " + table + " WHERE active = 1";
+ }
+
+ public String getKeyPath(String module) {
+ return "error." + module + ".invalid";
+ }
+
+ public String getToStringConcat() {
+ return "Order[id=" + orderId + ", total=" + total + "]";
+ }
+
+ // ============================================
+ // 5. STRINGBUILDER APPEND - Should BE flagged
+ // ============================================
+
+ public String buildMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("The process has completed successfully.");
+ return sb.toString();
+ }
+
+ public String buildErrorMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Error: Invalid input provided.");
+ sb.append("Please check your data and try again.");
+ return sb.toString();
+ }
+
+ public String buildNotification() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Your order has been shipped.");
+ return sb.toString();
+ }
+
+ // ============================================
+ // 6. STRINGBUILDER APPEND - Should NOT be flagged
+ // ============================================
+
+ public String buildSqlQuery() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT u.id, u.name ");
+ sb.append("FROM users u ");
+ sb.append("WHERE u.active = ? ");
+ sb.append("ORDER BY u.created_date DESC");
+ return sb.toString();
+ }
+
+ public String buildHql() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("FROM Order o ");
+ sb.append("JOIN o.customer c ");
+ sb.append("WHERE o.status = :status");
+ return sb.toString();
+ }
+
+ public String buildTechnicalString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("user_");
+ sb.append(userId);
+ sb.append("_session");
+ return sb.toString();
+ }
+
+ // ============================================
+ // 7. DATE FORMATS - Should BE flagged
+ // ============================================
+
+ public SimpleDateFormat getDateFormatter1() {
+ return new SimpleDateFormat("MM/dd/yyyy");
+ }
+
+ public SimpleDateFormat getDateFormatter2() {
+ return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
+ }
+
+ public DateTimeFormatter getDateFormatter3() {
+ return DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ }
+
+ public DateTimeFormatter getDateFormatter4() {
+ return DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
+ }
+
+ // ============================================
+ // 8. DATE FORMATS - Should NOT be flagged
+ // ============================================
+
+ public DateTimeFormatter getLocalizedDateFormatter() {
+ return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
+ }
+
+ public DateTimeFormatter getLocalizedDateTimeFormatter() {
+ return DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT);
+ }
+
+ // Comment with date format: "MM/dd/yyyy" - should not be flagged
+
+ // ============================================
+ // 9. NUMBER FORMATS - Should BE flagged
+ // ============================================
+
+ public DecimalFormat getNumberFormatter1() {
+ return new DecimalFormat("#,##0.00");
+ }
+
+ public DecimalFormat getNumberFormatter2() {
+ return new DecimalFormat("0.00");
+ }
+
+ public String formatPrice(double price) {
+ return String.format("%.2f", price);
+ }
+
+ public String formatPercentage(double value) {
+ return String.format("%.1f%%", value);
+ }
+
+ // ============================================
+ // 10. NUMBER FORMATS - Should NOT be flagged
+ // ============================================
+
+ public String getFormattedNumber(double value) {
+ NumberFormat formatter = NumberFormat.getInstance(locale);
+ return formatter.format(value);
+ }
+
+ // Comment with format: "#,##0.00" - should not be flagged
+
+ // ============================================
+ // 11. VALIDATION MESSAGE - Should BE flagged
+ // ============================================
+
+ public String validateEmail(String email) {
+ if (email == null || !email.contains("@")) {
+ return "Please enter a valid email address";
+ }
+ return null;
+ }
+
+ public String validatePassword(String password) {
+ if (password.length() < 8) {
+ return "Password must be at least 8 characters long";
+ }
+ return null;
+ }
+
+ public String validateAge(int age) {
+ if (age < 18) {
+ return "You must be at least 18 years old";
+ }
+ return null;
+ }
+
+ // ============================================
+ // 12. VALIDATION MESSAGE - Should NOT be flagged
+ // ============================================
+
+ public String validateEmailCorrect(String email) {
+ if (email == null || !email.contains("@")) {
+ return bundle.getString("validation.email.invalid");
+ }
+ return null;
+ }
+
+ public String validateWithKey(String password) {
+ if (password.length() < 8) {
+ return "error.password.tooShort";
+ }
+ return null;
+ }
+
+ public String validateWithSql() {
+ return "SELECT COUNT(*) FROM users WHERE email = ?";
+ }
+
+ // ============================================
+ // 13. ERROR MESSAGE - Should BE flagged
+ // ============================================
+
+ public String handleError1() {
+ return "Error: Unable to process request";
+ }
+
+ public String handleError2() {
+ return "Invalid username format";
+ }
+
+ public String handleError3() {
+ return "Please try again later";
+ }
+
+ public String handleWarning() {
+ return "Warning: This action cannot be undone";
+ }
+
+ // ============================================
+ // 14. ERROR MESSAGE - Should NOT be flagged
+ // ============================================
+
+ public String handleErrorCorrect() {
+ return bundle.getString("error.processing.failed");
+ }
+
+ public String getErrorKey() {
+ return "error.authentication.invalid";
+ }
+
+ public String getErrorCode() {
+ return "ERR_401";
+ }
+
+ // ============================================
+ // 15. EXCEPTION MESSAGE - Should BE flagged
+ // ============================================
+
+ public void throwException1() {
+ throw new IllegalArgumentException("Invalid input provided");
+ }
+
+ public void throwException2() {
+ throw new RuntimeException("Operation failed");
+ }
+
+ public void throwException3() {
+ throw new IllegalStateException("User is not authenticated");
+ }
+
+ public void throwException4() {
+ if (data == null) {
+ throw new NullPointerException("Data cannot be null");
+ }
+ }
+
+ // ============================================
+ // 16. EXCEPTION MESSAGE - Should NOT be flagged
+ // ============================================
+
+ public void throwExceptionCorrect1() {
+ throw new IllegalArgumentException(bundle.getString("error.invalid.input"));
+ }
+
+ public void throwExceptionCorrect2() {
+ throw new RuntimeException("error.operation.failed");
+ }
+
+ public void throwExceptionCorrect3(Exception e) {
+ throw new RuntimeException(e); // Exception as cause, no message
+ }
+
+ public void throwExceptionCorrect4() {
+ throw new IllegalArgumentException("ERR_500");
+ }
+
+ // ============================================
+ // 17. GREETING MESSAGE - Should BE flagged
+ // ============================================
+
+ public String getGreeting1() {
+ return "Welcome to our application";
+ }
+
+ public String getGreeting2() {
+ return "Dear Customer";
+ }
+
+ public String getGreeting3() {
+ return "Hello, thank you for visiting";
+ }
+
+ public String getGreeting4() {
+ return "Hi there!";
+ }
+
+ public String getGreeting5() {
+ return "Greetings from our team";
+ }
+
+ public String getGreeting6() {
+ return "Congratulations on your purchase";
+ }
+
+ // ============================================
+ // 18. GREETING MESSAGE - Should NOT be flagged
+ // ============================================
+
+ public String getGreetingCorrect() {
+ return bundle.getString("greeting.welcome");
+ }
+
+ // Comment: "Welcome to the system" - should not be flagged
+
+ public void logTest() {
+ // Test data: "Dear Test User"
+ System.out.println("Running test");
+ }
+
+ public void throwHibernateException() {
+ // Should NOT flag "Hi" in "HibernateException"
+ throw new HibernateException("Database connection error");
+ }
+
+ // ============================================
+ // 19. MEASUREMENT UNITS - Should BE flagged
+ // ============================================
+
+ public String getWeight(double weight) {
+ return weight + " lbs";
+ }
+
+ public String getDistance(double distance) {
+ return distance + " miles";
+ }
+
+ public String getHeight(double height) {
+ return height + " inches";
+ }
+
+ public String getVolume(double volume) {
+ return volume + " gallons";
+ }
+
+ public String getMetricWeight(double weight) {
+ return weight + " kg";
+ }
+
+ public String getMetricDistance(double distance) {
+ return distance + " km";
+ }
+
+ public String getMetricHeight(double height) {
+ return height + " cm";
+ }
+
+ public String getMetricVolume(double volume) {
+ return volume + " liters";
+ }
+
+ // ============================================
+ // 20. MEASUREMENT UNITS - Should NOT be flagged
+ // ============================================
+
+ public String getWeightCorrect(double weight, String unit) {
+ return MessageFormat.format(
+ bundle.getString("measurement.weight"),
+ weight,
+ unit
+ );
+ }
+
+ // Comment: "Weight: 150 lbs" - should not be flagged
+
+ // ============================================
+ // 21. PLURALIZATION - Should BE flagged
+ // ============================================
+
+ public String getItemCount1(int count) {
+ if (count == 1) {
+ return "1 item";
+ } else {
+ return count + " items";
+ }
+ }
+
+ public String getFileCount(int count) {
+ if (count == 1) {
+ return "1 file selected";
+ } else {
+ return count + " files selected";
+ }
+ }
+
+ public String getUserCount(int count) {
+ if (count == 1) {
+ return "1 user online";
+ } else {
+ return count + " users online";
+ }
+ }
+
+ // ============================================
+ // 22. PLURALIZATION - Should NOT be flagged
+ // ============================================
+
+ public String getItemCountCorrect(int count) {
+ MessageFormat mf = new MessageFormat(bundle.getString("items.count"));
+ return mf.format(new Object[]{count});
+ }
+
+ public String getFileCountCorrect(int count) {
+ return MessageFormat.format(
+ bundle.getString("files.selected"),
+ count
+ );
+ }
+
+ public int getTechnicalCount(int count) {
+ // Technical counting, not display
+ if (count == 1) {
+ return 1;
+ } else {
+ return count;
+ }
+ }
+
+ // ============================================
+ // 23. MIXED EXAMPLES - Should BE flagged
+ // ============================================
+
+ public String processOrder(String customerName, int itemCount, double total) {
+ StringBuilder message = new StringBuilder();
+
+ // Multiple issues in one method
+ message.append("Hello, " + customerName + "!"); // Concatenation
+
+ if (itemCount == 1) {
+ message.append("You have 1 item in your cart."); // Pluralization
+ } else {
+ message.append("You have " + itemCount + " items in your cart."); // Pluralization + Concatenation
+ }
+
+ message.append("Total: $" + String.format("%.2f", total)); // Number format
+
+ if (total > 100) {
+ message.append("Congratulations! You qualify for free shipping."); // Greeting + hardcoded
+ }
+
+ return message.toString();
+ }
+
+ public String validateAndFormat(String email, double price, int quantity) {
+ // Validation message
+ if (email == null || !email.contains("@")) {
+ return "Error: Please provide a valid email address";
+ }
+
+ // Number formatting
+ DecimalFormat df = new DecimalFormat("#,##0.00");
+ String formattedPrice = df.format(price);
+
+ // String concatenation with measurement
+ return "Order total: " + formattedPrice + " for " + quantity + " kg";
+ }
+
+ public void validateUserInput(String username, int age) {
+ // Exception messages
+ if (username == null || username.isEmpty()) {
+ throw new IllegalArgumentException("Username cannot be empty");
+ }
+
+ if (age < 18) {
+ throw new IllegalStateException("User must be at least 18 years old");
+ }
+
+ // Date formatting
+ SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
+ String dateStr = sdf.format(new Date());
+
+ // Return with greeting
+ System.out.println("Welcome " + username + ", registered on " + dateStr);
+ }
+}
diff --git a/docs/multiple-tests/i18n/src/OrderController.java b/docs/multiple-tests/i18n/src/OrderController.java
index 135b18b..be03cd4 100644
--- a/docs/multiple-tests/i18n/src/OrderController.java
+++ b/docs/multiple-tests/i18n/src/OrderController.java
@@ -1,5 +1,8 @@
// OrderController.java (excerpt with intentional i18n gaps)
+public class OrderController {
+
+
@PostMapping
public ResponseEntity> createOrder(@Valid @RequestBody Order order) {
order.setId(idGen.incrementAndGet());
@@ -28,3 +31,4 @@ public ResponseEntity> updateOrder(@PathVariable Long id, @Valid @RequestBody
// ❌ Hardcoded error message
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", "Order not found"));
}
+}
\ No newline at end of file
diff --git a/internal/docgen/parsing.go b/internal/docgen/parsing.go
index ef7cf09..d8ca208 100644
--- a/internal/docgen/parsing.go
+++ b/internal/docgen/parsing.go
@@ -121,6 +121,7 @@ func getCodacyRules(docsDir string) (*ParsedSemgrepRules, error) {
"codacy-rules.yaml",
"codacy-rules-i18n.yaml",
"codacy-rules-ai.yaml",
+ "codacy-rules-exotic.yaml",
}
for _, file := range customRulesFiles {
filePath, _ := filepath.Abs(path.Join(docsDir, file))
diff --git a/internal/tool/command.go b/internal/tool/command.go
index 5a1dc04..299176e 100644
--- a/internal/tool/command.go
+++ b/internal/tool/command.go
@@ -87,7 +87,7 @@ func createCommandParameters(language string, configurationFile *os.File, filesT
"--taint-intrafile",
//"--pro",
//"--error-recovery",
- "--max-memory", "2560",
+ "--max-memory", "5000",
//"-j", strconv.Itoa(runtime.NumCPU()),
//"-fast",
// adding pro features