Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,20 @@
+ "[^>]*?\\breferencedTableName\\s*+=\\s*+\"(\\w++)\"");

// -- Liquibase YAML patterns (regex-based; avoids pulling in SnakeYAML here) --
// Intermediate lines use a negative-lookahead + possessive `*+` instead of reluctant `*?`:
// no backtracking (prevents SonarCloud S5998 stack-overflow / S5852 ReDoS), same
// semantics — lines that *would* match the target key are excluded from the skip group,
// so the outer match terminates exactly where the reluctant version would have.
private static final Pattern LQ_CREATE_TABLE_YAML = Pattern.compile(
"createTable\\s*+:[^\\n]*+\\n(?:\\s++[^\\n]*+\\n)*?\\s++tableName\\s*+:\\s*+([\\w\"']++)");
"createTable\\s*+:[^\\n]*+\\n"

Check warning on line 150 in src/main/java/io/github/randomcodespace/iq/detector/sql/SqlMigrationDetector.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Simplify this regular expression to reduce its complexity from 22 to the 20 allowed.

See more on https://sonarcloud.io/project/issues?id=RandomCodeSpace_code-iq&issues=AZ26-vyXPOv4nsEshjkD&open=AZ26-vyXPOv4nsEshjkD&pullRequest=61
+ "(?:(?!\\s++tableName\\s*+:)\\s++[^\\n]*+\\n)*+"
+ "\\s++tableName\\s*+:\\s*+([\\w\"']++)");
private static final Pattern LQ_ADD_FK_YAML = Pattern.compile(
"addForeignKeyConstraint\\s*+:[^\\n]*+\\n"
+ "(?:\\s++[^\\n]*+\\n)*?\\s++baseTableName\\s*+:\\s*+([\\w\"']++)[^\\n]*+\\n"
+ "(?:\\s++[^\\n]*+\\n)*?\\s++referencedTableName\\s*+:\\s*+([\\w\"']++)");
+ "(?:(?!\\s++baseTableName\\s*+:)\\s++[^\\n]*+\\n)*+"
+ "\\s++baseTableName\\s*+:\\s*+([\\w\"']++)[^\\n]*+\\n"
+ "(?:(?!\\s++referencedTableName\\s*+:)\\s++[^\\n]*+\\n)*+"
+ "\\s++referencedTableName\\s*+:\\s*+([\\w\"']++)");

// -- Flyway version parsing --
private static final Pattern FLYWAY_VERSION = Pattern.compile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,42 @@ void liquibaseYamlChangeSetDetected() {
&& e.getTarget().getId().endsWith(":invoices")));
}

@Test
void liquibaseYamlChangeSet_largeIntermediateContent_completesQuickly() {
// Regression guard for SonarCloud S5998 / S5852 on LQ_*_YAML: the reluctant-outer
// `(?:\s++[^\n]*+\n)*?` patterns were rewritten with a negative-lookahead +
// possessive outer so stack/runtime cannot blow up on many indented lines.
// Pathological input: a createTable with 500 indented column lines preceding
// tableName — the pre-fix reluctant walk would scale quadratically.
StringBuilder columns = new StringBuilder();
for (int i = 0; i < 500; i++) {
columns.append(" - column_").append(i).append(": stub_value\n");
}
String yaml = """
databaseChangeLog:
- changeSet:
id: 1
author: bob
changes:
- createTable:
"""
+ columns
+ " tableName: wide_table\n";
DetectorContext ctx = new DetectorContext(
"src/main/resources/db/db.changelog-wide.yml", "yaml", yaml);

long start = System.nanoTime();
DetectorResult result = detector.detect(ctx);
long elapsedMs = (System.nanoTime() - start) / 1_000_000;

assertTrue(hasEntity(sqlEntitiesOf(result), "wide_table", "table"),
"wide_table must still be detected after the anti-backtracking rewrite");
// 2s is 100x the observed fast-path time; we only care that it doesn't blow up
// exponentially — the exact threshold isn't load-bearing.
assertTrue(elapsedMs < 2000,
"detection of wide_table should complete in under 2s, was " + elapsedMs + "ms");
}

// -- Positive: Rails --

@Test
Expand Down
Loading