Skip to content

feat(extensions): migrate to NFS#2527

Open
debsmita1 wants to merge 1 commit intoredhat-developer:mainfrom
debsmita1:extensions-nfs
Open

feat(extensions): migrate to NFS#2527
debsmita1 wants to merge 1 commit intoredhat-developer:mainfrom
debsmita1:extensions-nfs

Conversation

@debsmita1
Copy link
Member

@debsmita1 debsmita1 commented Mar 12, 2026

Hey, I just made a Pull Request!

Resolves:
https://issues.redhat.com/browse/RHIDP-11629

Solution description:

  • Restructured extensions workspace: moved the existing app to app-legacy and introduced a new NFS-based app package.
  • Migrated to NFS: added a new frontend app using the new frontend system, with nav, sign-in, and app shell modules.
  • Added alpha components to extensions, and dev entry points for NFS and legacy.

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

@rhdh-qodo-merge
Copy link

Review Summary by Qodo

Migrate extensions plugin to new frontend system with dual app mode support

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• **Migrated extensions plugin to new frontend system (NFS)**: Restructured the extensions workspace
  by moving the existing app to app-legacy and introducing a new NFS-based app package with modern
  frontend architecture
• **Implemented comprehensive E2E test suite**: Added extensive Playwright tests for extensions
  catalog with support for multiple locales, filters, badges, and accessibility validation
• **Created NFS app modules**: Developed sign-in, navigation, and app shell modules using the new
  frontend plugin API with lazy-loaded components and modular architecture
• **Added alpha components and APIs**: Implemented API blueprints for extensionApi and
  dynamicPluginsInfoApi with dependency injection, and created NFS-compatible page and nav item
  blueprints
• **Dual app mode support**: Added configuration for running both legacy and NFS apps with separate
  dev entry points, mock data, and test scripts
• **Updated plugin dependencies**: Migrated from @backstage/app-defaults to
  @backstage/frontend-defaults and added NFS-specific dependencies
• **Comprehensive documentation**: Updated README with setup instructions for both new frontend
  system and legacy configurations
• **Fixed error page handling**: Simplified error page component usage by removing useApp() hook
  dependency
Diagram
flowchart LR
  A["Legacy App<br/>app-legacy/"] -->|"preserved"| B["Original Routes<br/>& Plugins"]
  C["NFS App<br/>app/"] -->|"new"| D["Frontend Modules<br/>nav, signIn, app"]
  E["Extensions Plugin"] -->|"alpha exports"| F["NFS Blueprints<br/>page, navItem"]
  E -->|"legacy support"| G["Dev Entry Points<br/>legacy.tsx, index.tsx"]
  H["E2E Tests"] -->|"covers"| I["Both App Modes<br/>Legacy & NFS"]
  J["Mock APIs"] -->|"provides"| K["Dev & Test Data<br/>extensions, plugins"]
Loading

Grey Divider

File Changes

1. workspaces/extensions/plugins/extensions/dev/__data__/mockExtensions.ts 🧪 Tests +334/-0

Mock extensions API implementation for development

• Created comprehensive mock data for extensions API with mockPlugins, mockCollections, and
 mockPackages arrays
• Implemented MockExtensionsApi class providing all required API methods for testing (getPlugins,
 getCollections, getPackages, etc.)
• Added filtering utility function filterByRequest to support entity filtering by metadata name

workspaces/extensions/plugins/extensions/dev/data/mockExtensions.ts


2. workspaces/extensions/packages/app-legacy/e2e-tests/extensions.test.ts 🧪 Tests +283/-0

E2E tests for extensions catalog functionality

• Added comprehensive E2E test suite for extensions catalog with multiple test cases covering
 search, filters, and badges
• Implemented locale switching functionality and translation support for multiple languages (en, fr,
 it, ja)
• Tests verify category/author filters, support type badges (certified, GA, tech preview, etc.), and
 installed packages page

workspaces/extensions/packages/app-legacy/e2e-tests/extensions.test.ts


3. workspaces/extensions/packages/app-legacy/e2e-tests/pages/extensions.ts 🧪 Tests +284/-0

Page object for extensions E2E testing

• Created Extensions page object class for Playwright E2E tests with methods for UI interactions
• Implemented helper methods for dropdown selection, filter toggling, badge verification, and plugin
 details validation
• Provides reusable test utilities for extensions catalog page interactions

workspaces/extensions/packages/app-legacy/e2e-tests/pages/extensions.ts


View more (64)
4. workspaces/extensions/packages/app-legacy/e2e-tests/utils/helper.ts 🧪 Tests +146/-0

E2E test helper utilities

• Created ExtensionHelper utility class with common test helper methods for E2E tests
• Provides methods for text verification, table validation, input filling, and UI element
 interactions
• Includes error handling and scroll-into-view functionality for reliable test execution

workspaces/extensions/packages/app-legacy/e2e-tests/utils/helper.ts


5. workspaces/extensions/playwright.config.ts ⚙️ Configuration changes +18/-8

Playwright config for dual app mode support

• Added APP_MODE environment variable support to switch between legacy and NFS app configurations
• Dynamically set test directory, start command, and output folder based on app mode
• Removed hardcoded testDir from individual projects and centralized configuration

workspaces/extensions/playwright.config.ts


6. workspaces/extensions/packages/app-legacy/e2e-tests/utils/translations.ts 🧪 Tests +78/-0

Translation utilities for E2E tests

• Created translation utility module importing extensions translations for multiple locales (en, de,
 es, fr, it, ja)
• Implemented getTranslations function to retrieve locale-specific translation objects
• Added replaceTemplate helper for placeholder substitution in template strings

workspaces/extensions/packages/app-legacy/e2e-tests/utils/translations.ts


7. workspaces/extensions/plugins/extensions/src/alpha/apis.ts ✨ Enhancement +73/-0

API blueprints for extensions and dynamic plugins

• Created API blueprint modules for extensionApi and dynamicPluginsInfoApi using new frontend
 plugin API
• Configured dependency injection for discovery, fetch, identity, and config APIs
• Provides factory functions for instantiating ExtensionsBackendClient and
 DynamicPluginsInfoClient

workspaces/extensions/plugins/extensions/src/alpha/apis.ts


8. workspaces/extensions/packages/app/e2e-tests/utils/translations.ts Miscellaneous +6/-6

Update translation import paths

• Updated import paths from src/translations to src/alpha/translations to reflect new directory
 structure
• Maintains same translation loading functionality for all supported locales

workspaces/extensions/packages/app/e2e-tests/utils/translations.ts


9. workspaces/extensions/packages/app-legacy/e2e-tests/utils/accessibility.ts 🧪 Tests +41/-0

Accessibility testing utilities

• Created accessibility testing utility using Axe Core for WCAG compliance validation
• Implements runAccessibilityTests function that scans pages and attaches violation reports
• Supports configurable failure handling for accessibility violations

workspaces/extensions/packages/app-legacy/e2e-tests/utils/accessibility.ts


10. workspaces/extensions/packages/backend/src/index.ts ⚙️ Configuration changes +3/-6

Backend permission plugin configuration

• Added explicit @backstage/plugin-permission-backend import for authorization endpoint
• Kept RBAC backend as policy implementation replacing allow-all policy
• Removed commented-out alternative permission backend configuration

workspaces/extensions/packages/backend/src/index.ts


11. workspaces/extensions/packages/app/src/modules/signIn/index.ts ✨ Enhancement +29/-0

Sign-in module for new frontend system

• Created sign-in module using new frontend plugin API with createFrontendModule
• Configured SignInPageBlueprint with lazy-loaded SignInPageComponent
• Provides modular sign-in page extension for NFS app

workspaces/extensions/packages/app/src/modules/signIn/index.ts


12. workspaces/extensions/packages/app/src/modules/nav/index.ts ✨ Enhancement +23/-0

Navigation module for new frontend system

• Created navigation module using new frontend plugin API
• Exports navModule with SidebarContent extension
• Provides modular navigation for NFS app

workspaces/extensions/packages/app/src/modules/nav/index.ts


13. workspaces/extensions/plugins/extensions/src/utils.ts Miscellaneous +1/-1

Update translation reference import path

• Updated import path for extensionsTranslationRef from ./translations to ./alpha/translations
• Maintains same utility functionality with new directory structure

workspaces/extensions/plugins/extensions/src/utils.ts


14. workspaces/extensions/plugins/extensions/src/plugin.ts Miscellaneous +1/-1

Update translation reference import path

• Updated import path for extensionsTranslationRef from ./translations to ./alpha/translations
• Maintains plugin initialization and route configuration

workspaces/extensions/plugins/extensions/src/plugin.ts


15. workspaces/extensions/plugins/extensions/src/labels.ts Miscellaneous +1/-1

Update translation reference import path

• Updated import path for extensionsTranslationRef from ./translations to ./alpha/translations
• Maintains label mapping functionality with new import location

workspaces/extensions/plugins/extensions/src/labels.ts


16. workspaces/extensions/plugins/extensions/src/test-utils/mockTranslations.ts Miscellaneous +1/-1

Update mock translations import path

• Updated import path for extensionsMessages from ../translations/ref to
 ../alpha/translations/ref
• Maintains mock translation flattening functionality

workspaces/extensions/plugins/extensions/src/test-utils/mockTranslations.ts


17. workspaces/extensions/plugins/extensions/src/hooks/useTranslation.ts Miscellaneous +1/-1

Update translation reference import path

• Updated import path for extensionsTranslationRef from ../translations to
 ../alpha/translations
• Maintains translation hook functionality with new import location

workspaces/extensions/plugins/extensions/src/hooks/useTranslation.ts


18. workspaces/extensions/packages/app/src/modules/nav/LogoFull.tsx ✨ Enhancement +44/-0

Full logo SVG component

• Created full logo SVG component with Material-UI styling
• Implements responsive SVG with teal fill color (#7df3e1)
• Provides logo component for navigation module

workspaces/extensions/packages/app/src/modules/nav/LogoFull.tsx


19. workspaces/extensions/plugins/extensions/report-alpha.api.md 📝 Documentation +187/-51

API report updates for alpha exports

• Updated API report with new exports including extensionApi and dynamicPluginsInfoApi
 blueprints
• Added extensionsNavItem and extensionsPage extension definitions for NFS
• Reorganized translation reference structure with additional imports and type definitions

workspaces/extensions/plugins/extensions/report-alpha.api.md


20. workspaces/extensions/packages/app/src/modules/nav/LogoIcon.tsx ✨ Enhancement +44/-0

Icon logo SVG component

• Created icon logo SVG component with Material-UI styling
• Implements responsive SVG with teal fill color (#7df3e1)
• Provides compact logo icon for navigation module

workspaces/extensions/packages/app/src/modules/nav/LogoIcon.tsx


21. workspaces/extensions/packages/app/src/App.tsx ✨ Enhancement +6/-135

Migrate app to new frontend system

• Completely refactored from legacy app-defaults to new frontend system using createApp from
 @backstage/frontend-defaults
• Removed all legacy route definitions and plugin configurations
• Integrated new modules (nav, signIn, extensionsTranslations) as features

workspaces/extensions/packages/app/src/App.tsx


22. workspaces/extensions/packages/app-legacy/src/App.tsx ✨ Enhancement +153/-0

Legacy app configuration

• Created new legacy app file containing original App.tsx content from NFS migration
• Maintains all legacy plugin routes and configurations (catalog, techdocs, scaffolder, etc.)
• Preserves original app-defaults setup with traditional route-based architecture

workspaces/extensions/packages/app-legacy/src/App.tsx


23. workspaces/extensions/package.json ⚙️ Configuration changes +5/-1

Package scripts for dual app modes

• Added start:legacy script to run legacy app with backend
• Added test:legacy and test:nfs scripts with APP_MODE environment variable
• Added test:e2e:ci script to run both legacy and NFS E2E tests sequentially
• Added playwright wrapper script for conditional test execution

workspaces/extensions/package.json


24. workspaces/extensions/packages/app-legacy/src/index.tsx ✨ Enhancement +6/-1

Legacy app entry point

• Updated to render React app using ReactDOM.createRoot instead of exporting translations
• Added imports for Backstage CLI asset types and global styles
• Mounts App component to root DOM element

workspaces/extensions/packages/app-legacy/src/index.tsx


25. workspaces/extensions/plugins/extensions/dev/index.tsx ✨ Enhancement +105/-25

Migrate dev entry point to new frontend system

• Migrated dev entry point from legacy createDevApp() to new frontend system using createApp()
 and ReactDOM.createRoot()
• Added mock API blueprints for extensionsApiRef and dynamicPluginsInfoApiRef with factory
 functions
• Implemented custom sidebar navigation with language switcher and sign-out button using
 NavContentBlueprint
• Imported and registered extensions page, nav item, and translations module as frontend features

workspaces/extensions/plugins/extensions/dev/index.tsx


26. workspaces/extensions/packages/app-legacy/package.json ⚙️ Configuration changes +83/-0

Create legacy app package configuration

• Created new legacy app package configuration with Backstage frontend role
• Defined build scripts for start, build, clean, test, and lint operations
• Added comprehensive dependencies including Backstage core, plugins, and UI libraries
• Configured browser compatibility and output files for distribution

workspaces/extensions/packages/app-legacy/package.json


27. workspaces/extensions/plugins/extensions/README.md 📝 Documentation +78/-8

Comprehensive documentation for plugin setup and usage

• Rewrote documentation with comprehensive administrator setup instructions
• Added prerequisites section referencing backend plugin and catalog module dependencies
• Documented installation steps for both new frontend system and legacy setup
• Added development section explaining legacy and NFS dev modes with mock data

workspaces/extensions/plugins/extensions/README.md


28. workspaces/extensions/plugins/extensions/dev/legacy.tsx ✨ Enhancement +87/-0

Create legacy dev mode with mock API providers

• Created new legacy dev mode entry point using createDevApp() pattern
• Implemented ExtensionsWrapper component providing mock APIs via TestApiProvider
• Added mock implementations for extensionsApiRef and dynamicPluginsInfoApiRef
• Configured mock extensions configuration with installation settings

workspaces/extensions/plugins/extensions/dev/legacy.tsx


29. workspaces/extensions/plugins/extensions/package.json Dependencies +8/-2

Update exports and add NFS dependencies

• Updated alpha export path from src/alpha.ts to src/alpha/index.tsx
• Added start:legacy script for legacy dev mode with custom entrypoint
• Added new dependencies for NFS: @backstage/frontend-defaults, @backstage/frontend-plugin-api,
 @backstage/plugin-app-react, @backstage/core-compat-api, and @backstage/ui

workspaces/extensions/plugins/extensions/package.json


30. workspaces/extensions/plugins/extensions/src/alpha/index.tsx ✨ Enhancement +84/-0

Create NFS alpha module with plugin blueprints

• Created new alpha module exporting NFS-compatible plugin and page blueprints
• Defined extensionsPage using PageBlueprint with lazy-loaded DynamicExtensionsPluginRouter
• Defined extensionsNavItem using NavItemBlueprint with shopping basket icon
• Exported extensionsTranslationsModule and default plugin with all extensions and routes

workspaces/extensions/plugins/extensions/src/alpha/index.tsx


31. workspaces/extensions/packages/app/src/modules/nav/Sidebar.tsx ✨ Enhancement +66/-0

Create NFS sidebar navigation component

• Created new sidebar component using NavContentBlueprint for NFS app
• Implemented sidebar structure with logo, search, menu groups, and settings
• Added search modal, user settings avatar, and sidebar settings components
• Used compatWrapper for compatibility with legacy components

workspaces/extensions/packages/app/src/modules/nav/Sidebar.tsx


32. workspaces/extensions/packages/app/src/modules/nav/SidebarLogo.tsx ✨ Enhancement +48/-0

Create responsive sidebar logo component

• Created sidebar logo component with responsive open/closed state handling
• Implemented logo display logic showing full logo when sidebar is open, icon when closed
• Used Material-UI styling and Backstage sidebar configuration utilities

workspaces/extensions/packages/app/src/modules/nav/SidebarLogo.tsx


33. workspaces/extensions/packages/app/package.json Dependencies +5/-2

Update app dependencies for NFS migration

• Removed @backstage/app-defaults and @backstage-community/plugin-rbac dependencies
• Added NFS dependencies: @backstage/frontend-defaults, @backstage/frontend-plugin-api,
 @backstage/core-compat-api, @backstage/plugin-app, and @backstage/plugin-app-react
• Restructured dependencies to support new frontend system architecture

workspaces/extensions/packages/app/package.json


34. workspaces/extensions/packages/app/src/modules/signIn/SignInPageComponent.tsx ✨ Enhancement +30/-0

Create NFS sign-in page component

• Created sign-in page component for NFS app using SignInPage from core components
• Configured GitHub authentication provider with guest fallback option
• Implemented SignInPageProps interface for plugin integration

workspaces/extensions/packages/app/src/modules/signIn/SignInPageComponent.tsx


35. workspaces/extensions/app-config.yaml ⚙️ Configuration changes +17/-0

Configure app extensions and admin settings

• Added packages: all configuration for app initialization
• Configured extensions with catalog page at root path and language settings
• Disabled user-settings and search navigation items
• Added admin configuration with guest user as superuser

workspaces/extensions/app-config.yaml


36. workspaces/extensions/plugins/extensions/src/pages/ExtensionsFullPageRouter.tsx 🐞 Bug fix +3/-4

Simplify error page handling in router

• Removed useApp() hook dependency for NotFoundErrorPage
• Replaced dynamic NotFoundErrorPage with static ErrorPage component from core-components
• Simplified error handling for 404 pages

workspaces/extensions/plugins/extensions/src/pages/ExtensionsFullPageRouter.tsx


37. workspaces/extensions/packages/app/public/manifest.json Formatting +2/-8

Format manifest JSON file

• Reformatted manifest JSON with inline icons array
• Removed trailing newline for consistency

workspaces/extensions/packages/app/public/manifest.json


38. workspaces/extensions/plugins/extensions/src/components/ExtensionsCollectionGrid.tsx Miscellaneous +1/-1

Update translation utilities import path

• Updated import path for getTranslatedText from ../translations/utils to
 ../alpha/translations/utils

workspaces/extensions/plugins/extensions/src/components/ExtensionsCollectionGrid.tsx


39. workspaces/extensions/packages/app-legacy/public/manifest.json ⚙️ Configuration changes +15/-0

Create legacy app manifest configuration

• Created manifest.json for legacy app package with standard Backstage configuration
• Defined app metadata, icons, and display settings

workspaces/extensions/packages/app-legacy/public/manifest.json


40. workspaces/extensions/plugins/extensions/src/pages/ExtensionsCollectionPage.tsx Miscellaneous +1/-1

Update translation utilities import path

• Updated import path for getTranslatedText from ../translations/utils to
 ../alpha/translations/utils

workspaces/extensions/plugins/extensions/src/pages/ExtensionsCollectionPage.tsx


41. workspaces/extensions/plugins/extensions/src/components/CollectionHorizontalScrollRow.tsx Miscellaneous +1/-1

Update translation utilities import path

• Updated import path for getTranslatedText from ../translations/utils to
 ../alpha/translations/utils

workspaces/extensions/plugins/extensions/src/components/CollectionHorizontalScrollRow.tsx


42. workspaces/extensions/plugins/extensions/src/components/Badges.tsx Miscellaneous +1/-1

Update translation reference import path

• Updated import path for extensionsTranslationRef from ../translations/ref to
 ../alpha/translations/ref

workspaces/extensions/plugins/extensions/src/components/Badges.tsx


43. workspaces/extensions/packages/app/src/index.tsx ✨ Enhancement +1/-1

Update app initialization for NFS

• Changed ReactDOM render call from <App /> to App.createRoot() for NFS compatibility
• Removed trailing newline for consistency

workspaces/extensions/packages/app/src/index.tsx


44. workspaces/extensions/.changeset/large-cougars-draw.md 📝 Documentation +5/-0

Add changeset for NFS migration

• Created changeset documenting migration of extensions plugin to new frontend system
• Marked as minor version bump for @red-hat-developer-hub/backstage-plugin-extensions

workspaces/extensions/.changeset/large-cougars-draw.md


45. workspaces/extensions/packages/app-legacy/.eslintignore Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/.eslintignore


46. workspaces/extensions/packages/app-legacy/.eslintrc.js Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/.eslintrc.js


47. workspaces/extensions/packages/app-legacy/knip-report.md Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/knip-report.md


48. workspaces/extensions/packages/app-legacy/public/index.html Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/public/index.html


49. workspaces/extensions/packages/app-legacy/public/robots.txt Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/public/robots.txt


50. workspaces/extensions/packages/app-legacy/src/App.test.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/App.test.tsx


51. workspaces/extensions/packages/app-legacy/src/apis.ts Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/apis.ts


52. workspaces/extensions/packages/app-legacy/src/components/Root/LogoFull.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/Root/LogoFull.tsx


53. workspaces/extensions/packages/app-legacy/src/components/Root/LogoIcon.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/Root/LogoIcon.tsx


54. workspaces/extensions/packages/app-legacy/src/components/Root/Root.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/Root/Root.tsx


55. workspaces/extensions/packages/app-legacy/src/components/Root/index.ts Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/Root/index.ts


56. workspaces/extensions/packages/app-legacy/src/components/catalog/EntityPage.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/catalog/EntityPage.tsx


57. workspaces/extensions/packages/app-legacy/src/components/search/SearchPage.tsx Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/components/search/SearchPage.tsx


58. workspaces/extensions/packages/app-legacy/src/setupTests.ts Additional files +0/-0

...

workspaces/extensions/packages/app-legacy/src/setupTests.ts


59. workspaces/extensions/plugins/catalog-backend-module-extensions/package.json Additional files +0/-60

...

workspaces/extensions/plugins/catalog-backend-module-extensions/package.json


60. workspaces/extensions/plugins/extensions/src/alpha/translations/de.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/de.ts


61. workspaces/extensions/plugins/extensions/src/alpha/translations/es.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/es.ts


62. workspaces/extensions/plugins/extensions/src/alpha/translations/fr.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/fr.ts


63. workspaces/extensions/plugins/extensions/src/alpha/translations/index.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/index.ts


64. workspaces/extensions/plugins/extensions/src/alpha/translations/it.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/it.ts


65. workspaces/extensions/plugins/extensions/src/alpha/translations/ja.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/ja.ts


66. workspaces/extensions/plugins/extensions/src/alpha/translations/ref.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/ref.ts


67. workspaces/extensions/plugins/extensions/src/alpha/translations/utils.ts Additional files +0/-0

...

workspaces/extensions/plugins/extensions/src/alpha/translations/utils.ts


Grey Divider

Qodo Logo

@rhdh-qodo-merge
Copy link

rhdh-qodo-merge bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Extensions plugin omitted 🐞 Bug ✓ Correctness
Description
The NFS app only registers nav/sign-in/translations modules and never registers the Extensions NFS
plugin, so the Extensions page/nav-item extensions are not created in NFS mode and NFS e2e tests
that navigate via the “Extensions” link will fail.
Code

workspaces/extensions/packages/app/src/App.tsx[R17-24]

+import { createApp } from '@backstage/frontend-defaults';
+import { extensionsTranslationsModule } from '@red-hat-developer-hub/backstage-plugin-extensions/alpha';
+import { navModule } from './modules/nav';
+import { signInModule } from './modules/signIn';

-import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder';
-import { orgPlugin } from '@backstage/plugin-org';
-import { SearchPage } from '@backstage/plugin-search';
-import {
-  TechDocsIndexPage,
-  techdocsPlugin,
-  TechDocsReaderPage,
-} from '@backstage/plugin-techdocs';
-import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
-import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
-import { UserSettingsPage } from '@backstage/plugin-user-settings';
-import {
-  AlertDisplay,
-  OAuthRequestDialog,
-  SignInPage,
-} from '@backstage/core-components';
-import { createApp } from '@backstage/app-defaults';
-import { AppRouter, FlatRoutes } from '@backstage/core-app-api';
-import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
-import { RequirePermission } from '@backstage/plugin-permission-react';
-import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
-import { githubAuthApiRef } from '@backstage/core-plugin-api';
-
-import { getAllThemes } from '@red-hat-developer-hub/backstage-plugin-theme';
-
-import { DynamicExtensionsPluginRouter as Extensions } from '@red-hat-developer-hub/backstage-plugin-extensions';
-import { extensionsTranslations } from '@red-hat-developer-hub/backstage-plugin-extensions/alpha';
-
-import { apis } from './apis';
-import { entityPage } from './components/catalog/EntityPage';
-import { searchPage } from './components/search/SearchPage';
-import { Root } from './components/Root';
-
-const app = createApp({
-  apis,
-  __experimentalTranslations: {
-    availableLanguages: ['en', 'de', 'es', 'fr', 'it', 'ja'],
-    resources: [extensionsTranslations],
-  },
-  bindRoutes({ bind }) {
-    bind(catalogPlugin.externalRoutes, {
-      createComponent: scaffolderPlugin.routes.root,
-      viewTechDoc: techdocsPlugin.routes.docRoot,
-      createFromTemplate: scaffolderPlugin.routes.selectedTemplate,
-    });
-    bind(apiDocsPlugin.externalRoutes, {
-      registerApi: catalogImportPlugin.routes.importPage,
-    });
-    bind(scaffolderPlugin.externalRoutes, {
-      registerComponent: catalogImportPlugin.routes.importPage,
-      viewTechDoc: techdocsPlugin.routes.docRoot,
-    });
-    bind(orgPlugin.externalRoutes, {
-      catalogIndex: catalogPlugin.routes.catalogIndex,
-    });
-  },
-  components: {
-    SignInPage: props => (
-      <SignInPage
-        {...props}
-        auto
-        providers={[
-          'guest',
-          {
-            id: 'github-auth-provider',
-            title: 'GitHub',
-            message: 'Sign in using GitHub',
-            apiRef: githubAuthApiRef,
-          },
-        ]}
-      />
-    ),
-  },
-  themes: getAllThemes(),
+export default createApp({
+  features: [ navModule, extensionsTranslationsModule, signInModule],
});
-
-const routes = (
-  <FlatRoutes>
-    <Route path="/" element={<Navigate to="catalog" />} />
-    <Route path="/catalog" element={<CatalogIndexPage />} />
-    <Route
-      path="/catalog/:namespace/:kind/:name"
-      element={<CatalogEntityPage />}
-    >
-      {entityPage}
-    </Route>
-    <Route path="/docs" element={<TechDocsIndexPage />} />
-    <Route
-      path="/docs/:namespace/:kind/:name/*"
-      element={<TechDocsReaderPage />}
-    >
-      <TechDocsAddons>
-        <ReportIssue />
-      </TechDocsAddons>
-    </Route>
-    <Route path="/rbac" element={<RbacPage />} />
-    <Route path="/create" element={<ScaffolderPage />} />
-    <Route path="/api-docs" element={<ApiExplorerPage />} />
-    <Route
-      path="/catalog-import"
-      element={
-        <RequirePermission permission={catalogEntityCreatePermission}>
-          <CatalogImportPage />
-        </RequirePermission>
-      }
-    />
-    <Route path="/search" element={<SearchPage />}>
-      {searchPage}
-    </Route>
-    <Route path="/settings" element={<UserSettingsPage />} />
-    <Route path="/catalog-graph" element={<CatalogGraphPage />} />
-    <Route path="/extensions" element={<Extensions />} />
-  </FlatRoutes>
-);
-
-export default app.createRoot(
-  <>
-    <AlertDisplay />
-    <OAuthRequestDialog />
-    <AppRouter>
-      <Root>{routes}</Root>
-    </AppRouter>
-  </>,
-);
Evidence
The NFS app’s createApp({ features: [...] }) list does not include the Extensions NFS plugin
default export, while the plugin’s own README states the plugin must be added to features to
provide /extensions and the sidebar nav item; the NFS e2e tests then immediately try to navigate
via an “Extensions” link.

workspaces/extensions/packages/app/src/App.tsx[17-24]
workspaces/extensions/plugins/extensions/README.md[54-76]
workspaces/extensions/packages/app/e2e-tests/extensions.test.ts[59-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The NFS app (`workspaces/extensions/packages/app`) does not include the Extensions NFS plugin in its `createApp({ features: [...] })` list, so the Extensions page and sidebar nav item won’t be registered in NFS mode.

## Issue Context
The plugin README states that adding `extensionsPlugin` to the `features` array is what provides `/extensions` and the sidebar item. The NFS e2e tests navigate via an &quot;Extensions&quot; link.

## Fix Focus Areas
- workspaces/extensions/packages/app/src/App.tsx[17-24]
- workspaces/extensions/plugins/extensions/README.md[54-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Guest RBAC superuser 🐞 Bug ⛨ Security
Description
The base app-config grants user:development/guest RBAC superuser/admin privileges, and the
production config explicitly layers on top of app-config.yaml, meaning a production setup can
unintentionally grant full admin to an unauthenticated guest.
Code

workspaces/extensions/app-config.yaml[R140-147]

    pluginsWithPermission:
      - catalog
      - extensions
+    admin:
+      superUsers:
+        - name: user:development/guest
+      users:
+        - name: user:development/guest
Evidence
app-config.yaml explicitly makes the guest identity a superUser/admin;
app-config.production.yaml indicates it overrides defaults from app-config.yaml, implying the
base RBAC admin settings may carry into production unless explicitly overridden/removed.

workspaces/extensions/app-config.yaml[135-147]
workspaces/extensions/app-config.production.yaml[36-38]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`workspaces/extensions/app-config.yaml` grants RBAC superuser/admin privileges to the guest user. Since production config layers on top of `app-config.yaml`, this can leak into production.

## Issue Context
Guest auth is enabled in configs; RBAC superUsers should never include an unauthenticated guest identity in shared configs.

## Fix Focus Areas
- workspaces/extensions/app-config.yaml[135-147]
- workspaces/extensions/app-config.production.yaml[1-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Docs API id mismatch 🐞 Bug ✓ Correctness
Description
The generated API report shows the Extensions API extension id as api:extensions/extensions, but
the README documents it as api:extensions, causing users to configure/override a non-existent
extension id.
Code

workspaces/extensions/plugins/extensions/README.md[R79-84]

+The following extensions are available in the plugin:
+
+- `api:extensions`
+- `api:extensions/dynamic-plugins-info`
+- `page:extensions`
+- `nav-item:extensions`
Evidence
The NFS API blueprint is named extensions, and the generated API report enumerates the resulting
extension id as api:extensions/extensions, while the README lists api:extensions instead.

workspaces/extensions/plugins/extensions/src/alpha/apis.ts[33-52]
workspaces/extensions/plugins/extensions/report-alpha.api.md[40-61]
workspaces/extensions/plugins/extensions/README.md[79-84]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The README documents an API extension id that does not match the generated API report (`api:extensions` vs `api:extensions/extensions`).

## Issue Context
Users rely on these ids in `app-config.yaml` `app.extensions` blocks to enable/disable/override extensions.

## Fix Focus Areas
- workspaces/extensions/plugins/extensions/README.md[79-84]
- workspaces/extensions/plugins/extensions/src/alpha/apis.ts[33-52]
- workspaces/extensions/plugins/extensions/report-alpha.api.md[40-61]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. README start:nfs wrong 🐞 Bug ⛯ Reliability
Description
The Extensions plugin README instructs running yarn start:nfs, but the package only defines
start and start:legacy, so the documented command fails.
Code

workspaces/extensions/plugins/extensions/README.md[R88-92]

+You can serve the plugin in isolation for local development. The setup is in the [dev](./dev) directory.
+
+- **Legacy dev mode**: Run `yarn start:legacy` in the plugin directory to use the legacy app with Full Page and Tabbed Page routers.
+- **NFS dev mode**: Run `yarn start:nfs` in the plugin directory to use the new frontend system with mock data.
+
Evidence
The README mentions a start:nfs script that does not exist in the plugin package.json scripts
list.

workspaces/extensions/plugins/extensions/README.md[88-92]
workspaces/extensions/plugins/extensions/package.json[40-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
README references a non-existent `start:nfs` script.

## Issue Context
This breaks the documented developer workflow for running the NFS dev mode.

## Fix Focus Areas
- workspaces/extensions/plugins/extensions/README.md[88-92]
- workspaces/extensions/plugins/extensions/package.json[40-49]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@rhdh-gh-app
Copy link

rhdh-gh-app bot commented Mar 12, 2026

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
app-legacy workspaces/extensions/packages/app-legacy none v0.0.0
app workspaces/extensions/packages/app none v0.0.0
backend workspaces/extensions/packages/backend none v0.0.0
@red-hat-developer-hub/backstage-plugin-extensions workspaces/extensions/plugins/extensions minor v0.14.5

Comment on lines +17 to 24
import { createApp } from '@backstage/frontend-defaults';
import { extensionsTranslationsModule } from '@red-hat-developer-hub/backstage-plugin-extensions/alpha';
import { navModule } from './modules/nav';
import { signInModule } from './modules/signIn';

import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder';
import { orgPlugin } from '@backstage/plugin-org';
import { SearchPage } from '@backstage/plugin-search';
import {
TechDocsIndexPage,
techdocsPlugin,
TechDocsReaderPage,
} from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
import { UserSettingsPage } from '@backstage/plugin-user-settings';
import {
AlertDisplay,
OAuthRequestDialog,
SignInPage,
} from '@backstage/core-components';
import { createApp } from '@backstage/app-defaults';
import { AppRouter, FlatRoutes } from '@backstage/core-app-api';
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
import { githubAuthApiRef } from '@backstage/core-plugin-api';

import { getAllThemes } from '@red-hat-developer-hub/backstage-plugin-theme';

import { DynamicExtensionsPluginRouter as Extensions } from '@red-hat-developer-hub/backstage-plugin-extensions';
import { extensionsTranslations } from '@red-hat-developer-hub/backstage-plugin-extensions/alpha';

import { apis } from './apis';
import { entityPage } from './components/catalog/EntityPage';
import { searchPage } from './components/search/SearchPage';
import { Root } from './components/Root';

const app = createApp({
apis,
__experimentalTranslations: {
availableLanguages: ['en', 'de', 'es', 'fr', 'it', 'ja'],
resources: [extensionsTranslations],
},
bindRoutes({ bind }) {
bind(catalogPlugin.externalRoutes, {
createComponent: scaffolderPlugin.routes.root,
viewTechDoc: techdocsPlugin.routes.docRoot,
createFromTemplate: scaffolderPlugin.routes.selectedTemplate,
});
bind(apiDocsPlugin.externalRoutes, {
registerApi: catalogImportPlugin.routes.importPage,
});
bind(scaffolderPlugin.externalRoutes, {
registerComponent: catalogImportPlugin.routes.importPage,
viewTechDoc: techdocsPlugin.routes.docRoot,
});
bind(orgPlugin.externalRoutes, {
catalogIndex: catalogPlugin.routes.catalogIndex,
});
},
components: {
SignInPage: props => (
<SignInPage
{...props}
auto
providers={[
'guest',
{
id: 'github-auth-provider',
title: 'GitHub',
message: 'Sign in using GitHub',
apiRef: githubAuthApiRef,
},
]}
/>
),
},
themes: getAllThemes(),
export default createApp({
features: [ navModule, extensionsTranslationsModule, signInModule],
});

Choose a reason for hiding this comment

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

Action required

1. Extensions plugin omitted 🐞 Bug ✓ Correctness

The NFS app only registers nav/sign-in/translations modules and never registers the Extensions NFS
plugin, so the Extensions page/nav-item extensions are not created in NFS mode and NFS e2e tests
that navigate via the “Extensions” link will fail.
Agent Prompt
## Issue description
The NFS app (`workspaces/extensions/packages/app`) does not include the Extensions NFS plugin in its `createApp({ features: [...] })` list, so the Extensions page and sidebar nav item won’t be registered in NFS mode.

## Issue Context
The plugin README states that adding `extensionsPlugin` to the `features` array is what provides `/extensions` and the sidebar item. The NFS e2e tests navigate via an "Extensions" link.

## Fix Focus Areas
- workspaces/extensions/packages/app/src/App.tsx[17-24]
- workspaces/extensions/plugins/extensions/README.md[54-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 140 to +147
pluginsWithPermission:
- catalog
- extensions
admin:
superUsers:
- name: user:development/guest
users:
- name: user:development/guest

Choose a reason for hiding this comment

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

Action required

2. Guest rbac superuser 🐞 Bug ⛨ Security

The base app-config grants user:development/guest RBAC superuser/admin privileges, and the
production config explicitly layers on top of app-config.yaml, meaning a production setup can
unintentionally grant full admin to an unauthenticated guest.
Agent Prompt
## Issue description
`workspaces/extensions/app-config.yaml` grants RBAC superuser/admin privileges to the guest user. Since production config layers on top of `app-config.yaml`, this can leak into production.

## Issue Context
Guest auth is enabled in configs; RBAC superUsers should never include an unauthenticated guest identity in shared configs.

## Fix Focus Areas
- workspaces/extensions/app-config.yaml[135-147]
- workspaces/extensions/app-config.production.yaml[1-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
12.8% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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