Skip to content

Add repository-wide safeguards to prevent Material UI v4 reintroduction - #4847

Open
lokanandaprabhu wants to merge 10 commits into
redhat-developer:mainfrom
lokanandaprabhu:feat/mui-v4-enforcement
Open

lokanandaprabhu wants to merge 10 commits into
redhat-developer:mainfrom
lokanandaprabhu:feat/mui-v4-enforcement

Conversation

@lokanandaprabhu

@lokanandaprabhu lokanandaprabhu commented Sep 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Added a centralized eslint.frontend-shared.cjs at the repo root to block @material-ui/* imports (and deprecated @mui/styles) with guidance to use @mui/*, Backstage UI, or Canon.
  • Updated 13 migrated workspaces to re-export the shared root config via workspace-level eslint.frontend-shared.cjs wrappers.
  • Wired MUI v4 ESLint rules to migrated frontend UI plugins only (~21 plugins). packages/app was reverted to default eslint-factory; packages/app-legacy has no shared ESLint config (legacy quarantine).
  • Added scripts/ci/verify-no-material-ui-v4.js as the CI policy gate, backed by scripts/ci/material-ui-v4-policy.json (explicit migratedWorkspaces list + allowlist exceptions).
  • Added a Repository-wide checks (verify-repo) job in CI and yarn verify:no-material-ui-v4 for local validation.
  • Updated the workspace scaffolding template so new workspaces get the shared ESLint wrapper automatically.

Enforcement model

Layer Scope Purpose
verify-no-material-ui-v4.js Workspaces in material-ui-v4-policy.json CI contract — scans package.json deps and source imports
ESLint frontend-shared Migrated frontend plugins Local dev feedback (no-restricted-imports)
repo lint --since origin/main Changed packages General incremental lint (not sufficient alone for MUI v4)

Policy config (scripts/ci/material-ui-v4-policy.json)

  • migratedWorkspaces: explicit list of 13 UI-team migrated workspaces (single source of truth for verify scope)
  • allowedPackageJsonPaths: temporary exceptions for workspaces still migrating (konflux, x2a, dcm, augment, cost-management, mcp-integrations, extensions app-legacy, theme mui4-test, etc.)
  • allowedSourcePathPrefixes: allowlisted legacy source paths (e.g. extensions/packages/app-legacy/, theme/plugins/mui4-test/)

The verify script also warns on policy drift (e.g. migrated workspace missing eslint.frontend-shared.cjs).

Scope

In scope (13 workspaces): adoption-insights, ai-integrations, app-defaults, bulk-import, extensions, global-header, homepage, intelligent-assistant, orchestrator, quickstart, scorecard, theme, translations

Out of scope (per epic owner): konflux, x2a, dcm, augment, cost-management, mcp-integrations, etc. — covered by allowlist, not in changed-workspace ESLint wiring.

Notes

  • Lockfiles are not scanned because many workspaces still resolve @material-ui/* transitively through Backstage dependencies. Direct package.json enforcement is in place; lockfile validation can be added once upstream removes transitive MUI v4 packages.
  • eslint.frontend-shared.cjs = eslint-factory + MUI v4 rules only. Reverting packages/app removed MUI extras, not other Backstage lint rules.
  • verify-repo is a repository-wide job bucket — more repo-level checks can be added as steps later.

Test plan

  • yarn verify:no-material-ui-v4 passes on a clean repo
  • Temp @material-ui/core in a migrated package.json fails the verify script
  • Temp @material-ui/core source import fails ESLint on a wired frontend plugin (no-restricted-imports)
  • CI Repository-wide checks failed with intentional test file (__ci-test-mui-v4__.ts) — confirm verify script catches violations
  • CI workspace lint jobs pass after scoping ESLint away from app-legacy / packages/app
  • Test file removed; verify script passes locally before merge

@rhdh-gh-app

rhdh-gh-app Bot commented Sep 17, 2026

Copy link
Copy Markdown

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/rhdh-repo-tools workspaces/repo-tools/packages/cli none v0.0.1

Comment thread .github/workflows/ci.yml Fixed
@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.65%. Comparing base (78e8e14) to head (8acc471).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4847   +/-   ##
=======================================
  Coverage   63.65%   63.65%           
=======================================
  Files        2692     2692           
  Lines      107325   107325           
  Branches    30062    30061    -1     
=======================================
  Hits        68318    68318           
+ Misses      37236    37232    -4     
- Partials     1771     1775    +4     
Flag Coverage Δ *Carryforward flag
adoption-insights 84.77% <ø> (ø)
ai-integrations 82.63% <ø> (ø)
app-defaults 63.39% <ø> (ø)
augment 46.67% <ø> (ø) Carriedforward from 78e8e14
boost 84.97% <ø> (ø) Carriedforward from 78e8e14
bulk-import 73.12% <ø> (ø)
cost-management 13.53% <ø> (ø) Carriedforward from 78e8e14
dcm 73.47% <ø> (ø) Carriedforward from 78e8e14
e2e-adoption-insights 60.00% <ø> (ø) Carriedforward from 78e8e14
e2e-extensions 62.31% <ø> (ø) Carriedforward from 78e8e14
e2e-global-header 51.82% <ø> (ø) Carriedforward from 78e8e14
e2e-homepage 61.11% <ø> (ø) Carriedforward from 78e8e14
e2e-intelligent-assistant 46.01% <ø> (ø) Carriedforward from 78e8e14
e2e-orchestrator 49.49% <ø> (ø) Carriedforward from 78e8e14
e2e-orchestrator-plugin 49.48% <ø> (ø) Carriedforward from 78e8e14
e2e-quickstart 55.21% <ø> (ø) Carriedforward from 78e8e14
e2e-scorecard 50.00% <ø> (ø) Carriedforward from 78e8e14
e2e-theme 16.36% <ø> (ø) Carriedforward from 78e8e14
extensions 58.30% <ø> (ø)
global-floating-action-button 71.18% <ø> (ø) Carriedforward from 78e8e14
global-header 67.76% <ø> (ø)
homepage 55.05% <ø> (ø)
install-dynamic-plugins 73.52% <ø> (ø) Carriedforward from 78e8e14
intelligent-assistant 78.04% <ø> (ø)
konflux 91.98% <ø> (ø) Carriedforward from 78e8e14
lightspeed 69.02% <ø> (ø) Carriedforward from 78e8e14
mcp-integrations 84.46% <ø> (ø) Carriedforward from 78e8e14
orchestrator 77.69% <ø> (ø)
quickstart 63.74% <ø> (ø)
sandbox 79.56% <ø> (ø) Carriedforward from 78e8e14
scorecard 88.71% <ø> (ø)
theme 87.94% <ø> (ø)
translations 5.12% <ø> (ø)
x2a 78.44% <ø> (ø) Carriedforward from 78e8e14

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 78e8e14...8acc471. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@debsmita1

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:21 PM UTC · Completed 3:44 PM UTC

Commit: abfaf29 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $6.57

@fullsend-ai-review fullsend-ai-review Bot added the risk/elevated PR risk: elevated label Sep 17, 2026
@fullsend-ai-review

Copy link
Copy Markdown

Risk Assessment: elevated (3/5)

Details

This large-scale ESLint consolidation and Material UI v4 safeguard PR touches 41 files across 14 workspaces with a large blast radius, CI workflow changes, 3 protected paths, a dependency file update, and zero test coverage — all high Tier 1 signals — but the underlying files exhibit very low churn, no regression history, and minimal author contention in git history, yielding an elevated composite score of 3.

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

High

  • [protected-path] .github/workflows/ci.yml, scripts/ci/material-ui-v4-policy.json, scripts/ci/verify-no-material-ui-v4.js — This PR modifies 3 files under protected paths (.github/, scripts/). No linked issue is present to justify changes to governance or infrastructure files. Human approval is required for protected-path changes.
    Remediation: Link an authorizing issue or obtain human approval for changes to protected paths.

Low

  • [enforcement-gap] scripts/ci/verify-no-material-ui-v4.js:89 — The reportMigratedWorkspaceDrift function (lines 89–124) logs warnings when a migrated workspace directory or its eslint.frontend-shared.cjs file is missing, but does not contribute to the violations array or call process.exit(1). The CI check passes with only a console warning that may go unnoticed in CI logs, allowing the policy file to silently drift out of sync with the actual workspace structure.
    Remediation: Add drift entries to the violations array so they cause a CI failure, or at minimum emit a structured annotation (::warning::) visible in the GitHub Actions UI.

  • [defense-in-depth-regression] workspaces/adoption-insights/packages/app/.eslintrc.js:1 — The 9 remaining packages/app/.eslintrc.js files now call @backstage/cli/config/eslint-factory directly, bypassing the shared config that included materialUiMigrationEslintConfig with v4 import guards. Plugin packages that reference the workspace-level eslint.frontend-shared.cjs still receive the v4 guards via the root config. Only packages/app packages lose inline ESLint feedback for @material-ui/* imports; the CI script still catches violations in migrated workspaces.

  • [error-handling-idiom] scripts/ci/verify-no-material-ui-v4.js:273 — Top-level await main() deviates from the established entry-point idiom in this directory. The three sibling scripts (verify-changesets.js, validate-codeowners.js, verify-lockfile-duplicates.js) use main().catch(error => { console.error(error.stack); process.exit(1); }). On Node.js 22/24 the practical impact is negligible (unhandled rejections already terminate with exit code 1), but consistency with sibling scripts is preferred.
    Remediation: Replace await main(); with main().catch(error => { console.error(error.stack); process.exit(1); });.

  • [documentation-comment-format] scripts/ci/verify-no-material-ui-v4.js:15 — Copyright attribution Copyright Red Hat, Inc. differs from the three existing scripts/ci/ scripts which carry Copyright The Backstage Authors. The new file is genuinely Red Hat-authored so the attribution may be factually correct, but inconsistency within the directory may cause confusion.
    Remediation: Consider whether the project has a policy on copyright headers for new files and align accordingly.

  • [stale-description] .github/workflows/README.md:5 — The ci.yml description says the workflow runs tests "focusing only on workspaces that have changes." The new verify-repo job runs unconditionally on every PR regardless of which workspaces changed, making this characterization incomplete.
    Remediation: Update the ci.yml description to mention that the workflow also runs repository-wide checks.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread scripts/ci/verify-no-material-ui-v4.js Outdated
return migratedWorkspaces.map(name => join(workspacesDir, name));
}

async function reportMigratedWorkspaceDrift(migratedWorkspaces) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] enforcement gap

The reportMigratedWorkspaceDrift function (lines 89-124) logs warnings when a migrated workspace directory or its eslint.frontend-shared.cjs file is missing, but does not contribute to the violations array or call process.exit(1). The CI check passes with only a console warning that may go unnoticed.

Suggested fix: Add drift entries to the violations array so they cause a CI failure, or emit a structured annotation (::warning::) visible in the GitHub Actions UI.


// eslint-disable-next-line @backstage/no-relative-monorepo-imports -- workspace ESLint shared config
module.exports = require('../../eslint.frontend-shared.cjs')(__dirname);
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] defense-in-depth regression

The 9 remaining packages/app/.eslintrc.js files now call @backstage/cli/config/eslint-factory directly, bypassing the shared config that included materialUiMigrationEslintConfig with v4 import guards. Plugin packages retain the guards via the root config. Only app packages lose inline ESLint feedback; the CI script still catches violations.

Comment thread scripts/ci/verify-no-material-ui-v4.js Outdated
process.exit(1);
}

await main();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] error-handling-idiom

Top-level await main() deviates from the established entry-point idiom used by sibling scripts in this directory, which use main().catch(error => { console.error(error.stack); process.exit(1); }). On Node.js 22/24 the practical impact is negligible but consistency is preferred.

Suggested fix: Replace await main(); with main().catch(error => { console.error(error.stack); process.exit(1); });.

* Lockfiles are not scanned because many workspaces still resolve Material UI
* v4 transitively through Backstage dependencies.
*
* Copyright Red Hat, Inc.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] documentation-comment-format

Copyright attribution Copyright Red Hat, Inc. differs from the three existing scripts/ci/ scripts which carry Copyright The Backstage Authors. The new file is genuinely Red Hat-authored so the attribution may be correct, but inconsistency within the directory may cause confusion.

Suggested fix: Consider whether the project has a policy on copyright headers for new files and align accordingly.

@its-mitesh-kumar its-mitesh-kumar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Several packages/app / packages/app-legacy missing .eslintrc.js entirely — now have they no ESLint config. Are we sure on it ?

Comment thread workspaces/adoption-insights/packages/app/.eslintrc.js Outdated
Comment thread workspaces/app-defaults/packages/app/.eslintrc.js
Comment thread workspaces/bulk-import/packages/app-legacy/.eslintrc.js
Comment thread workspaces/extensions/packages/app-legacy/.eslintrc.js
Comment thread workspaces/global-header/packages/app-legacy/.eslintrc.js
Comment thread workspaces/intelligent-assistant/packages/app/.eslintrc.js
@lokanandaprabhu

Copy link
Copy Markdown
Member Author

@its-mitesh-kumar Thanks for catching this, I have restored them all.

lokanandaprabhu and others added 10 commits September 18, 2026 19:34
Centralize ESLint import restrictions and add CI validation for direct @material-ui/* dependencies so migrated workspaces cannot accidentally reintroduce deprecated MUI v4 packages.

Co-authored-by: Cursor <cursoragent@cursor.com>
Disable Yarn lifecycle scripts in the verify-repo install step and address Sonar code smells in the verification script.

Co-authored-by: Cursor <cursoragent@cursor.com>
Intentionally includes @material-ui/core to confirm CI lint fails. Revert after validation.

Co-authored-by: Cursor <cursoragent@cursor.com>
Run full workspace lint in CI, extend verify-no-material-ui-v4.js to scan source imports in migrated workspaces, and restore the temporary MUI v4 test file to validate CI catches violations.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove before merge.

Co-authored-by: Cursor <cursoragent@cursor.com>
Revert packages/app to default eslint-factory and remove shared ESLint
from app-legacy to avoid legacy blast-radius failures. Restore
repo lint --since origin/main while keeping the verify script as the
MUI v4 policy gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
…t file.

Replace implicit eslint.frontend-shared.cjs detection with
material-ui-v4-policy.json as the single source of truth for migrated
workspaces. Remove the temporary __ci-test-mui-v4__.ts file after
confirming CI enforcement via the verify script.

Co-authored-by: Cursor <cursoragent@cursor.com>
Fail CI on migrated-workspace policy drift, align script entry-point
error handling with sibling CI scripts, and document repository-wide
checks in the CI workflow README.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use try/await/catch so Sonar rule S7785 is satisfied while still
logging stack traces and exiting non-zero on unexpected failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep existing license headers and frontend-shared wiring that already
existed on main; the earlier scoping pass incorrectly removed them.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants