Skip to content

New Vulnerabilities list tab and page - #1031

Merged
jeremylenz merged 5 commits into
theforeman:developfrom
ShimShtein:new_cve_tab
Jul 18, 2025
Merged

New Vulnerabilities list tab and page#1031
jeremylenz merged 5 commits into
theforeman:developfrom
ShimShtein:new_cve_tab

Conversation

@ShimShtein

@ShimShtein ShimShtein commented Jul 16, 2025

Copy link
Copy Markdown
Member

It's based on #1025

It introduces CVEs list to host details as a new "Vulnerabiliy" tab.
It also introduces the CVE List page from #1019.

Summary by Sourcery

Introduce a new Vulnerability tab on host details and a standalone Vulnerability page by integrating remote modules via Scalprum and provide a context wrapper for plugin configuration.

New Features:

  • Add a new "Vulnerability" tab on the host details page that loads the SystemDetailTable module via Scalprum
  • Add a standalone Vulnerability page that loads the CveListPage module via Scalprum
  • Introduce a ScalprumContextWrapper to configure the vulnerability plugin environment with mocked user and manifest settings

Enhancements:

  • Wrap CVE components with ScalprumContextWrapper and Foreman PageLayout for consistent layout and context
  • Update fill registrations and routes to use the new wrapped components

Build:

  • Add @scalprum/react-core and @scalprum/core as project dependencies

@sourcery-ai

sourcery-ai Bot commented Jul 16, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR replaces placeholder CVEs and Vulnerability pages with Scalprum-based microfrontend integration by wrapping them in a custom ScalprumContextWrapper, updating component exports and plugin registrations, and adding the necessary Scalprum dependencies.

Class diagram for ScalprumContextWrapper and related components

classDiagram
    class ScalprumContextWrapper {
      +children: node
      +config: object
      +mockUser: object
    }
    class CVEsHostDetailsTabWrapper {
      +Renders: ScalprumContextWrapper
    }
    class CVEsHostDetailsTab {
      +Renders: ScalprumComponent
      +Renders: PageLayout
    }
    class InsightsVulnerabilityWrap {
      +Renders: ScalprumContextWrapper
    }
    class InsightsVulnerability {
      +Renders: ScalprumComponent
      +Renders: PageLayout
    }
    ScalprumContextWrapper <|-- CVEsHostDetailsTabWrapper
    ScalprumContextWrapper <|-- InsightsVulnerabilityWrap
    CVEsHostDetailsTabWrapper *-- CVEsHostDetailsTab
    InsightsVulnerabilityWrap *-- InsightsVulnerability
    CVEsHostDetailsTab *-- ScalprumComponent
    InsightsVulnerability *-- ScalprumComponent
    ScalprumContextWrapper *-- ScalprumProvider
Loading

File-Level Changes

Change Details Files
Refactor CVEsHostDetailsTab to use Scalprum microfrontend
  • Remove hostName prop and PropTypes usage
  • Embed ScalprumComponent (scope='vulnerability', module='./SystemDetailTable')
  • Wrap content in PageLayout with a development placeholder
  • Introduce CVEsHostDetailsTabWrapper that applies ScalprumContextWrapper
  • Switch default export to the wrapper component
webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js
webpack/CVEsHostDetailsTab/index.js
Refactor InsightsVulnerability page to use Scalprum microfrontend
  • Embed ScalprumComponent (scope='vulnerability', module='./CveListPage')
  • Wrap content in PageLayout preserving the placeholder
  • Introduce InsightsVulnerabilityWrap with ScalprumContextWrapper
  • Switch default export to the wrapper component
webpack/InsightsVulnerability/InsightsVulnerability.js
Update plugin fills and page registrations to use new wrappers
  • Import and use CVEsHostDetailsTabWrapper in host-details-page-tabs fill
  • Register InsightsVulnerabilityWrap instead of the original component in pages and routes
webpack/ForemanRhCloudFills.js
webpack/ForemanRhCloudPages.js
Add ScalprumContextWrapper for vulnerability plugin configuration
  • Create ScalprumContextWrapper component with ScalprumProvider
  • Configure plugin manifest transforms and mock user api
webpack/common/ScalprumModule/ScalprumContext.js
Add Scalprum dependencies
  • Add @scalprum/react-core and @scalprum/core to package.json dependencies
package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai 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.

Hey @ShimShtein - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Using a hardcoded mockUser may cause issues in production. (link)

General comments:

  • The wrapper components (CVEsHostDetailsTabWrapper and InsightsVulnerabilityWrap) don’t forward incoming props (e.g. hostName) to their inner components—ensure you spread or pass those props through if they’re needed downstream.
  • You’re wrapping each page component in its own ScalprumContextWrapper, which leads to repeated context providers—consider lifting the provider to a higher level (e.g. in your routes setup) to reduce duplication.
  • ScalprumContextWrapper hardcodes manifestLocation and cdnPath using window.location—extract these into configuration or environment variables to make deployments and testing more flexible.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The wrapper components (CVEsHostDetailsTabWrapper and InsightsVulnerabilityWrap) don’t forward incoming props (e.g. hostName) to their inner components—ensure you spread or pass those props through if they’re needed downstream.
- You’re wrapping each page component in its own ScalprumContextWrapper, which leads to repeated context providers—consider lifting the provider to a higher level (e.g. in your routes setup) to reduce duplication.
- ScalprumContextWrapper hardcodes manifestLocation and cdnPath using window.location—extract these into configuration or environment variables to make deployments and testing more flexible.

## Individual Comments

### Comment 1
<location> `webpack/common/ScalprumModule/ScalprumContext.js:14` </location>
<code_context>
+    },
+  };
+
+  const mockUser = {
+    entitlements: {},
+    identity: {
+      account_number: 'string',
+      org_id: 'string',
+      internal: {
+        org_id: 'string',
+        account_id: 'string',
+      },
+      type: 'string',
+      user: {
+        username: 'string',
+        email: 'string',
+        first_name: 'string',
+        last_name: 'string',
+        is_active: 'boolean',
+        is_internal: 'boolean',
+        is_org_admin: 'boolean',
+        locale: 'string',
+      },
+    },
+  };
+  return (
+    <ScalprumProvider
</code_context>

<issue_to_address>
Using a hardcoded mockUser may cause issues in production.

Returning a hardcoded mockUser from chrome.auth.getUser can result in incorrect user context or security vulnerabilities in production. Make this behavior conditional on the environment or configurable.
</issue_to_address>

### Comment 2
<location> `webpack/common/ScalprumModule/ScalprumContext.js:58` </location>
<code_context>
+      api={{
+        chrome: {
+          isBeta: () => false,
+          on: () => {},
+          auth: {
+            getUser: () => Promise.resolve(mockUser),
</code_context>

<issue_to_address>
The chrome.on stub may not be sufficient for all event listeners.

Modules relying on event subscription or unsubscription may fail silently. Consider adding minimal event emitter functionality or a warning.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
        chrome: {
          isBeta: () => false,
          on: () => {},
          auth: {
            getUser: () => Promise.resolve(mockUser),
          },
        },
=======
        chrome: (() => {
          // Minimal event emitter for mocking
          const listeners = {};
          return {
            isBeta: () => false,
            on: (event, handler) => {
              if (!listeners[event]) {
                listeners[event] = [];
              }
              listeners[event].push(handler);
              // Optionally, log a warning to indicate this is a mock
              // eslint-disable-next-line no-console
              console.warn(`[ScalprumContext] chrome.on('${event}') registered in mock context.`);
            },
            off: (event, handler) => {
              if (listeners[event]) {
                listeners[event] = listeners[event].filter(h => h !== handler);
                // eslint-disable-next-line no-console
                console.warn(`[ScalprumContext] chrome.off('${event}') unregistered in mock context.`);
              }
            },
            // Optionally, a method to trigger events in tests
            __emit: (event, ...args) => {
              if (listeners[event]) {
                listeners[event].forEach(handler => handler(...args));
              }
            },
            auth: {
              getUser: () => Promise.resolve(mockUser),
            },
          };
        })(),
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread webpack/common/ScalprumModule/ScalprumContext.js Outdated
Comment thread webpack/common/ScalprumModule/ScalprumContext.js Outdated
@ShimShtein

Copy link
Copy Markdown
Member Author

As for @MariaAga 's request got rid of the ScalprumProviderWrapper and simplified the code.
@jeremylenz I think we can reuse the common scalprum properties and make sure we have all the paths e.t.c. in the same place. The same goes if we need changes to user definition or any other context.

@vkrizan

vkrizan commented Jul 17, 2025

Copy link
Copy Markdown
Contributor

@ShimShtein can you please update the title and description to reflect that this adds CVE list as well? PR #1025 was closed in favor of this one.

@vkrizan vkrizan 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.

Thank you. I've left a couple of comments.

Comment thread package.json
Comment thread webpack/InsightsVulnerability/InsightsVulnerability.js
Comment thread webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js Outdated
Comment thread webpack/InsightsVulnerability/InsightsVulnerability.js Outdated
Comment thread webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js
component: props => <CVEsHostDetailsTabWrapper {...props} />,
weight: 300,
metadata: {
hideTab: vulnerabilityDisabled,

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.

The tab is not showing for me. How do I debug it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

  1. Are there any errors in web console?
  2. Take a look at the /hosts/:id API call, there is a flag that is passed there under the vulnerability: enabled path.If it is passed as false, it means you need to set the advisor_local setting

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.

There is no such key vulnerability on the API response. Probably I've registered the system w/o Insights enabled. How to enable it?

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.

@jeremylenz ^ 🙏

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like the vulnerability node is only sent with index and not show:

api_view :list => 'api/v2/hosts/insights/insights', :single => 'api/v2/hosts/insights/single'
set_dependent_action :destroy

Need to add it to app/views/api/v2/hosts/insights/base.rabl.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Another option is to have vulnerabilityDisabled look at the :use_local_advisor_engine node instead, which is already in the base rabl.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

From Shim: "We are adding it to API, specifically to a single rabl. The only thing that needs to exist, is the insights facet. If the facet is not there, we won't add the node. Now the facet should be created on each package upload. Maybe in Viliam's case the host was there before my package upload pr got in, so he doesn't have the insights facet on the host. The easiest way would be to sync hosts with a button. I think I have enabled this use case, and it will properly sync the ids"

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.

I did a resycn with "Generate and upload report" but some hosts still don't show it. Interesting fact is that navigating from CVE counts form the hosts list table gets the tab shown, but it doesn't provide it a subscription/system id.

@ShimShtein ShimShtein changed the title New CVE tab New CVE list tab and CVE list page Jul 17, 2025
@ShimShtein

Copy link
Copy Markdown
Member Author

Ready for another round!

Comment thread webpack/ForemanRhCloudFills.js Outdated
systemId: PropTypes.string.isRequired,
};

const CVEsHostDetailsTabWrapper = ({ response }) => (

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.

The tab content is missing a bounding box. Its contents are rendered very close to the edges.

image

Comment thread webpack/ForemanRhCloudFills.js Outdated

@vkrizan vkrizan 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.

Feel free to merge. The remaining issues can be done in a followup.

@jeremylenz jeremylenz changed the title New CVE list tab and CVE list page New Vulnerabilities list tab and page Jul 18, 2025
@jeremylenz
jeremylenz merged commit dba5454 into theforeman:develop Jul 18, 2025
15 checks 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.

5 participants