Skip to content

chore/plugin-wide-review: apply plugin-wide code-review findings (T1+T2+T3)#30

Merged
vedanthvdev merged 1 commit intomasterfrom
chore/plugin-wide-review
Apr 22, 2026
Merged

chore/plugin-wide-review: apply plugin-wide code-review findings (T1+T2+T3)#30
vedanthvdev merged 1 commit intomasterfrom
chore/plugin-wide-review

Conversation

@vedanthvdev
Copy link
Copy Markdown
Owner

Why this PR exists

A four-reviewer sweep (correctness, security, maintainability, simplicity) ran against the plugin source tree as it landed in v1.9.18. Ten findings were triaged into three tiers; all ten ship here so v1.9.19 carries the security-critical, correctness, and polish fixes together instead of dribbling them out over three releases.

A re-review by the code-reviewer subagent ran against the staged diff before push; its two tier-2 findings (two missed log-sanitisation sites, C1 control range not covered) are applied in the same commit. Tier-3 polish suggestions (deep-copy of the subtype-closure map, joinSanitized null-tolerance, Locale.ROOT on hex formatting, CHANGELOG rewording) are folded in too.

Tier 1 — safety-critical

  • TransitiveStrategy no longer drops consumer tests when a production class is deleted. git rm FooService.java MRs were silently losing coverage on every consumer of FooService because the reverse-dependency map was built from on-disk files only. Fix unions changedProductionClasses into allKnownFqns.
  • SourceFileScanner rejects symlinks whose real path escapes the project root. Closes both a DoS (walking /) and an information-leak surface (.java filenames flowing into --explain / WARN).
  • New LogSanitizer escapes C0 + DEL + C1 control characters. Every filename-derived log site — four total: --explain sample, engine unmapped-file WARN, AffectedTestTask malformed-FQN WARN, engine per-test INFO — now routes through it. A hostile MR can no longer forge plugin log lines or hide real warnings behind ANSI escapes.
  • AffectedTestsConfig#effectiveMode() always returns a concrete Mode. Previously returned null for zero-config callers despite a Javadoc contract promising LOCAL/CI/STRICT; downstream switches that followed the docs NPE'd.
  • OutOfScopeMatchers literal branch now matches exact directory paths. ProjectIndex relativises without a trailing slash; that was the exact shape the matcher was missing, so literal entries silently leaked tests into discovery.

Tier 2 — correctness gaps that silently dropped tests

  • UsageStrategy now selects tests that reference the changed class via inner-class imports (import x.Outer.Inner) and static imports (import static x.Constants.MAX, including the wildcard form).
  • ImplementationStrategy now performs a fixpoint subtype-closure walk, bounded by transitiveDepth as a sanity cap. Given A ← B ← C, the single-pass walk stopped at B and silently dropped CTest; the grandchild is now discovered.

Tier 3 — polish in adjacent code

  • PathToClassMapper rejects path-traversal segments (..) in diff input (segment-aware, not substring) and routes them to the unmapped bucket at debug level so a hostile diff cannot flood the build log.
  • AffectedTestsConfig baseRef validation is now JGit-native — delegates to Repository.isValidRefName plus a SHA/rev-expression whitelist, dropping the brittle contains(\"..\") rule.
  • Deleted dead PathToClassMapper#extractModule and its three unit tests. No in-tree caller.
  • LogSanitizer gained null-tolerance on joinSanitized and Locale.ROOT on its hex format. ImplementationStrategy deep-copies its simple-name-to-FQN map so fixpoint mutations can't leak.

Test coverage added

  • `TransitiveStrategyTest#discoversConsumerTestsForDeletedProductionClass`
  • `SourceFileScannerTest#rejectsSymlinkEscapingProjectRoot` + `acceptsSymlinkThatStaysInsideProjectRoot`
  • `LogSanitizerTest` — 11 cases covering C0, DEL, C1, null, and the join helper
  • `AffectedTestsConfigTest#effectiveModeIsAlwaysConcreteForZeroConfigCallers` + `baseRefRejectsRefnameSlurGarbage`
  • `OutOfScopeMatchersTest#literalEntryMatchesExactDirectoryPath`
  • `UsageStrategyTest` — three cases for inner-class, static single, static wildcard
  • `ImplementationStrategyTest#findsGrandchildImplementationThroughMultiLevelHierarchy`
  • `PathToClassMapperTest#rejectsPathsWithTraversalSegmentAsUnmapped` + `allowsLegitimateFilenamesThatContainDotDotSubstring`

Verification

  • `./gradlew check` — green (unit + functional tests)
  • code-reviewer subagent re-review — no Tier-1 findings; all Tier-2 applied; cheap Tier-3 polish applied

Behaviour for users

No API or default-value changes. All fixes either close a latent bug or tighten a boundary that was documented-but-not-enforced. The only operator-visible difference is log output: filenames with control characters now show as \\n / \\x1B etc. instead of corrupting the log line.

…T2+T3)

A four-reviewer sweep (correctness, security, maintainability, simplicity)
against the plugin source tree as it landed in v1.9.18 surfaced ten
actionable findings. This PR lands all of them in a single change so
v1.9.19 carries the security-critical, correctness, and polish fixes
together.

Tier 1 — safety-critical:
  * TransitiveStrategy no longer drops consumer tests when a production
    class is deleted by the MR (`git rm FooService.java` MRs were
    silently losing coverage on every consumer).
  * SourceFileScanner now rejects symlinks whose real path escapes the
    project root, closing both a DoS (walking `/`) and an information-
    leak surface (`.java` filenames flowing into --explain / WARN).
  * New LogSanitizer escapes C0 + DEL + C1 control characters; every
    filename-derived log site (four total: --explain sample, engine
    unmapped-file WARN, AffectedTestTask malformed-FQN WARN, engine
    per-test INFO) now routes through it so a hostile MR cannot forge
    log lines or hide real warnings with ANSI escapes.
  * AffectedTestsConfig#effectiveMode() now always returns a concrete
    Mode (falls back to Builder.detectMode()), matching the Javadoc
    contract that downstream switches depend on.
  * OutOfScopeMatchers literal branch now matches path.equals(bare) and
    path.endsWith("/" + bare) — ProjectIndex relativises paths without
    a trailing slash, which was exactly the shape the matcher was
    missing.

Tier 2 — correctness gaps that silently dropped tests:
  * UsageStrategy now selects tests that reference the changed class
    via inner-class imports (import x.Outer.Inner) or static imports
    (import static x.Constants.MAX), including the wildcard form.
  * ImplementationStrategy now performs a fixpoint subtype-closure
    walk bounded by transitiveDepth, so grandchildren of a changed
    interface (A <- B <- C) are discovered and C's tests run when A
    changes.

Tier 3 — polish in adjacent code:
  * PathToClassMapper rejects path-traversal segments (`..`) in diff
    input (segment-aware, not substring) and routes them to the
    unmapped bucket at debug level.
  * AffectedTestsConfig baseRef validation now delegates to JGit's
    Repository.isValidRefName plus a SHA/rev-expression whitelist,
    replacing the brittle `contains("..")` rule.
  * Deleted dead PathToClassMapper#extractModule + its 3 unit tests;
    the method had no in-tree caller.
  * LogSanitizer gained null-tolerance on joinSanitized and
    Locale.ROOT on its hex format; ImplementationStrategy deep-copies
    its simple-name-to-FQN map so fixpoint mutations can't leak.

CHANGELOG entry describes every listed fix and the behaviour change for
operators. ./gradlew check passes (unit + functional).
@vedanthvdev vedanthvdev merged commit 6ab3742 into master Apr 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant