Skip to content

feat(devspaces): add workspace devfile, startup scripts, and Dev Spaces guide#272

Open
BoseKarthikeyan wants to merge 9 commits into
redhat-developer:mainfrom
BoseKarthikeyan:rhdh-local-devspace
Open

feat(devspaces): add workspace devfile, startup scripts, and Dev Spaces guide#272
BoseKarthikeyan wants to merge 9 commits into
redhat-developer:mainfrom
BoseKarthikeyan:rhdh-local-devspace

Conversation

@BoseKarthikeyan

Copy link
Copy Markdown

Description

Adds OpenShift Dev Spaces support for this repository with the following changes:

  • devfile.yaml: Defines a Dev Spaces workspace with three containers (tools, rhdh, sonataflow), persistent volumes, public endpoints, and a full set of runnable commands for starting RHDH, developing Backstage plugins, and running SonataFlow workflows.
  • scripts/start-rhdh.sh: Bootstrap script that sets up config symlinks, dynamic plugin layout, .npmrc from Kubernetes secret, and starts the RHDH backend.
  • scripts/start-orchestrator.sh: Startup script that merges workflow resources and launches SonataFlow in devmode.
  • docs/rhdh-local-guide/devspaces-guide.md: New user guide covering workspace setup, endpoints, command reference, development flows, troubleshooting, and private registry configuration.
  • docs/rhdh-local-guide/index.md and mkdocs.yaml: Updated to include the new Dev Spaces guide in navigation.

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

  • Fixes #issue_number

PR acceptance criteria

  • Tests updated and passing
  • Documentation updated
  • Built-in TechDocs updated if needed. Note that TechDocs changes may need to be reviewed by a Product Manager and/or Architect to ensure content accuracy, clarity, and alignment with user needs.

How to test changes / Special notes to the reviewer

  1. Open a Dev Spaces workspace from this repository using the new devfile.yaml.
  2. Confirm the start-rhdh post-start event runs automatically and RHDH becomes reachable on port 7007.
  3. Manually run the start-sonataflow task and confirm the SonataFlow endpoint becomes available on port 8899 (allow ~15 minutes for first startup).
  4. Review the new Dev Spaces guide in TechDocs under RHDH Local User Guide → Dev Spaces Guide.

@BoseKarthikeyan

Copy link
Copy Markdown
Author

Attached the evidence for reference:

workflow-run rhdh-homepage hello-world-plugin example-workflows

@rhdh-qodo-merge

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add OpenShift Dev Spaces workspace definition, startup scripts, and guide

✨ Enhancement 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add Dev Spaces devfile defining RHDH, SonataFlow, and plugin-dev containers/endpoints.
• Add SonataFlow startup script to merge workflows, configure Maven, and run devmode.
• Publish Dev Spaces guide and link it in TechDocs navigation.
Diagram

graph TD
ws(["Dev Spaces workspace"]) --> devfile["devfile.yaml"]
devfile --> tools(["tools container"]) --> volumes[("workspace volumes")]
devfile --> rhdh(["RHDH container"]) --> scripts["startup scripts"]
devfile --> sonata(["SonataFlow container"]) --> scripts
devfile --> docs["TechDocs guide"]
rhdh --> volumes
sonata --> volumes

subgraph Legend
direction LR
_c(["Container"]) ~~~ _f["File/Doc"] ~~~ _v[("Volume")]
end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make containers run scripts as entrypoints (no tail + manual exec)
  • ➕ Simpler lifecycle: start happens automatically with container start
  • ➕ Avoids nohup/background processes and manual PID/port cleanup logic
  • ➖ Harder to restart individual runtimes without restarting the workspace/container
  • ➖ Less flexibility for running optional tasks (e.g., SonataFlow on-demand)
2. Package startup scripts into dedicated images
  • ➕ Removes dependence on mounted sources and hard-coded /projects paths
  • ➕ Versioned, reproducible runtime behavior across workspaces
  • ➖ Requires image build/publish workflow and registry access
  • ➖ Slower iteration when modifying scripts
3. Consolidate command paths and script naming under /projects/rhdh-local/scripts
  • ➕ Eliminates drift between devfile command paths and repo layout
  • ➕ Reduces onboarding friction and troubleshooting time
  • ➖ Requires keeping devfile/docs in sync with any future script moves/renames

Recommendation: Keep the current devfile-driven command approach (good for on-demand tasks), but align and harden the wiring: ensure the referenced startup scripts exist at the exact paths used in devfile commands (notably the SonataFlow start path) and populate scripts/start-rhdh.sh since start-rhdh/postStart depends on it. If script path stability becomes a recurring issue, move toward packaging scripts into images or using container entrypoints.

Files changed (6) +842 / -0 · 1 not counted

Enhancement (1) +222 / -0
start-orchestrator.shAdd SonataFlow Dev Spaces startup/orchestration script +222/-0

Add SonataFlow Dev Spaces startup/orchestration script

• Adds a Bash entrypoint that discovers workflow roots under /projects, merges workflow resources and Java sources into the devmode project, and launches SonataFlow in the local-dev Quarkus profile. Also writes a clean Maven settings.xml (including optional proxy), clears stale Maven resolution caches, and performs an HTTP health check with log tailing.

scripts/start-orchestrator.sh

Documentation (2) +173 / -0
devspaces-guide.mdDocument Dev Spaces setup, endpoints, commands, and troubleshooting +172/-0

Document Dev Spaces setup, endpoints, commands, and troubleshooting

• Adds a TechDocs page describing the Dev Spaces workspace components, exposed endpoints, and common development flows. Includes troubleshooting guidance and an example Kubernetes Secret format for injecting private npm registry configuration.

docs/rhdh-local-guide/devspaces-guide.md

index.mdLink Dev Spaces guide from the RHDH Local user guide index +1/-0

Link Dev Spaces guide from the RHDH Local user guide index

• Adds the Dev Spaces Guide entry to the RHDH Local User Guide landing page to make the new documentation discoverable.

docs/rhdh-local-guide/index.md

Other (3) +447 / -0
devfile.yamlAdd Dev Spaces workspace definition with containers, volumes, endpoints, and commands +446/-0

Add Dev Spaces workspace definition with containers, volumes, endpoints, and commands

• Introduces a Devfile v2.3 workspace with three containers (tools, RHDH, SonataFlow), persistent volumes, and public endpoints for RHDH, plugin dev, and SonataFlow. Defines runnable commands for starting/restarting RHDH and SonataFlow plus Backstage plugin scaffolding/dev/export flows, and triggers RHDH startup via a postStart event.

devfile.yaml

mkdocs.yamlAdd Dev Spaces guide to TechDocs navigation +1/-0

Add Dev Spaces guide to TechDocs navigation

• Updates the MkDocs nav tree so the Dev Spaces guide appears under “RHDH Local User Guide”.

mkdocs.yaml

start-rhdh.shAdd RHDH startup script placeholder not counted

Add RHDH startup script placeholder

• Adds the 'start-rhdh.sh' script file that is referenced by the devfile’s 'start-rhdh' and 'restart-rhdh' commands. In the current PR state the file is empty, so the devfile startup workflow will require the script implementation to be added for RHDH bootstrap to function as documented.

scripts/start-rhdh.sh

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Context used
✅ Cross-repo context
  Explored: repo: redhat-developer/rhdh (sha: d090bd1a)
  Explored: repo: redhat-developer/rhdh-plugins (sha: 83d8a479)

Grey Divider


Action required

1. SonataFlow script path wrong ✓ Resolved 🐞 Bug ≡ Correctness
Description
The start-sonataflow/restart-sonataflow commands invoke
/projects/rhdh-devspaces/start-sonataflow.sh, but this PR only adds
scripts/start-orchestrator.sh under the cloned repo path (/projects/rhdh-local/scripts). As
written, SonataFlow start/restart tasks will fail with “file not found” in the Dev Spaces workspace.
Code

devfile.yaml[R399-441]

+  - id: start-sonataflow
+    exec:
+      component: sonataflow
+      workingDir: /home/kogito/serverless-workflow-project
+      commandLine: |
+        chmod +x "/projects/rhdh-devspaces/start-sonataflow.sh" 2>/dev/null
+        "/projects/rhdh-devspaces/start-sonataflow.sh"
+      group:
+        kind: run
+
+  - id: restart-sonataflow
+    exec:
+      component: sonataflow # 5005, 8899
+      commandLine: |
+        echo "[sonataflow] Stopping SonataFlow server..."
+        # Find PID bound to tcp port 8899 (hex 22C3) without requiring lsof/netstat/fuser.
+        find_pid_by_port_hex() {
+          _hex_port="$1"
+          for fd in /proc/[0-9]*/fd/*; do
+            link=$(readlink "$fd" 2>/dev/null) || continue
+            case "$link" in socket:*)
+              inode=${link#socket:[}; inode=${inode%]}
+              if grep ":${_hex_port} " /proc/net/tcp6 2>/dev/null | grep -q "$inode" || \
+                 grep ":${_hex_port} " /proc/net/tcp 2>/dev/null | grep -q "$inode"; then
+                echo "$fd" | cut -d/ -f3
+                return 0
+              fi
+            ;; esac
+          done
+          return 1
+        }
+
+        PID=$(find_pid_by_port_hex 22C3) || true
+        if [ -n "${PID:-}" ]; then
+          kill "$PID" 2>/dev/null && echo "[sonataflow] ✓ Stopped SonataFlow server (PID $PID)" || \
+          { kill -9 "$PID" 2>/dev/null; echo "[sonataflow] ✓ Force-killed SonataFlow server (PID $PID)"; }
+        else
+          echo "[sonataflow] SonataFlow server is not running on port 8899"
+        fi
+
+        echo "[sonataflow] Starting sonataflow server..."
+        chmod +x "/projects/rhdh-devspaces/start-sonataflow.sh" 2>/dev/null
+        "/projects/rhdh-devspaces//start-sonataflow.sh"
Relevance

⭐⭐⭐ High

Hardcoded script path doesn’t exist in PR; straightforward fix to prevent task failure.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The devfile calls /projects/rhdh-devspaces/start-sonataflow.sh, while the only SonataFlow
entrypoint script added in this PR branch is scripts/start-orchestrator.sh under scripts/.

devfile.yaml[399-406]
devfile.yaml[409-441]
scripts/start-orchestrator.sh[1-5]

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

### Issue description
`devfile.yaml` references a SonataFlow startup script path (`/projects/rhdh-devspaces/start-sonataflow.sh`) that is not provided by this PR. The PR adds `scripts/start-orchestrator.sh`, but it is never used.

### Issue Context
Dev Spaces commands should invoke scripts that exist under the repo clone (`/projects/rhdh-local/...`).

### Fix Focus Areas
- devfile.yaml[399-441]
- scripts/start-orchestrator.sh[1-20]

### Suggested fix
- Update `start-sonataflow` and `restart-sonataflow` to execute `/projects/rhdh-local/scripts/start-orchestrator.sh` (or rename/add a script to match `start-sonataflow.sh`).
- Remove the accidental double slash in the restart command path.

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


2. Dynamic plugins mount mismatch ✓ Resolved 🔗 Cross-repo conflict ≡ Correctness
Description
The Dev Spaces devfile mounts the dynamic plugins volume only at
/opt/app-root/src/dynamic-plugins-root, but RHDH’s standard install-dynamic-plugins flow invokes
./install-dynamic-plugins.sh with target /dynamic-plugins-root and mounts that path. This prevents
using the upstream-supported dynamic plugin installer behavior with the pinned RHDH image and can
break plugin installation/persistence expectations.
Code

devfile.yaml[R121-127]

+      volumeMounts:
+        - name: dynamic-plugins-root
+          path: /opt/app-root/src/dynamic-plugins-root
+        - name: extensions-catalog
+          path: /opt/app-root/src/extensions
+        - name: rhdh-generated
+          path: /opt/app-root/src/generated
Relevance

⭐⭐ Medium

Potential mismatch with upstream path, but could be repo-specific layout; no clear historical
pattern.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR devfile mounts the dynamic plugins volume only at /opt/app-root/src/dynamic-plugins-root. In
rhdh, the documented/templated deployment runs ./install-dynamic-plugins.sh /dynamic-plugins-root
and mounts the dynamic plugins volume at /dynamic-plugins-root, and documentation references the
lock file under /dynamic-plugins-root.

devfile.yaml[121-127]
External repo: redhat-developer/rhdh, scripts/rhdh-openshift-setup/values.yaml [358-374]
External repo: redhat-developer/rhdh, docs/dynamic-plugins/installing-plugins.md [286-291]

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 Dev Spaces workspace mounts the dynamic plugins PVC only at `/opt/app-root/src/dynamic-plugins-root`. In `redhat-developer/rhdh`, the supported installer entrypoint runs `./install-dynamic-plugins.sh /dynamic-plugins-root` and expects the same volume mounted at `/dynamic-plugins-root`.

## Issue Context
In the rhdh repo, the init container contract is:
- workingDir: `/opt/app-root/src`
- command: `./install-dynamic-plugins.sh /dynamic-plugins-root`
- volumeMount: `/dynamic-plugins-root`

To keep compatibility with that contract (and still let the backend read plugins at `/opt/app-root/src/dynamic-plugins-root`), mount the same volume at both paths.

## Fix Focus Areas
- devfile.yaml[121-127]

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



Remediation recommended

3. allexport leaks helper vars 🐞 Bug ⚙ Maintainability ⭐ New
Description
In scripts/start-orchestrator.sh, the .env loader reads into variables named key and value
while set -a (allexport) is enabled, which causes those helper variables themselves to be exported
to the Quarkus process environment. This unintentionally injects generic key/value env vars
(with whatever was last parsed) into the runtime environment.
Code

scripts/start-orchestrator.sh[R22-27]

+  while IFS='=' read -r key value; do
+    # Skip empty lines and comments
+    [[ -z "$key" || "$key" =~ ^[[:space:]]*# ]] && continue
+    # Validate key format (alphanumeric and underscore only)
+    [[ "$key" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && export "$key"="$value"
+  done < "$_env_file"
Relevance

⭐⭐⭐ High

Clear shell-script bug: set -a exports helper vars; team commonly accepts bash safety/correctness
fixes.

PR-#78
PR-#262

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script enables set -a and then assigns to key/value via read; with allexport enabled,
those assignments become exported environment variables, independent of the validated `export
"$key"="$value"` line.

scripts/start-orchestrator.sh[16-29]

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 `.env` loader enables `set -a` and then uses `read -r key value`, which causes `key` and `value` to be exported unintentionally. This pollutes the environment inherited by the SonataFlow/Quarkus process.

## Issue Context
The script already explicitly exports only validated keys (`export "$key"="$value"`), so `set -a` is unnecessary.

## Fix Focus Areas
- scripts/start-orchestrator.sh[16-29]

## Suggested fix
- Remove `set -a` / `set +a` and rely on the existing explicit `export "$key"="$value"`.
- (Optional hardening) After the loop, `unset key value` to avoid carrying those variables forward in the script environment.

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


4. RHDH restart kill logic broken ✓ Resolved 🐞 Bug ☼ Reliability
Description
restart-rhdh’s kill_port_7007() only scans /proc/net/tcp6 (IPv6) and can miss IPv4-only
listeners on /proc/net/tcp, and the “graceful kill” call passes an empty first argument to kill,
which results in a no-op that is silently ignored. This can leave port 7007 occupied and make
restart-rhdh intermittently fail or spin until timeout.
Code

devfile.yaml[R239-270]

+        kill_port_7007() {
+          for fd in /proc/[0-9]*/fd/*; do
+            link=$(readlink "$fd" 2>/dev/null) || continue
+            case "$link" in socket:*)
+              inode=${link#socket:[}; inode=${inode%]}
+              if grep ':1B5F ' /proc/net/tcp6 2>/dev/null | grep -q "$inode"; then
+                pid=$(echo "$fd" | cut -d/ -f3)
+                echo "  killing PID $pid (port 7007)"
+                kill "$1" "$pid" 2>/dev/null || true
+                return 0
+              fi
+            ;; esac
+          done
+          return 1
+        }
+        # Graceful kill
+        kill_port_7007 "" && sleep 2
+        # Force kill if still there
+        kill_port_7007 "-9" && sleep 1
+        # Also kill any remaining node processes
+        pkill -9 -f 'node.*packages/backend' 2>/dev/null || true
+        sleep 1
+        # Verify port is free
+        for i in $(seq 1 15); do
+          if ! grep -q ':1B5F ' /proc/net/tcp6 2>/dev/null && \
+             ! grep -q ':1B5F ' /proc/net/tcp 2>/dev/null; then
+            echo "[rhdh] Port 7007 is free"
+            break
+          fi
+          echo "  port 7007 still in use ($i/15)..."
+          kill_port_7007 "-9"
+          sleep 1
Relevance

⭐⭐⭐ High

Deterministic restart bug (IPv4 miss + empty kill arg) likely to be fixed for reliability.

PR-#262

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PID detection path in kill_port_7007() greps only /proc/net/tcp6, and the graceful kill path
calls kill "$1" "$pid" with $1 set to an empty string, while later the port-free verification
checks both tcp6 and tcp.

devfile.yaml[239-250]
devfile.yaml[254-257]
devfile.yaml[261-265]

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 restart helper for RHDH has two correctness issues:
1) It only looks in `/proc/net/tcp6` when identifying the PID by port.
2) The “graceful” call passes an empty string as the signal argument to `kill`, which fails but is suppressed.

### Issue Context
The verification loop later checks both `/proc/net/tcp6` and `/proc/net/tcp`, so the code already anticipates IPv4 bindings.

### Fix Focus Areas
- devfile.yaml[239-257]
- devfile.yaml[261-270]

### Suggested fix
- Update `kill_port_7007()` to check both `/proc/net/tcp6` and `/proc/net/tcp` when mapping inode → PID.
- Change the kill invocation to only include a signal flag when one is provided, e.g.:
 - if no signal: `kill "$pid"`
 - if signal provided: `kill "$sig" "$pid"`
- Consider returning non-zero if no PID was actually killed so the caller can react appropriately.

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


5. .env sourced as shell ✓ Resolved 🐞 Bug ⛨ Security
Description
scripts/start-orchestrator.sh uses source /projects/rhdh-local/.env, which executes the file as
shell code (not just KEY=VALUE parsing). A malformed or unexpectedly modified .env can run
arbitrary commands in the SonataFlow container context and/or break startup.
Code

scripts/start-orchestrator.sh[R16-27]

+# Source the dev .env file so secrets like CLDCTL_GITHUB_TOKEN are available
+# to the Quarkus JVM process started later in this script.
+_env_file="${PROJECTS_DIR}/rhdh-local/.env"
+if [ -f "$_env_file" ]; then
+  set -a
+  # shellcheck source=/dev/null
+  source "$_env_file"
+  set +a
+  log "Sourced env from $_env_file (CLDCTL_GITHUB_TOKEN set=$([ -n "${CLDCTL_GITHUB_TOKEN:-}" ] && echo yes || echo NO))"
+else
+  warn ".env not found at $_env_file — CLDCTL_GITHUB_TOKEN will be empty; check WORKFLOW_REPO_DIR"
+fi
Relevance

⭐⭐ Medium

.env sourcing risk is real, but common in dev scripts; repo shows some injection-hardening but not
directly analogous.

PR-#180

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script explicitly enables auto-export and executes .env via source, which evaluates its
contents as bash code.

scripts/start-orchestrator.sh[16-24]

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 SonataFlow startup script loads `.env` with `source`, which can execute arbitrary shell syntax and is fragile if `.env` contains unexpected content.

### Issue Context
In Dev Spaces, repo files are user-writable; using `source` makes the startup path sensitive to accidental edits and increases blast radius of unexpected `.env` content.

### Fix Focus Areas
- scripts/start-orchestrator.sh[16-27]

### Suggested fix
- Replace `source "$_env_file"` with a safe parser that only accepts `^[A-Za-z_][A-Za-z0-9_]*=` lines (ignore others) and exports those values.
- Alternatively, mount required secrets via Dev Spaces/Kubernetes Secret env vars and avoid reading `.env` altogether.

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


View more (1)
6. TLS verification disabled ✓ Resolved 🐞 Bug ⛨ Security
Description
The rhdh container sets NODE_TLS_REJECT_UNAUTHORIZED=0, disabling TLS certificate verification
for Node’s HTTPS stack. This can allow man-in-the-middle interception inside the cluster and can
mask real CA/cert configuration problems during development.
Code

devfile.yaml[R93-99]

+        - name: NODE_ENV
+          value: development
+        - name: NODE_TLS_REJECT_UNAUTHORIZED
+          value: "0"
+        - name: NODE_OPTIONS
+          value: --inspect=0.0.0.0:9229 --no-node-snapshot
+        - name: CATALOG_INDEX_IMAGE
Relevance

⭐⭐ Medium

Security concern, but may be intentional for Dev Spaces/development; no close repo precedent found.

PR-#180

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The devfile explicitly sets NODE_TLS_REJECT_UNAUTHORIZED to 0 in the rhdh container environment.

devfile.yaml[93-99]

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 devfile disables Node TLS verification globally via `NODE_TLS_REJECT_UNAUTHORIZED=0`.

### Issue Context
Even in dev workspaces this can unintentionally expose tokens/credentials sent to internal/external services over HTTPS and makes TLS misconfigurations harder to detect.

### Fix Focus Areas
- devfile.yaml[93-99]

### Suggested fix
- Remove `NODE_TLS_REJECT_UNAUTHORIZED=0`.
- If self-signed/internal certs are required, mount the cluster CA bundle and configure Node to trust it (e.g., `NODE_EXTRA_CA_CERTS`) or fix service certificates.
- If you must keep it for a narrow case, scope it to the minimal command/process rather than the entire container environment.

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



Informational

7. Catalog index tag drift ✓ Resolved 🔗 Cross-repo conflict ☼ Reliability
Description
The devfile pins the RHDH runtime image to 1.10 but sets CATALOG_INDEX_IMAGE to
quay.io/rhdh/plugin-catalog-index:1.9, diverging from the rhdh repo’s 1.10 default catalog index
tag. This version skew can lead to stale/mismatched default plugin configuration and marketplace
entity extraction versus what RHDH 1.10 expects.
Code

devfile.yaml[R99-104]

+        - name: CATALOG_INDEX_IMAGE
+          value: quay.io/rhdh/plugin-catalog-index:1.9
+        - name: WAIT_FOR_PLUGINS_TIMEOUT
+          value: "180"
+        - name: CATALOG_ENTITIES_EXTRACT_DIR
+          value: /opt/app-root/src/extensions
Relevance

⭐ Low

Repo previously rejected bumping catalog index to 1.10; likely will keep 1.9 despite skew.

PR-#205

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR sets RHDH image tag 1.10 while pointing CATALOG_INDEX_IMAGE to 1.9. In rhdh’s runtime deployment
utilities, the default catalog index for the 1.10 chart path is explicitly
quay.io/rhdh/plugin-catalog-index:1.10.

devfile.yaml[74-105]
External repo: redhat-developer/rhdh, e2e-tests/playwright/utils/runtime-config.ts [234-237]

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 Dev Spaces config runs `quay.io/rhdh-community/rhdh:1.10` but pins `CATALOG_INDEX_IMAGE=quay.io/rhdh/plugin-catalog-index:1.9`. In the rhdh repo, 1.10 deployments default to `quay.io/rhdh/plugin-catalog-index:1.10`.

## Issue Context
Keeping the catalog index aligned with the runtime version reduces the risk of mismatched `dynamic-plugins.default.yaml` content and extracted marketplace entities.

## Fix Focus Areas
- devfile.yaml[74-105]

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


Grey Divider

Previous review results

Review updated until commit 07b4f2c

Results up to commit ae37b61 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. SonataFlow script path wrong ✓ Resolved 🐞 Bug ≡ Correctness
Description
The start-sonataflow/restart-sonataflow commands invoke
/projects/rhdh-devspaces/start-sonataflow.sh, but this PR only adds
scripts/start-orchestrator.sh under the cloned repo path (/projects/rhdh-local/scripts). As
written, SonataFlow start/restart tasks will fail with “file not found” in the Dev Spaces workspace.
Code

devfile.yaml[R399-441]

+  - id: start-sonataflow
+    exec:
+      component: sonataflow
+      workingDir: /home/kogito/serverless-workflow-project
+      commandLine: |
+        chmod +x "/projects/rhdh-devspaces/start-sonataflow.sh" 2>/dev/null
+        "/projects/rhdh-devspaces/start-sonataflow.sh"
+      group:
+        kind: run
+
+  - id: restart-sonataflow
+    exec:
+      component: sonataflow # 5005, 8899
+      commandLine: |
+        echo "[sonataflow] Stopping SonataFlow server..."
+        # Find PID bound to tcp port 8899 (hex 22C3) without requiring lsof/netstat/fuser.
+        find_pid_by_port_hex() {
+          _hex_port="$1"
+          for fd in /proc/[0-9]*/fd/*; do
+            link=$(readlink "$fd" 2>/dev/null) || continue
+            case "$link" in socket:*)
+              inode=${link#socket:[}; inode=${inode%]}
+              if grep ":${_hex_port} " /proc/net/tcp6 2>/dev/null | grep -q "$inode" || \
+                 grep ":${_hex_port} " /proc/net/tcp 2>/dev/null | grep -q "$inode"; then
+                echo "$fd" | cut -d/ -f3
+                return 0
+              fi
+            ;; esac
+          done
+          return 1
+        }
+
+        PID=$(find_pid_by_port_hex 22C3) || true
+        if [ -n "${PID:-}" ]; then
+          kill "$PID" 2>/dev/null && echo "[sonataflow] ✓ Stopped SonataFlow server (PID $PID)" || \
+          { kill -9 "$PID" 2>/dev/null; echo "[sonataflow] ✓ Force-killed SonataFlow server (PID $PID)"; }
+        else
+          echo "[sonataflow] SonataFlow server is not running on port 8899"
+        fi
+
+        echo "[sonataflow] Starting sonataflow server..."
+        chmod +x "/projects/rhdh-devspaces/start-sonataflow.sh" 2>/dev/null
+        "/projects/rhdh-devspaces//start-sonataflow.sh"
Relevance

⭐⭐⭐ High

Hardcoded script path doesn’t exist in PR; straightforward fix to prevent task failure.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The devfile calls /projects/rhdh-devspaces/start-sonataflow.sh, while the only SonataFlow
entrypoint script added in this PR branch is scripts/start-orchestrator.sh under scripts/.

devfile.yaml[399-406]
devfile.yaml[409-441]
scripts/start-orchestrator.sh[1-5]

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

### Issue description
`devfile.yaml` references a SonataFlow startup script path (`/projects/rhdh-devspaces/start-sonataflow.sh`) that is not provided by this PR. The PR adds `scripts/start-orchestrator.sh`, but it is never used.

### Issue Context
Dev Spaces commands should invoke scripts that exist under the repo clone (`/projects/rhdh-local/...`).

### Fix Focus Areas
- devfile.yaml[399-441]
- scripts/start-orchestrator.sh[1-20]

### Suggested fix
- Update `start-sonataflow` and `restart-sonataflow` to execute `/projects/rhdh-local/scripts/start-orchestrator.sh` (or rename/add a script to match `start-sonataflow.sh`).
- Remove the accidental double slash in the restart command path.

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


2. Dynamic plugins mount mismatch ✓ Resolved 🔗 Cross-repo conflict ≡ Correctness
Description
The Dev Spaces devfile mounts the dynamic plugins volume only at
/opt/app-root/src/dynamic-plugins-root, but RHDH’s standard install-dynamic-plugins flow invokes
./install-dynamic-plugins.sh with target /dynamic-plugins-root and mounts that path. This prevents
using the upstream-supported dynamic plugin installer behavior with the pinned RHDH image and can
break plugin installation/persistence expectations.
Code

devfile.yaml[R121-127]

+      volumeMounts:
+        - name: dynamic-plugins-root
+          path: /opt/app-root/src/dynamic-plugins-root
+        - name: extensions-catalog
+          path: /opt/app-root/src/extensions
+        - name: rhdh-generated
+          path: /opt/app-root/src/generated
Relevance

⭐⭐ Medium

Potential mismatch with upstream path, but could be repo-specific layout; no clear historical
pattern.

PR-#34

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR devfile mounts the dynamic plugins volume only at /opt/app-root/src/dynamic-plugins-root. In
rhdh, the documented/templated deployment runs ./install-dynamic-plugins.sh /dynamic-plugins-root
and mounts the dynamic plugins volume at /dynamic-plugins-root, and documentation references the
lock file under /dynamic-plugins-root.

devfile.yaml[121-127]
External repo: redhat-developer/rhdh, scripts/rhdh-openshift-setup/values.yaml [358-374]
External repo: redhat-developer/rhdh, docs/dynamic-plugins/installing-plugins.md [286-291]

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 Dev Spaces workspace mounts the dynamic plugins PVC only at `/opt/app-root/src/dynamic-plugins-root`. In `redhat-developer/rhdh`, the supported installer entrypoint runs `./install-dynamic-plugins.sh /dynamic-plugins-root` and expects the same volume mounted at `/dynamic-plugins-root`.

## Issue Context
In the rhdh repo, the init container contract is:
- workingDir: `/opt/app-root/src`
- command: `./install-dynamic-plugins.sh /dynamic-plugins-root`
- volumeMount: `/dynamic-plugins-root`

To keep compatibility with that contract (and still let the backend read plugins at `/opt/app-root/src/dynamic-plugins-root`), mount the same volume at both paths.

## Fix Focus Areas
- devfile.yaml[121-127]

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



Remediation recommended
3. RHDH restart kill logic broken ✓ Resolved 🐞 Bug ☼ Reliability
Description
restart-rhdh’s kill_port_7007() only scans /proc/net/tcp6 (IPv6) and can miss IPv4-only
listeners on /proc/net/tcp, and the “graceful kill” call passes an empty first argument to kill,
which results in a no-op that is silently ignored. This can leave port 7007 occupied and make
restart-rhdh intermittently fail or spin until timeout.
Code

devfile.yaml[R239-270]

+        kill_port_7007() {
+          for fd in /proc/[0-9]*/fd/*; do
+            link=$(readlink "$fd" 2>/dev/null) || continue
+            case "$link" in socket:*)
+              inode=${link#socket:[}; inode=${inode%]}
+              if grep ':1B5F ' /proc/net/tcp6 2>/dev/null | grep -q "$inode"; then
+                pid=$(echo "$fd" | cut -d/ -f3)
+                echo "  killing PID $pid (port 7007)"
+                kill "$1" "$pid" 2>/dev/null || true
+                return 0
+              fi
+            ;; esac
+          done
+          return 1
+        }
+        # Graceful kill
+        kill_port_7007 "" && sleep 2
+        # Force kill if still there
+        kill_port_7007 "-9" && sleep 1
+        # Also kill any remaining node processes
+        pkill -9 -f 'node.*packages/backend' 2>/dev/null || true
+        sleep 1
+        # Verify port is free
+        for i in $(seq 1 15); do
+          if ! grep -q ':1B5F ' /proc/net/tcp6 2>/dev/null && \
+             ! grep -q ':1B5F ' /proc/net/tcp 2>/dev/null; then
+            echo "[rhdh] Port 7007 is free"
+            break
+          fi
+          echo "  port 7007 still in use ($i/15)..."
+          kill_port_7007 "-9"
+          sleep 1
Relevance

⭐⭐⭐ High

Deterministic restart bug (IPv4 miss + empty kill arg) likely to be fixed for reliability.

PR-#262

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PID detection path in kill_port_7007() greps only /proc/net/tcp6, and the graceful kill path
calls kill "$1" "$pid" with $1 set to an empty string, while later the port-free verification
checks both tcp6 and tcp.

devfile.yaml[239-250]
devfile.yaml[254-257]
devfile.yaml[261-265]

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 restart helper for RHDH has two correctness issues:
1) It only looks in `/proc/net/tcp6` when identifying the PID by port.
2) The “graceful” call passes an empty string as the signal argument to `kill`, which fails but is suppressed.

### Issue Context
The verification loop later checks both `/proc/net/tcp6` and `/proc/net/tcp`, so the code already anticipates IPv4 bindings.

### Fix Focus Areas
- devfile.yaml[239-257]
- devfile.yaml[261-270]

### Suggested fix
- Update `kill_port_7007()` to check both `/proc/net/tcp6` and `/proc/net/tcp` when mapping inode → PID.
- Change the kill invocation to only include a signal flag when one is provided, e.g.:
 - if no signal: `kill "$pid"`
 - if signal provided: `kill "$sig" "$pid"`
- Consider returning non-zero if no PID was actually killed so the caller can react appropriately.

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


4. .env sourced as shell ✓ Resolved 🐞 Bug ⛨ Security
Description
scripts/start-orchestrator.sh uses source /projects/rhdh-local/.env, which executes the file as
shell code (not just KEY=VALUE parsing). A malformed or unexpectedly modified .env can run
arbitrary commands in the SonataFlow container context and/or break startup.
Code

scripts/start-orchestrator.sh[R16-27]

+# Source the dev .env file so secrets like CLDCTL_GITHUB_TOKEN are available
+# to the Quarkus JVM process started later in this script.
+_env_file="${PROJECTS_DIR}/rhdh-local/.env"
+if [ -f "$_env_file" ]; then
+  set -a
+  # shellcheck source=/dev/null
+  source "$_env_file"
+  set +a
+  log "Sourced env from $_env_file (CLDCTL_GITHUB_TOKEN set=$([ -n "${CLDCTL_GITHUB_TOKEN:-}" ] && echo yes || echo NO))"
+else
+  warn ".env not found at $_env_file — CLDCTL_GITHUB_TOKEN will be empty; check WORKFLOW_REPO_DIR"
+fi
Relevance

⭐⭐ Medium

.env sourcing risk is real, but common in dev scripts; repo shows some injection-hardening but not
directly analogous.

PR-#180

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script explicitly enables auto-export and executes .env via source, which evaluates its
contents as bash code.

scripts/start-orchestrator.sh[16-24]

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 SonataFlow startup script loads `.env` with `source`, which can execute arbitrary shell syntax and is fragile if `.env` contains unexpected content.

### Issue Context
In Dev Spaces, repo files are user-writable; using `source` makes the startup path sensitive to accidental edits and increases blast radius of unexpected `.env` content.

### Fix Focus Areas
- scripts/start-orchestrator.sh[16-27]

### Suggested fix
- Replace `source "$_env_file"` with a safe parser that only accepts `^[A-Za-z_][A-Za-z0-9_]*=` lines (ignore others) and exports those values.
- Alternatively, mount required secrets via Dev Spaces/Kubernetes Secret env vars and avoid reading `.env` altogether.

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


5. TLS verification disabled ✓ Resolved 🐞 Bug ⛨ Security
Description
The rhdh container sets NODE_TLS_REJECT_UNAUTHORIZED=0, disabling TLS certificate verification
for Node’s HTTPS stack. This can allow man-in-the-middle interception inside the cluster and can
mask real CA/cert configuration problems during development.
Code

devfile.yaml[R93-99]

+        - name: NODE_ENV
+          value: development
+        - name: NODE_TLS_REJECT_UNAUTHORIZED
+          value: "0"
+        - name: NODE_OPTIONS
+          value: --inspect=0.0.0.0:9229 --no-node-snapshot
+        - name: CATALOG_INDEX_IMAGE
Relevance

⭐⭐ Medium

Security concern, but may be intentional for Dev Spaces/development; no close repo precedent found.

PR-#180

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The devfile explicitly sets NODE_TLS_REJECT_UNAUTHORIZED to 0 in the rhdh container environment.

devfile.yaml[93-99]

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 devfile disables Node TLS verification globally via `NODE_TLS_REJECT_UNAUTHORIZED=0`.

### Issue Context
Even in dev workspaces this can unintentionally expose tokens/credentials sent to internal/external services over HTTPS and makes TLS misconfigurations harder to detect.

### Fix Focus Areas
- devfile.yaml[93-99]

### Suggested fix
- Remove `NODE_TLS_REJECT_UNAUTHORIZED=0`.
- If self-signed/internal certs are required, mount the cluster CA bundle and configure Node to trust it (e.g., `NODE_EXTRA_CA_CERTS`) or fix service certificates.
- If you must keep it for a narrow case, scope it to the minimal command/process rather than the entire container environment.

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



Informational
6. Catalog index tag drift ✓ Resolved 🔗 Cross-repo conflict ☼ Reliability
Description
The devfile pins the RHDH runtime image to 1.10 but sets CATALOG_INDEX_IMAGE to
quay.io/rhdh/plugin-catalog-index:1.9, diverging from the rhdh repo’s 1.10 default catalog index
tag. This version skew can lead to stale/mismatched default plugin configuration and marketplace
entity extraction versus what RHDH 1.10 expects.
Code

devfile.yaml[R99-104]

+        - name: CATALOG_INDEX_IMAGE
+          value: quay.io/rhdh/plugin-catalog-index:1.9
+        - name: WAIT_FOR_PLUGINS_TIMEOUT
+          value: "180"
+        - name: CATALOG_ENTITIES_EXTRACT_DIR
+          value: /opt/app-root/src/extensions
Relevance

⭐ Low

Repo previously rejected bumping catalog index to 1.10; likely will keep 1.9 despite skew.

PR-#205

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR sets RHDH image tag 1.10 while pointing CATALOG_INDEX_IMAGE to 1.9. In rhdh’s runtime deployment
utilities, the default catalog index for the 1.10 chart path is explicitly
quay.io/rhdh/plugin-catalog-index:1.10.

devfile.yaml[74-105]
External repo: redhat-developer/rhdh, e2e-tests/playwright/utils/runtime-config.ts [234-237]

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 Dev Spaces config runs `quay.io/rhdh-community/rhdh:1.10` but pins `CATALOG_INDEX_IMAGE=quay.io/rhdh/plugin-catalog-index:1.9`. In the rhdh repo, 1.10 deployments default to `quay.io/rhdh/plugin-catalog-index:1.10`.

## Issue Context
Keeping the catalog index aligned with the runtime version reduces the risk of mismatched `dynamic-plugins.default.yaml` content and extracted marketplace entities.

## Fix Focus Areas
- devfile.yaml[74-105]

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


Qodo Logo

@rhdh-qodo-merge rhdh-qodo-merge Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Jul 23, 2026
Comment thread scripts/start-orchestrator.sh Fixed
@rm3l

rm3l commented Jul 23, 2026

Copy link
Copy Markdown
Member

/agentic_review

@rhdh-qodo-merge

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit ffc1728

Comment thread scripts/start-rhdh.sh Fixed
Comment thread scripts/start-rhdh.sh Fixed
@BoseKarthikeyan

Copy link
Copy Markdown
Author

@rm3l, can you kickoff the pipeline?

@sonarqubecloud

Copy link
Copy Markdown

@BoseKarthikeyan

Copy link
Copy Markdown
Author

@rm3l,do you need anyother details to merge this PR?

@rm3l

rm3l commented Jul 24, 2026

Copy link
Copy Markdown
Member

/cc

@openshift-ci
openshift-ci Bot requested a review from rm3l July 24, 2026 13:16
@rm3l

rm3l commented Jul 24, 2026

Copy link
Copy Markdown
Member

@rm3l,do you need anyother details to merge this PR?

@BoseKarthikeyan Thanks for this PR, but I'm curious: is there a motivation or specific request behind this? A link to a JIRA or GH issue would be great, to provide us with more context.
At a very quick glance, I'm a bit worried that the additional scripts and additional configuration in the devfile.yaml (like duplicating the same images already defined in the compose files) would mean additional maintenance burden.
Thanks.

@BoseKarthikeyan

Copy link
Copy Markdown
Author

@rm3l,As you know, installing Podman on Windows with WSL can often be challenging. Our developers were spending significant time struggling to set up their local development environments.To provide a better developer experience, we evaluated DevSpace and found it to be a great solution—it is OS-independent, easy to use, and allows us to push global configuration updates effortlessly whenever changes are required. To remove onboarding friction, we have created a standardized Devfile for the team.

@rm3l

rm3l commented Jul 25, 2026

Copy link
Copy Markdown
Member

@rm3l,As you know, installing Podman on Windows with WSL can often be challenging. Our developers were spending significant time struggling to set up their local development environments.To provide a better developer experience, we evaluated DevSpace and found it to be a great solution—it is OS-independent, easy to use, and allows us to push global configuration updates effortlessly whenever changes are required. To remove onboarding friction, we have created a standardized Devfile for the team.

Thanks for the additional context, @BoseKarthikeyan! That definitely makes sense.
Just curious again, have you considered running podman compose directly from your DevSpaces workspaces? I can see from the DevSpaces docs that nested container run capabilities can be enabled by an admin: https://docs.redhat.com/en/documentation/red_hat_openshift_dev_spaces/3.29/html-single/administration_guide/index#proc_enabling-container-run-capabilities_administration_guide
If so, I guess the Devfile could be simplified to reuse as much from the Compose stacks as possible. Could that be an option here? (Just trying to see how we could reduce the maintenance burden by reusing as much as we can from the existing configuration and scripts).
Anyway, let me discuss this with the rest of team and come back to you. But I'll be off next week, so probably the week after. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants