Skip to content

feat: add IOP mode support with custom routes - #2036

Merged
adonispuente merged 1 commit into
RedHatInsights:foreman-3.18from
adonispuente:IOPr
Jul 28, 2026
Merged

adonispuente merged 1 commit into
RedHatInsights:foreman-3.18from
adonispuente:IOPr

Conversation

@adonispuente

@adonispuente adonispuente commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

To test this PR, all you need to do:

  • Run npm i
  • export IOP_URL={current IOP instance, DM if you need a url} npm run start:proxy:iop
  • verify everything works as expected after navigating to iop.foo.redhat.com and logging in

Theres currently an issue where when trying to kill the applicaiton, it doesnt always kill webpack instances. If it hangs up, try
ps aux | grep webpack | grep -v grep
and then kill -9 whatever port is running

Theres a currently a PR in FEC to fix this: RedHatInsights/frontend-components#2397

Summary by Sourcery

Add support for running the Advisor frontend in IOP mode with custom routes and compatibility tweaks for Foreman/IOP-hosted module federation.

New Features:

  • Introduce an IOP-specific dev proxy script that wires environment variables and custom routes for running against an IOP instance.
  • Expose additional module federation entry points for IOP-specific recommendation list and details views.
  • Add configuration to toggle SPA fallback and deployment/publicPath based on IOP mode.

Enhancements:

  • Patch frontend module federation utilities so that react/jsx-runtime and react-intl are bundled in the remote instead of assumed to be chrome-provided in IOP environments.
  • Update frontend-components-config dependency to a newer version to support the new configuration and IOP-related behavior.

Build:

  • Adjust fec configuration to better support IOP deployments, including conditional deployment paths and SPA fallback behavior.

@adonispuente
adonispuente requested a review from a team as a code owner June 24, 2026 19:52
@coderabbitai

coderabbitai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f28c70f-08fa-4214-9c82-0ba5a7497cfa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Adds IOP mode support for the Advisor frontend by patching the federated modules config, wiring new IOP-specific entry points, and introducing an IOP proxy start script and custom routes configuration, along with a required frontend-components-config version bump.

Flow diagram for start:proxy:iop development startup

flowchart LR
  Dev[Developer]
  NpmScriptStartProxyIop[npm run start:proxy:iop]
  FecDevProxy[fec dev-proxy --iop]
  EnvVars[IOP=true, HCC_ENV=iop,<br>HCC_ENV_URL, FEC_IOP_CUSTOM_ROUTES_PATH]
  AdvisorApp[Advisor frontend in IOP mode]

  Dev --> NpmScriptStartProxyIop
  NpmScriptStartProxyIop --> EnvVars
  EnvVars --> FecDevProxy
  FecDevProxy --> AdvisorApp
Loading

File-Level Changes

Change Details Files
Wire fec.config to support IOP deployments and SPA behavior while exposing IOP-specific module federation remotes.
  • Require a new patchFederationForIop helper at config load time so its side-effects adjust module federation behavior for IOP.
  • Toggle SPAFallback based on the IOP environment to avoid SPA fallback under IOP while preserving it otherwise.
  • Refactor deployment/publicPath selection into a single conditional spread using process.env.IOP.
  • Add ListIop and IopRecommendationDetails as additional moduleFederation exposes for IOP entry points.
  • Remove the explicit webpack output.publicPath override to rely on fec defaults/conditional publicPath.
fec.config.js
Introduce a runtime patch for frontend-components module federation includes to make the app compatible with IOP-hosted React.
  • Resolve and require the frontend-components federated-modules utility module at runtime.
  • Wrap createIncludes to call the original implementation and then delete chromeProvided entries for react/jsx-runtime and react-intl so they are bundled with the remote under IOP.
  • Document the motivation for the patch via in-file comments describing IOP/Foreman hosting behavior and the specific runtime errors being addressed.
config/patchFederationForIop.js
Add an IOP proxy start script and align dependency versions to support IOP and custom routes.
  • Add start:proxy:iop npm script that sets PROXY, IOP, HCC_ENV=iop, HCC_ENV_URL from IOP_URL, and FEC_IOP_CUSTOM_ROUTES_PATH to custom_routes.json while invoking fec dev-proxy with --iop.
  • Upgrade @redhat-cloud-services/frontend-components-config to a newer minor version compatible with the IOP utilities used by the patch script.
  • Introduce an empty custom_routes.json file as a placeholder for IOP custom route configuration.
package.json
package-lock.json
custom_routes.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 - I've left some high level feedback:

  • The start:proxy:iop script relies on shell-specific syntax like $(pwd) and $IOP_URL, which may not work on all environments (e.g. Windows/npm on non-bash shells); consider using a cross-platform approach or deferring this logic to a small Node script.
  • The custom_routes.json currently hardcodes port 8004; consider reading the target port from an environment variable or shared config so the routes automatically stay in sync with the --staticPort you pass to the dev server.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `start:proxy:iop` script relies on shell-specific syntax like `$(pwd)` and `$IOP_URL`, which may not work on all environments (e.g. Windows/npm on non-bash shells); consider using a cross-platform approach or deferring this logic to a small Node script.
- The `custom_routes.json` currently hardcodes port 8004; consider reading the target port from an environment variable or shared config so the routes automatically stay in sync with the `--staticPort` you pass to the dev server.

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.

@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 - I've found 9 security issues, 2 other issues, and left some high level feedback:

Security issues:

  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)
  • FSL-1.1-MIT: Open-source license could not be identified (link)

General comments:

  • The global require('./config/patchFederationForIop'); in fec.config.js will modify the federated-modules behaviour for all environments; consider gating this patch behind process.env.IOP === 'true' so standard Chrome-hosted builds keep the default sharing behavior.
  • In patchFederationForIop.js, it would be safer to guard against missing or unexpected shapes of includes.chromeProvided before deleting keys (e.g., check that includes.chromeProvided exists and is an object) to avoid hard-to-debug runtime errors if the upstream utilities package changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The global `require('./config/patchFederationForIop');` in `fec.config.js` will modify the federated-modules behaviour for all environments; consider gating this patch behind `process.env.IOP === 'true'` so standard Chrome-hosted builds keep the default sharing behavior.
- In `patchFederationForIop.js`, it would be safer to guard against missing or unexpected shapes of `includes.chromeProvided` before deleting keys (e.g., check that `includes.chromeProvided` exists and is an object) to avoid hard-to-debug runtime errors if the upstream utilities package changes.

## Individual Comments

### Comment 1
<location path="fec.config.js" line_range="4" />
<code_context>
 const { resolve } = require('path');
 const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');

+require('./config/patchFederationForIop');
+
 module.exports = {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Conditionally apply the federation patch only in IOP environments.

Since `patchFederationForIop` is intended only for Foreman/IOP hosts, consider guarding the `require('./config/patchFederationForIop')` with `if (process.env.IOP === 'true')` so that non-IOP environments keep their existing federation behavior.

```suggestion
if (process.env.IOP === 'true') {
  require('./config/patchFederationForIop');
}
```
</issue_to_address>

### Comment 2
<location path="config/patchFederationForIop.js" line_range="17-21" />
<code_context>
+const federatedModulesUtil = require(federatedModulesPath);
+const originalCreateIncludes = federatedModulesUtil.createIncludes;
+
+federatedModulesUtil.createIncludes = () => {
+    const includes = originalCreateIncludes();
+    delete includes.chromeProvided['react/jsx-runtime'];
+    delete includes.chromeProvided['react-intl'];
+    return includes;
+};
</code_context>
<issue_to_address>
**issue (bug_risk):** Preserve the original `createIncludes` signature and guard against missing `chromeProvided`.

Two robustness points:

1. This override drops any arguments to `createIncludes`, so future upstream parameters would be ignored. Forward them instead:

```js
federatedModulesUtil.createIncludes = (...args) => {
  const includes = originalCreateIncludes(...args);
  if (includes.chromeProvided) {
    delete includes.chromeProvided['react/jsx-runtime'];
    delete includes.chromeProvided['react-intl'];
  }
  return includes;
};
```

2. Guard `includes.chromeProvided` to avoid a possible `TypeError` if that field is ever missing or the structure changes.
</issue_to_address>

### Comment 3
<location path="package-lock.json" line_range="7675-7683" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 4
<location path="package-lock.json" line_range="7705-7712" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-darwin):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 5
<location path="package-lock.json" line_range="7718-7735" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-linux-arm):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 6
<location path="package-lock.json" line_range="7736-7753" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-linux-arm64):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 7
<location path="package-lock.json" line_range="7754-7772" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-linux-i686):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 8
<location path="package-lock.json" line_range="7773-7790" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-linux-x64):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 9
<location path="package-lock.json" line_range="7791-7806" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-win32-arm64):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 10
<location path="package-lock.json" line_range="7807-7818" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-win32-i686):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

### Comment 11
<location path="package-lock.json" line_range="7824-7834" />
<code_context>

</code_context>
<issue_to_address>
**security (license/@sentry/cli-win32-x64):** FSL-1.1-MIT: Open-source license could not be identified

The obligations of the `FSL-1.1-MIT` license for this code could not be determined automatically. Unknown licenses may carry obligations or restrictions and should be reviewed manually to ensure compliance

*Source: trivy*
</issue_to_address>

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 fec.config.js
Comment on lines +17 to +21
federatedModulesUtil.createIncludes = () => {
const includes = originalCreateIncludes();
delete includes.chromeProvided['react/jsx-runtime'];
delete includes.chromeProvided['react-intl'];
return includes;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Preserve the original createIncludes signature and guard against missing chromeProvided.

Two robustness points:

  1. This override drops any arguments to createIncludes, so future upstream parameters would be ignored. Forward them instead:
federatedModulesUtil.createIncludes = (...args) => {
  const includes = originalCreateIncludes(...args);
  if (includes.chromeProvided) {
    delete includes.chromeProvided['react/jsx-runtime'];
    delete includes.chromeProvided['react-intl'];
  }
  return includes;
};
  1. Guard includes.chromeProvided to avoid a possible TypeError if that field is ever missing or the structure changes.

Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
Comment thread package-lock.json
@Fewwy

Fewwy commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

After updating frontend development proxy and adding symlink it worked :) https://github.com/RedHatInsights/frontend-development-proxy#iop-mode

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

LGTM

@adonispuente

Copy link
Copy Markdown
Contributor Author

/retest

@adonispuente
adonispuente merged commit 54cfc6c into RedHatInsights:foreman-3.18 Jul 28, 2026
4 of 5 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.

2 participants