Skip to content

fix(sonar): repair quality gate baseline and clear new-code issues#103

Merged
cevheri merged 2 commits into
mainfrom
fix/quality-gate
Jun 29, 2026
Merged

fix(sonar): repair quality gate baseline and clear new-code issues#103
cevheri merged 2 commits into
mainfrom
fix/quality-gate

Conversation

@cevheri

@cevheri cevheri commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Problem

The SonarCloud quality gate on main is failing:

Condition Threshold Actual
new_reliability_rating ≤ A D
new_security_rating ≤ A C

Root cause

sonar.projectVersion was hardcoded to 0.6.38 in sonar-project.properties while the package is at 0.9.35. With the "previous_version" new-code definition, the baseline was frozen at 0.6.18 (Feb 2026), so ~4 months of code counted as "new" and surfaced pre-existing issues against the gate. Left unfixed it keeps degrading, since the version string never changes.

Changes

Config

  • Stop hardcoding sonar.projectVersion. CI now injects it from package.json (-Dsonar.projectVersion=<version>) so the new-code baseline resets at every release. Kept in ci.yml (not a separate workflow) so the Sonar job keeps consuming the coverage artifact from the test job. Mirrors the proven libredb-database pattern.
  • Suppress S2245 for TestDataGenerator only: Math.random there generates fake sample rows (names, addresses, lorem ipsum), not security/crypto material. Documented false positive, scoped to the one file.

Code (real technical debt surfaced by the gate)

  • diff-engine (S2871 + latent mutation bug): the old idx.columns.sort() sorted the array in place, corrupting the original column order later rendered in diff messages. Now sorts a copy with localeCompare for the map key while preserving display order.
  • PivotTable (S2871): localeCompare comparator for column keys.
  • SchemaDiagram (S3923): removed the tautological stroke ternary that returned the same colour in both branches (highlight is already conveyed by strokeWidth + opacity).
  • S1082 × 12: added keyboard activation to clickable non-interactive elements across the results grid, schema explorer, tab bar, charts, snapshot timeline, saved queries, and import modal. New activateOnKey helper keeps it DRY; the saved-charts menu item uses Radix onSelect; the import dropzone uses an inline handler (ref access trips the React Compiler through the helper).
  • Removed a dead Button import in TableItem.

Verification

Ran the full pre-commit suite locally — all pass:

format · lint (oxlint + ESLint) · typecheck · knip · build · build:lib · attw · test (18 groups, 486 tests)

Note on the gate

The main gate turns fully green once this merges and main is re-analyzed at version 0.9.35 (the baseline resets at that point). The PR analysis itself only removes issues, so the PR gate passes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to restore SonarCloud quality gate health on main by fixing the “previous_version” baseline behavior (injecting the current package version at scan time instead of hardcoding it) and addressing/mitigating newly surfaced “new code” issues (deterministic sorting and keyboard accessibility for clickable non-interactive elements).

Changes:

  • Remove hardcoded sonar.projectVersion and inject it via GitHub Actions during the SonarCloud scan; add a narrowly-scoped rule suppression for typescript:S2245 in TestDataGenerator.
  • Fix in-place sort/mutation in schema diff index comparison by sorting copies with a comparator.
  • Add keyboard activation support to multiple clickable non-interactive UI elements via a shared activateOnKey helper (plus a targeted inline handler in the import dropzone) and adjust a few related UI behaviors.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/lib/schema-diff/diff-engine.ts Avoid in-place mutation when sorting index column sets by sorting copies with a comparator.
src/lib/a11y.ts Introduce activateOnKey helper to mirror click activation via keyboard for non-interactive elements.
src/components/VisualExplain.tsx Add keyboard activation for expandable plan nodes.
src/components/studio/StudioTabBar.tsx Add keyboard activation to tab selection elements.
src/components/SnapshotTimeline.tsx Add keyboard activation for snapshot selection elements.
src/components/SchemaDiagram.tsx Simplify a tautological stroke ternary and clarify intent in comments.
src/components/schema-explorer/TableItem.tsx Remove unused import and add keyboard activation for table item toggling.
src/components/SavedQueries.tsx Add keyboard activation for saved-query selection rows.
src/components/ResultsGrid.tsx Add keyboard activation for sortable headers and (mobile) row selection; stop propagation for key events in filter/editing UI.
src/components/results-grid/ResultCard.tsx Add keyboard activation for result-card selection.
src/components/PivotTable.tsx Use a comparator when sorting pivot column keys.
src/components/DataImportModal.tsx Add keyboard activation to the upload dropzone (inline handler due to compiler/ref constraints).
src/components/DataCharts.tsx Use Radix onSelect for saved chart menu activation and remove nested click handler.
sonar-project.properties Stop hardcoding sonar.projectVersion; add scoped suppression for typescript:S2245 on TestDataGenerator.
.github/workflows/ci.yml Resolve package version in CI and pass it to SonarCloud scanner args.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/ci.yml
Comment on lines +195 to +197
- name: Resolve project version
id: pkg
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
Comment thread src/lib/a11y.ts Outdated
Comment on lines +12 to +19
export function activateOnKey<T extends HTMLElement = HTMLElement>(handler: () => void) {
return (event: KeyboardEvent<T>) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handler();
}
};
}
Comment thread src/lib/schema-diff/diff-engine.ts Outdated
Comment on lines +82 to +85
// Build a stable map key from the column set. Copy before sorting so the
// original column order is preserved for the diff messages below, and use
// localeCompare for a deterministic, locale-aware ordering.
const columnKey = (idx: IndexSchema) => idx.name || [...idx.columns].sort((a, b) => a.localeCompare(b)).join(",");
Comment thread src/lib/schema-diff/diff-engine.ts Outdated
const changes: string[] = [];
const sourceColStr = sourceIdx.columns.sort().join(",");
const targetColStr = targetIdx.columns.sort().join(",");
const sortedJoin = (cols: string[]) => [...cols].sort((a, b) => a.localeCompare(b)).join(",");
Comment thread src/components/DataImportModal.tsx Outdated
Comment on lines +315 to +322
onKeyDown={(e) => {
// Inlined (not activateOnKey) so the compiler sees this as a
// deferred event handler and allows the ref access.
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
fileInputRef.current?.click();
}
}}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/ci.yml
Comment on lines +195 to +197
- name: Resolve project version
id: pkg
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
The SonarCloud quality gate failed on main with new_reliability_rating=D
and new_security_rating=C. Root cause: sonar.projectVersion was hardcoded
to 0.6.38 while the package is at 0.9.35, so the "previous_version"
new-code baseline was frozen at 0.6.18 (Feb 2026). Months of code counted
as "new", surfacing pre-existing issues against the gate.

Config:
- Stop hardcoding sonar.projectVersion; CI now injects it from package.json
  so the new-code baseline resets at every release (mirrors libredb-database).
- Suppress S2245 for TestDataGenerator only: Math.random there produces fake
  sample rows, not security/crypto material (documented false positive).
- Suppress S2871 for diff-engine only: its .sort() calls build internal
  canonical keys for index-column SETS (equality matching), which must be
  deterministic and locale-independent. The default code-point sort is correct
  here; localeCompare would tie the key to the host locale.

Code (real bugs surfaced by the gate):
- diff-engine: sort index columns on a copy (was an in-place .sort() that
  mutated idx.columns, corrupting the column order shown in diff messages).
- PivotTable: localeCompare comparator for user-facing column keys (S2871).
- SchemaDiagram: drop the tautological stroke ternary that returned the same
  colour in both branches (S3923).
- DataCharts: move the saved-chart click from a non-interactive <span> to the
  Radix menu item's onSelect, which is keyboard-accessible (S1082).

The broader S1082 keyboard-accessibility cleanup is deferred to a focused
follow-up: fixing it via role="button" trades a minor bug for a major
maintainability smell (S6819), and the correct per-component fix deserves
its own PR.

Verified locally: format, lint, typecheck, knip, build, build:lib, attw,
and the full test suite (486 tests) all pass.
@cevheri cevheri force-pushed the fix/quality-gate branch from bff90da to 9109615 Compare June 29, 2026 08:46
@sonarqubecloud

Copy link
Copy Markdown

@cevheri cevheri merged commit 9f6f17c into main Jun 29, 2026
11 checks passed
@cevheri cevheri deleted the fix/quality-gate branch June 29, 2026 09:01
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.

2 participants