From 7ff3a27c9ffd14bb7820db6cf16499fa03158229 Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Thu, 28 Sep 2023 10:29:19 +0200
Subject: [PATCH 1/8] Increase minor version

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/Chart.yaml | 2 +-
 charts/backstage/README.md  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/charts/backstage/Chart.yaml b/charts/backstage/Chart.yaml
index 4d58584..50f1140 100644
--- a/charts/backstage/Chart.yaml
+++ b/charts/backstage/Chart.yaml
@@ -41,4 +41,4 @@ sources:
 # This is the chart version. This version number should be incremented each time you make changes
 # to the chart and its templates, including the app version.
 # Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 2.8.1
+version: 2.9.0
diff --git a/charts/backstage/README.md b/charts/backstage/README.md
index 8a6ea6c..692c09e 100644
--- a/charts/backstage/README.md
+++ b/charts/backstage/README.md
@@ -2,7 +2,7 @@
 # Janus-IDP Backstage Helm Chart
 
 [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/janus-idp&style=flat-square)](https://artifacthub.io/packages/search?repo=janus-idp)
-![Version: 2.8.1](https://img.shields.io/badge/Version-2.8.1-informational?style=flat-square)
+![Version: 2.9.0](https://img.shields.io/badge/Version-2.9.0-informational?style=flat-square)
 ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
 
 A Helm chart for deploying a Backstage application

From ddeca349b7eeffb76ae6e7e5c32ab0a227a9286f Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Wed, 13 Sep 2023 15:48:17 +0200
Subject: [PATCH 2/8] Add values for dynamic backend plugin support

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/README.md   |  5 +++
 charts/backstage/values.yaml | 67 ++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/charts/backstage/README.md b/charts/backstage/README.md
index 692c09e..ae4c8d1 100644
--- a/charts/backstage/README.md
+++ b/charts/backstage/README.md
@@ -129,6 +129,9 @@ Kubernetes: `>= 1.19.0-0`
 | Key | Description | Type | Default |
 |-----|-------------|------|---------|
 | global.clusterRouterBase | Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. | string | `"apps.example.com"` |
+| global.dynamic.includes | Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field. Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`). | list | `["dynamic-plugins.default.yaml"]` |
+| global.dynamic.includes[0] | List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` |
+| global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. | list | `[]` |
 | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig` | string | `""` |
 | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` |
 | route.annotations | Route specific annotations | object | `{}` |
@@ -145,6 +148,8 @@ Kubernetes: `>= 1.19.0-0`
 | route.tls.termination | Specify TLS termination. | string | `"edge"` |
 | route.wildcardPolicy | Wildcard policy if any for the route. Currently only 'Subdomain' or 'None' is allowed. | string | `"None"` |
 | upstream | Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) | object | Use Openshift compatible settings |
+| upstream.backstage.extraVolumes[0] | Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). | object | `{"emptyDir":{},"name":"dynamic-plugins-root"}` |
+| upstream.backstage.initContainers[0].image | Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. It could be replaced by a custom image based on this one. | string | `quay.io/janus-idp/backstage-showcase:latest` |
 
 ## Opinionated Backstage deployment
 
diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml
index 7a9e84c..06b897e 100644
--- a/charts/backstage/values.yaml
+++ b/charts/backstage/values.yaml
@@ -1,4 +1,18 @@
 global:
+  dynamic:
+    # -- Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field.
+    # Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`).
+    includes:
+      # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default.
+      # This file ONLY works with the `janus-idp/backstage-showcase` container image.
+      - 'dynamic-plugins.default.yaml'
+
+    # -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files.
+    # Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec),
+    # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin
+    # listed in `includes` files.
+    plugins: []
+
   # -- Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled.
   clusterRouterBase: apps.example.com
   # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`
@@ -60,6 +74,48 @@ upstream:
             key: postgres-password
             name: "{{ .Release.Name }}-postgresql"
 
+    args:
+      # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins.
+      - '--config'
+      - dynamic-plugins-root/app-config.dynamic-plugins.yaml
+    extraVolumeMounts:
+      # The initContainer below will install dynamic plugins in this volume mount.
+      - name: dynamic-plugins-root
+        mountPath: /opt/app-root/src/dynamic-plugins-root
+    extraVolumes:
+      # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start.
+      # To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html)
+      # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes).
+      - name: dynamic-plugins-root
+        emptyDir: {}
+
+      # 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: dynamic-plugins
+          optional: true
+    initContainers:
+      - name: install-dynamic-plugins
+        # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount.
+        # It could be replaced by a custom image based on this one.
+        # @default -- `quay.io/janus-idp/backstage-showcase:latest`
+        image: '{{ include "backstage.image" . }}'
+        command:
+          - python
+          - install-dynamic-plugins.py
+          - /dynamic-plugins-root
+        imagePullPolicy: Always
+        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
+        workingDir: /opt/app-root/src
+    installDir: /opt/app-root/src
   postgresql:
     enabled: true
     postgresqlDataDir: /var/lib/pgsql/data/userdata
@@ -91,6 +147,17 @@ upstream:
   ingress:
     host: "{{ .Values.global.host }}"
 
+  extraDeploy:
+    - |
+      apiVersion: v1
+      data:
+        dynamic-plugins.yaml: |
+          {{- include "common.tplvalues.render" ( dict "value"
+          .Values.global.dynamic "context" $) | nindent 4 }}
+      kind: ConfigMap
+      metadata:
+        name: dynamic-plugins
+
 # -- OpenShift Route parameters
 route:
   # -- Route specific annotations

From 1c4689030d918d2f9eda2c1e04674f414a5229db Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Mon, 2 Oct 2023 10:46:48 +0200
Subject: [PATCH 3/8] Restart the deployment on dynamic plugins change.

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/values.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml
index 06b897e..0cf3775 100644
--- a/charts/backstage/values.yaml
+++ b/charts/backstage/values.yaml
@@ -116,6 +116,10 @@ upstream:
             subPath: dynamic-plugins.yaml
         workingDir: /opt/app-root/src
     installDir: /opt/app-root/src
+    podAnnotations:
+      checksum/dynamic-plugins: >-
+        {{- include "common.tplvalues.render" ( dict "value"
+        .Values.global.dynamic "context" $) | sha256sum }}
   postgresql:
     enabled: true
     postgresqlDataDir: /var/lib/pgsql/data/userdata

From c3a6b702aa2ad9d79bf6cc63c28f5ca67172b42c Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Thu, 28 Sep 2023 16:54:05 +0200
Subject: [PATCH 4/8] Support `.npmrc` when getting dynamic plugins

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/values.yaml | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml
index 0cf3775..71ce740 100644
--- a/charts/backstage/values.yaml
+++ b/charts/backstage/values.yaml
@@ -96,6 +96,13 @@ upstream:
           defaultMode: 420
           name: dynamic-plugins
           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: dynamic-plugins-npmrc
     initContainers:
       - name: install-dynamic-plugins
         # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount.
@@ -106,6 +113,9 @@ upstream:
           - python
           - install-dynamic-plugins.py
           - /dynamic-plugins-root
+        env:
+          - name: NPM_CONFIG_USERCONFIG
+            value: /opt/app-root/src/.npmrc.dynamic-plugins
         imagePullPolicy: Always
         volumeMounts:
           - mountPath: /dynamic-plugins-root
@@ -114,6 +124,10 @@ upstream:
             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
         workingDir: /opt/app-root/src
     installDir: /opt/app-root/src
     podAnnotations:

From 30d5a018802c276eb3f8d0cf7a30ca4b76ce123a Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Mon, 2 Oct 2023 10:48:56 +0200
Subject: [PATCH 5/8] Add `dynamicPlugins` in Values schema.

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/values.schema.json      | 40 ++++++++++++++++++++++++
 charts/backstage/values.schema.tmpl.json | 38 ++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json
index d2d786a..25ccc47 100644
--- a/charts/backstage/values.schema.json
+++ b/charts/backstage/values.schema.json
@@ -8,6 +8,46 @@
                     "title": "Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled.",
                     "type": "string"
                 },
+                "dynamic": {
+                    "additionalProperties": false,
+                    "properties": {
+                        "includes": {
+                            "default": [],
+                            "items": {
+                                "type": "string"
+                            },
+                            "title": "List of YAML files to include, each of which should contain a `plugins` array.",
+                            "type": "array"
+                        },
+                        "plugins": {
+                            "items": {
+                                "properties": {
+                                    "disabled": {
+                                        "default": false,
+                                        "title": "Disable the plugin.",
+                                        "type": "boolean"
+                                    },
+                                    "package": {
+                                        "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command.",
+                                        "type": "string"
+                                    },
+                                    "pluginConfig": {
+                                        "title": "Optional plugin-specific app-config YAML fragment.",
+                                        "type": "object"
+                                    }
+                                },
+                                "required": [
+                                    "package"
+                                ],
+                                "type": "object"
+                            },
+                            "title": "List of dynamic plugins that should be installed in the backstage application.",
+                            "type": "array"
+                        }
+                    },
+                    "title": "Dynamic plugins configuration.",
+                    "type": "object"
+                },
                 "host": {
                     "default": "",
                     "title": "Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`",
diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json
index d5d2a34..b9ad056 100644
--- a/charts/backstage/values.schema.tmpl.json
+++ b/charts/backstage/values.schema.tmpl.json
@@ -29,6 +29,44 @@
                     "title": "Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`",
                     "type": "string",
                     "default": ""
+                },
+                "dynamic": {
+                    "title": "Dynamic plugins configuration.",
+                    "type": "object",
+                    "additionalProperties": false,
+                    "properties": {
+                        "plugins": {
+                            "title": "List of dynamic plugins that should be installed in the backstage application.",
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "properties": {
+                                    "package": {
+                                        "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command.",
+                                        "type": "string"
+                                    },
+                                    "pluginConfig": {
+                                        "title": "Optional plugin-specific app-config YAML fragment.",
+                                        "type": "object"
+                                    },
+                                    "disabled": {
+                                        "title": "Disable the plugin.",
+                                        "type": "boolean",
+                                        "default": false
+                                    }
+                                },
+                                "required": ["package"]
+                            }
+                        },
+                        "includes": {
+                            "title": "List of YAML files to include, each of which should contain a `plugins` array.",
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            },
+                            "default": []
+                        }
+                    }
                 }
             }
         },

From 890c641b1163920f8499b136a61cc91fc4d9b6f2 Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Thu, 28 Sep 2023 12:18:12 +0200
Subject: [PATCH 6/8] Dynamic plugins config map as a template

Signed-off-by: David Festal <dfestal@redhat.com>
---
 .../templates/dynamic-plugins-configmap.yaml          |  8 ++++++++
 charts/backstage/values.yaml                          | 11 -----------
 2 files changed, 8 insertions(+), 11 deletions(-)
 create mode 100644 charts/backstage/templates/dynamic-plugins-configmap.yaml

diff --git a/charts/backstage/templates/dynamic-plugins-configmap.yaml b/charts/backstage/templates/dynamic-plugins-configmap.yaml
new file mode 100644
index 0000000..25cf919
--- /dev/null
+++ b/charts/backstage/templates/dynamic-plugins-configmap.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: dynamic-plugins
+data:
+  dynamic-plugins.yaml: |
+    {{- include "common.tplvalues.render" ( dict "value"
+    .Values.global.dynamic "context" $) | nindent 4 }}
diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml
index 71ce740..692ae44 100644
--- a/charts/backstage/values.yaml
+++ b/charts/backstage/values.yaml
@@ -165,17 +165,6 @@ upstream:
   ingress:
     host: "{{ .Values.global.host }}"
 
-  extraDeploy:
-    - |
-      apiVersion: v1
-      data:
-        dynamic-plugins.yaml: |
-          {{- include "common.tplvalues.render" ( dict "value"
-          .Values.global.dynamic "context" $) | nindent 4 }}
-      kind: ConfigMap
-      metadata:
-        name: dynamic-plugins
-
 # -- OpenShift Route parameters
 route:
   # -- Route specific annotations

From 7f896503c15029eab6c0f53a3895470ea246dcea Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Mon, 30 Oct 2023 19:46:05 +0100
Subject: [PATCH 7/8] include test timeouts

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/templates/tests/test-connection.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/charts/backstage/templates/tests/test-connection.yaml b/charts/backstage/templates/tests/test-connection.yaml
index 855b1c3..a382602 100644
--- a/charts/backstage/templates/tests/test-connection.yaml
+++ b/charts/backstage/templates/tests/test-connection.yaml
@@ -16,5 +16,5 @@ spec:
       command: ["/bin/sh", "-c"]
       args:
         - |
-          curl --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 10 --retry-max-time 30 --retry-all-errors {{ include "common.names.fullname" . }}:{{ .Values.upstream.service.ports.backend }}
+          curl --connect-timeout 5 --max-time 20 --retry 20 --retry-delay 10 --retry-max-time 60 --retry-all-errors {{ include "common.names.fullname" . }}:{{ .Values.upstream.service.ports.backend }}
   restartPolicy: Never

From 1bc21b2ebbd2ee63f0426cd964ccc5d770e936c7 Mon Sep 17 00:00:00 2001
From: David Festal <dfestal@redhat.com>
Date: Mon, 6 Nov 2023 20:01:14 +0100
Subject: [PATCH 8/8] Add the required secret in the CI default values

Signed-off-by: David Festal <dfestal@redhat.com>
---
 charts/backstage/ci/default-values.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/charts/backstage/ci/default-values.yaml b/charts/backstage/ci/default-values.yaml
index da4457a..65f133b 100644
--- a/charts/backstage/ci/default-values.yaml
+++ b/charts/backstage/ci/default-values.yaml
@@ -6,3 +6,9 @@ upstream:
     primary:
       persistence:
         enabled: false
+  backstage:
+    appConfig:
+      backend:
+        auth:
+          keys:
+            - secret: sEKIT4CwJ4MwVLzen5SFL6fJmwOPB2sl