Skip to content

✨ Import the reference client stack (client core, hub-shim, UI, harnesses, demo)#35

Open
ibolton336 wants to merge 4 commits into
konveyor:mainfrom
ibolton336:clients-reference-stack
Open

✨ Import the reference client stack (client core, hub-shim, UI, harnesses, demo)#35
ibolton336 wants to merge 4 commits into
konveyor:mainfrom
ibolton336:clients-reference-stack

Conversation

@ibolton336

@ibolton336 ibolton336 commented Jul 9, 2026

Copy link
Copy Markdown
Member

Imports the working client stack prototyped in ibolton336/agentcontroller-client (the running system behind the contract proposal on #22), cleaned of POC scaffolding, as clients/ — plus ADRs 0004/0005 continuing this repo's ADR sequence.

What this is

A verified, end-to-end client-side implementation of this repo's AgentRun/ACP contract, developed against the live controller on minikube (Agent Sandbox v0.5.0) with both a deterministic mock agent and a real goose+Bedrock agent. Each piece is the reference for a planned stream:

Piece Stream Replaced by
clients/packages/hub-shim 2 (#21) the real Hub passthrough proxy — the shim's route table (SHIM HTTP API v1) is the proposed surface
clients/packages/agentic-client + clients/ui 3 (#22#24) the tackle2-ui client layer — isomorphic core (contract types, AcpSession, HTTP transport) + PatternFly SPA with streaming chat and HITL permission round-trips
clients/packages/agentrun-client node-side client shaped for konveyor/editor-extensions (AgentRun CRUD/watch, endpoint resolution, port-forward tunnel)
clients/harness-goose 4 (#25/#26) the real base image — working reference for the KONVEYOR_* env contract (clone, model env mapping, prompt hints)
clients/harness-mock stays: deterministic ACP agent (no LLM) with scripted behaviors (TEST_PERMISSION, TEST_CANCEL, TEST_DROP) — useful as an e2e fixture
clients/deploy interim in-cluster deployment (gateway + UI) until Hub takes the seat

clients/docs/DEMO.md is the narrated end-to-end runbook (browser create → real goose+Bedrock agent → IDE attach/handoff → connection-drop resilience); clients/hack/demo-check.sh smokes the full ACP round-trip against a live cluster.

What was cleared out

Relative to the prototype repo: the controller simulator and vendored CRD copies (this repo's reconcilers are the real thing now), the rendered controller install snapshot, prepared upstream patch files (delivered separately as PRs), simulator-era docs, and posted issue-comment drafts.

Verification

  • All four packages npm install + typecheck/build clean in the new location; the client core's protocol selfcheck passes 17/17.
  • Go build/tests untouched (no Go changes in this PR).
  • Cross-package imports preserved by keeping the prototype's internal layout.

Notes for reviewers

  • ADR 0004 documents the contract facts every client depends on (pod name == status.sandboxName, ACP Secret data key secret-key, headless portless Service, whole-spec immutability) — worth a close read as the stream-2 handover spec.
  • The two controller fixes this work surfaced (sandbox pod run-labels, multi-key SigV4 provider credentials) are a separate focused PR.
  • Happy to split this into per-stream PRs if that reviews easier.

Summary by CodeRabbit

  • New Features
    • Added a reference client stack with browser UI, ACP session client, mock/Goose harnesses, and in-cluster Kubernetes gateway/UI deployment.
    • Delivered a hub-shim HTTP + WebSocket gateway with readiness-aware ACP dialing and end-to-end AgentRun session streaming (including permissions, tool details, reconnection, and cancellation).
    • Expanded the UI to support playbook runs and detailed stage progression.
  • Documentation
    • Updated the project structure overview and added client stack, in-cluster deployment, and end-to-end demo runbooks plus quickstarts and ADRs.
  • Tests
    • Added browser/WebSocket smoke checks and drop/reconnect drills, plus agentic client contract self-check coverage.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR imports a reference client stack with shared AgentRun and ACP clients, a hub-shim service, mock and Goose harnesses, a PatternFly UI, Kubernetes deployment resources, demo workflows, and ADR documentation.

Changes

Reference client contracts and transports

Layer / File(s) Summary
Shared contracts and client transports
clients/packages/agentic-client/..., clients/packages/agentrun-client/..., docs/adr/*
Adds CRD types, secret and parameter resolution, ACP session APIs, Kubernetes run operations, port forwarding, HTTP shim transport, and documented client contracts.

Hub-shim and harness runtime

Layer / File(s) Summary
Hub-shim service and ACP bridge
clients/packages/hub-shim/...
Adds HTTP APIs for inventory and AgentRuns plus a WebSocket ACP bridge with readiness retries, authentication, buffering, and liveness handling.
Mock and Goose harnesses
clients/harness-mock/..., clients/harness-goose/..., clients/manifests/*
Adds deterministic ACP mock behavior, Goose startup/configuration logic, and sample provider, agent, skill, and run manifests.

Browser UI and cluster deployment

Layer / File(s) Summary
React run-management UI
clients/ui/...
Adds run listing, creation, deletion, detail polling, ACP chat, permissions, tool diffs, session replay, and PatternFly styling.
In-cluster packaging
clients/deploy/...
Adds gateway and UI images, Kubernetes RBAC, Deployments, Services, Kustomize resources, ingress guidance, and Nginx REST/WebSocket routing.

Demo workflows and documentation

Layer / File(s) Summary
Demo automation and validation
clients/hack/*, clients/packages/hub-shim/dev/*, clients/docs/demo/*
Adds Minikube startup/shutdown scripts, readiness checks, browser smoke tests, dial/drop checks, and demo manifests.
Project documentation and release metadata
README.md, clients/README.md, clients/deploy/README.md, clients/docs/DEMO.md, changes/unreleased/*, .gitignore files
Documents the stack layout, setup paths, in-cluster operation, demo flow, and unreleased feature contents.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • #1 — The PR implements the issue’s Hub, UI, ACP proxy, and Goose harness workstreams under clients/.
  • #50 — The PR adds playbook-run contracts, hub-shim endpoints, and UI list/detail flows.

Possibly related PRs

Suggested reviewers: djzager

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the imported client stack and matches the feature-focused changeset.
Description check ✅ Passed The description covers the scope, verification, exclusions, and reviewer notes with the expected detail.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@ibolton336
ibolton336 force-pushed the clients-reference-stack branch from 9b4a171 to 310f00c Compare July 20, 2026 18:34
@ibolton336
ibolton336 requested a review from djzager July 20, 2026 18:34
@ibolton336

Copy link
Copy Markdown
Member Author

Rebased onto main (post #33/#34/#37) — no conflicts — plus a follow-up commit aligning the stack with what merged while this sat:

  • Keyless credentialRef (✨ Multi-variable LLM provider credentials + sandbox pod run labels #34): the Bedrock demo path now relies on the controller's whole-secret envFrom injection; removed the client-side envFrom workaround from real-run.yaml that ✨ Multi-variable LLM provider credentials + sandbox pod run labels #34 obsoleted, and credentialRef.key is now optional in the TS contract types to match the CRD.
  • ADR 0004 (still proposed): updated the pod-label facts — run labels are merged reality now, name-based pod resolution stays mandated (works against every controller build) — and completed the injected-env list with KONVEYOR_MODEL_<ROLE>_{PROVIDER,MODEL,ENDPOINT,API_KEY}.
  • Runbook facts refreshed: sandbox restartPolicy is OnFailure since ✨ Harness init #33; dropped the stale "proposed as a follow-up PR" talking points; log selector uses the now-working konveyor.io/agentrun label.
  • READMEs: cross-referenced the repo-root harness/ + images/agent-base-goose-java from ✨ Harness init #33clients/harness-goose stays as the interactive (goose serve/ACP) reference; both consume the same KONVEYOR_MODEL_* env contract.

All packages typecheck/build green (tsc + vite). @djzager ready for review when you get a chance.

🤖 Generated with Claude Code

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

Actionable comments posted: 4

🧹 Nitpick comments (7)
clients/hack/demo-up.sh (1)

83-84: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Use a project-local directory for state files instead of /tmp. Hardcoding predictable paths in the world-writable /tmp directory exposes the scripts to local symlink attacks (CWE-377) and pollutes global state. Consider creating a project-local directory like STATE_DIR="$ROOT/.demo" and writing PID and log files there.

  • clients/hack/demo-up.sh#L83-L84: redirect the port-forward log and pid to $STATE_DIR/demo-hub-pf....
  • clients/hack/demo-up.sh#L110-L111: redirect the hub-shim log and pid to $STATE_DIR/demo-hub-shim....
  • clients/hack/demo-up.sh#L128-L129: redirect the ui log and pid to $STATE_DIR/demo-ui....
  • clients/hack/demo-down.sh#L8-L8: read the pidfiles from $ROOT/.demo/demo-$name.pid instead of /tmp.
🤖 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 `@clients/hack/demo-up.sh` around lines 83 - 84, Replace world-writable /tmp
state paths with a project-local STATE_DIR under $ROOT/.demo, creating it before
use. In clients/hack/demo-up.sh lines 83-84, 110-111, and 128-129, write each
demo log and PID file beneath STATE_DIR; in clients/hack/demo-down.sh line 8,
read the demo-$name.pid files from $ROOT/.demo instead of /tmp.

Source: Linters/SAST tools

clients/deploy/ui/nginx.conf (1)

12-13: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Startup-time DNS resolution of the gateway upstream can crashloop the UI pod.

proxy_pass to the bare agentic-gateway hostname is resolved once at nginx startup. If the agentic-gateway Service object isn't present when this pod starts, nginx fails with "host not found in upstream" and crashloops. Applying gateway.yaml and ui.yaml together via the kustomization usually avoids this, but ordering isn't guaranteed. For resilience, resolve lazily via a resolver + variable upstream (appending $request_uri to preserve the path).

🤖 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 `@clients/deploy/ui/nginx.conf` around lines 12 - 13, Update the nginx location
/api/ configuration to resolve agentic-gateway lazily using a resolver directive
and a variable-based proxy_pass, appending $request_uri so the original request
path and query are preserved; avoid the bare static upstream form that performs
DNS resolution during nginx startup.
clients/deploy/manifests/gateway.yaml (1)

59-84: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Harden both Deployments with an explicit container securityContext. Both containers run with the default security context (root-capable, privilege escalation allowed), flagged by Trivy (KSV-0014/KSV-0118) and Checkov (CKV_K8S_20/CKV_K8S_23). The gateway holds secrets: get RBAC, so this is worth tightening even for an interim deployment. Apply the always-safe subset below; readOnlyRootFilesystem: true additionally needs writable emptyDir mounts (e.g. /tmp, /var/cache/nginx for the UI) so add it separately once volumes are wired.

  • clients/deploy/manifests/gateway.yaml#L59-L84: add a securityContext to the gateway container.
  • clients/deploy/manifests/ui.yaml#L22-L40: add the same securityContext to the ui container (the nginx-unprivileged base already runs as uid 101, so runAsNonRoot is consistent).
          securityContext:
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
            seccompProfile:
              type: RuntimeDefault
🤖 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 `@clients/deploy/manifests/gateway.yaml` around lines 59 - 84, The gateway
container in clients/deploy/manifests/gateway.yaml lines 59-84 and the UI
container in clients/deploy/manifests/ui.yaml lines 22-40 both require the same
explicit container securityContext: set runAsNonRoot, disable privilege
escalation, drop all capabilities, and use the RuntimeDefault seccomp profile.
Do not enable readOnlyRootFilesystem until the required writable emptyDir mounts
are added.

Source: Linters/SAST tools

clients/ui/src/app.css (1)

59-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace deprecated word-break: break-word.

The word-break: break-word property is deprecated in modern CSS. Use overflow-wrap: break-word instead to achieve the same result in a standard-compliant way.

♻️ Proposed refactor
   white-space: pre-wrap;
-  word-break: break-word;
+  overflow-wrap: break-word;
 }
🤖 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 `@clients/ui/src/app.css` around lines 59 - 61, In the affected CSS rule in
app.css, replace the deprecated word-break: break-word declaration with
overflow-wrap: break-word, preserving the existing white-space behavior and
other declarations.

Source: Linters/SAST tools

clients/deploy/README.md (1)

8-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a language identifier to the fenced code block.

As suggested by static analysis, fenced code blocks should have a language specified. Since this is an ASCII architecture diagram, using text is appropriate.

♻️ Proposed refactor
-```
+```text
 browser ── ingress/route (TLS + SSO) ── agentic-ui (nginx, static SPA)
                                             │  /api + WS, same-origin
                                         agentic-gateway (SA + RBAC)
                                             │  CRs via k8s API · pod :4000 via service DNS
                                         agentic-controller / Agent Sandbox / sandbox pods
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In @clients/deploy/README.md around lines 8 - 14, Update the fenced architecture
diagram code block in the README to include the text language identifier,
changing the opening fence to ```text while preserving the diagram content
unchanged.


</details>

<!-- cr-comment:v1:b79bc3a37843f16e04d4d1ac -->

_Source: Linters/SAST tools_

</blockquote></details>
<details>
<summary>clients/harness-mock/Dockerfile (1)</summary><blockquote>

`1-7`: _🔒 Security & Privacy_ | _🔵 Trivial_ | _💤 Low value_

**Both harness images run as `root` (Trivy DS-0002).** Shared root cause: no `USER` directive. Since the goose harness clones arbitrary repos and executes agent tooling, dropping root is especially worthwhile there.
- `clients/harness-mock/Dockerfile#L1-L7`: add `USER node` before `CMD` (ensure `/app` is readable by it).
- `clients/harness-goose/Dockerfile#L28-L33`: create/own a non-root user with write access to `/workspace` and switch to it before `CMD`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In `@clients/harness-mock/Dockerfile` around lines 1 - 7, Both harness Dockerfiles
currently run as root because they lack a USER directive. In
clients/harness-mock/Dockerfile, ensure /app is readable by the existing node
user and add USER node before CMD. In clients/harness-goose/Dockerfile, create
and own a non-root user with write access to /workspace, then switch to that
user before CMD.
```

</details>

<!-- cr-comment:v1:1f137d115f67f507714e07ba -->

_Source: Linters/SAST tools_

</blockquote></details>
<details>
<summary>clients/manifests/goose-bedrock.yaml (1)</summary><blockquote>

`15-17`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_

**Stale references to the removed simulator in both sample manifests.** This PR excludes the prototype simulator scaffolding, yet both files still cite it.
- `clients/manifests/goose-bedrock.yaml#L15-L17`: drop/replace the "See simulate-controller.ts" comment.
- `clients/manifests/samples.yaml#L66-L68`: reword "The controller simulator substitutes the mock ACP harness image" to describe the real-controller behavior.

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In `@clients/manifests/goose-bedrock.yaml` around lines 15 - 17, Remove or replace
the stale “See simulate-controller.ts” reference in
clients/manifests/goose-bedrock.yaml lines 15-17 while preserving the
goose-provider contract comment. In clients/manifests/samples.yaml lines 66-68,
reword the note about the controller simulator substituting the mock ACP harness
image to accurately describe real-controller behavior.
```

</details>

<!-- cr-comment:v1:581301e5b9d12d02b6377a9d -->

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

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 @clients/hack/demo-up.sh:

  • Line 104: Update both npm install commands in clients/hack/demo-up.sh at lines
    104-104 and 125-125 to handle failures explicitly: retain or replace the
    redirection with visible/logged output and append failure handling that calls
    die with a context-specific npm install error for hub-shim and the UI. Ensure
    set -e failures no longer terminate the script silently.

In @clients/harness-goose/Dockerfile:

  • Around line 6-19: Update the GOOSE_ARCH default used by the Dockerfile
    download flow to match the target platform, using Docker’s TARGETARCH mapping
    where appropriate so x86_64 builds select the goose-x86_64-unknown-linux-gnu
    archive while preserving the correct ARM mapping. Keep the existing download,
    extraction, and version-check steps unchanged.

In @clients/packages/agentic-client/src/transport-shim/index.ts:

  • Around line 98-119: Update the transport shim’s send method to pass an
    AbortSignal.timeout(30_000) signal in the fetch options, ensuring stalled
    requests abort after 30 seconds while preserving the existing error handling and
    response validation.

In @clients/packages/agentrun-client/src/kube.ts:

  • Around line 183-197: Update the sandbox pod lookup around readNamespacedPod so
    only a 404 result is treated as a missing pod and falls through to the
    label-selector fallback. Preserve the fallback for not-found responses, but
    rethrow non-404 errors such as RBAC, network, or server failures instead of
    converting them into the generic “No sandbox pod found” error; use the existing
    k8sStatusCode helper or equivalent status check.

Nitpick comments:
In @clients/deploy/manifests/gateway.yaml:

  • Around line 59-84: The gateway container in
    clients/deploy/manifests/gateway.yaml lines 59-84 and the UI container in
    clients/deploy/manifests/ui.yaml lines 22-40 both require the same explicit
    container securityContext: set runAsNonRoot, disable privilege escalation, drop
    all capabilities, and use the RuntimeDefault seccomp profile. Do not enable
    readOnlyRootFilesystem until the required writable emptyDir mounts are added.

In @clients/deploy/README.md:

  • Around line 8-14: Update the fenced architecture diagram code block in the
    README to include the text language identifier, changing the opening fence to

In `@clients/deploy/ui/nginx.conf`:
- Around line 12-13: Update the nginx location /api/ configuration to resolve
agentic-gateway lazily using a resolver directive and a variable-based
proxy_pass, appending $request_uri so the original request path and query are
preserved; avoid the bare static upstream form that performs DNS resolution
during nginx startup.

In `@clients/hack/demo-up.sh`:
- Around line 83-84: Replace world-writable /tmp state paths with a
project-local STATE_DIR under $ROOT/.demo, creating it before use. In
clients/hack/demo-up.sh lines 83-84, 110-111, and 128-129, write each demo log
and PID file beneath STATE_DIR; in clients/hack/demo-down.sh line 8, read the
demo-$name.pid files from $ROOT/.demo instead of /tmp.

In `@clients/harness-mock/Dockerfile`:
- Around line 1-7: Both harness Dockerfiles currently run as root because they
lack a USER directive. In clients/harness-mock/Dockerfile, ensure /app is
readable by the existing node user and add USER node before CMD. In
clients/harness-goose/Dockerfile, create and own a non-root user with write
access to /workspace, then switch to that user before CMD.

In `@clients/manifests/goose-bedrock.yaml`:
- Around line 15-17: Remove or replace the stale “See simulate-controller.ts”
reference in clients/manifests/goose-bedrock.yaml lines 15-17 while preserving
the goose-provider contract comment. In clients/manifests/samples.yaml lines
66-68, reword the note about the controller simulator substituting the mock ACP
harness image to accurately describe real-controller behavior.

In `@clients/ui/src/app.css`:
- Around line 59-61: In the affected CSS rule in app.css, replace the deprecated
word-break: break-word declaration with overflow-wrap: break-word, preserving
the existing white-space behavior and other declarations.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: bb2b57cb-0172-4b89-b1ca-b2de1851834d

📥 Commits

Reviewing files that changed from the base of the PR and between 0fbaaba and 310f00c.

⛔ Files ignored due to path filters (5)
  • clients/harness-mock/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/agentic-client/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/agentrun-client/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/hub-shim/package-lock.json is excluded by !**/package-lock.json
  • clients/ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (68)
  • README.md
  • changes/unreleased/clients-reference-stack.yaml
  • clients/.gitignore
  • clients/README.md
  • clients/deploy/README.md
  • clients/deploy/gateway/Dockerfile
  • clients/deploy/manifests/gateway.yaml
  • clients/deploy/manifests/ingress.example.yaml
  • clients/deploy/manifests/kustomization.yaml
  • clients/deploy/manifests/ui.yaml
  • clients/deploy/ui/Dockerfile
  • clients/deploy/ui/nginx.conf
  • clients/docs/DEMO.md
  • clients/docs/demo/real-run.yaml
  • clients/docs/demo/skill-probe.yaml
  • clients/hack/demo-check.sh
  • clients/hack/demo-down.sh
  • clients/hack/demo-up.sh
  • clients/harness-goose/Dockerfile
  • clients/harness-goose/entrypoint.sh
  • clients/harness-mock/Dockerfile
  • clients/harness-mock/package.json
  • clients/harness-mock/server.mjs
  • clients/manifests/goose-bedrock.yaml
  • clients/manifests/samples.yaml
  • clients/packages/agentic-client/dev/selfcheck.ts
  • clients/packages/agentic-client/package.json
  • clients/packages/agentic-client/src/acp/index.ts
  • clients/packages/agentic-client/src/contract/index.ts
  • clients/packages/agentic-client/src/index.ts
  • clients/packages/agentic-client/src/transport-shim/index.ts
  • clients/packages/agentic-client/tsconfig.json
  • clients/packages/agentrun-client/dev/demo.ts
  • clients/packages/agentrun-client/dev/local-smoke.ts
  • clients/packages/agentrun-client/package.json
  • clients/packages/agentrun-client/src/acp.ts
  • clients/packages/agentrun-client/src/index.ts
  • clients/packages/agentrun-client/src/kube.ts
  • clients/packages/agentrun-client/src/portforward.ts
  • clients/packages/agentrun-client/src/types.ts
  • clients/packages/agentrun-client/tsconfig.json
  • clients/packages/hub-shim/dev/browser-smoke.ts
  • clients/packages/hub-shim/dev/dial-check.ts
  • clients/packages/hub-shim/dev/drop-check.ts
  • clients/packages/hub-shim/package.json
  • clients/packages/hub-shim/src/acp-dial.ts
  • clients/packages/hub-shim/src/server.ts
  • clients/packages/hub-shim/tsconfig.json
  • clients/ui/.gitignore
  • clients/ui/README.md
  • clients/ui/index.html
  • clients/ui/package.json
  • clients/ui/src/App.tsx
  • clients/ui/src/app.css
  • clients/ui/src/components/ChatPanel.tsx
  • clients/ui/src/components/CreateRunModal.tsx
  • clients/ui/src/components/PhaseLabel.tsx
  • clients/ui/src/components/RunDetailPage.tsx
  • clients/ui/src/components/RunsPage.tsx
  • clients/ui/src/format.ts
  • clients/ui/src/main.tsx
  • clients/ui/src/vite-env.d.ts
  • clients/ui/tsconfig.app.json
  • clients/ui/tsconfig.json
  • clients/ui/tsconfig.node.json
  • clients/ui/vite.config.ts
  • docs/adr/0004-client-contract-and-transports.md
  • docs/adr/0005-platform-resolved-params.md

Comment thread clients/hack/demo-up.sh Outdated
Comment thread clients/harness-goose/Dockerfile
Comment thread clients/packages/agentic-client/src/transport-shim/index.ts
Comment thread clients/packages/agentrun-client/src/kube.ts
@ibolton336
ibolton336 force-pushed the clients-reference-stack branch from 310f00c to 7e54526 Compare July 20, 2026 19:10
djzager pushed a commit that referenced this pull request Jul 21, 2026
Fixes #48.

The `changelog` job runs under `pull_request_target` and checked out
`github.event.pull_request.head.sha`, which actions/checkout now refuses
for fork PRs ("Refusing to check out fork pull request code from a
'pull_request_target' workflow"). Every fork PR of type
feature/bugfix/breaking failed the check — e.g. [this
run](https://github.com/konveyor/agentic-controller/actions/runs/29768454525/job/88440535802)
on PR #35.

Since the job only diffs file names and never executes PR code, this
checks out the **base** repo and fetches the PR head as a plain ref
(`git fetch origin pull/<n>/head:pr-head`), then diffs
`origin/<base>...pr-head`. Fork code is never checked out into the
workspace, so no `allow-unsafe-pr-checkout: true` escape hatch is needed
and the workflow keeps its safety guarantees.

Verification: YAML validated; the diff expression is unchanged apart
from `HEAD` → `pr-head`. The fix itself can only be fully exercised by a
fork PR against a repo where this workflow already runs on main
(pull_request_target uses the base branch's workflow definition), so the
real proof will be the next fork PR after this merges.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Improved pull request checks for changelog fragments.
* Changelog verification now more reliably compares proposed changes
with the target branch.
* Updated validation behavior helps ensure checks run consistently
without affecting the application experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: ibolton336 <ibolton@redhat.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
ibolton336 and others added 3 commits July 20, 2026 21:42
Working client-side implementation of this repo's AgentRun/ACP contract,
developed and verified against the live controller on minikube (Agent
Sandbox v0.5.0) with both a deterministic mock agent and a real
goose+Bedrock agent:

- packages/agentic-client: isomorphic client core — contract types,
  AcpSession over WebSocket (JSON-RPC 2.0), shim HTTP transport
- packages/agentrun-client: node client — AgentRun CRUD/watch, ACP
  endpoint resolution, port-forward tunnel (shaped for editor-extensions)
- packages/hub-shim: localhost gateway serving the SHIM HTTP API v1
  proposed as the Hub passthrough proxy surface (stream 2, konveyor#21)
- ui: PatternFly SPA — run list, create form with platform-resolved
  params, streaming chat with permission round-trips (stream 3, konveyor#22-konveyor#24)
- harness-mock / harness-goose: deterministic ACP test agent and the
  working goose agent base (stream 4 reference, konveyor#25/konveyor#26)
- deploy/: in-cluster gateway + UI manifests (interim, pre-Hub)
- clients/hack + docs/DEMO.md: converge/smoke/teardown scripts and the
  narrated end-to-end demo runbook

ADRs 0004 (verified client contract and layered transports) and 0005
(platform-resolved params) continue the repo's ADR sequence.

Cleared out relative to the prototype repo: the controller simulator and
vendored CRD copies (the real reconcilers live here now), the rendered
controller install snapshot, upstream patch files (delivered as PRs), and
simulator-era docs. All packages npm-install/typecheck/build clean in the
new location; the client-core selfcheck passes 17/17.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: ibolton336 <ibolton@redhat.com>
- goose-bedrock.yaml: keyless credentialRef — the controller now exposes
  the whole credential Secret via envFrom (konveyor#34); drop the run-level
  envFrom workaround from real-run.yaml that konveyor#34 obsoleted
- ADR 0004 (still proposed): pod run labels are merged reality (konveyor#34),
  name-based pod resolution stays mandated; complete the injected-env
  list with KONVEYOR_MODEL_<ROLE>_{PROVIDER,MODEL,ENDPOINT,API_KEY}
- DEMO.md / demo-up.sh: sandbox restartPolicy is OnFailure since konveyor#33;
  refresh stale "proposed as a follow-up PR" talking points; use the
  now-working konveyor.io/agentrun log selector
- types.ts: credentialRef.key optional, matching the CRD post-konveyor#34
- refresh stale credential/pod-label comments in hub-shim server.ts,
  agentrun-client kube.ts, contract index.ts, harness-goose entrypoint
- READMEs: cross-reference repo-root harness/ + images/ (konveyor#33) and add
  them to the project-structure block

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: ibolton336 <ibolton@redhat.com>
- transport-shim: abort REST calls after 30s (AbortSignal.timeout) so a
  stalled shim can't hang every RunApi call forever
- agentrun-client kube.ts: only a 404 on the by-name pod lookup falls
  through to the label-selector fallback; RBAC/network/5xx rethrow
  instead of surfacing as a generic "No sandbox pod found"
- harness-goose Dockerfile: derive the goose release triple from
  TARGETARCH (or dpkg) instead of hardcoding aarch64 — x86_64 builds
  fetched a binary that couldn't execute
- demo-up.sh: npm install failures now die with a pointer to their log
  instead of silently killing the script via set -e

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: ibolton336 <ibolton@redhat.com>
@ibolton336
ibolton336 force-pushed the clients-reference-stack branch from b5215e3 to 130a052 Compare July 21, 2026 01:42

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
clients/packages/agentrun-client/dev/local-smoke.ts (1)

11-15: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider using || instead of ?? for environment variable fallbacks.

If process.env.PORT or process.env.GOOSE_SERVER__SECRET_KEY are set to empty strings, the nullish coalescing operator (??) will not trigger the fallback. For PORT, Number("") evaluates to 0, which is likely unintended. Using || ensures a proper fallback for empty strings.

💡 Proposed fix
 const target = {
   host: "127.0.0.1",
-  port: Number(process.env.PORT ?? 4100),
-  secretKey: process.env.GOOSE_SERVER__SECRET_KEY ?? "localtest",
+  port: Number(process.env.PORT || 4100),
+  secretKey: process.env.GOOSE_SERVER__SECRET_KEY || "localtest",
 };
🤖 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 `@clients/packages/agentrun-client/dev/local-smoke.ts` around lines 11 - 15,
Update the target configuration’s environment fallbacks for PORT and
GOOSE_SERVER__SECRET_KEY to use || instead of ??, so empty-string values select
the existing defaults before port conversion or secret assignment.
clients/deploy/manifests/ui.yaml (1)

21-40: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add explicit securityContext hardening to the UI container.

Lower risk than the gateway (no RBAC/secrets access), but still missing securityContext at pod/container level. Note: if you set readOnlyRootFilesystem: true, nginx will need writable emptyDir mounts for its cache/pid dirs (e.g. /var/cache/nginx, /tmp, /var/run).

🔒 Proposed fix
     spec:
+      securityContext:
+        runAsNonRoot: true
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: ui
           image: agentic-ui:dev
           imagePullPolicy: IfNotPresent
+          securityContext:
+            allowPrivilegeEscalation: false
+            capabilities:
+              drop: ["ALL"]
           ports:
             - containerPort: 8080
               name: http

As per static analysis hints (Trivy KSV-0014/KSV-0118, Checkov CKV_K8S_20/CKV_K8S_23).

🤖 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 `@clients/deploy/manifests/ui.yaml` around lines 21 - 40, Add explicit
securityContext hardening for the UI container identified by the `name: ui`
entry: run it as non-root, disallow privilege escalation, drop unnecessary Linux
capabilities, and set the root filesystem read-only. Add writable `emptyDir`
mounts for nginx runtime/cache paths such as `/var/cache/nginx`, `/tmp`, and
`/var/run` so the existing nginx process continues to function.

Source: Linters/SAST tools

clients/packages/hub-shim/src/server.ts (1)

374-387: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Application-identity envFrom isn't marked optional, unlike the model-provider path.

resolveModels() (Line 446) deliberately sets secretRef.optional: true so a missing provider Secret doesn't wedge pod creation. The identity-credential injection here (Line 381) uses a bare secretRef: { name: app.identitySecret }. If an IDENTITY_SECRET_BRIDGE entry ever points at a Secret that hasn't been created yet, the run's pod will fail with CreateContainerConfigError instead of degrading gracefully the way the model path does.

🔧 Proposed fix
     if (app.identitySecret) {
-      resolved.envFrom.push({ secretRef: { name: app.identitySecret } });
+      resolved.envFrom.push({ secretRef: { name: app.identitySecret, optional: true } });
     } else {
🤖 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 `@clients/packages/hub-shim/src/server.ts` around lines 374 - 387, Update the
application-identity credential injection in the credentialSources loop to mark
the generated secretRef as optional, matching the optional secret reference
behavior in resolveModels(). Preserve the existing identitySecret check and
skip/log behavior.
clients/harness-mock/Dockerfile (1)

3-4: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider pinning installs with a committed lockfile + npm ci.

Only package.json is copied and npm install is used, so the resolved dependency tree isn't reproducible across builds/environments. If clients/harness-mock has (or gets) a package-lock.json, copy it too and switch to npm ci --omit=dev for deterministic, cache-friendly builds.

🤖 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 `@clients/harness-mock/Dockerfile` around lines 3 - 4, Update the
clients/harness-mock Dockerfile dependency installation to copy the committed
package-lock.json alongside package.json and replace npm install with npm ci
--omit=dev, preserving the existing production-only installation behavior.
clients/harness-goose/Dockerfile (1)

1-45: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Both harness images run as root. Neither Dockerfile drops privileges before CMD; the shared fix is adding a non-root USER to each.

  • clients/harness-goose/Dockerfile#L1-L45: add a dedicated user (e.g. useradd -m agent), chown /workspace and /usr/local/bin/agent-entrypoint.sh, then USER agent before CMD.
  • clients/harness-mock/Dockerfile#L1-L8: switch to the built-in node user (node:24-alpine ships one) via USER node before CMD, after ensuring /app is writable by it.
🤖 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 `@clients/harness-goose/Dockerfile` around lines 1 - 45, Both harness images
currently run as root; update clients/harness-goose/Dockerfile lines 1-45 to
create a dedicated agent user, grant it ownership of /workspace and
/usr/local/bin/agent-entrypoint.sh, and set USER agent before CMD. Update
clients/harness-mock/Dockerfile lines 1-8 to ensure /app is writable by the
built-in node user and set USER node before CMD.

Source: Linters/SAST tools

🤖 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 `@clients/deploy/manifests/gateway.yaml`:
- Around line 59-84: Harden both Deployments: in
clients/deploy/manifests/gateway.yaml lines 59-84, add pod-level runAsNonRoot
and RuntimeDefault seccompProfile, plus container-level allowPrivilegeEscalation
false, readOnlyRootFilesystem true, and drop ALL capabilities for gateway; in
clients/deploy/manifests/ui.yaml lines 21-40, add the same pod-level settings
and container-level privilege-escalation and capability restrictions for ui,
adding emptyDir mounts for nginx writable directories if enabling
readOnlyRootFilesystem.

In `@clients/hack/demo-up.sh`:
- Around line 45-54: Update the minikube image build commands in the
acp-mock-harness and goose-harness blocks to use the same explicit failure
handling as the existing npm install commands, invoking die with a clear,
image-specific message when either build fails. Preserve the current directory
changes, build arguments, and success flow.

---

Nitpick comments:
In `@clients/deploy/manifests/ui.yaml`:
- Around line 21-40: Add explicit securityContext hardening for the UI container
identified by the `name: ui` entry: run it as non-root, disallow privilege
escalation, drop unnecessary Linux capabilities, and set the root filesystem
read-only. Add writable `emptyDir` mounts for nginx runtime/cache paths such as
`/var/cache/nginx`, `/tmp`, and `/var/run` so the existing nginx process
continues to function.

In `@clients/harness-goose/Dockerfile`:
- Around line 1-45: Both harness images currently run as root; update
clients/harness-goose/Dockerfile lines 1-45 to create a dedicated agent user,
grant it ownership of /workspace and /usr/local/bin/agent-entrypoint.sh, and set
USER agent before CMD. Update clients/harness-mock/Dockerfile lines 1-8 to
ensure /app is writable by the built-in node user and set USER node before CMD.

In `@clients/harness-mock/Dockerfile`:
- Around line 3-4: Update the clients/harness-mock Dockerfile dependency
installation to copy the committed package-lock.json alongside package.json and
replace npm install with npm ci --omit=dev, preserving the existing
production-only installation behavior.

In `@clients/packages/agentrun-client/dev/local-smoke.ts`:
- Around line 11-15: Update the target configuration’s environment fallbacks for
PORT and GOOSE_SERVER__SECRET_KEY to use || instead of ??, so empty-string
values select the existing defaults before port conversion or secret assignment.

In `@clients/packages/hub-shim/src/server.ts`:
- Around line 374-387: Update the application-identity credential injection in
the credentialSources loop to mark the generated secretRef as optional, matching
the optional secret reference behavior in resolveModels(). Preserve the existing
identitySecret check and skip/log 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12d8f2e5-617d-4e8b-a085-a0c0ad36f38d

📥 Commits

Reviewing files that changed from the base of the PR and between 310f00c and 130a052.

⛔ Files ignored due to path filters (5)
  • clients/harness-mock/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/agentic-client/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/agentrun-client/package-lock.json is excluded by !**/package-lock.json
  • clients/packages/hub-shim/package-lock.json is excluded by !**/package-lock.json
  • clients/ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (68)
  • README.md
  • changes/unreleased/clients-reference-stack.yaml
  • clients/.gitignore
  • clients/README.md
  • clients/deploy/README.md
  • clients/deploy/gateway/Dockerfile
  • clients/deploy/manifests/gateway.yaml
  • clients/deploy/manifests/ingress.example.yaml
  • clients/deploy/manifests/kustomization.yaml
  • clients/deploy/manifests/ui.yaml
  • clients/deploy/ui/Dockerfile
  • clients/deploy/ui/nginx.conf
  • clients/docs/DEMO.md
  • clients/docs/demo/real-run.yaml
  • clients/docs/demo/skill-probe.yaml
  • clients/hack/demo-check.sh
  • clients/hack/demo-down.sh
  • clients/hack/demo-up.sh
  • clients/harness-goose/Dockerfile
  • clients/harness-goose/entrypoint.sh
  • clients/harness-mock/Dockerfile
  • clients/harness-mock/package.json
  • clients/harness-mock/server.mjs
  • clients/manifests/goose-bedrock.yaml
  • clients/manifests/samples.yaml
  • clients/packages/agentic-client/dev/selfcheck.ts
  • clients/packages/agentic-client/package.json
  • clients/packages/agentic-client/src/acp/index.ts
  • clients/packages/agentic-client/src/contract/index.ts
  • clients/packages/agentic-client/src/index.ts
  • clients/packages/agentic-client/src/transport-shim/index.ts
  • clients/packages/agentic-client/tsconfig.json
  • clients/packages/agentrun-client/dev/demo.ts
  • clients/packages/agentrun-client/dev/local-smoke.ts
  • clients/packages/agentrun-client/package.json
  • clients/packages/agentrun-client/src/acp.ts
  • clients/packages/agentrun-client/src/index.ts
  • clients/packages/agentrun-client/src/kube.ts
  • clients/packages/agentrun-client/src/portforward.ts
  • clients/packages/agentrun-client/src/types.ts
  • clients/packages/agentrun-client/tsconfig.json
  • clients/packages/hub-shim/dev/browser-smoke.ts
  • clients/packages/hub-shim/dev/dial-check.ts
  • clients/packages/hub-shim/dev/drop-check.ts
  • clients/packages/hub-shim/package.json
  • clients/packages/hub-shim/src/acp-dial.ts
  • clients/packages/hub-shim/src/server.ts
  • clients/packages/hub-shim/tsconfig.json
  • clients/ui/.gitignore
  • clients/ui/README.md
  • clients/ui/index.html
  • clients/ui/package.json
  • clients/ui/src/App.tsx
  • clients/ui/src/app.css
  • clients/ui/src/components/ChatPanel.tsx
  • clients/ui/src/components/CreateRunModal.tsx
  • clients/ui/src/components/PhaseLabel.tsx
  • clients/ui/src/components/RunDetailPage.tsx
  • clients/ui/src/components/RunsPage.tsx
  • clients/ui/src/format.ts
  • clients/ui/src/main.tsx
  • clients/ui/src/vite-env.d.ts
  • clients/ui/tsconfig.app.json
  • clients/ui/tsconfig.json
  • clients/ui/tsconfig.node.json
  • clients/ui/vite.config.ts
  • docs/adr/0004-client-contract-and-transports.md
  • docs/adr/0005-platform-resolved-params.md
🚧 Files skipped from review as they are similar to previous changes (51)
  • clients/ui/vite.config.ts
  • clients/packages/agentic-client/src/index.ts
  • clients/harness-mock/package.json
  • clients/docs/demo/real-run.yaml
  • clients/ui/src/vite-env.d.ts
  • clients/deploy/ui/nginx.conf
  • clients/ui/package.json
  • clients/.gitignore
  • clients/packages/agentrun-client/package.json
  • clients/ui/index.html
  • clients/packages/agentrun-client/src/index.ts
  • clients/ui/src/components/PhaseLabel.tsx
  • clients/README.md
  • clients/ui/tsconfig.node.json
  • clients/ui/tsconfig.app.json
  • clients/ui/src/format.ts
  • clients/ui/.gitignore
  • clients/docs/demo/skill-probe.yaml
  • clients/packages/agentic-client/package.json
  • changes/unreleased/clients-reference-stack.yaml
  • README.md
  • clients/ui/src/App.tsx
  • clients/ui/src/main.tsx
  • clients/packages/agentrun-client/src/portforward.ts
  • clients/packages/hub-shim/dev/dial-check.ts
  • clients/deploy/manifests/ingress.example.yaml
  • clients/packages/agentrun-client/tsconfig.json
  • clients/hack/demo-check.sh
  • clients/packages/hub-shim/tsconfig.json
  • clients/packages/agentrun-client/src/acp.ts
  • clients/packages/agentic-client/tsconfig.json
  • clients/ui/tsconfig.json
  • clients/ui/README.md
  • clients/packages/agentic-client/src/transport-shim/index.ts
  • clients/packages/agentic-client/dev/selfcheck.ts
  • clients/packages/hub-shim/src/acp-dial.ts
  • clients/manifests/goose-bedrock.yaml
  • clients/deploy/gateway/Dockerfile
  • clients/manifests/samples.yaml
  • clients/ui/src/components/RunsPage.tsx
  • clients/hack/demo-down.sh
  • clients/ui/src/components/RunDetailPage.tsx
  • clients/packages/agentic-client/src/acp/index.ts
  • clients/packages/agentrun-client/dev/demo.ts
  • clients/ui/src/components/ChatPanel.tsx
  • clients/ui/src/components/CreateRunModal.tsx
  • clients/harness-mock/server.mjs
  • clients/packages/hub-shim/dev/drop-check.ts
  • clients/packages/agentrun-client/src/types.ts
  • clients/packages/agentrun-client/src/kube.ts
  • clients/packages/agentic-client/src/contract/index.ts

Comment on lines +59 to +84
spec:
serviceAccountName: agentic-gateway
containers:
- name: gateway
image: agentic-gateway:dev
imagePullPolicy: IfNotPresent
ports:
- containerPort: 7080
name: http
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 2
periodSeconds: 5
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 512Mi

Copy link
Copy Markdown

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

Missing securityContext hardening across both deploy Deployments. Neither agentic-gateway nor agentic-ui sets a pod/container securityContext, so both run with the default (root-capable, writable-rootfs, privilege-escalation-allowed) context. Same fix pattern applies to both; the gateway is higher priority since it also holds RBAC to read secrets and pods.

  • clients/deploy/manifests/gateway.yaml#L59-L84: add securityContext.runAsNonRoot: true + seccompProfile.type: RuntimeDefault at pod level, and allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, capabilities.drop: ["ALL"] on the gateway container.
  • clients/deploy/manifests/ui.yaml#L21-L40: add the same pod-level securityContext, and allowPrivilegeEscalation: false + capabilities.drop: ["ALL"] on the ui container (if adding readOnlyRootFilesystem: true, mount emptyDir volumes for nginx's writable dirs, e.g. /var/cache/nginx, /tmp, /var/run).
📍 Affects 2 files
  • clients/deploy/manifests/gateway.yaml#L59-L84 (this comment)
  • clients/deploy/manifests/ui.yaml#L21-L40
🤖 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 `@clients/deploy/manifests/gateway.yaml` around lines 59 - 84, Harden both
Deployments: in clients/deploy/manifests/gateway.yaml lines 59-84, add pod-level
runAsNonRoot and RuntimeDefault seccompProfile, plus container-level
allowPrivilegeEscalation false, readOnlyRootFilesystem true, and drop ALL
capabilities for gateway; in clients/deploy/manifests/ui.yaml lines 21-40, add
the same pod-level settings and container-level privilege-escalation and
capability restrictions for ui, adding emptyDir mounts for nginx writable
directories if enabling readOnlyRootFilesystem.

Source: Linters/SAST tools

Comment thread clients/hack/demo-up.sh
Comment on lines +45 to +54
if ! minikube image ls 2>/dev/null | grep -q 'acp-mock-harness:dev'; then
warn "building acp-mock-harness:dev"
(cd "$ROOT/harness-mock" && minikube image build -t acp-mock-harness:dev -f Dockerfile . >/dev/null)
fi
ok "acp-mock-harness:dev"
if ! minikube image ls 2>/dev/null | grep -q 'goose-harness:dev'; then
warn "building goose-harness:dev"
(cd "$ROOT/harness-goose" && minikube image build -t goose-harness:dev -f Dockerfile . >/dev/null)
fi
ok "goose-harness:dev"

Copy link
Copy Markdown

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

Make minikube image build failures explicit, consistent with the npm install fix.

If either build fails, set -e will still abort the script, but with minikube's raw output instead of a clear die message — inconsistent with the || die pattern now used for npm install (lines 105-106, 128-129).

🩹 Proposed fix
 if ! minikube image ls 2>/dev/null | grep -q 'acp-mock-harness:dev'; then
   warn "building acp-mock-harness:dev"
-  (cd "$ROOT/harness-mock" && minikube image build -t acp-mock-harness:dev -f Dockerfile . >/dev/null)
+  (cd "$ROOT/harness-mock" && minikube image build -t acp-mock-harness:dev -f Dockerfile . >/dev/null) \
+    || die "minikube image build failed for acp-mock-harness:dev"
 fi
 ok "acp-mock-harness:dev"
 if ! minikube image ls 2>/dev/null | grep -q 'goose-harness:dev'; then
   warn "building goose-harness:dev"
-  (cd "$ROOT/harness-goose" && minikube image build -t goose-harness:dev -f Dockerfile . >/dev/null)
+  (cd "$ROOT/harness-goose" && minikube image build -t goose-harness:dev -f Dockerfile . >/dev/null) \
+    || die "minikube image build failed for goose-harness:dev"
 fi
 ok "goose-harness:dev"
📝 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
if ! minikube image ls 2>/dev/null | grep -q 'acp-mock-harness:dev'; then
warn "building acp-mock-harness:dev"
(cd "$ROOT/harness-mock" && minikube image build -t acp-mock-harness:dev -f Dockerfile . >/dev/null)
fi
ok "acp-mock-harness:dev"
if ! minikube image ls 2>/dev/null | grep -q 'goose-harness:dev'; then
warn "building goose-harness:dev"
(cd "$ROOT/harness-goose" && minikube image build -t goose-harness:dev -f Dockerfile . >/dev/null)
fi
ok "goose-harness:dev"
if ! minikube image ls 2>/dev/null | grep -q 'acp-mock-harness:dev'; then
warn "building acp-mock-harness:dev"
(cd "$ROOT/harness-mock" && minikube image build -t acp-mock-harness:dev -f Dockerfile . >/dev/null) \
|| die "minikube image build failed for acp-mock-harness:dev"
fi
ok "acp-mock-harness:dev"
if ! minikube image ls 2>/dev/null | grep -q 'goose-harness:dev'; then
warn "building goose-harness:dev"
(cd "$ROOT/harness-goose" && minikube image build -t goose-harness:dev -f Dockerfile . >/dev/null) \
|| die "minikube image build failed for goose-harness:dev"
fi
ok "goose-harness:dev"
🤖 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 `@clients/hack/demo-up.sh` around lines 45 - 54, Update the minikube image
build commands in the acp-mock-harness and goose-harness blocks to use the same
explicit failure handling as the existing npm install commands, invoking die
with a clear, image-specific message when either build fails. Preserve the
current directory changes, build arguments, and success flow.

Read-only slice of konveyor#50. Shim serves agentplaybooks/agentplaybookruns
through the generic READ_ONLY dispatch; agentic-client gains the
AgentPlaybookRun contract types (no duration field — computed from
timestamps; Ready=False/StageRunning documented as the healthy running
state) and list/get methods. UI adds an Agent runs / Playbook runs
toggle, a playbook-runs list (phase, x/y stages, computed duration),
and a detail page with a ProgressStepper stage ladder where each stage
links into the existing RunDetailPage via status.stages[].agentRunName
(never recomputed — names hash-truncate past 63 chars). Stage-owned
AgentRuns in the flat runs list get a parent-playbook badge and a
disabled Delete (deleting one terminally fails the parent, konveyor#36).

Verified against a live 3-stage playbook run (upgrade-run-1) on
minikube with the merged konveyor#36 controllers.

Refs konveyor#50.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
clients/ui/src/components/PlaybookRunDetailPage.tsx (2)

1-1: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Duplicate, inconsistent duration formatting between the playbook list and detail pages. Both render the same playbookDuration() seconds value, but with different output for sub-minute durations (45s vs 0m45s), because the detail page reimplements the formatting inline instead of reusing the list page's formatSeconds.

  • clients/ui/src/components/PlaybookRunDetailPage.tsx#L131-136: replace the inline ${Math.floor(duration / 60)}m${...} expression with a call to the shared formatSeconds(duration).
  • clients/ui/src/components/PlaybookRunsPage.tsx#L30-35: export formatSeconds (it currently isn't exported) so PlaybookRunDetailPage.tsx can import it alongside the already-imported playbookDuration.
Proposed fix
--- a/clients/ui/src/components/PlaybookRunsPage.tsx
+++ b/clients/ui/src/components/PlaybookRunsPage.tsx
@@
-function formatSeconds(seconds?: number): string {
+export function formatSeconds(seconds?: number): string {
--- a/clients/ui/src/components/PlaybookRunDetailPage.tsx
+++ b/clients/ui/src/components/PlaybookRunDetailPage.tsx
@@
-import { playbookDuration } from "./PlaybookRunsPage";
+import { formatSeconds, playbookDuration } from "./PlaybookRunsPage";
@@
-              <DescriptionListDescription>
-                {duration !== undefined ? `${Math.floor(duration / 60)}m${String(duration % 60).padStart(2, "0")}s` : "—"}
-              </DescriptionListDescription>
+              <DescriptionListDescription>{formatSeconds(duration)}</DescriptionListDescription>
🤖 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 `@clients/ui/src/components/PlaybookRunDetailPage.tsx` at line 1, Export the
existing formatSeconds helper from PlaybookRunsPage, then import and reuse it in
PlaybookRunDetailPage wherever playbookDuration is displayed. Replace the detail
page’s inline minute/second formatting with formatSeconds(duration) so
sub-minute durations match the list page.

60-75: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Polling continues (as a no-op) indefinitely after gone is set.

Once gone becomes true, refresh is recreated (dependency change) and the effect restarts setInterval, which now just no-ops every 2s forever instead of being torn down. Harmless given the guard, but the interval could simply not be (re)started once gone.

🤖 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 `@clients/ui/src/components/PlaybookRunDetailPage.tsx` around lines 60 - 75,
Update the polling effect that invokes refresh so it does not create or restart
its interval when gone is true. Ensure the effect depends on gone and cleans up
any existing interval when the run becomes gone, while preserving normal polling
behavior before that state.
clients/ui/src/components/PlaybookRunsPage.tsx (1)

22-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

playbookDuration/formatSeconds look correct; formatSeconds should be exported for reuse.

See consolidated comment — PlaybookRunDetailPage.tsx reimplements the same seconds-to-Xm YYs formatting inline with slightly different (inconsistent) behavior for sub-minute durations, instead of importing this function the way it already imports playbookDuration.

🤖 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 `@clients/ui/src/components/PlaybookRunsPage.tsx` around lines 22 - 35, Export
the existing formatSeconds function alongside playbookDuration, then update
PlaybookRunDetailPage to import and reuse it instead of maintaining its inline
seconds formatting. Preserve the current formatSeconds behavior for undefined,
sub-minute, and minute-plus durations.
clients/ui/src/App.tsx (1)

73-125: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a switch/lookup instead of the 4-way nested ternary for readability.

The view.kind === "list" ? ... : view.kind === "playbooks" ? ... : view.kind === "playbookDetail" ? ... : (...) chain is functionally correct but getting hard to scan. A switch (view.kind) (or a small per-kind render map) would read more clearly as more view kinds are added.

🤖 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 `@clients/ui/src/App.tsx` around lines 73 - 125, Refactor the nested view-kind
ternary in the App component into a clearer switch or per-kind render lookup
keyed by view.kind. Preserve the existing RunsPage, PlaybookRunsPage,
PlaybookRunDetailPage, and RunDetailPage props and navigation callbacks,
including the detail back-navigation 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 `@clients/ui/src/components/PlaybookRunDetailPage.tsx`:
- Around line 131-136: Update the Duration rendering in PlaybookRunDetailPage to
reuse the existing formatSeconds helper used by PlaybookRunsPage instead of
constructing an inline minutes-and-seconds string. Preserve the undefined
fallback of "—" while ensuring identical playbookDuration() values use the same
formatting in list and detail views.
- Around line 66-71: Update the 404 detection in the getPlaybookRun error
handling catch block to match the specific HTTP 404 status, using the same
stricter “HTTP 404” check as RunDetailPage; retain the existing not-found
message check and setFetchError behavior.

---

Nitpick comments:
In `@clients/ui/src/App.tsx`:
- Around line 73-125: Refactor the nested view-kind ternary in the App component
into a clearer switch or per-kind render lookup keyed by view.kind. Preserve the
existing RunsPage, PlaybookRunsPage, PlaybookRunDetailPage, and RunDetailPage
props and navigation callbacks, including the detail back-navigation behavior.

In `@clients/ui/src/components/PlaybookRunDetailPage.tsx`:
- Line 1: Export the existing formatSeconds helper from PlaybookRunsPage, then
import and reuse it in PlaybookRunDetailPage wherever playbookDuration is
displayed. Replace the detail page’s inline minute/second formatting with
formatSeconds(duration) so sub-minute durations match the list page.
- Around line 60-75: Update the polling effect that invokes refresh so it does
not create or restart its interval when gone is true. Ensure the effect depends
on gone and cleans up any existing interval when the run becomes gone, while
preserving normal polling behavior before that state.

In `@clients/ui/src/components/PlaybookRunsPage.tsx`:
- Around line 22-35: Export the existing formatSeconds function alongside
playbookDuration, then update PlaybookRunDetailPage to import and reuse it
instead of maintaining its inline seconds formatting. Preserve the current
formatSeconds behavior for undefined, sub-minute, and minute-plus durations.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6f589f55-ec30-4b39-b310-4980030df577

📥 Commits

Reviewing files that changed from the base of the PR and between 130a052 and e05dd42.

📒 Files selected for processing (8)
  • clients/packages/agentic-client/src/contract/index.ts
  • clients/packages/agentic-client/src/transport-shim/index.ts
  • clients/packages/agentrun-client/src/types.ts
  • clients/packages/hub-shim/src/server.ts
  • clients/ui/src/App.tsx
  • clients/ui/src/components/PlaybookRunDetailPage.tsx
  • clients/ui/src/components/PlaybookRunsPage.tsx
  • clients/ui/src/components/RunsPage.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • clients/packages/agentic-client/src/transport-shim/index.ts
  • clients/packages/agentrun-client/src/types.ts
  • clients/ui/src/components/RunsPage.tsx
  • clients/packages/hub-shim/src/server.ts

Comment on lines +66 to +71
} catch (err) {
const msg = errorMessage(err);
if (msg.includes("404") || msg.toLowerCase().includes("not found")) {
setGone(true);
}
setFetchError(msg);

Copy link
Copy Markdown

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

Loose "404" substring match can misclassify unrelated errors as "run deleted".

errorMessage(err) for a failed getPlaybookRun call includes the full request URL (which embeds name) followed by HTTP ${status} (per ShimClient.send()). If a playbook run's name happens to contain the digits 404 (e.g. a generated suffix), any unrelated failure — a 500, a network blip — will match this check and permanently set gone, which short-circuits refresh() on every future poll (if (inFlight.current || gone) return;), leaving the user stuck on a false "no longer exists" screen with no way to recover short of a page reload. RunDetailPage's equivalent check uses the stricter msg.includes("HTTP 404"), which doesn't have this collision risk.

Proposed fix
     } catch (err) {
       const msg = errorMessage(err);
-      if (msg.includes("404") || msg.toLowerCase().includes("not found")) {
+      if (msg.includes("HTTP 404")) {
         setGone(true);
       }
       setFetchError(msg);
📝 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
} catch (err) {
const msg = errorMessage(err);
if (msg.includes("404") || msg.toLowerCase().includes("not found")) {
setGone(true);
}
setFetchError(msg);
} catch (err) {
const msg = errorMessage(err);
if (msg.includes("HTTP 404")) {
setGone(true);
}
setFetchError(msg);
🤖 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 `@clients/ui/src/components/PlaybookRunDetailPage.tsx` around lines 66 - 71,
Update the 404 detection in the getPlaybookRun error handling catch block to
match the specific HTTP 404 status, using the same stricter “HTTP 404” check as
RunDetailPage; retain the existing not-found message check and setFetchError
behavior.

Comment on lines +131 to +136
<DescriptionListGroup>
<DescriptionListTerm>Duration</DescriptionListTerm>
<DescriptionListDescription>
{duration !== undefined ? `${Math.floor(duration / 60)}m${String(duration % 60).padStart(2, "0")}s` : "—"}
</DescriptionListDescription>
</DescriptionListGroup>

Copy link
Copy Markdown

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

Duration formatting diverges from PlaybookRunsPage's formatSeconds for the same data.

For durations under 60s, this inlines 0m45s while formatSeconds (used on the playbook list page for the identical playbookDuration() value) renders 45s. Same underlying data, inconsistent presentation between the list and detail views. 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 `@clients/ui/src/components/PlaybookRunDetailPage.tsx` around lines 131 - 136,
Update the Duration rendering in PlaybookRunDetailPage to reuse the existing
formatSeconds helper used by PlaybookRunsPage instead of constructing an inline
minutes-and-seconds string. Preserve the undefined fallback of "—" while
ensuring identical playbookDuration() values use the same formatting in list and
detail views.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant