Skip to content

feat(agent-ops): OpenShell SDK prototype with federation fixes - #8515

Closed
Gkrumbach07 wants to merge 1 commit into
opendatahub-io:mainfrom
Gkrumbach07:agent-ops/openshell-prototype
Closed

Gkrumbach07 wants to merge 1 commit into
opendatahub-io:mainfrom
Gkrumbach07:agent-ops/openshell-prototype

Conversation

@Gkrumbach07

@Gkrumbach07 Gkrumbach07 commented Jul 13, 2026 •

Copy link
Copy Markdown
Member

Summary

  • OpenShell SDK integration: deploy/list/get/delete agents through OpenShell Gateway, stop/start via direct CR patch
  • Federation architecture: bundled area extension for nav visibility, federated module for full UI
  • BFF: endpoint URL, service info, pod name/count populated from OpenShell sandbox status
  • Local dev: split webpack proxy for agent-ops API routing, dev feature flag enabled

Test plan

  • Verify Agents nav appears under AI Hub
  • Deploy an agent via the deploy wizard
  • List agents shows real data from OpenShell
  • Agent detail page shows endpoints, pod name, status
  • Stop/start agent toggles operatingMode

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an Agent Operations area for viewing agent deployments, statuses, frameworks, namespaces, and synchronization times.
    • Added support for deploying and managing agents through OpenShell.
    • Added runtime chat for supported agents.
    • Added agent card information and pod details to runtime views.
    • Added OpenShell connection status to health information.
  • Bug Fixes

    • Improved local development routing and compatibility for Agent Operations services.
    • Updated default feature settings and build tooling for improved reliability.

@openshift-ci openshift-ci Bot added the needs-rebase PR needs to be rebased label Jul 13, 2026
@openshift-ci openshift-ci Bot added the area/agent-ops Agent ops package label Jul 13, 2026
@openshift-ci

openshift-ci Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign fedealonso for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds OpenShell configuration and sandbox lifecycle integration to the BFF, including agent listing, deployment, deletion, start/stop operations, agent-card probing, health status, and chat proxying. Extends runtime metadata with pod names and readiness fallbacks. Enables the Agent Ops dashboard area, adds frontend proxy and webpack configuration, provides an agent-card API helper, and introduces an agent deployments page. Updates dashboard defaults, Go dependencies, and Go build images.

🚥 Pre-merge checks | ✅ 9 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The body is missing the required issue reference, detailed Description, How Has This Been Tested, Test Impact, and checklist sections. Add the issue link, expand the change rationale, fill in testing and test-impact sections, and complete the request-review checklist.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: OpenShell SDK integration plus federation and local-dev fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Contribution Quality And Spam Detection ✅ Passed PASS: cohesive feature PR with repo-specific changes and existing tests; only weak AI-assisted prose signal, no second independent spam/quality signal.
No Hardcoded Secrets ✅ Passed No CWE-798/CWE-259 hits: added lines contain no api_key/secret/token/password literals, no embedded-creds URLs, and go.sum only updates dependency checksums.
No Weak Cryptography ✅ Passed PASS: No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, no custom crypto, and no secret/HMAC comparison code in touched files (CWE-327).
No Injection Vectors ✅ Passed No CWE-89/78/94/502/79 sinks in touched code; inspected AgentDeploymentsPage, agent_chat_handler, and openshell client.
No Privileged Containers ✅ Passed No PR file sets privileged/host* or SYS_ADMIN; Dockerfiles end as non-root USER 65532:65532, with no USER root or runAsUser:0 found.
No Sensitive Data In Logs ✅ Passed PASS: New logs only emit agent name/namespace/gateway; no tokens, bodies, or PII. The config dump is debug-only. No CWE-200/532 issue.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Trivy (0.69.3)

Trivy execution failed: 2026-07-13T14:12:35Z FATAL Fatal error run error: fs scan error: scan error: scan failed: failed analysis: post analysis error: post analysis error: azure-arm scan error: fs filter error: fs filter error: walk error range error: stat backend/doctor.config.json: no such file or directory: range error: stat backend/doctor.config.json: no such file or directory


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

@Gkrumbach07
Gkrumbach07 force-pushed the agent-ops/openshell-prototype branch from 537e7bd to d5f4cb2 Compare July 13, 2026 13:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/agent-ops/bff/internal/mapper/agent.go (1)

202-216: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

ReadyReplicaCount fallback conflates "pod name present" with "ready".

When readyReplicas/ready_replicas are absent, the function returns 1 merely because AgentPodName(status) is non-empty — i.e., a pod being named in status is treated as proof it's ready. A pod can be present but crashing/pending, in which case this reports PodCount: 1 for a non-ready workload, misleading callers of a field whose name promises actual readiness.

♻️ Suggested tightening
 	if v, ok := intFromAny(status["ready_replicas"]); ok {
 		return v
 	}
-	if podName := AgentPodName(status); podName != "" {
-		return 1
-	}
-	return 0
+	// Only treat pod presence as a proxy for ready count if the workload is
+	// otherwise reporting a ready condition; avoid asserting readiness solely
+	// from pod-name presence.
+	return 0
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/mapper/agent.go` around lines 202 - 216,
Update ReadyReplicaCount so the fallback after checking readyReplicas and
ready_replicas does not infer readiness from AgentPodName; return zero when no
explicit ready-replica count is available, preserving the existing numeric
parsing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/config/webpack.dev.js`:
- Around line 258-271: Update the agentOpsProxies entry in the webpack dev proxy
configuration to forward the user token using the same onProxyReq or equivalent
header logic as the neighboring proxy blocks. Ensure both
x-forwarded-access-token and Authorization are propagated to the agent-ops
target while preserving its existing context, target, and pathRewrite settings.

In `@packages/agent-ops/bff/GAPS.md`:
- Around line 20-24: Update the Sandbox CR route-creation flow so every created
Route includes an OwnerReference pointing to its owning Sandbox resource. Ensure
deletion of the Sandbox garbage-collects the Route, while preserving the
existing ownerReference behavior for the AgentRuntime path.
- Around line 5-11: Update DeleteAgent, StopAgent, and StartAgent to perform a
per-request SubjectAccessReview for the relevant Sandbox CR delete/patch action
before executing it, using the authenticated caller’s identity and target
resource context. Deny the operation when SSAR is not allowed, and remove the
documentation framing this authorization as an unassigned backlog item.

In `@packages/agent-ops/bff/go.mod`:
- Around line 3-11: Replace the unvetted github.com/rhuss/openshell-sdk-go
dependency in go.mod with the official NVIDIA/OpenShell Go SDK or an
upstream-maintained equivalent, updating imports and usages throughout the
affected code to match its API. If no suitable upstream package exists, remove
the dependency and vendor an approved, provenance-reviewed implementation
instead.

In `@packages/agent-ops/bff/internal/api/agent_chat_handler.go`:
- Around line 54-60: Update the response-body proxying flow around the handler’s
header forwarding and io.Copy call to copy through io.LimitReader with the
configured response-size limit, handle the copy error instead of discarding it,
and filter hop-by-hop headers such as Transfer-Encoding and Connection before
forwarding them. Preserve the upstream status code and bounded body forwarding
behavior.

In `@packages/agent-ops/bff/internal/api/app.go`:
- Around line 127-129: The AUTH_METHOD=disabled validation in app initialization
now permits a real OpenShell backend without a development-only safeguard.
Update the condition around cfg.AuthMethod, cfg.MockAgentClient, and
cfg.OpenShellGatewayURL so disabled authentication remains restricted to the
explicitly approved MockAgentClient path, or add an equivalent explicit dev-only
safeguard and warning for OpenShell; preserve rejection of unsafe
unauthenticated production configurations.
- Around line 184-201: Update the OpenShell client construction in the
cfg.OpenShellGatewayURL branch to use the configured TLS verification behavior
and gateway authentication instead of hard-coded v1.NoAuth() and Insecure: true.
Map cfg.InsecureSkipVerify and the existing configured credential/authentication
settings into v1.Config, preserving the current error handling and factory
setup.

In `@packages/agent-ops/bff/internal/api/healthcheck_handler.go`:
- Around line 17-22: Update the healthcheck handler’s healthCheck.OpenShell
construction to expose only the Enabled status; remove the Gateway and Namespace
assignments from the unauthenticated liveness response, leaving internal
OpenShell details for an authenticated route if needed.

In `@packages/agent-ops/bff/internal/integrations/agents/openshell/client.go`:
- Around line 280-291: Update the AgentSummary construction flow containing
displayName, description, and framework so the annotation-derived displayName is
assigned to the appropriate AgentSummary field instead of being discarded.
Remove the `_ = displayName` suppression and preserve the existing fallback
behavior for description and framework.
- Around line 45-83: Enforce the request namespace in ListAgents, GetAgent, and
DeleteAgent before invoking OpenShell operations. Replace ignored namespace
parameters with the requested namespace and reject requests when it differs from
c.namespace, returning the existing authorization/validation error used by the
integration. Ensure all read and delete paths operate only on the validated
configured namespace.
- Around line 326-333: Update the spec map construction in the relevant Sandbox
response logic to source operatingMode from the Sandbox spec rather than the
status phase, preserving values such as Suspended and Running; alternatively
remove the operatingMode key if this response should expose only phase. Do not
populate it from status.

In `@packages/agent-ops/Dockerfile`:
- Line 7: Update the GOLANG_BASE_IMAGE argument to use a reproducible, immutable
image reference by pinning golang to a specific full patch version and
preferably its sha256 digest; do not leave it as the floating golang:1.25 tag.

In `@packages/agent-ops/Dockerfile.workspace`:
- Line 12: Update the GOLANG_BASE_IMAGE argument in the workspace Dockerfile to
use a fixed, immutable image digest instead of the floating golang:1.25 tag,
preserving the intended Go 1.25 base image.

In `@packages/agent-ops/src/AgentDeploymentsPage.tsx`:
- Around line 55-71: Update fetchAgents and the other agent-runtime fetch paths
to use the existing validated API layer in
frontend/src/app/api/agentRuntimes.ts, including isModArchResponse and
handleRestFailures, instead of raw fetch parsing. Ensure the validated response
confirms runtimes is an array before passing it to setAgents, preserving the
existing loading and error-state handling.

In `@packages/agent-ops/V1-IMPLEMENTATION-GAPS.md`:
- Around line 98-102: Update item 10, “Env var secrets via k8s Secret,” to
require v1 gating: block plaintext API_KEY-style inputs or require creation and
reference of a Kubernetes Secret before deployment. Do not leave plaintext
environment-variable storage as an unassigned follow-up; document the deployment
wizard behavior and acceptance criteria accordingly.

---

Outside diff comments:
In `@packages/agent-ops/bff/internal/mapper/agent.go`:
- Around line 202-216: Update ReadyReplicaCount so the fallback after checking
readyReplicas and ready_replicas does not infer readiness from AgentPodName;
return zero when no explicit ready-replica count is available, preserving the
existing numeric parsing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: f8eb6cbf-785c-4f74-bffb-5fcb8074963f

📥 Commits

Reviewing files that changed from the base of the PR and between 4737682 and 537e7bd.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
  • packages/agent-ops/bff/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (27)
  • backend/src/types.ts
  • backend/src/utils/constants.ts
  • frontend/config/webpack.common.js
  • frontend/config/webpack.dev.js
  • frontend/src/concepts/areas/const.ts
  • packages/agent-ops/Dockerfile
  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/V1-IMPLEMENTATION-GAPS.md
  • packages/agent-ops/bff/GAPS.md
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/go.mod
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/extensions.ts
  • packages/agent-ops/frontend/GAPS.md
  • packages/agent-ops/frontend/config/webpack.common.js
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • packages/agent-ops/frontend/src/app/components/DeleteAgentModal.tsx
  • packages/agent-ops/frontend/src/app/hooks/useAgentCardDetail.ts
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: ODH Dashboard Agent
  • GitHub Check: preflight (8515, 537e7bd, agent-ops/openshell-prototype, Gkrumba...
⚠️ CI failures not shown inline (5)

Commit Status: ci/prow/images: ci/prow/images

Conclusion: failure

Job failed.                     BaseSHA:47376829260e320babe797f02e7dcd570b98ac99

Commit Status: ci/prow/odh-mod-arch-agent-ops-pr-image-mirror: ci/prow/odh-mod-arch-agent-ops-pr-image-mirror

Conclusion: failure

Job failed.                     BaseSHA:47376829260e320babe797f02e7dcd570b98ac99

Commit Status: tide: tide

Conclusion: failure

Not mergeable. PR has a merge conflict.

Commit Status: ci/prow/odh-dashboard-operator-pr-image-mirror: ci/prow/odh-dashboard-operator-pr-image-mirror

Conclusion: failure

Job failed.                     BaseSHA:47376829260e320babe797f02e7dcd570b98ac99

Commit Status: ci/prow/odh-dashboard-pr-image-mirror: ci/prow/odh-dashboard-pr-image-mirror

Conclusion: failure

Job failed.                     BaseSHA:47376829260e320babe797f02e7dcd570b98ac99
🧰 Additional context used
📓 Path-based instructions (10)
**

⚙️ CodeRabbit configuration file

**: REVIEW PRIORITIES:

  1. Security vulnerabilities — provide severity, exploit scenario,
    and remediation code. Cite CWE/CVE IDs.
  2. Bugs that could reach production — logic errors, null/undefined,
    race conditions, incorrect async handling, resource leaks.
  3. API contract correctness — shape mismatches, missing error handling,
    silent failures, wrong HTTP status codes.
  4. Performance only when measurable — O(n^2) in hot paths, unbounded
    memory growth, missing pagination.

Do not comment on:

  • Naming preferences (unless genuinely misleading)
  • Import ordering or formatting (handled by ESLint and Prettier)
  • Alternative patterns that are equally valid
  • Missing docs unless a public API is genuinely unclear
  • Code deduplication / DRY suggestions where both copies are short
    and self-contained (< 20 lines)
  • Adding explicit type annotations when TypeScript can infer the type
  • Suggesting exhaustive switch/if-else when a default branch exists

Files:

  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/frontend/GAPS.md
  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/frontend/src/app/components/DeleteAgentModal.tsx
  • packages/agent-ops/bff/GAPS.md
  • packages/agent-ops/Dockerfile
  • backend/src/types.ts
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/extensions.ts
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/frontend/src/app/hooks/useAgentCardDetail.ts
  • frontend/src/concepts/areas/const.ts
  • frontend/config/webpack.common.js
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/V1-IMPLEMENTATION-GAPS.md
  • frontend/config/webpack.dev.js
  • backend/src/utils/constants.ts
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
  • packages/agent-ops/frontend/config/webpack.common.js
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
  • packages/agent-ops/bff/go.mod
**/Dockerfile*

⚙️ CodeRabbit configuration file

**/Dockerfile*: DOCKERFILES:

  1. Multi-stage builds: separate build and runtime stages.
  2. Copy only necessary artifacts to runtime stage (no source code, node_modules, .git).
  3. Use the same base image version as the main Dockerfile where possible.
  4. No npm install in runtime stage — copy from build stage.
  5. Dockerfile.workspace files are for dev workspace images — follow the same base image
    conventions.

Files:

  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/Dockerfile
packages/*/bff/**/*.go

⚙️ CodeRabbit configuration file

packages/*/bff/**/*.go: GO BFF SERVICE (Backend-for-Frontend):
Packages with BFFs: automl, autorag, eval-hub, gen-ai, maas, mlflow.

  1. Validate all incoming request bodies and query parameters at handler level.
  2. No credentials in BFF code — use mounted secrets or environment variables.
  3. Use the shared K8s client config; do not create ad-hoc kubeconfig readers.
  4. HTTP clients to external services must set timeouts and use TLS verification.
  5. No panic in handlers — use explicit error returns with context.
  6. OpenAPI spec in api/ or docs/ must match actual handler signatures.
  7. Follow .golangci.yaml rules in the package root.
  8. Repository pattern: data access through repository interfaces, not direct K8s calls
    in handlers. Mock interfaces for unit testing (see mocks/ directory).

Files:

  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: GO SECURITY (Kubernetes Controllers):

  1. Use io.LimitReader for HTTP response bodies (prevent memory exhaustion)
  2. Validate all data from json.Unmarshal before storing in ConfigMaps/Secrets
  3. No InsecureSkipVerify in TLS configs (enables MITM attacks)
  4. Validate CR spec fields before using in ConfigMaps/Secrets
  5. Set OwnerReferences on all child resources
  6. Validate inputs before exec.Command (prevent command injection)
  7. Never log sensitive fields (Password, Token, APIKey, Secret.Data)
  8. Avoid weak cryptography (MD5, SHA1) for security operations

Files:

  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
packages/*/frontend/src/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

packages/*/frontend/src/**/*.{ts,tsx}: FEATURE PLUGIN FRONTEND (Module Federation):
These packages (automl, autorag, eval-hub, gen-ai, maas, mlflow) use Module Federation
to load as remotes into the host dashboard app.

  1. Plugins must use plugin-core APIs for navigation, not direct router manipulation.
  2. Shared dependencies (React, PatternFly, Redux) must come from the host app — do not
    bundle duplicates.
  3. No global CSS — use PatternFly utility classes or CSS modules only.
  4. Lazy-load heavy components; plugins load on demand via Module Federation.
  5. Follow PatternFly v6 patterns consistent with the main frontend app.

Files:

  • packages/agent-ops/frontend/src/app/components/DeleteAgentModal.tsx
  • packages/agent-ops/frontend/src/app/hooks/useAgentCardDetail.ts
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

**/*.{ts,tsx,js,jsx}: WEB SECURITY (XSS, CSRF Prevention):

  1. No dangerouslySetInnerHTML without sanitization (XSS - CWE-79)
  2. Validate all API responses before rendering
  3. CSRF token validation for state-changing operations
  4. No sensitive data in localStorage

Files:

  • packages/agent-ops/frontend/src/app/components/DeleteAgentModal.tsx
  • backend/src/types.ts
  • packages/agent-ops/extensions.ts
  • packages/agent-ops/frontend/src/app/hooks/useAgentCardDetail.ts
  • frontend/src/concepts/areas/const.ts
  • frontend/config/webpack.common.js
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • frontend/config/webpack.dev.js
  • backend/src/utils/constants.ts
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
  • packages/agent-ops/frontend/config/webpack.common.js
backend/src/**/*.{ts,js}

⚙️ CodeRabbit configuration file

backend/src/**/*.{ts,js}: ODH DASHBOARD BACKEND (Node.js BFF):

  1. All external API calls must use the service account token, never user-provided tokens.
  2. Validate and sanitize route parameters before K8s API calls (prevent injection).
  3. Proxy endpoints must not expose internal cluster addresses to the client.
  4. Error responses must not leak cluster internals (pod names, IPs, stack traces).
  5. Verify RBAC: backend routes should check user permissions via SubjectAccessReview.

Files:

  • backend/src/types.ts
  • backend/src/utils/constants.ts
frontend/src/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

frontend/src/**/*.{ts,tsx}: ODH DASHBOARD FRONTEND (main app):

  1. PatternFly v6: use PF6 imports from @patternfly/react-core, not custom wrappers.
    Avoid custom CSS — if you need to "nudge" PF layout, check frontend/src/concepts/dashboard first.
  2. Functional components only (no class components). Use hooks for state management.
  3. API calls: use the shared API utilities, never raw fetch(); handle loading/error states.
  4. No hardcoded cluster URLs or API endpoints — use config from backend.
  5. Route guards: protected routes must check user permissions before rendering.
  6. Performance: avoid unnecessary useCallback/useMemo/useRef — React is performant by default.
    Only use useCallback when the function is passed as a prop, used as a useEffect dependency,
    or returned from a custom hook (see docs/best-practices.md).
  7. Custom components go in frontend/src/components. PF-first: verify with the team before
    creating new custom components.

Files:

  • frontend/src/concepts/areas/const.ts
**/webpack.{common,dev,prod}.{ts,js}

⚙️ CodeRabbit configuration file

**/webpack.{common,dev,prod}.{ts,js}: WEBPACK CONFIG:
(Suppression) Do not suggest alternative bundler configurations
or plugin replacements. Only flag security issues and broken build logic.

Files:

  • frontend/config/webpack.common.js
  • frontend/config/webpack.dev.js
  • packages/agent-ops/frontend/config/webpack.common.js
**/go.mod

⚙️ CodeRabbit configuration file

**/go.mod: GO DEPENDENCY SECURITY (CWE-829):

  1. Verify new dependencies are from trusted organizations
  2. Check for replace directives pointing to forks (supply chain risk).
    Flag replace directives that redirect well-known modules
    (golang.org/x/, k8s.io/, sigs.k8s.io/*) to personal forks
  3. Flag indirect dependency additions unrelated to the PR
  4. Verify no downgrade of security-critical dependencies
  5. retract directives that could force consumers to upgrade to
    specific versions (potential for malicious version steering)
  6. toolchain directive changes (Go 1.21+) that force specific Go
    toolchain downloads from untrusted sources

Files:

  • packages/agent-ops/bff/go.mod
🪛 LanguageTool
packages/agent-ops/frontend/GAPS.md

[uncategorized] ~44-~44: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... cross-module navigation which causes a full page reload. Consider using a shared navigat...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

packages/agent-ops/V1-IMPLEMENTATION-GAPS.md

[uncategorized] ~91-~91: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...es window.location.href** - Causes full page reload instead of SPA navigation - S...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.23.0)
packages/agent-ops/frontend/GAPS.md

[warning] 24-24: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 36-36: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 40-40: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 54-54: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

packages/agent-ops/V1-IMPLEMENTATION-GAPS.md

[warning] 14-14: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 36-36: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 72-72: Ordered list item prefix
Expected: 1; Actual: 4; Style: 1/2/3

(MD029, ol-prefix)


[warning] 76-76: Ordered list item prefix
Expected: 2; Actual: 5; Style: 1/2/3

(MD029, ol-prefix)


[warning] 80-80: Ordered list item prefix
Expected: 3; Actual: 6; Style: 1/2/3

(MD029, ol-prefix)


[warning] 85-85: Ordered list item prefix
Expected: 4; Actual: 7; Style: 1/2/3

(MD029, ol-prefix)


[warning] 90-90: Ordered list item prefix
Expected: 5; Actual: 8; Style: 1/2/3

(MD029, ol-prefix)


[warning] 94-94: Ordered list item prefix
Expected: 6; Actual: 9; Style: 1/2/3

(MD029, ol-prefix)


[warning] 98-98: Ordered list item prefix
Expected: 7; Actual: 10; Style: 1/2/3

(MD029, ol-prefix)


[warning] 105-105: Ordered list item prefix
Expected: 1; Actual: 11; Style: 1/2/3

(MD029, ol-prefix)


[warning] 106-106: Ordered list item prefix
Expected: 2; Actual: 12; Style: 1/2/3

(MD029, ol-prefix)


[warning] 107-107: Ordered list item prefix
Expected: 3; Actual: 13; Style: 1/2/3

(MD029, ol-prefix)


[warning] 108-108: Ordered list item prefix
Expected: 4; Actual: 14; Style: 1/2/3

(MD029, ol-prefix)


[warning] 109-109: Ordered list item prefix
Expected: 5; Actual: 15; Style: 1/2/3

(MD029, ol-prefix)


[warning] 110-110: Ordered list item prefix
Expected: 6; Actual: 16; Style: 1/2/3

(MD029, ol-prefix)

🔇 Additional comments (18)
packages/agent-ops/frontend/GAPS.md (1)

1-57: LGTM!

packages/agent-ops/bff/internal/models/agent_runtime_detail.go (1)

30-30: LGTM!

packages/agent-ops/frontend/src/app/api/agentRuntimes.ts (1)

3-8: LGTM!

Also applies to: 64-70

packages/agent-ops/frontend/src/app/hooks/useAgentCardDetail.ts (1)

1-29: LGTM!

packages/agent-ops/frontend/src/app/components/DeleteAgentModal.tsx (1)

1-66: LGTM!

packages/agent-ops/bff/internal/api/agent_chat_handler.go (1)

20-25: 🎯 Functional Correctness

Drop the SSRF concern validateAgentPathParams already rejects non-DNS1123 ns/name, and the route is further gated by AttachNamespaceFromParam plus RequireAccessToAgent before ChatAgentHandler runs.

			> Likely an incorrect or invalid review comment.
backend/src/types.ts (1)

57-57: LGTM!

backend/src/utils/constants.ts (1)

89-89: LGTM!

frontend/src/concepts/areas/const.ts (1)

35-35: LGTM!

packages/agent-ops/extensions.ts (1)

1-18: LGTM!

packages/agent-ops/frontend/config/webpack.common.js (1)

251-251: LGTM!

packages/agent-ops/bff/cmd/main.go (1)

56-61: 🎯 Functional Correctness

Drop this warning. packages/agent-ops/bff/internal/api/app.go already falls back to agent-ops-demo when the namespace flag is empty, so this does not break sandbox operations.

			> Likely an incorrect or invalid review comment.
frontend/config/webpack.common.js (1)

319-325: 🩺 Stability & Availability

Confirm no runtime import of react-dom/server frontend/config/webpack.common.js:323-325
alias: false only stubs the module. If any bundled dependency reaches react-dom/server, the failure moves to runtime instead of build time.

packages/agent-ops/bff/internal/config/environment.go (1)

115-121: LGTM!

packages/agent-ops/bff/internal/models/health_check.go (1)

7-16: LGTM!

packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go (1)

31-47: LGTM!

packages/agent-ops/bff/internal/integrations/agents/openshell/client.go (1)

364-372: 🎯 Functional Correctness

Remove this concern: agentPodName() only populates status. The probe and chat paths build their URLs from sb.Name directly, so this fallback does not affect connectivity here.

			> Likely an incorrect or invalid review comment.
packages/agent-ops/bff/internal/api/app.go (1)

267-269: 🔒 Security & Privacy

No SSRF path here. ns and name are validated as DNS-1123 labels before the proxy URL is built, so they can’t introduce an arbitrary host or scheme.

			> Likely an incorrect or invalid review comment.

Comment on lines +258 to +271
const agentOpsProxies = mfProxies.filter((p) => p.startsWith('/agent-ops'));
const otherMfProxies = mfProxies.filter((p) => !p.startsWith('/agent-ops'));
return [
...(agentOpsProxies.length > 0
? [
{
context: agentOpsProxies,
target: `http://0.0.0.0:${process.env.AGENT_OPS_PORT || 4001}`,
pathRewrite: { '^/agent-ops': '' },
},
]
: []),
{
context: ['/api', '/_mf', '/mlflow', ...mfProxies],
context: ['/api', '/_mf', '/mlflow', ...otherMfProxies],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="frontend/config/webpack.dev.js"

echo "== relevant proxy blocks =="
rg -n "agentOpsProxies|getCurrentToken|shouldFwdAccessToken|onProxyReq|Authorization|x-forwarded-access-token|auth-method|agent-ops" "$file"

echo
echo "== surrounding lines =="
sed -n '220,290p' "$file"

Repository: opendatahub-io/odh-dashboard

Length of output: 4257


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== agent-ops references =="
rg -n "AGENT_OPS_PORT|agent-ops|auth-method=user_token|x-forwarded-access-token|getCurrentToken|shouldFwdAccessToken" . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

echo
echo "== files containing AGENT_OPS_PORT =="
rg -n "AGENT_OPS_PORT" frontend . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

echo
echo "== package/service hints around agent-ops =="
fd -H "agent-ops|AgentOps|agentOps" .

Repository: opendatahub-io/odh-dashboard

Length of output: 44301


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' packages/agent-ops/frontend/config/webpack.dev.js
echo
sed -n '1,260p' packages/agent-ops/bff/README.md | sed -n '145,220p'

Repository: opendatahub-io/odh-dashboard

Length of output: 8019


Forward the user token in the agent-ops dev proxy
frontend/config/webpack.dev.js:258-271 needs the same auth forwarding as the neighboring proxy blocks. Without onProxyReq or equivalent headers, the local agent-ops BFF gets no x-forwarded-access-token/Authorization, and AUTH_METHOD=user_token dev requests fail (CWE-306, CWE-287).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/config/webpack.dev.js` around lines 258 - 271, Update the
agentOpsProxies entry in the webpack dev proxy configuration to forward the user
token using the same onProxyReq or equivalent header logic as the neighboring
proxy blocks. Ensure both x-forwarded-access-token and Authorization are
propagated to the agent-ops target while preserving its existing context,
target, and pathRewrite settings.

Comment on lines +5 to +11
## RBAC / SSAR for Sandbox CRs

- The deploy RBAC checks now verify `agents.x-k8s.io/sandboxes` create/get, but there is no SSAR
check for delete/patch (used by DeleteAgent, StopAgent, StartAgent). Story 73189 covers this
but is unassigned.
- The enrichment RBAC still checks `agents.x-k8s.io/sandboxes` get/list for card enrichment
access, which is correct but may need refinement once the Sandbox CRD stabilizes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Missing SSAR authorization for delete/patch — CWE-862 Missing Authorization.

Stop/Start/Delete operate on Sandbox CRs with no per-request SubjectAccessReview check. If the BFF's own service account has broader RBAC than the calling user (typical for a BFF pattern), any user reaching these routes can stop/start/delete sandboxes they aren't authorized to touch. This should not ship as a "should-address" backlog item — it's an authz bypass on destructive operations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/GAPS.md` around lines 5 - 11, Update DeleteAgent,
StopAgent, and StartAgent to perform a per-request SubjectAccessReview for the
relevant Sandbox CR delete/patch action before executing it, using the
authenticated caller’s identity and target resource context. Deny the operation
when SSAR is not allowed, and remove the documentation framing this
authorization as an unassigned backlog item.

Comment on lines +20 to +24
## Route creation for external access

- Routes are created without an ownerReference when using the Sandbox CR path (unlike the old
AgentRuntime path where the CR was the owner). The Sandbox controller may auto-create Routes
in the future. Needs alignment with the controller team.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Routes created without OwnerReference — orphaned child resources.

Routes created on the Sandbox CR path have no ownerReference, so deleting the Sandbox leaves orphaned Route objects (resource leak, and a stale-endpoint exposure risk if the Route continues routing traffic to a torn-down agent). Go security conventions for controllers require OwnerReferences on all child resources.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/GAPS.md` around lines 20 - 24, Update the Sandbox CR
route-creation flow so every created Route includes an OwnerReference pointing
to its owning Sandbox resource. Ensure deletion of the Sandbox garbage-collects
the Route, while preserving the existing ownerReference behavior for the
AgentRuntime path.

Source: Path instructions

Comment on lines +3 to +11
go 1.25.0

require (
github.com/getkin/kin-openapi v0.132.0
github.com/google/uuid v1.6.0
github.com/julienschmidt/httprouter v1.3.0
github.com/rhuss/openshell-sdk-go v0.2.2
github.com/rs/cors v1.11.1
github.com/stretchr/testify v1.11.0
github.com/stretchr/testify v1.11.1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is github.com/rhuss/openshell-sdk-go an official or community Go SDK for the OpenShell project (github.com/NVIDIA/OpenShell)?

💡 Result:

No, github.com/rhuss/openshell-sdk-go is not an official community Go SDK for the NVIDIA OpenShell project [1][2]. It is a third-party project created by a contributor who proposed it as a potential starting point for an official Go SDK [1]. As of July 13, 2026, the NVIDIA OpenShell project has not adopted this repository, and official development efforts for OpenShell SDKs are currently focused on other languages and architectures (such as Rust and Python) as outlined in the project's official RFCs [3]. Official communication and documentation for the project are hosted within the main NVIDIA/OpenShell GitHub repository and the official NVIDIA documentation site [2][4][5].

Citations:


Unvetted OpenShell SDK dependency (CWE-829). github.com/rhuss/openshell-sdk-go is a third-party personal-account repository, not the official NVIDIA/OpenShell Go SDK. Pulling this client into go.mod adds supply-chain risk; use an upstream-maintained package or vendor the code only after provenance review.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/go.mod` around lines 3 - 11, Replace the unvetted
github.com/rhuss/openshell-sdk-go dependency in go.mod with the official
NVIDIA/OpenShell Go SDK or an upstream-maintained equivalent, updating imports
and usages throughout the affected code to match its API. If no suitable
upstream package exists, remove the dependency and vendor an approved,
provenance-reviewed implementation instead.

Source: Path instructions

Comment on lines +54 to +60
for key, values := range resp.Header {
for _, v := range values {
w.Header().Add(key, v)
}
}
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing io.LimitReader on proxied response body; io.Copy error swallowed.

Path instructions require io.LimitReader for HTTP response bodies to prevent memory/resource exhaustion. Here resp.Body is copied to w unbounded, and io.Copy's error return is discarded so partial/failed proxy writes go unnoticed. All response headers (including hop-by-hop ones like Transfer-Encoding/Connection) are also forwarded verbatim without filtering.

As per path instructions, "Use io.LimitReader for HTTP response bodies (prevent memory exhaustion)."

🛡️ Proposed fix
-	w.WriteHeader(resp.StatusCode)
-	io.Copy(w, resp.Body)
+	w.WriteHeader(resp.StatusCode)
+	if _, copyErr := io.Copy(w, io.LimitReader(resp.Body, maxChatResponseBytes)); copyErr != nil {
+		logger.Error("Failed to stream agent chat response", slog.Any("error", copyErr))
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/api/agent_chat_handler.go` around lines 54 -
60, Update the response-body proxying flow around the handler’s header
forwarding and io.Copy call to copy through io.LimitReader with the configured
response-size limit, handle the copy error instead of discarding it, and filter
hop-by-hop headers such as Transfer-Encoding and Connection before forwarding
them. Preserve the upstream status code and bounded body forwarding behavior.

Source: Path instructions

Comment on lines +326 to +333
spec := map[string]any{
"operatingMode": status,
}
if sb.Spec.Template != nil {
spec["image"] = sb.Spec.Template.Image
spec["environment"] = sb.Spec.Environment
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file and inspect relevant regions around the referenced lines and related methods.
ast-grep outline packages/agent-ops/bff/internal/integrations/agents/openshell/client.go --view expanded || true
printf '\n--- lines 280-380 ---\n'
sed -n '280,380p' packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
printf '\n--- search for operatingMode / Phase / StopAgent / StartAgent ---\n'
rg -n 'operatingMode|Phase|StopAgent|StartAgent|Spec\.OperatingMode|operatingMode"' packages/agent-ops/bff/internal/integrations/agents/openshell/client.go

Repository: opendatahub-io/odh-dashboard

Length of output: 4743


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- relevant type definitions ---'
rg -n 'type AgentDetail|operatingMode|ReadyStatus|phase|AgentService|AgentMetadata' packages/agent-ops -g '!**/*_test.go'

printf '\n%s\n' '--- callers/usages of AgentDetail.Spec operatingMode ---'
rg -n '"operatingMode"|Spec\[.*operatingMode|ReadyStatus|AgentDetail' packages/agent-ops packages -g '!**/*_test.go'

printf '\n%s\n' '--- surrounding code for StopAgent/StartAgent ---'
sed -n '145,205p' packages/agent-ops/bff/internal/integrations/agents/openshell/client.go

Repository: opendatahub-io/odh-dashboard

Length of output: 30631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- sandbox type definitions / operatingMode field ---'
rg -n 'type Sandbox|type .*Spec|OperatingMode|operatingMode' packages/agent-ops -g '!**/*_test.go'

printf '\n%s\n' '--- open-shell client type imports and any spec field access in the file ---'
sed -n '1,140p' packages/agent-ops/bff/internal/integrations/agents/openshell/client.go

printf '\n%s\n' '--- sandbox API / CRD references in repo ---'
rg -n 'operatingMode' . -g '!**/*_test.go' | sed -n '1,120p'

Repository: opendatahub-io/odh-dashboard

Length of output: 8960


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- AgentDetail type ---'
sed -n '1,140p' packages/agent-ops/bff/internal/integrations/agents/types.go

printf '\n%s\n' '--- runtime detail model ---'
sed -n '1,120p' packages/agent-ops/bff/internal/models/agent_runtime_detail.go

printf '\n%s\n' '--- mapper from AgentDetail ---'
sed -n '1,220p' packages/agent-ops/bff/internal/mapper/agent.go

printf '\n%s\n' '--- frontend references to operatingMode ---'
rg -n 'operatingMode|readyStatus|ReadyStatus|AgentRuntimeDetail|AgentDetail' packages/agent-ops/frontend packages/agent-ops/bff -g '!**/*_test.go'

Repository: opendatahub-io/odh-dashboard

Length of output: 25381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- AgentDetail schema in OpenAPI ---'
rg -n 'AgentDetail:|operatingMode|spec:|readyStatus|status:' packages/agent-ops/bff/openapi/src/agent-ops.yaml

printf '\n%s\n' '--- AgentRuntimeDetail schema in OpenAPI around definition ---'
sed -n '424,520p' packages/agent-ops/bff/openapi/src/agent-ops.yaml

Repository: opendatahub-io/odh-dashboard

Length of output: 3244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- where AgentDetail.Spec is read ---'
rg -n '\.Spec\b|Spec\]' packages/agent-ops/bff packages/agent-ops/frontend -g '!**/*_test.go'

printf '\n%s\n' '--- AgentCardDetail model/schema around any spec-bearing fields ---'
rg -n 'type AgentCardDetail|spec|Spec' packages/agent-ops/bff/internal/models packages/agent-ops/bff/openapi/src/agent-ops.yaml

printf '\n%s\n' '--- mapper files that consume AgentDetail ---'
sed -n '1,220p' packages/agent-ops/bff/internal/mapper/agent_card.go

Repository: opendatahub-io/odh-dashboard

Length of output: 10111


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- AgentDetail in OpenAPI / API handlers ---'
rg -n 'AgentDetail|GetAgentHandler|GetAgentRuntimeDetailHandler|AgentRuntimeDetailResponse|AgentDetailResponse' packages/agent-ops/bff/openapi/src packages/agent-ops/bff/internal/api packages/agent-ops/frontend -g '!**/*_test.go'

printf '\n%s\n' '--- any direct reads of spec.operatingMode ---'
rg -n 'spec\.operatingMode|operatingMode"\]|operatingMode\]' packages/agent-ops/bff packages/agent-ops/frontend -g '!**/*_test.go'

Repository: opendatahub-io/odh-dashboard

Length of output: 909


Populate operatingMode from the Sandbox spec, not Status.Phase packages/agent-ops/bff/internal/integrations/agents/openshell/client.go:326-333 currently writes Ready/Pending/Unknown into spec.operatingMode, while stop/start patch the actual spec value to Suspended/Running. That conflates readiness with configuration; read the spec field here or drop this key if the response is meant to expose only phase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/integrations/agents/openshell/client.go`
around lines 326 - 333, Update the spec map construction in the relevant Sandbox
response logic to source operatingMode from the Sandbox spec rather than the
status phase, preserving values such as Suspended and Running; alternatively
remove the operatingMode key if this response should expose only phase. Do not
populate it from status.

@@ -4,7 +4,7 @@ ARG BFF_SOURCE_CODE=./bff

# Set the base images for the build stages
ARG NODE_BASE_IMAGE=node:22
ARG GOLANG_BASE_IMAGE=golang:1.24.3
ARG GOLANG_BASE_IMAGE=golang:1.25

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Unpinned floating tag — supply chain risk (CWE-829).

golang:1.25 floats to the latest patch/point release on every rebuild. Untested toolchain changes get pulled in silently, and the build is not reproducible or attestable. Pin to a digest (golang:1.25@sha256:...) or at minimum a full patch version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/Dockerfile` at line 7, Update the GOLANG_BASE_IMAGE
argument to use a reproducible, immutable image reference by pinning golang to a
specific full patch version and preferably its sha256 digest; do not leave it as
the floating golang:1.25 tag.

@@ -9,7 +9,7 @@ ARG BFF_SOURCE_CODE=./packages/${MODULE_NAME}/bff

# Set the base images for the build stages
ARG NODE_BASE_IMAGE=registry.access.redhat.com/ubi9/nodejs-22:latest
ARG GOLANG_BASE_IMAGE=registry.access.redhat.com/ubi9/go-toolset:1.24
ARG GOLANG_BASE_IMAGE=docker.io/library/golang:1.25

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Unpinned floating tag — same supply chain concern as the main Dockerfile.

See consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/Dockerfile.workspace` at line 12, Update the
GOLANG_BASE_IMAGE argument in the workspace Dockerfile to use a fixed, immutable
image digest instead of the floating golang:1.25 tag, preserving the intended Go
1.25 base image.

Comment thread packages/agent-ops/src/AgentDeploymentsPage.tsx
Comment on lines +98 to +102
10. **Env var secrets via k8s Secret** (RHOAIENG-73640, New)
- Deploy wizard creates plain env vars visible via `oc describe`
- Secret creation story exists but unassigned
- Security hygiene gap for API_KEY values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

API keys stored as plaintext env vars — CWE-312 cleartext storage of sensitive info.

Item 10 documents that the deploy wizard writes API_KEY-style values as plain env vars, visible to anyone with oc describe/get pod -o yaml RBAC. This is shipping a real credential-exposure vector, not a cosmetic gap — recommend gating this in v1 (block plaintext secret input, or require k8s Secret creation) rather than deferring to an unassigned story.

🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 98-98: Ordered list item prefix
Expected: 7; Actual: 10; Style: 1/2/3

(MD029, ol-prefix)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/V1-IMPLEMENTATION-GAPS.md` around lines 98 - 102, Update
item 10, “Env var secrets via k8s Secret,” to require v1 gating: block plaintext
API_KEY-style inputs or require creation and reference of a Kubernetes Secret
before deployment. Do not leave plaintext environment-variable storage as an
unassigned follow-up; document the deployment wizard behavior and acceptance
criteria accordingly.

@Gkrumbach07
Gkrumbach07 force-pushed the agent-ops/openshell-prototype branch from d5f4cb2 to c87631b Compare July 13, 2026 14:03
@openshift-ci openshift-ci Bot removed the needs-rebase PR needs to be rebased label Jul 13, 2026

@odh-dashboard-agent odh-dashboard-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Preflight Agent Report

Verdict: ❌ NOT READY
Commit: 537e7bd

Checks
Check Status Details
Conflicts ❌ PR has a merge conflict — rebase required
CI ⚠️ router ✅; Prow image/mirror jobs ❌ (ran on old base SHA before conflict; tide blocked: "Not mergeable"); Konflux ⚠️ still queued
Lint ⚠️ GHA Lint job pending (router passed, downstream jobs still running)
Type Check ⚠️ GHA Type-Check job pending
Unit Tests ⚠️ GHA Unit-Tests job pending
Jira ❌ No Jira key found in PR title, body, or branch
Test Coverage ❌ 29 files changed, no test files added; no Test Impact explanation in PR body
PR Body ❌ Does not follow template: uses ## Summary instead of ## Description; missing ## How Has This Been Tested?, ## Test Impact, checklist, and Jira URL; has .tsx UI changes with no screenshots
Review (Claude) 🟠 2 major Wrong Spec.Environment field (confirmed); hop-by-hop headers forwarded in chat proxy (confirmed) — see inline comments

Automated by ODH Dashboard Agent

}
if sb.Spec.Template != nil {
spec["image"] = sb.Spec.Template.Image
spec["environment"] = sb.Spec.Environment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Major · Claude review

Wrong field: reads sb.Spec.Environment instead of sb.Spec.Template.Environment, silently discarding deployed env vars.

The guard above checks sb.Spec.Template != nil, so Template-level fields are intended here. sb.Spec.Environment is a separate outer Spec field that is never populated by DeployAgent — which writes env vars to SandboxSpec.Template.Environment. Any UI that displays the agent's environment variables will always show empty regardless of what was set at deploy time.

Suggested fix
-		spec["environment"] = sb.Spec.Environment
+		spec["environment"] = sb.Spec.Template.Environment

defer resp.Body.Close()

// Forward the agent's response headers and body back to the client
for key, values := range resp.Header {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Major · Claude review

Hop-by-hop headers (e.g. Transfer-Encoding, Connection) forwarded verbatim to the client, corrupting chunked responses.

All upstream agent response headers — including hop-by-hop headers that must not be retransmitted — are copied to the downstream writer with no filtering. When the upstream agent sends Transfer-Encoding: chunked, the Go HTTP server applies its own chunked framing on top, resulting in double-encoded responses that clients cannot parse. Filter hop-by-hop headers before forwarding.

Suggested fix
+	hopByHop := map[string]bool{
+		"Connection": true, "Keep-Alive": true, "Transfer-Encoding": true,
+		"Trailer": true, "Te": true, "Upgrade": true, "Proxy-Authorization": true,
+	}
 	for key, values := range resp.Header {
+		if hopByHop[key] {
+			continue
+		}
 		for _, v := range values {
 			w.Header().Add(key, v)
 		}
 	}

}

if cfg.AuthMethod == config.AuthMethodDisabled && !cfg.MockAgentClient {
if cfg.AuthMethod == config.AuthMethodDisabled && !cfg.MockAgentClient && cfg.OpenShellGatewayURL == "" {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Major · Claude review

Security gate weakened: AUTH_METHOD=disabled + OpenShellGatewayURL set allows real agent routes with no authentication.

The original guard ensured AUTH_METHOD=disabled was only safe with the mock client. The new condition allows a real OpenShell Gateway URL to bypass this check — the gateway is configured with v1.NoAuth() and the RequireAccessToAgent middleware short-circuits entirely when auth is disabled. An operator who sets OPENSHELL_GATEWAY_URL in an environment with AUTH_METHOD=disabled (e.g. misconfigured staging) will expose live agent CRUD routes without any auth. The change should at minimum log a prominent warning when this combination is detected, and the production operator deployment should enforce AUTH_METHOD != disabled.

- OpenShell SDK integration: deploy/list/get/delete via Gateway, stop/start via CR patch
- Bundled area extension for nav visibility without federated module
- BFF: endpoint URL, service info, pod name/count from sandbox status
- Backend type fix: agentOps in DashboardConfig for /api/config passthrough
- Webpack: resolve fallbacks for Node.js built-ins, agent-ops proxy split
- Go 1.25 base image for OpenShell SDK compatibility
- getAgentCard API function for agent card detail hook

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Gkrumbach07
Gkrumbach07 force-pushed the agent-ops/openshell-prototype branch from c87631b to b6fa36d Compare July 13, 2026 14:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

♻️ Duplicate comments (2)
frontend/config/webpack.dev.js (1)

261-267: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Forward the authentication context through the Agent Ops proxy.

The new proxy only sets context, target, and pathRewrite. It still lacks the token-forwarding logic from the existing authenticated proxy path, so local AUTH_METHOD=user_token requests arrive without x-forwarded-access-token/Authorization and fail authentication. This is an authentication integration failure, not an auth bypass.

Reuse the neighboring proxy’s header-forwarding logic.
As per path instructions, webpack configuration changes must be reviewed for security and broken build logic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/config/webpack.dev.js` around lines 261 - 267, Update the Agent Ops
proxy entry in the webpack configuration to reuse the neighboring authenticated
proxy’s header-forwarding logic, forwarding both x-forwarded-access-token and
Authorization for local AUTH_METHOD=user_token requests. Keep the existing
context, target, and pathRewrite behavior unchanged.

Source: Path instructions

packages/agent-ops/src/AgentDeploymentsPage.tsx (1)

59-65: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the validated runtime API helper before rendering.

json.data?.runtimes ?? [] only handles an absent value. A non-array response reaches agents.length/agents.map() and crashes rendering, while this page also bypasses the existing validated API layer in packages/agent-ops/frontend/src/app/api/agentRuntimes.ts.

Reuse that helper and verify that runtimes is an array before calling setAgents.
As per path instructions, API responses must be validated before rendering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/src/AgentDeploymentsPage.tsx` around lines 59 - 65, Update
the runtime-loading logic in AgentDeploymentsPage to reuse the validated helper
from agentRuntimes.ts instead of directly parsing fetch JSON. Before calling
setAgents, ensure the returned runtimes value is an array, using the existing
helper’s validation and fallback behavior so agents always contains render-safe
data.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/config/webpack.common.js`:
- Around line 319-322: Update the resolve.conditionNames configuration near the
fallback setting to preserve Webpack’s default export conditions, including
webpack and browser. Add the spread defaults marker alongside the existing
conditions or remove the override entirely, while keeping the fallback
diagnostics_channel configuration unchanged.
- Around line 243-245: Update the NormalModuleReplacementPlugin callback to
apply the node: prefix removal to both resource.request and
resource.createData.request, preserving the existing replacement behavior for
each request value.

In `@packages/agent-ops/bff/cmd/main.go`:
- Around line 56-58: Update the OpenShell gateway configuration used by the
openshell-gateway-url flag and the client construction in app.go to require
verified TLS with a configured CA bundle. Remove or disable the
TLSConfig{Insecure: true} behavior, and ensure privileged agent operations
cannot proceed unless certificate verification is enabled.

In `@packages/agent-ops/bff/GAPS.md`:
- Around line 15-18: Reconcile the endpoint documentation in GAPS.md with the
route registrations in app.go: remove or revise the undocumented /restart and
/card endpoint entries unless they are actually registered, and document the
existing GetAgent response enrichment with card data instead. Verify the delete,
stop, start, and chat routes remain accurately represented before updating
OpenAPI.
- Around line 28-31: Update the GetAgent card-probe host selection to use the
Sandbox CR status.serviceFQDN value first, falling back to the constructed
service host only when that field is empty; preserve the existing probe behavior
otherwise.

In `@packages/agent-ops/bff/internal/api/app.go`:
- Line 127: Update the configuration branch around cfg.AuthMethod,
cfg.MockAgentClient, and cfg.OpenShellGatewayURL to reject real OpenShell when
authentication is disabled: require cfg.MockAgentClient to be true, or otherwise
fail configuration before constructing the unauthenticated client. Preserve the
existing behavior for mock-agent mode and configured gateway URLs.

In `@packages/agent-ops/bff/internal/integrations/agents/openshell/client.go`:
- Line 26: Harden cardProbeClient against SSRF by disabling automatic redirect
following, so agent-controlled Location responses cannot reach internal
endpoints. Validate the SDK-provided sandbox and namespace values as DNS-1123
labels before constructing the card-probe target URL, rejecting invalid values.
Apply these changes to every card-probe request path, including the usages near
the noted locations.

In `@packages/agent-ops/bff/internal/models/health_check.go`:
- Around line 7-10: Update OpenShellStatus to expose only the enabled field in
the unauthenticated health-check response, removing Gateway and Namespace plus
their JSON fields. Keep any diagnostic gateway or namespace data available only
through an existing admin-only endpoint, without exposing it from /healthcheck.
- Line 16: Add openshell to the health response schema and optional podName to
the runtime-detail schema in packages/agent-ops/api/openapi/agent-ops.yaml, then
synchronize packages/agent-ops/bff/openapi/src/agent-ops.yaml with the OpenAPI
definitions and the OpenShellStatus, health-check, and agent runtime-detail
models in packages/agent-ops/bff/internal/models/health_check.go and
packages/agent-ops/bff/internal/models/agent_runtime_detail.go.

In `@packages/agent-ops/src/AgentDeploymentsPage.tsx`:
- Around line 60-67: Update the fetch error handling in AgentDeploymentsPage
around the !res.ok branch to stop including res.text() in the Error message
displayed through setError and the Alert. Throw a fixed generic failure message
for non-2xx responses, while preserving server-side logging of the raw response
body if an existing logging path is available.

---

Duplicate comments:
In `@frontend/config/webpack.dev.js`:
- Around line 261-267: Update the Agent Ops proxy entry in the webpack
configuration to reuse the neighboring authenticated proxy’s header-forwarding
logic, forwarding both x-forwarded-access-token and Authorization for local
AUTH_METHOD=user_token requests. Keep the existing context, target, and
pathRewrite behavior unchanged.

In `@packages/agent-ops/src/AgentDeploymentsPage.tsx`:
- Around line 59-65: Update the runtime-loading logic in AgentDeploymentsPage to
reuse the validated helper from agentRuntimes.ts instead of directly parsing
fetch JSON. Before calling setAgents, ensure the returned runtimes value is an
array, using the existing helper’s validation and fallback behavior so agents
always contains render-safe data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: eefd1780-37bf-432a-a275-cee394117cf8

📥 Commits

Reviewing files that changed from the base of the PR and between 537e7bd and b6fa36d.

⛔ Files ignored due to path filters (1)
  • packages/agent-ops/bff/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (22)
  • backend/src/types.ts
  • backend/src/utils/constants.ts
  • frontend/config/webpack.common.js
  • frontend/config/webpack.dev.js
  • frontend/src/concepts/areas/const.ts
  • packages/agent-ops/Dockerfile
  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/bff/GAPS.md
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/go.mod
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/extensions.ts
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (14)
  • GitHub Check: Cypress-Setup (packages/autorag, @odh-dashboard/autorag)
  • GitHub Check: Cypress-Setup (frontend, odh-dashboard-frontend)
  • GitHub Check: Cypress-Setup (packages/agent-ops, @odh-dashboard/agent-ops)
  • GitHub Check: Cypress-Setup (packages/automl, @odh-dashboard/automl)
  • GitHub Check: Cypress-Setup (packages/eval-hub, @odh-dashboard/eval-hub)
  • GitHub Check: Cypress-Setup (packages/mlflow, @odh-dashboard/mlflow)
  • GitHub Check: Cypress-Setup (packages/maas, @odh-dashboard/maas)
  • GitHub Check: Cypress-Setup (packages/gen-ai, @odh-dashboard/gen-ai)
  • GitHub Check: Cypress-Setup (packages/model-registry, @odh-dashboard/model-registry)
  • GitHub Check: Phase 1: Docker Build (ODH mode)
  • GitHub Check: Phase 1: Docker Build (RHOAI mode)
  • GitHub Check: Get-Test-Groups
  • GitHub Check: Lint
  • GitHub Check: Type-Check
🧰 Additional context used
📓 Path-based instructions (10)
**

⚙️ CodeRabbit configuration file

**: REVIEW PRIORITIES:

  1. Security vulnerabilities — provide severity, exploit scenario,
    and remediation code. Cite CWE/CVE IDs.
  2. Bugs that could reach production — logic errors, null/undefined,
    race conditions, incorrect async handling, resource leaks.
  3. API contract correctness — shape mismatches, missing error handling,
    silent failures, wrong HTTP status codes.
  4. Performance only when measurable — O(n^2) in hot paths, unbounded
    memory growth, missing pagination.

Do not comment on:

  • Naming preferences (unless genuinely misleading)
  • Import ordering or formatting (handled by ESLint and Prettier)
  • Alternative patterns that are equally valid
  • Missing docs unless a public API is genuinely unclear
  • Code deduplication / DRY suggestions where both copies are short
    and self-contained (< 20 lines)
  • Adding explicit type annotations when TypeScript can infer the type
  • Suggesting exhaustive switch/if-else when a default branch exists

Files:

  • backend/src/types.ts
  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • frontend/src/concepts/areas/const.ts
  • frontend/config/webpack.common.js
  • packages/agent-ops/bff/GAPS.md
  • packages/agent-ops/extensions.ts
  • packages/agent-ops/bff/cmd/main.go
  • backend/src/utils/constants.ts
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • packages/agent-ops/Dockerfile
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
  • frontend/config/webpack.dev.js
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/go.mod
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
backend/src/**/*.{ts,js}

⚙️ CodeRabbit configuration file

backend/src/**/*.{ts,js}: ODH DASHBOARD BACKEND (Node.js BFF):

  1. All external API calls must use the service account token, never user-provided tokens.
  2. Validate and sanitize route parameters before K8s API calls (prevent injection).
  3. Proxy endpoints must not expose internal cluster addresses to the client.
  4. Error responses must not leak cluster internals (pod names, IPs, stack traces).
  5. Verify RBAC: backend routes should check user permissions via SubjectAccessReview.

Files:

  • backend/src/types.ts
  • backend/src/utils/constants.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

**/*.{ts,tsx,js,jsx}: WEB SECURITY (XSS, CSRF Prevention):

  1. No dangerouslySetInnerHTML without sanitization (XSS - CWE-79)
  2. Validate all API responses before rendering
  3. CSRF token validation for state-changing operations
  4. No sensitive data in localStorage

Files:

  • backend/src/types.ts
  • frontend/src/concepts/areas/const.ts
  • frontend/config/webpack.common.js
  • packages/agent-ops/extensions.ts
  • backend/src/utils/constants.ts
  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
  • packages/agent-ops/src/AgentDeploymentsPage.tsx
  • frontend/config/webpack.dev.js
**/Dockerfile*

⚙️ CodeRabbit configuration file

**/Dockerfile*: DOCKERFILES:

  1. Multi-stage builds: separate build and runtime stages.
  2. Copy only necessary artifacts to runtime stage (no source code, node_modules, .git).
  3. Use the same base image version as the main Dockerfile where possible.
  4. No npm install in runtime stage — copy from build stage.
  5. Dockerfile.workspace files are for dev workspace images — follow the same base image
    conventions.

Files:

  • packages/agent-ops/Dockerfile.workspace
  • packages/agent-ops/Dockerfile
packages/*/bff/**/*.go

⚙️ CodeRabbit configuration file

packages/*/bff/**/*.go: GO BFF SERVICE (Backend-for-Frontend):
Packages with BFFs: automl, autorag, eval-hub, gen-ai, maas, mlflow.

  1. Validate all incoming request bodies and query parameters at handler level.
  2. No credentials in BFF code — use mounted secrets or environment variables.
  3. Use the shared K8s client config; do not create ad-hoc kubeconfig readers.
  4. HTTP clients to external services must set timeouts and use TLS verification.
  5. No panic in handlers — use explicit error returns with context.
  6. OpenAPI spec in api/ or docs/ must match actual handler signatures.
  7. Follow .golangci.yaml rules in the package root.
  8. Repository pattern: data access through repository interfaces, not direct K8s calls
    in handlers. Mock interfaces for unit testing (see mocks/ directory).

Files:

  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
**/*.go

⚙️ CodeRabbit configuration file

**/*.go: GO SECURITY (Kubernetes Controllers):

  1. Use io.LimitReader for HTTP response bodies (prevent memory exhaustion)
  2. Validate all data from json.Unmarshal before storing in ConfigMaps/Secrets
  3. No InsecureSkipVerify in TLS configs (enables MITM attacks)
  4. Validate CR spec fields before using in ConfigMaps/Secrets
  5. Set OwnerReferences on all child resources
  6. Validate inputs before exec.Command (prevent command injection)
  7. Never log sensitive fields (Password, Token, APIKey, Secret.Data)
  8. Avoid weak cryptography (MD5, SHA1) for security operations

Files:

  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go
  • packages/agent-ops/bff/internal/api/healthcheck_handler.go
  • packages/agent-ops/bff/cmd/main.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go
  • packages/agent-ops/bff/internal/config/environment.go
  • packages/agent-ops/bff/internal/models/health_check.go
  • packages/agent-ops/bff/internal/api/agent_chat_handler.go
  • packages/agent-ops/bff/internal/mapper/agent.go
  • packages/agent-ops/bff/internal/api/app.go
  • packages/agent-ops/bff/internal/integrations/agents/openshell/client.go
frontend/src/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

frontend/src/**/*.{ts,tsx}: ODH DASHBOARD FRONTEND (main app):

  1. PatternFly v6: use PF6 imports from @patternfly/react-core, not custom wrappers.
    Avoid custom CSS — if you need to "nudge" PF layout, check frontend/src/concepts/dashboard first.
  2. Functional components only (no class components). Use hooks for state management.
  3. API calls: use the shared API utilities, never raw fetch(); handle loading/error states.
  4. No hardcoded cluster URLs or API endpoints — use config from backend.
  5. Route guards: protected routes must check user permissions before rendering.
  6. Performance: avoid unnecessary useCallback/useMemo/useRef — React is performant by default.
    Only use useCallback when the function is passed as a prop, used as a useEffect dependency,
    or returned from a custom hook (see docs/best-practices.md).
  7. Custom components go in frontend/src/components. PF-first: verify with the team before
    creating new custom components.

Files:

  • frontend/src/concepts/areas/const.ts
**/webpack.{common,dev,prod}.{ts,js}

⚙️ CodeRabbit configuration file

**/webpack.{common,dev,prod}.{ts,js}: WEBPACK CONFIG:
(Suppression) Do not suggest alternative bundler configurations
or plugin replacements. Only flag security issues and broken build logic.

Files:

  • frontend/config/webpack.common.js
  • frontend/config/webpack.dev.js
packages/*/frontend/src/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

packages/*/frontend/src/**/*.{ts,tsx}: FEATURE PLUGIN FRONTEND (Module Federation):
These packages (automl, autorag, eval-hub, gen-ai, maas, mlflow) use Module Federation
to load as remotes into the host dashboard app.

  1. Plugins must use plugin-core APIs for navigation, not direct router manipulation.
  2. Shared dependencies (React, PatternFly, Redux) must come from the host app — do not
    bundle duplicates.
  3. No global CSS — use PatternFly utility classes or CSS modules only.
  4. Lazy-load heavy components; plugins load on demand via Module Federation.
  5. Follow PatternFly v6 patterns consistent with the main frontend app.

Files:

  • packages/agent-ops/frontend/src/app/api/agentRuntimes.ts
**/go.mod

⚙️ CodeRabbit configuration file

**/go.mod: GO DEPENDENCY SECURITY (CWE-829):

  1. Verify new dependencies are from trusted organizations
  2. Check for replace directives pointing to forks (supply chain risk).
    Flag replace directives that redirect well-known modules
    (golang.org/x/, k8s.io/, sigs.k8s.io/*) to personal forks
  3. Flag indirect dependency additions unrelated to the PR
  4. Verify no downgrade of security-critical dependencies
  5. retract directives that could force consumers to upgrade to
    specific versions (potential for malicious version steering)
  6. toolchain directive changes (Go 1.21+) that force specific Go
    toolchain downloads from untrusted sources

Files:

  • packages/agent-ops/bff/go.mod
🔇 Additional comments (18)
packages/agent-ops/bff/GAPS.md (3)

7-9: Previously reported: destructive Sandbox operations still lack per-request SSAR.

This remains the documented CWE-862 authorization gap for DeleteAgent, StopAgent, and StartAgent. Do not treat an unassigned story as sufficient mitigation.


22-24: Previously reported: Sandbox-created Routes still lack ownerReferences.

This remains the documented orphaned-resource risk. The controller path must establish ownership or explicitly guarantee cleanup.


49-51: 🎯 Functional Correctness

Clarify Sandbox CRD cache behavior. Add TTL/invalidation for isSandboxCRDAvailable(), or document restart as a hard requirement; otherwise the BFF can keep using the Deployment fallback after the CRD appears.

packages/agent-ops/bff/internal/api/healthcheck_handler.go (1)

17-22: Remove Gateway and Namespace from the unauthenticated healthcheck response (CWE-200). This remains the previously reported internal-information disclosure.

packages/agent-ops/Dockerfile (1)

7-7: Pin the Go builder image to an immutable digest (CWE-829). golang:1.25 remains a floating tag.

packages/agent-ops/Dockerfile.workspace (1)

12-12: Pin the Go builder image to an immutable digest (CWE-829). docker.io/library/golang:1.25 remains a floating tag.

packages/agent-ops/bff/internal/api/app.go (1)

184-201: Replace hard-coded NoAuth() and insecure TLS (CWE-295, CWE-306). This remains the previously reported OpenShell gateway transport vulnerability.

packages/agent-ops/bff/internal/api/agent_chat_handler.go (1)

54-60: Bound proxied responses and filter hop-by-hop headers (CWE-400). This remains the previously reported unbounded response-body and header-forwarding issue.

packages/agent-ops/bff/go.mod (2)

9-9: Previously flagged supply-chain risk remains (CWE-829).

github.com/rhuss/openshell-sdk-go remains a personal-account dependency rather than an upstream-maintained OpenShell SDK. The existing provenance-review comment still applies to v0.2.2.

Source: Path instructions


3-8: LGTM!

Also applies to: 10-11, 54-62

packages/agent-ops/bff/internal/integrations/agents/openshell/client.go (4)

41-45: Namespace authorization mismatch remains (CWE-863).

CanListAgentsInNamespace always allows access, reads/deletes discard the authorized namespace, while lifecycle patches accept it. The previously reported requirement to enforce namespace == c.namespace consistently remains applicable.

Also applies to: 59-60, 145-148, 159-198


280-291: Previously flagged: displayName is still discarded.

The annotation is parsed and then suppressed rather than mapped into the summary.


326-332: Previously flagged detail mapping defects remain.

operatingMode still receives readiness phase rather than the Sandbox spec value, and environment data is still read from sb.Spec.Environment instead of sb.Spec.Template.Environment.


20-39: LGTM!

Also applies to: 87-143, 220-270, 293-308, 334-372

packages/agent-ops/bff/cmd/main.go (1)

59-61: LGTM!

packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go (1)

1-47: LGTM!

packages/agent-ops/bff/internal/mapper/agent.go (1)

84-84: LGTM!

Also applies to: 212-228

frontend/src/concepts/areas/const.ts (1)

28-28: 🎯 Functional Correctness

Verify the MaaS redesign flag precedence.

frontend/src/concepts/areas/const.ts keeps maasSettingsIaRedesign enabled while backend/src/utils/constants.ts changes the default dashboard value to false. Confirm which source wins when flags are merged; otherwise the UI can expose a redesign that the backend configuration disables.

Comment on lines +243 to +245
new webpack.NormalModuleReplacementPlugin(/^node:/, (resource) => {
resource.request = resource.request.replace(/^node:/, '');
}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the file and inspect the relevant section with line numbers.
git ls-files 'frontend/config/webpack.common.js'
wc -l frontend/config/webpack.common.js
sed -n '210,280p' frontend/config/webpack.common.js

# Inspect surrounding resolver configuration and any related comments/usages.
rg -n "conditionNames|NormalModuleReplacementPlugin|node:" frontend/config/webpack.common.js frontend -S

Repository: opendatahub-io/odh-dashboard

Length of output: 6212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the webpack version and any explicit resolver fallbacks/polyfills.
sed -n '1,220p' package.json
printf '\n---\n'
sed -n '300,340p' frontend/config/webpack.common.js

# Check for any existing node: imports in the repo.
rg -n --glob '!**/node_modules/**' 'from ['\''"]node:|require\(['\''"]node:' frontend src . -S

Repository: opendatahub-io/odh-dashboard

Length of output: 6272


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find actual node:-prefixed imports in the browser-facing workspaces.
rg -n --glob 'frontend/**/*.{js,jsx,ts,tsx,mjs,cjs}' --glob 'packages/**/*.{js,jsx,ts,tsx,mjs,cjs}' 'node:' frontend packages -S

# Inspect the webpack resolver's handling of builtins/polyfills in this config.
sed -n '312,332p' frontend/config/webpack.common.js

Repository: opendatahub-io/odh-dashboard

Length of output: 14410


🌐 Web query:

webpack 5 node: prefix NormalModuleReplacementPlugin builtin module resolution browser target userland package conflict

💡 Result:

In Webpack 5, the node: prefix (introduced in Node.js v14.13.1/v16) for built-in modules is treated as a specialized URI scheme [1]. When using a target: 'web' (or browser-like) configuration, this often triggers an UnhandledSchemeError because Webpack routes node:-prefixed requests directly to a scheme handler that, until recently, had no default implementation for non-Node.js targets [2][3][4]. Key points regarding conflict and resolution: 1. Handling of 'node:' Imports: Because Webpack's NormalModuleFactory previously routed these requests through resolveForScheme, they often bypassed standard resolve.alias and resolve.fallback configuration pipelines [5][4]. Recent updates (e.g., Pull Request #20733) have improved this by allowing the resolver to check aliases and fallbacks for node:-prefixed modules before falling back to the default scheme resolution [5][4]. 2. Using NormalModuleReplacementPlugin: If you are encountering conflicts with userland packages or need to polyfill built-ins, NormalModuleReplacementPlugin can be used to rewrite the request [6]. When using this plugin, be aware that Webpack 5 requires you to modify both resource.request and resource.createData.request to ensure the replacement is applied consistently across different resolution phases [7]. Additionally, you may need to manually update resource.createData.context to ensure subsequent imports inside the replaced module are resolved correctly [8][9]. Example of polyfilling a node module via the plugin: new webpack.NormalModuleReplacementPlugin(/^node:fs$/, (resource) => { resource.request = 'fs-browserify'; if (resource.createData) { resource.createData.request = 'fs-browserify'; } }); 3. Best Practices: While NormalModuleReplacementPlugin is flexible, resolve.alias or resolve.fallback is often preferred for simple replacements or disabling modules (e.g., setting them to false) [3][4][10]. Ensure your Webpack version is up to date to take advantage of improved node: scheme support, which reduces the need for custom plugin workarounds [5][4]. If a userland package is specifically causing conflicts by providing its own node:* implementation, verify that your alias order correctly prioritizes the desired polyfill or implementation [5].

Citations:


🌐 Web query:

webpack resolve.conditionNames browser target default conditionNames web target browser export condition

💡 Result:

In Webpack, resolve.conditionNames is used to determine which conditions in a package's package.json exports field should be matched during module resolution [1][2]. Default Behavior The default value for conditionNames is not a static list; it is determined dynamically based on several factors, including the Webpack mode (development or production), the configured target (e.g., web, node, electron), and the type of dependency being resolved (e.g., import, require) [3][4]. Common Conditions While the list is dynamic, Webpack commonly supports the following conditions when resolving exports [2]: - import: Matched when the package is loaded via ESM import or import. - require: Matched when the package is loaded via CommonJS require. - node: Matched when the target is node or electron. - electron: Matched when the target is electron. - browser: Matched when the target is a web environment (e.g., target: 'web'). - worker: Matched when the target is 'webworker'. - development / production: Matched based on the Webpack mode. - webpack: Always included as a Webpack-specific condition. - default: A catch-all condition. Key Points - Priority: The order of conditions inside a package.json exports object takes precedence over the order defined in conditionNames [5]. The general practice is to order entries from most specific to least specific [5]. - Configuration: You can override the defaults by explicitly setting resolve.conditionNames in your Webpack configuration [1][6]. - Target Impact: If your target is set to browser (the default for most web projects), the browser condition is automatically included, ensuring that exports defined under "browser" are prioritized [7][2]. For authoritative details on the current implementation for your specific version, you can consult the Webpack source code [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the top-level webpack target and any built-in handling in the config.
sed -n '1,120p' frontend/config/webpack.common.js
printf '\n---\n'
rg -n "target:|fallback:|alias:|conditionNames|NormalModuleReplacementPlugin" frontend/config/webpack.common.js -n -S

Repository: opendatahub-io/odh-dashboard

Length of output: 4747


🌐 Web query:

webpack NormalModuleReplacementPlugin resource.createData.request webpack 5 official docs

💡 Result:

When using the NormalModuleReplacementPlugin in webpack 5 with a function to modify the resource, you may need to update both resource.request and resource.createData.request to ensure the replacement is applied correctly across the plugin's multiple lifecycle phases [1][2]. The NormalModuleReplacementPlugin operates during both the beforeResolve and afterResolve hooks [1][3]. While modifying resource.request is sufficient in some contexts, internal structures in webpack 5 can lead to situations where this modification is not persisted or correctly utilized if the resolution process has already progressed [1]. To ensure robust behavior that works reliably across these phases, it is a recommended best practice to update both properties when using the function callback approach [1]: new webpack.NormalModuleReplacementPlugin(/-APP_TARGET$/, (resource) => { // Update the primary request resource.request = resource.request.replace(/-APP_TARGET/, '-new-value'); // Ensure compatibility by updating createData if it exists if (resource.createData) { resource.createData.request = resource.request; } }); This pattern addresses known issues where documentation might only show updating resource.request, which may cause inconsistencies in webpack 5 depending on exactly when the plugin executes in the dependency graph resolution [1].

Citations:


Mirror the rewritten request into resource.createData.request. resource.request alone can be ignored in later webpack 5 resolution phases, so some node: imports may not be replaced consistently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/config/webpack.common.js` around lines 243 - 245, Update the
NormalModuleReplacementPlugin callback to apply the node: prefix removal to both
resource.request and resource.createData.request, preserving the existing
replacement behavior for each request value.

Source: Path instructions

Comment on lines +319 to +322
conditionNames: ['import', 'module', 'require', 'default'],
fallback: {
diagnostics_channel: false,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restore Webpack’s default export conditions.
resolve.conditionNames replaces the defaults here, so webpack/browser are no longer considered during conditional export resolution. That can select a non-browser entrypoint and break the client bundle. Keep the defaults with '...' or remove this override.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/config/webpack.common.js` around lines 319 - 322, Update the
resolve.conditionNames configuration near the fallback setting to preserve
Webpack’s default export conditions, including webpack and browser. Add the
spread defaults marker alongside the existing conditions or remove the override
entirely, while keeping the fallback diagnostics_channel configuration
unchanged.

Comment on lines +56 to +58
flag.StringVar(&cfg.OpenShellGatewayURL, "openshell-gateway-url",
os.Getenv("OPENSHELL_GATEWAY_URL"),
"gRPC address of the OpenShell Gateway (e.g. localhost:8090). When set, uses OpenShell SDK for agent operations.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target files and nearby symbols first.
ast-grep outline packages/agent-ops/bff/cmd/main.go --view expanded
printf '\n---\n'
ast-grep outline packages/agent-ops/bff/internal/api/app.go --view expanded

printf '\n--- main.go excerpt ---\n'
sed -n '1,140p' packages/agent-ops/bff/cmd/main.go

printf '\n--- app.go excerpt ---\n'
sed -n '1,220p' packages/agent-ops/bff/internal/api/app.go

Repository: opendatahub-io/odh-dashboard

Length of output: 16411


Do not activate an insecure OpenShell transport (CWE-295).
packages/agent-ops/bff/cmd/main.go:56-58 enables packages/agent-ops/bff/internal/api/app.go to build the OpenShell client with TLSConfig{Insecure: true}, which lets a network attacker MITM privileged agent deploy/stop/chat traffic. Require verified TLS and a CA bundle instead of disabling certificate checks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/cmd/main.go` around lines 56 - 58, Update the
OpenShell gateway configuration used by the openshell-gateway-url flag and the
client construction in app.go to require verified TLS with a configured CA
bundle. Remove or disable the TLSConfig{Insecure: true} behavior, and ensure
privileged agent operations cannot proceed unless certificate verification is
enabled.

Source: Path instructions

Comment on lines +15 to +18
- `POST /agents/:ns/:name/restart` is implemented as stop + start (paused -> running). A true
restart (delete pod, let controller recreate) requires looking up the Pod owned by the Sandbox
CR and deleting it. This needs a separate story once the Sandbox controller's pod ownership
model is confirmed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reconcile the documented endpoints with actual route registrations.

The supplied packages/agent-ops/bff/internal/api/app.go route table shows delete, stop, start, and chat routes, but no /restart or /card route. The supplied OpenShell client instead enriches agent details with card data during GetAgent. Verify these routes before updating OpenAPI; otherwise the spec may document nonexistent endpoints while missing the actual response-schema change.

Also applies to: 42-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/GAPS.md` around lines 15 - 18, Reconcile the endpoint
documentation in GAPS.md with the route registrations in app.go: remove or
revise the undocumented /restart and /card endpoint entries unless they are
actually registered, and document the existing GetAgent response enrichment with
card data instead. Verify the delete, stop, start, and chat routes remain
accurately represented before updating OpenAPI.

Comment on lines +28 to +31
- The code falls back to constructing the service URL from the agent name when no Service object
is found. The Sandbox CR `status.serviceFQDN` field is read but only used as a fallback in
summary listing. Once the controller reliably populates this, we should prefer it over manual
Service lookups.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== File list ==\n'
git ls-files 'packages/agent-ops/bff/GAPS.md' 'packages/agent-ops/bff/internal/integrations/agents/openshell/client.go' 'packages/agent-ops/bff/internal/integrations/agents/openshell/*' | sed 's#^`#-` #'

printf '\n== Outline: client.go ==\n'
ast-grep outline packages/agent-ops/bff/internal/integrations/agents/openshell/client.go --view expanded || true

printf '\n== serviceFQDN search ==\n'
rg -n --hidden --glob '!**/node_modules/**' 'serviceFQDN|serviceFqdn|FQDN' packages/agent-ops/bff || true

printf '\n== Relevant lines from GAPS.md ==\n'
cat -n packages/agent-ops/bff/GAPS.md | sed -n '1,120p'

printf '\n== Relevant lines from client.go ==\n'
cat -n packages/agent-ops/bff/internal/integrations/agents/openshell/client.go | sed -n '1,260p'

Repository: opendatahub-io/odh-dashboard

Length of output: 15245


🏁 Script executed:

#!/bin/bash
set -euo pipefail
git ls-files 'packages/agent-ops/bff/GAPS.md' 'packages/agent-ops/bff/internal/integrations/agents/openshell/client.go' 'packages/agent-ops/bff/internal/integrations/agents/openshell/*'
ast-grep outline packages/agent-ops/bff/internal/integrations/agents/openshell/client.go --view expanded || true
rg -n --hidden --glob '!**/node_modules/**' 'serviceFQDN|serviceFqdn|FQDN' packages/agent-ops/bff || true
cat -n packages/agent-ops/bff/GAPS.md | sed -n '1,120p'
cat -n packages/agent-ops/bff/internal/integrations/agents/openshell/client.go | sed -n '1,260p'

Repository: opendatahub-io/odh-dashboard

Length of output: 15098


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "README? no"

Repository: opendatahub-io/odh-dashboard

Length of output: 177


Use status.serviceFQDN for card probes.
GetAgent still builds <sandbox-name>.<namespace>.svc.cluster.local and probes that address, so a controller-advertised FQDN is ignored on the detail path. If the service name or cluster domain differs, the card probe will miss the agent; read status.serviceFQDN first and fall back to the constructed host only when it is empty.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/GAPS.md` around lines 28 - 31, Update the GetAgent
card-probe host selection to use the Sandbox CR status.serviceFQDN value first,
falling back to the constructed service host only when that field is empty;
preserve the existing probe behavior otherwise.

}

if cfg.AuthMethod == config.AuthMethodDisabled && !cfg.MockAgentClient {
if cfg.AuthMethod == config.AuthMethodDisabled && !cfg.MockAgentClient && cfg.OpenShellGatewayURL == "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go --items all
rg -n -C 4 '\bk8sFactory\b' packages/agent-ops/bff/internal/integrations/agents/openshell -g '*.go'

Repository: opendatahub-io/odh-dashboard

Length of output: 3710


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline packages/agent-ops/bff/internal/api/app.go --items all
sed -n '110,230p' packages/agent-ops/bff/internal/api/app.go

echo '---'

sed -n '1,120p' packages/agent-ops/bff/internal/integrations/agents/openshell/factory.go

Repository: opendatahub-io/odh-dashboard

Length of output: 8698


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline packages/agent-ops/bff/internal/integrations/agents/openshell --items all
rg -n -C 3 'k8sClient|operatingMode|stop|start|Patch|Sandbox' packages/agent-ops/bff/internal/integrations/agents/openshell -g '*.go'

Repository: opendatahub-io/odh-dashboard

Length of output: 15406


Reject real OpenShell when auth is disabled.
Require MOCK_AGENT_CLIENT=true on this branch; otherwise AUTH_METHOD=disabled still builds an OpenShell client with NoAuth() + TLS.Insecure=true and leaves k8sFactory nil, exposing agent routes without auth and breaking stop/start (CWE-306, CWE-295).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/api/app.go` at line 127, Update the
configuration branch around cfg.AuthMethod, cfg.MockAgentClient, and
cfg.OpenShellGatewayURL to reject real OpenShell when authentication is
disabled: require cfg.MockAgentClient to be true, or otherwise fail
configuration before constructing the unauthenticated client. Preserve the
existing behavior for mock-agent mode and configured gateway URLs.

Resource: "sandboxes",
}

var cardProbeClient = &http.Client{Timeout: 3 * time.Second}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Block agent-controlled redirects in the card probe (CWE-918).

A deployed agent can return 302 Location: http://169.254.169.254/...; http.Client.Get follows it with BFF network privileges. Disable redirects and validate SDK-provided sandbox and namespace values as DNS-1123 labels before constructing the target URL.

Remediation
-var cardProbeClient = &http.Client{Timeout: 3 * time.Second}
+var cardProbeClient = &http.Client{
+	Timeout: 3 * time.Second,
+	CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
+		return http.ErrUseLastResponse
+	},
+}

Also applies to: 75-77, 207-210

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/integrations/agents/openshell/client.go` at
line 26, Harden cardProbeClient against SSRF by disabling automatic redirect
following, so agent-controlled Location responses cannot reach internal
endpoints. Validate the SDK-provided sandbox and namespace values as DNS-1123
labels before constructing the card-probe target URL, rejecting invalid values.
Apply these changes to every card-probe request path, including the usages near
the noted locations.

Comment on lines +7 to +10
type OpenShellStatus struct {
Enabled bool `json:"enabled"`
Gateway string `json:"gateway,omitempty"`
Namespace string `json:"namespace,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== File list ==\n'
git ls-files 'packages/agent-ops/bff/internal/models/health_check.go' \
             'packages/agent-ops/bff' | sed -n '1,200p'

printf '\n== Outline: health_check.go ==\n'
ast-grep outline packages/agent-ops/bff/internal/models/health_check.go --view expanded || true

printf '\n== Relevant references ==\n'
rg -n --hidden --no-messages -S 'OpenShellStatus|gateway|namespace|health' packages/agent-ops/bff | sed -n '1,220p'

Repository: opendatahub-io/odh-dashboard

Length of output: 40162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== healthcheck handler ==\n'
cat -n packages/agent-ops/bff/internal/api/healthcheck_handler.go | sed -n '1,120p'

printf '\n== route wiring / middleware around healthcheck ==\n'
rg -n --hidden --no-messages -S 'healthcheck|/healthcheck|healthCheck|HealthCheck' packages/agent-ops/bff/internal/api packages/agent-ops/bff/cmd packages/agent-ops/bff/README.md | sed -n '1,220p'

printf '\n== openapi references for healthcheck/openShell ==\n'
rg -n --hidden --no-messages -S 'openshell|healthcheck|OpenShellStatus|HealthCheckModel' packages/agent-ops/bff/openapi packages/agent-ops/bff/internal | sed -n '1,220p'

Repository: opendatahub-io/odh-dashboard

Length of output: 6395


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '285,340p' packages/agent-ops/bff/openapi/src/agent-ops.yaml

Repository: opendatahub-io/odh-dashboard

Length of output: 1482


Remove OpenShell gateway/namespace from public /healthcheck (CWE-200)

/healthcheck is unauthenticated, but this response leaks OpenShellGatewayURL and OpenShellSandboxNamespace, exposing internal cluster topology to any caller. Keep only enabled here; move any diagnostic details behind an admin-only endpoint.

Remediation
 type OpenShellStatus struct {
-	Enabled   bool   `json:"enabled"`
-	Gateway   string `json:"gateway,omitempty"`
-	Namespace string `json:"namespace,omitempty"`
+	Enabled bool `json:"enabled"`
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type OpenShellStatus struct {
Enabled bool `json:"enabled"`
Gateway string `json:"gateway,omitempty"`
Namespace string `json:"namespace,omitempty"`
type OpenShellStatus struct {
Enabled bool `json:"enabled"`
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/models/health_check.go` around lines 7 - 10,
Update OpenShellStatus to expose only the enabled field in the unauthenticated
health-check response, removing Gateway and Namespace plus their JSON fields.
Keep any diagnostic gateway or namespace data available only through an existing
admin-only endpoint, without exposing it from /healthcheck.

SystemInfo SystemInfo `json:"system_info"`
Status string `json:"status"`
SystemInfo SystemInfo `json:"system_info"`
OpenShell OpenShellStatus `json:"openshell"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C3 '\bopenshell\b|\bpodName\b' packages/agent-ops/bff \
  -g '*.yaml' -g '*.yml' -g '*.json'

Repository: opendatahub-io/odh-dashboard

Length of output: 166


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== repo files mentioning openshell/podName =='
rg -n -S '\bopenshell\b|\bpodName\b' . || true

echo
echo '== likely OpenAPI/spec files in packages/agent-ops/bff =='
fd -a 'openapi*|swagger*|api.*(yaml|yml|json)|docs' packages/agent-ops/bff 2>/dev/null || true

echo
echo '== model file locations =='
git ls-files 'packages/agent-ops/bff/internal/models/*.go' | sed -n '1,200p'

Repository: opendatahub-io/odh-dashboard

Length of output: 24849


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== openapi tree =='
find packages/agent-ops/bff/openapi -maxdepth 3 -type f | sort

echo
echo '== search in openapi/docs for fields =='
rg -n -S '\bopenshell\b|\bpodName\b' packages/agent-ops/bff/openapi packages/agent-ops/bff/docs packages/agent-ops/bff/internal/api/openapi_handler.go || true

echo
echo '== openapi handler outline =='
ast-grep outline packages/agent-ops/bff/internal/api/openapi_handler.go --view expanded

Repository: opendatahub-io/odh-dashboard

Length of output: 1589


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== outline agent-ops.yaml =='
ast-grep outline packages/agent-ops/bff/openapi/src/agent-ops.yaml --view expanded || true

echo
echo '== field and schema search in agent-ops.yaml =='
rg -n -C 3 -S 'health|runtime|openshell|podName|pod_name|pod-name' packages/agent-ops/bff/openapi/src/agent-ops.yaml || true

echo
echo '== generated-type or spec consumer search =='
rg -n -S 'agent-ops\.yaml|openapi\.json|openapi\.yaml|openapi/src/agent-ops' packages/agent-ops/bff packages/agent-ops/frontend frontend packages/agent-ops || true

Repository: opendatahub-io/odh-dashboard

Length of output: 12935


Add openshell to the health response schema and optional podName to the runtime-detail schema in packages/agent-ops/api/openapi/agent-ops.yaml, then sync packages/agent-ops/bff/openapi/src/agent-ops.yaml so it matches packages/agent-ops/bff/internal/models/health_check.go and packages/agent-ops/bff/internal/models/agent_runtime_detail.go.

📍 Affects 2 files
  • packages/agent-ops/bff/internal/models/health_check.go#L16-L16 (this comment)
  • packages/agent-ops/bff/internal/models/agent_runtime_detail.go#L30-L30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/bff/internal/models/health_check.go` at line 16, Add
openshell to the health response schema and optional podName to the
runtime-detail schema in packages/agent-ops/api/openapi/agent-ops.yaml, then
synchronize packages/agent-ops/bff/openapi/src/agent-ops.yaml with the OpenAPI
definitions and the OpenShellStatus, health-check, and agent runtime-detail
models in packages/agent-ops/bff/internal/models/health_check.go and
packages/agent-ops/bff/internal/models/agent_runtime_detail.go.

Source: Path instructions

Comment on lines +60 to +67
if (!res.ok) {
const body = await res.text();
throw new Error(`${res.status}: ${body}`);
}
const json = await res.json();
setAgents(json.data?.runtimes ?? []);
} catch (e) {
setError(e instanceof Error ? e.message : String(e));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant file around the reported lines and render path
file="packages/agent-ops/src/AgentDeploymentsPage.tsx"
wc -l "$file"
sed -n '1,220p' "$file" | nl -ba | sed -n '1,220p'

# Search for setError usage and any sanitization helpers in the file
rg -n "setError|error|res\.text\(|dangerouslySetInnerHTML|sanitize|innerHTML" "$file"

Repository: opendatahub-io/odh-dashboard

Length of output: 258


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="packages/agent-ops/src/AgentDeploymentsPage.tsx"

# Show the whole file with line numbers using awk (nl unavailable)
awk '{printf("%4d  %s\n", NR, $0)}' "$file" | sed -n '1,220p'

# Focus on the error handling/render lines if present
awk '{printf("%4d  %s\n", NR, $0)}' "$file" | sed -n '50,110p'

# Search for the state and render usage in the file
rg -n "setError|error|res\.text\(|setAgents|setLoading|dangerouslySetInnerHTML|sanitize|innerHTML" "$file"

Repository: opendatahub-io/odh-dashboard

Length of output: 7179


Stop rendering upstream error bodies in the UI. res.text() is concatenated into the thrown message and shown in the <Alert>, so non-2xx responses can leak pod names, IPs, or stack traces to authenticated users (CWE-209). Replace this with a fixed generic message and keep the raw body server-side/logged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/agent-ops/src/AgentDeploymentsPage.tsx` around lines 60 - 67, Update
the fetch error handling in AgentDeploymentsPage around the !res.ok branch to
stop including res.text() in the Error message displayed through setError and
the Alert. Throw a fixed generic failure message for non-2xx responses, while
preserving server-side logging of the raw response body if an existing logging
path is available.

Source: Path instructions

@rhods-ci-bot

Copy link
Copy Markdown

/early-gate-build

@openshift-ci openshift-ci Bot added the needs-rebase PR needs to be rebased label Jul 16, 2026
@openshift-ci

openshift-ci Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

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.

2 participants