Skip to content

Conversation

@rm3l
Copy link
Member

@rm3l rm3l commented Jan 9, 2026

Description

As discussed in https://redhat-internal.slack.com/archives/C04CUSD4JSG/p1767790419980379, we need to extract the catalog entities from the index image to the /marketplace (to be replaced by /extensions in redhat-developer/rhdh-plugins#2006) folder, so that the extensions backend providers can automatically discover them. Otherwise, there are no plugins displayed in the RHDH Extensions UI.

redhat-developer/rhdh#3970 added support for specifying the extraction dir via a new CATALOG_ENTITIES_EXTRACT_DIR env var, which we now need to set in the Install Methods (and additionally add the right volume mounts - we cannot create that folder right in the main container because the root filesystem is read-only for security purposes).

Which issue(s) does this PR fix or relate to

How to test changes / Special notes to the reviewer

Before

image

With the changes here

image

Checklist

  • For each Chart updated, version bumped in the corresponding Chart.yaml according to Semantic Versioning.
  • For each Chart updated, variables are documented in the values.yaml and added to the corresponding README.md. The pre-commit utility can be used to generate the necessary content. Use pre-commit run -a to apply changes. The pre-commit Workflow will do this automatically for you if needed.
  • JSON Schema template updated and re-generated the raw schema via the pre-commit hook.
  • Tests pass using the Chart Testing tool and the ct lint command.
  • If you updated the orchestrator-infra chart, make sure the versions of the Knative CRDs are aligned with the versions of the CRDs installed by the OpenShift Serverless operators declared in the values.yaml file. See Installing Knative Eventing and Knative Serving CRDs for more details.

@rhdh-qodo-merge
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

RHIDP-11293 - Partially compliant

Compliant requirements:

  • Add an additional /marketplace volume mount into the RHDH container (Helm chart change).
  • Set the catalog entities extraction directory to use that new /marketplace mount.

Non-compliant requirements:

  • Ensure Helm users who override extraVolumes/extraVolumeMounts are made aware of the change (documentation/release notes/README/values comments).

Requires further human verification:

  • Verify the runtime behavior: entities extraction actually uses /marketplace and works across plugin install/initContainer + main container startup.
  • Confirm no breaking impact for existing deployments that set/override extraVolumes and/or extraVolumeMounts in their own values (upgrade test).
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🔒 No security concerns identified
⚡ Recommended focus areas for review

Breaking Change

The chart defaults add a new extensions-catalog entry under upstream.backstage.extraVolumes and extraVolumeMounts. Users who override these lists (rather than merging) may unintentionally drop required mounts/volumes after upgrading. Add explicit documentation/notes (e.g., README or values comments) explaining the new required entries and how to preserve/merge them when overriding.

extraVolumeMounts:
  # The initContainer below will install dynamic plugins in this volume mount.
  - name: dynamic-plugins-root
    mountPath: /opt/app-root/src/dynamic-plugins-root
  - name: extensions-catalog
    mountPath: /marketplace
  - name: temp
    mountPath: /tmp
extraVolumes:
  # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start.
  - name: dynamic-plugins-root
    ephemeral:
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins.
              storage: 5Gi
  # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map.
  # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field.
  - name: dynamic-plugins
    configMap:
      defaultMode: 420
      name: '{{ printf "%s-dynamic-plugins" .Release.Name }}'
      optional: true
  # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret)
  # to be used when running `npm pack` during the dynamic plugins installation by the initContainer.
  - name: dynamic-plugins-npmrc
    secret:
      defaultMode: 420
      optional: true
      secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}'
  # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret)
  # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer.
  - name: dynamic-plugins-registry-auth
    secret:
      defaultMode: 416
      optional: true
      secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}'
  - name: npmcacache
    emptyDir: {}
  - name: extensions-catalog
    emptyDir: {}
  - name: temp
Path Consistency

CATALOG_ENTITIES_EXTRACT_DIR is set to /marketplace and the new extensions-catalog volume is an emptyDir. Confirm this is the intended persistence model (ephemeral) and that all components expecting extracted entities can read from this location in the correct container(s).

  - name: CATALOG_INDEX_IMAGE
    value: '{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}'
  - name: CATALOG_ENTITIES_EXTRACT_DIR
    value: '/marketplace'
imagePullPolicy: ""
volumeMounts:
  - mountPath: /dynamic-plugins-root
    name: dynamic-plugins-root
  - mountPath: /opt/app-root/src/dynamic-plugins.yaml
    name: dynamic-plugins
    readOnly: true
    subPath: dynamic-plugins.yaml
  - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins
    name: dynamic-plugins-npmrc
    readOnly: true
    subPath: .npmrc
  - mountPath: /opt/app-root/src/.config/containers
    name: dynamic-plugins-registry-auth
    readOnly: true
  - mountPath: /opt/app-root/src/.npm/_cacache
    name: npmcacache
  - name: extensions-catalog
    mountPath: /marketplace
  - name: temp
📚 Focus areas based on broader codebase context

Missing Docs

The newly added extensions-catalog volume/mount is introduced without the inline documentation style used for other volumes (e.g., purpose, whether optional, and sizing/behavior notes). This makes it harder for chart users to understand what the volume is for and whether it’s safe to change or override. (Ref 1, Ref 2)

  - name: extensions-catalog
    mountPath: /marketplace
  - name: temp
    mountPath: /tmp
extraVolumes:
  # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start.
  - name: dynamic-plugins-root
    ephemeral:
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins.
              storage: 5Gi
  # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map.
  # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field.
  - name: dynamic-plugins
    configMap:
      defaultMode: 420
      name: '{{ printf "%s-dynamic-plugins" .Release.Name }}'
      optional: true
  # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret)
  # to be used when running `npm pack` during the dynamic plugins installation by the initContainer.
  - name: dynamic-plugins-npmrc
    secret:
      defaultMode: 420
      optional: true
      secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}'
  # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret)
  # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer.
  - name: dynamic-plugins-registry-auth
    secret:
      defaultMode: 416
      optional: true
      secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}'
  - name: npmcacache
    emptyDir: {}
  - name: extensions-catalog
    emptyDir: {}
  - name: temp

Reference reasoning: Existing volume entries (notably dynamic-plugins-root) include descriptive comments explaining intent and operational expectations (ephemeral PVC, storage sizing), and CI examples reinforce this documented/override-friendly pattern. Aligning extensions-catalog with the same documentation approach improves consistency and usability of values.yaml.

📄 References
  1. redhat-developer/rhdh-chart/charts/backstage/values.yaml [160-178]
  2. redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [2-27]
  3. redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [28-34]
  4. redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [35-50]
  5. redhat-developer/rhdh-chart/charts/backstage/ci/with-orchestrator-values.yaml [1-21]
  6. redhat-developer/rhdh-chart/charts/backstage/values.yaml [37-44]
  7. redhat-developer/rhdh-operator/examples/catalog-index.yaml [1-14]
  8. redhat-developer/rhdh-operator/integration_tests/testdata/rhdh-replace-dynaplugin-root.yaml [1-14]

@rhdh-qodo-merge rhdh-qodo-merge bot added the enhancement New feature or request label Jan 9, 2026
@rhdh-qodo-merge
Copy link

rhdh-qodo-merge bot commented Jan 9, 2026

PR Type

(Describe updated until commit 1742961)

Enhancement, Bug fix


Description

  • Add volume mount for extension catalog entities extraction to /extensions path

  • Set CATALOG_ENTITIES_EXTRACT_DIR environment variable in init container

  • Mount legacy /marketplace path as read-only for backward compatibility

  • Bump chart version to 5.0.0 (major version due to breaking changes)


File Walkthrough

Relevant files
Configuration changes
Chart.yaml
Bump chart version to 5.0.0                                                           

charts/backstage/Chart.yaml

  • Bump chart version from 4.9.0 to 5.0.0 to reflect breaking changes
+1/-1     
values.schema.json
Update JSON schema with extension catalog configuration   

charts/backstage/values.schema.json

  • Add /extensions volume mount to extraVolumeMounts with read-write
    access
  • Add /marketplace volume mount as read-only for backward compatibility
  • Add extensions-catalog emptyDir volume to extraVolumes
  • Add CATALOG_ENTITIES_EXTRACT_DIR environment variable set to
    /extensions in init container
  • Add volume mount for extensions catalog in init container volumeMounts
+21/-0   
Documentation
README.md
Update documentation with new version                                       

charts/backstage/README.md

  • Update version badge from 4.9.0 to 5.0.0
  • Update helm install command example with new version
+2/-2     
Tests
with-custom-dynamic-pvc-claim-spec-values.yaml
Add extensions catalog volume to test values                         

charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml

  • Add extensions-catalog emptyDir volume for test configuration
+2/-0     
Enhancement
values.yaml
Configure extension catalog volumes and environment variable

charts/backstage/values.yaml

  • Add /extensions volume mount to backstage container extraVolumeMounts
  • Add /marketplace read-only volume mount for backward compatibility
  • Add extensions-catalog emptyDir volume definition
  • Set CATALOG_ENTITIES_EXTRACT_DIR environment variable to /extensions
    in init container
  • Add volume mount for extensions catalog in init container
+12/-0   

@rhdh-qodo-merge
Copy link

rhdh-qodo-merge bot commented Jan 9, 2026

PR Code Suggestions ✨

No code suggestions found for the PR.

@rm3l rm3l force-pushed the rhidp-11293-helm-chart-add-a-new-marketplace-volume-into-the-rhdh-pod-and-set-catalog-entities-extraction-dir-to-it branch from 97c21c3 to 8585148 Compare January 9, 2026 08:25
@redhat-developer redhat-developer deleted a comment from github-actions bot Jan 9, 2026
Because this requires potential updates to `upstream.backstage.extraVolumes` for cases where it was overridden.
@rhdh-qodo-merge
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

RHIDP-11293 - Partially compliant

Compliant requirements:

  • Add an additional /marketplace volume mount into the RHDH container via the Helm chart.
  • Set the catalog entities extraction directory to use that new /marketplace volume.

Non-compliant requirements:

  • Ensure Helm users who override extraVolumes / extraVolumeMounts are made aware of the change.

Requires further human verification:

  • Validate at deployment time that catalog entity extraction artifacts are actually written under /marketplace and that permissions/SELinux contexts are correct in OpenShift.
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🔒 No security concerns identified
⚡ Recommended focus areas for review

Missing mount

The CI values add the extensions-catalog volume but do not add the corresponding extraVolumeMounts entry for /marketplace. If this file is used in tests, the initContainer env CATALOG_ENTITIES_EXTRACT_DIR=/marketplace may point to a non-mounted path, potentially causing runtime/test failures or masking the intended behavior.

- name: npmcacache
  emptyDir: {}
- name: temp
  emptyDir: {}
- name: extensions-catalog
  emptyDir: {}
Upgrade note

The change introduces a new default volume/volumeMount and a new env var affecting behavior. The ticket explicitly calls out that users overriding extraVolumes/extraVolumeMounts must be made aware; add an upgrade note / values documentation describing the new extensions-catalog mount at /marketplace and the CATALOG_ENTITIES_EXTRACT_DIR behavior to prevent breaking custom overrides.

# RHDH Backstage Helm Chart for OpenShift

![Version: 5.0.0](https://img.shields.io/badge/Version-5.0.0-informational?style=flat-square)
![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)

A Helm chart for deploying Red Hat Developer Hub, which is a Red Hat supported version of Backstage.

The telemetry data collection feature is enabled by default. Red Hat Developer Hub sends telemetry data to Red Hat by using the `backstage-plugin-analytics-provider-segment` plugin. To disable this and to learn what data is being collected, see https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.6/html-single/telemetry_data_collection_and_analysis/index

**Homepage:** <https://red.ht/rhdh>

## Productized RHDH

This repository now provides the productized RHDH chart.
For the **Generally Available** version of this chart, see:

* https://github.com/openshift-helm-charts/charts - official releases to https://charts.openshift.io/

## Maintainers

| Name | Email | Url |
| ---- | ------ | --- |
| Red Hat |  | <https://redhat.com> |

## TL;DR

```console
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add backstage https://backstage.github.io/charts
helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart

helm install my-backstage redhat-developer/backstage --version 5.0.0

Introduction


</details>

</td></tr>
<tr><td>

<details><summary>📄 References</summary><ol><li><a href="https://github.com/redhat-developer/rhdh-chart/blob/353db4e/charts/backstage/values.yaml/#L160-L178">redhat-developer/rhdh-chart/charts/backstage/values.yaml [160-178]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-chart/blob/5dab63f/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml/#L2-L27">redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [2-27]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-chart/blob/5dab63f/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml/#L28-L34">redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [28-34]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-chart/blob/5dab63f/charts/backstage/ci/with-orchestrator-values.yaml/#L1-L21">redhat-developer/rhdh-chart/charts/backstage/ci/with-orchestrator-values.yaml [1-21]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-chart/blob/353db4e/charts/backstage/values.yaml/#L37-L44">redhat-developer/rhdh-chart/charts/backstage/values.yaml [37-44]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-operator/blob/d5d22c9/integration_tests/testdata/rhdh-replace-dynaplugin-root.yaml/#L1-L14">redhat-developer/rhdh-operator/integration_tests/testdata/rhdh-replace-dynaplugin-root.yaml [1-14]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-operator/blob/d5d22c9/integration_tests/testdata/spec-deployment.yaml/#L1-L23">redhat-developer/rhdh-operator/integration_tests/testdata/spec-deployment.yaml [1-23]</a></li>

<li><a href="https://github.com/redhat-developer/rhdh-operator/blob/bfe3d48/examples/catalog-index.yaml/#L1-L14">redhat-developer/rhdh-operator/examples/catalog-index.yaml [1-14]</a></li>

</ol></details>

</td></tr>
</table>

@rhdh-qodo-merge
Copy link

rhdh-qodo-merge bot commented Jan 9, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Adding required volumes via overridable defaults is fragile

The PR adds a required volume by modifying default extraVolumes and
extraVolumeMounts lists, which breaks configurations for users who override
these values. A better approach is to define required volumes directly in the
Helm template and merge them with any user-provided extra... values.

Examples:

charts/backstage/values.yaml [152-157]
    extraVolumeMounts:
      # The initContainer below will install dynamic plugins in this volume mount.
      - name: dynamic-plugins-root
        mountPath: /opt/app-root/src/dynamic-plugins-root
      - name: extensions-catalog
        mountPath: /marketplace
charts/backstage/values.yaml [160-196]
    extraVolumes:
      # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start.
      - name: dynamic-plugins-root
        ephemeral:
          volumeClaimTemplate:
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:

 ... (clipped 27 lines)

Solution Walkthrough:

Before:

# In values.yaml
backstage:
  extraVolumeMounts:
    - name: dynamic-plugins-root
      ...
    - name: extensions-catalog # <-- New required mount
      mountPath: /marketplace
  extraVolumes:
    - name: dynamic-plugins-root
      ...
    - name: extensions-catalog # <-- New required volume
      emptyDir: {}

# In templates (conceptual)
# The entire list is replaced if user provides `extraVolumes`.
volumes:
  {{- toYaml .Values.backstage.extraVolumes | nindent 8 }}

After:

# In values.yaml
backstage:
  extraVolumeMounts: [] # For user-defined mounts only
  extraVolumes: [] # For user-defined volumes only

# In templates (conceptual)
# Required volumes are hardcoded, user values are appended.
volumes:
  - name: dynamic-plugins-root
    ...
  - name: extensions-catalog # <-- Required volume is part of the template
    emptyDir: {}
  # User-provided volumes are merged
  {{- toYaml .Values.backstage.extraVolumes | nindent 8 }}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a fragile design pattern where required volumes are added to overridable extra... lists, which is a breaking change for users who customize these values, and proposes a more robust standard Helm practice.

High
General
Parameterize catalog mountPath
Suggestion Impact:The commit addressed the underlying consistency issue by changing the catalog extract dir and primary volume mount from /marketplace to /extensions (and updating CATALOG_ENTITIES_EXTRACT_DIR accordingly), while keeping /marketplace as a legacy backward-compatible mount. It did not implement the exact templated parameterization of mountPath via the env value.

code diff:

       - name: extensions-catalog
+        mountPath: /extensions
+      - name: extensions-catalog
+        # TODO(asoro): legacy path for backward compatibility. Will be removed in a near future.
         mountPath: /marketplace
+        readOnly: true
       - name: temp
         mountPath: /tmp
     extraVolumes:
@@ -230,7 +234,7 @@
           - name: CATALOG_INDEX_IMAGE
             value: '{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}'
           - name: CATALOG_ENTITIES_EXTRACT_DIR
-            value: '/marketplace'
+            value: '/extensions'
         imagePullPolicy: ""
         volumeMounts:
           - mountPath: /dynamic-plugins-root
@@ -249,7 +253,7 @@
           - mountPath: /opt/app-root/src/.npm/_cacache
             name: npmcacache
           - name: extensions-catalog
-            mountPath: /marketplace
+            mountPath: /extensions
           - name: temp

Parameterize the hardcoded /marketplace mount path for extensions-catalog in
extraVolumeMounts to use the CATALOG_ENTITIES_EXTRACT_DIR value for better
consistency and maintainability.

charts/backstage/values.yaml [156-157]

 - name: extensions-catalog
-  mountPath: /marketplace
+  mountPath: {{ .Values.initContainers[0].env.CATALOG_ENTITIES_EXTRACT_DIR | default "/marketplace" }}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a hardcoded value and proposes parameterizing it to improve maintainability by using a value already defined in the chart, which is a good practice.

Medium
  • More

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 9, 2026

Comment on lines +158 to +161
- name: extensions-catalog
# TODO(asoro): legacy path for backward compatibility. Will be removed in a near future.
mountPath: /marketplace
readOnly: true
Copy link
Member Author

Choose a reason for hiding this comment

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

Might need to be removed when redhat-developer/rhdh-plugins#2006 is merged and a new catalog index image is built. or we can still keep it for now for backward compatibility.

@rm3l rm3l marked this pull request as ready for review January 12, 2026 15:54
@openshift-ci openshift-ci bot requested a review from Fortune-Ndlovu January 12, 2026 15:54
@openshift-ci openshift-ci bot requested a review from subhashkhileri January 12, 2026 15:54
@rhdh-qodo-merge
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

RHIDP-11293 - Partially compliant

Compliant requirements:

  • Add an additional /marketplace volume mount into the RHDH container (Helm chart change).

Non-compliant requirements:

  • Ensure Helm users who override extraVolumes / extraVolumeMounts are made aware, since defaults are changing.

Requires further human verification:

  • Validate in a real deployment that extensions are correctly extracted to the configured directory and appear in the Extensions UI.
  • Validate upgrade impact for existing Helm deployments that override extraVolumes / extraVolumeMounts (especially charts that may already define a volume with the same name).
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🔒 No security concerns identified
⚡ Recommended focus areas for review

YAML Validity

The newly added CATALOG_ENTITIES_EXTRACT_DIR entry under the initContainer env list should be double-checked for correct indentation/list structure to ensure it is actually part of env (otherwise Helm may render invalid YAML or silently place it at the wrong level).

env:
  - name: NPM_CONFIG_USERCONFIG
    value: /opt/app-root/src/.npmrc.dynamic-plugins
    # This following variable is required for orchestrator to startup properly.
  - name: MAX_ENTRY_SIZE
    value: "30000000"
  - name: CATALOG_INDEX_IMAGE
    value: '{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}'
  - name: CATALOG_ENTITIES_EXTRACT_DIR
    value: '/extensions'
imagePullPolicy: ""
Compatibility

The defaults introduce a new extensions-catalog volume and mount it in two locations (/extensions and legacy /marketplace with readOnly: true). Verify this does not break existing workloads that expect to write to /marketplace, and ensure the new default volume name doesn’t conflict with common user overrides of extraVolumes/extraVolumeMounts.

"extraVolumeMounts": {
    "default": [
        {
            "mountPath": "/opt/app-root/src/dynamic-plugins-root",
            "name": "dynamic-plugins-root"
        },
        {
            "mountPath": "/extensions",
            "name": "extensions-catalog"
        },
        {
            "mountPath": "/marketplace",
            "name": "extensions-catalog",
            "readOnly": true
        },
        {
            "mountPath": "/tmp",
            "name": "temp"
        }
    ],
    "items": {
        "description": "VolumeMount describes a mounting of a Volume within a container.",
        "properties": {
            "mountPath": {
                "description": "Path within the container at which the volume should be mounted.  Must not contain ':'.",
                "type": "string"
            },
            "mountPropagation": {
                "description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified (which defaults to None).",
                "type": "string"
            },
            "name": {
                "description": "This must match the Name of a Volume.",
                "type": "string"
            },
            "readOnly": {
                "description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
                "type": "boolean"
            },
            "recursiveReadOnly": {
                "description": "RecursiveReadOnly specifies whether read-only mounts should be handled recursively.\n\nIf ReadOnly is false, this field has no meaning and must be unspecified.\n\nIf ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only.  If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime.  If this field is set to Enabled, the mount is made recursively read-only if it is supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason.\n\nIf this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None).\n\nIf this field is not specified, it is treated as an equivalent of Disabled.",
                "type": "string"
            },
            "subPath": {
                "description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).",
                "type": "string"
            },
            "subPathExpr": {
                "description": "Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to \"\" (volume's root). SubPathExpr and SubPath are mutually exclusive.",
                "type": "string"
            }
        },
        "required": [
            "name",
            "mountPath"
        ],
        "type": "object"
    },
    "title": "Backstage container additional volume mounts",
    "type": "array"
},
"extraVolumes": {
    "default": [
        {
            "ephemeral": {
                "volumeClaimTemplate": {
                    "spec": {
                        "accessModes": [
                            "ReadWriteOnce"
                        ],
                        "resources": {
                            "requests": {
                                "storage": "5Gi"
                            }
                        }
                    }
                }
            },
            "name": "dynamic-plugins-root"
        },
        {
            "configMap": {
                "defaultMode": 420,
                "name": "{{ printf \"%s-dynamic-plugins\" .Release.Name }}",
                "optional": true
            },
            "name": "dynamic-plugins"
        },
        {
            "name": "dynamic-plugins-npmrc",
            "secret": {
                "defaultMode": 420,
                "optional": true,
                "secretName": "{{ printf \"%s-dynamic-plugins-npmrc\" .Release.Name }}"
            }
        },
        {
            "name": "dynamic-plugins-registry-auth",
            "secret": {
                "defaultMode": 416,
                "optional": true,
                "secretName": "{{ printf \"%s-dynamic-plugins-registry-auth\" .Release.Name }}"
            }
        },
        {
            "emptyDir": {},
            "name": "npmcacache"
        },
        {
            "emptyDir": {},
            "name": "extensions-catalog"
        },
        {
📚 Focus areas based on broader codebase context

Storage Type

The new extensions-catalog volume is configured as emptyDir, which ties catalog entity extraction storage to node ephemeral disk and can fail under disk-pressure or with larger catalogs. Validate whether this data should instead use an ephemeral.volumeClaimTemplate (PVC-backed) similar to how dynamic plugins storage is handled, especially if the extraction output can be sizable. (Ref 4, Ref 5)

# to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer.
- name: dynamic-plugins-registry-auth
  secret:
    defaultMode: 416
    optional: true
    secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}'
- name: npmcacache
  emptyDir: {}
- name: extensions-catalog
  emptyDir: {}
- name: temp
  emptyDir: {}

Reference reasoning: The chart’s existing pattern for storing dynamically installed plugin artifacts uses an ephemeral volume with a PVC claim template and an explicit storage request, indicating a preference for more predictable, size-bounded storage over emptyDir. Reusing that approach for extracted catalog entities would align storage behavior and reduce risk from node ephemeral disk limits.

📄 References
  1. redhat-developer/rhdh-operator/config/profile/rhdh/default-config/deployment.yaml [42-65]
  2. redhat-developer/rhdh-operator/config/profile/rhdh/default-config/deployment.yaml [66-76]
  3. redhat-developer/rhdh-operator/config/profile/rhdh/default-config/deployment.yaml [21-40]
  4. redhat-developer/rhdh-chart/charts/backstage/values.yaml [160-178]
  5. redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [2-27]
  6. redhat-developer/rhdh-chart/charts/backstage/ci/with-custom-dynamic-pvc-claim-spec-values.yaml [28-34]
  7. redhat-developer/rhdh-operator/pkg/model/testdata/janus-deployment.yaml [36-58]
  8. redhat-developer/rhdh-operator/examples/catalog-index.yaml [1-14]

@rhdh-qodo-merge
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Security
Make volume mount read-only for safety

In values.yaml, add readOnly: true to the extensions-catalog volume mount at
/extensions to prevent the main application from modifying its contents.

charts/backstage/values.yaml [156-157]

 - name: extensions-catalog
   mountPath: /extensions
+  readOnly: true
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that a volume populated by an init container should be mounted as read-only by the main container to prevent accidental writes, which is a security and robustness best practice.

Medium
  • More

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.

1 participant