-
Notifications
You must be signed in to change notification settings - Fork 12
✨ Import the reference client stack (client core, hub-shim, UI, harnesses, demo) #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| kind: feature | ||
|
|
||
| description: > | ||
| Import the reference client stack under clients/ — isomorphic client | ||
| core, hub-shim (the proposed Hub passthrough proxy surface), PatternFly | ||
| browser UI, mock and goose agent harnesses, in-cluster deploy manifests, | ||
| and the end-to-end demo — plus ADRs 0004 (verified client contract and | ||
| transports) and 0005 (platform-resolved params). The stack covers both | ||
| run kinds (AgentRun and AgentPlaybookRun with a stage ladder), a | ||
| management console for the catalog kinds (Agents, SkillCards, | ||
| SkillCollections, AgentPlaybooks) backed by shim write routes, an image | ||
| catalog with defaults, explicit model selection validated against | ||
| declared providers, and the env/param contract of the #53 | ||
| migration-harness. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| node_modules/ | ||
| dist/ | ||
|
|
||
| .claude/settings.local.json | ||
| .DS_Store |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| # clients/ — reference client stack | ||
|
|
||
| Working client-side implementation of this repository's AgentRun/ACP | ||
| contract, developed against the live controller on minikube and verified | ||
| end-to-end with both a deterministic mock agent and a real goose+Bedrock | ||
| agent. It exists so the Hub, UI, and base-image streams can build against | ||
| running code instead of a whiteboard: | ||
|
|
||
| - the **hub-shim** HTTP surface is the proposed contract for the Hub | ||
| passthrough proxy (stream 2, issue #21) — see ADR 0004 | ||
| - the **UI** and **client core** are the reference for the tackle2-ui | ||
| client layer (stream 3, issues #22–#24) | ||
| - the **goose harness** is a working reference for the interactive | ||
| (ACP-serving) side of the base image (stream 4, issues #25/#26). The | ||
| batch-mode harness landed separately as the repo-root `harness/` Go | ||
| module + `images/agent-base-goose-java` (#33); both consume the same | ||
| `KONVEYOR_MODEL_*` env contract. | ||
|
|
||
| ## Layout | ||
|
|
||
| | Path | What | | ||
| |------|------| | ||
| | `packages/agentic-client/` | Isomorphic (browser + node) client core: CRD contract types + helpers, `AcpSession` over WebSocket (JSON-RPC 2.0), hub-shim HTTP transport. Zero runtime dependencies. | | ||
| | `packages/agentrun-client/` | Node-side client: create/watch AgentRuns against the apiserver, resolve the ACP endpoint (`status.sandboxName` → pod, `status.secretKeyRef` → key), port-forward tunnel. Shaped for konveyor/editor-extensions. | | ||
| | `packages/hub-shim/` | Localhost gateway serving the SHIM HTTP API v1 (REST + WS `/acp` proxy with server-side `X-Secret-Key` injection). Stands in for the future Hub passthrough proxy. | | ||
| | `ui/` | Browser SPA (PatternFly): run list, create form with platform-resolved params (ADR 0005), streaming chat with permission (HITL) round-trips. | | ||
| | `harness-mock/` | Deterministic ACP agent (no LLM): real protocol via the ACP SDK's server side, scripted behaviors (`TEST_PERMISSION`, `TEST_CANCEL`, `TEST_DROP`). Test fixture and demo agent. | | ||
| | `harness-goose/` | Real agent base: goose `serve` on `:4000` behind an entrypoint that adapts the controller's `KONVEYOR_*` env contract (clones the `repository` param, maps model env, writes prompt hints). | | ||
| | `deploy/` | In-cluster deployment of gateway + UI (interim, pre-Hub). | | ||
| | `manifests/` | Sample Agent/LLMProvider CRs: `samples.yaml` (mock) and `goose-bedrock.yaml` (real goose on AWS Bedrock). | | ||
| | `hack/` | `demo-up.sh` / `demo-check.sh` / `demo-down.sh` — converge the cluster, smoke the full ACP round-trip, tear down. | | ||
| | `docs/DEMO.md` | Narrated end-to-end demo runbook (browser + IDE + real agent). | | ||
|
|
||
| Architecture write-ups live with the repo's ADRs: `docs/adr/0004` | ||
| (verified client contract and layered transports) and `docs/adr/0005` | ||
| (platform-resolved params). | ||
|
|
||
| ## Quickstart | ||
|
|
||
| Prereqs: minikube running, Agent Sandbox v0.5.0 installed, the controller | ||
| deployed from the repo root (`make docker-build deploy IMG=agentic-controller:dev`), | ||
| Node ≥ 22.9. | ||
|
|
||
| ```sh | ||
| cd clients | ||
| hack/demo-up.sh # converge cluster + start shim & UI, prints URLs | ||
| hack/demo-check.sh # smoke: full ACP round-trip on a throwaway mock run | ||
| hack/demo-down.sh # stop local processes; cluster untouched | ||
| ``` | ||
|
|
||
| Then follow `docs/DEMO.md`. | ||
|
|
||
| ## Status: interim by design | ||
|
|
||
| The controller and CRDs are the real ones from this repository. The rest | ||
| is scaffolding with a named replacement: | ||
|
|
||
| - `hub-shim` → the real Hub passthrough proxy (its route table is the | ||
| handover spec) | ||
| - `ui` → absorbed into tackle2-ui | ||
| - `harness-goose` → the stream-4 base image (the batch side already exists: | ||
| repo-root `harness/` + `images/agent-base-goose-java`, #33; this one | ||
| covers the interactive `goose serve` / ACP mode until they converge) | ||
| - `harness-mock` → stays, as a deterministic test fixture | ||
|
|
||
| Every piece encodes contract facts verified against the live controller | ||
| (pod name == `status.sandboxName`, ACP Secret data key `secret-key`, | ||
| headless portless Service, whole-spec immutability) — see ADR 0004 for | ||
| the full list and rationale. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # In-cluster deployment (interim, pre-Hub) | ||
|
|
||
| Runs the browser UI + gateway **on the cluster** — no laptop processes. | ||
| Both components are interim by design: the gateway seat is replaced by the | ||
| real Konveyor Hub passthrough proxy later, and the UI page is absorbed | ||
| into tackle2-ui (see `docs/adr/0004-client-contract-and-transports.md`). | ||
|
|
||
| ``` | ||
| 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 | ||
| ``` | ||
|
|
||
| Differences from laptop mode: the gateway **direct-dials** | ||
| `<sandboxName>.<ns>.svc:4000` (no port-forwarding; auto-detected | ||
| in-cluster, `ACP_DIAL` overrides) and authenticates as a namespace-scoped | ||
| ServiceAccount instead of your kubeconfig. | ||
|
|
||
| ## Build the images (context = repo root) | ||
|
|
||
| ```sh | ||
| # local cluster (minikube): | ||
| minikube image build -t agentic-gateway:dev -f deploy/gateway/Dockerfile . | ||
| minikube image build -t agentic-ui:dev -f deploy/ui/Dockerfile . | ||
|
|
||
| # real cluster: docker build + push, then kustomize-patch the image refs. | ||
| ``` | ||
|
|
||
| ## Deploy | ||
|
|
||
| ```sh | ||
| kubectl apply -k deploy/manifests | ||
| kubectl -n konveyor-agents rollout status deploy/agentic-gateway deploy/agentic-ui | ||
| ``` | ||
|
|
||
| Prereqs already on the cluster: the agentic-controller (deployed from | ||
| the repo root: `make deploy`), Agent Sandbox, and the sample | ||
| Agents/LLMProviders (`hack/demo-up.sh` converges all of that). | ||
|
|
||
| ## Access | ||
|
|
||
| With an ingress (see `ingress.example.yaml`) — or without one: | ||
|
|
||
| ```sh | ||
| kubectl -n konveyor-agents port-forward svc/agentic-ui 8081:80 | ||
| open http://localhost:8081 | ||
| ``` | ||
|
|
||
| Everything (REST + WebSocket chat) flows through that single origin. | ||
|
|
||
| ## Verify | ||
|
|
||
| The browser-constraint smoke works through the deployed stack end to end | ||
| (nginx → gateway → controller → sandbox ACP): | ||
|
|
||
| ```sh | ||
| cd packages/hub-shim | ||
| SHIM_URL=http://localhost:8081 npx tsx dev/browser-smoke.ts | ||
| ``` | ||
|
|
||
| ## Teardown | ||
|
|
||
| ```sh | ||
| kubectl delete -k deploy/manifests | ||
| ``` | ||
|
|
||
| ## Auth (deliberate gap) | ||
|
|
||
| The gateway has no auth of its own — protect it at the ingress (oauth2-proxy, | ||
| or an OpenShift Route with an oauth-proxy sidecar). Per-user identity and | ||
| RBAC on runs is precisely the value the real Hub proxy adds; bolting a full | ||
| auth stack onto this interim component would be building Hub twice. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # agentic-gateway: the hub-shim packaged for in-cluster use. | ||
| # Build context is the REPO ROOT (the shim imports ../agentrun-client/src): | ||
| # docker build -t agentic-gateway:dev -f deploy/gateway/Dockerfile . | ||
| # minikube image build -t agentic-gateway:dev -f deploy/gateway/Dockerfile . | ||
| FROM node:22-slim | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| # Install each package's deps (tsx runs the TypeScript sources directly, | ||
| # matching the repo's dev style; dev deps are required for that). | ||
| COPY packages/agentrun-client/package*.json packages/agentrun-client/ | ||
| COPY packages/hub-shim/package*.json packages/hub-shim/ | ||
| RUN cd packages/agentrun-client && npm ci --no-audit --no-fund \ | ||
| && cd ../hub-shim && npm ci --no-audit --no-fund | ||
|
|
||
| COPY packages/agentrun-client packages/agentrun-client | ||
| COPY packages/hub-shim packages/hub-shim | ||
|
|
||
| # In-cluster defaults: bind all interfaces; ACP dial mode auto-detects | ||
| # "direct" from the serviceaccount env (no port-forwarding in-cluster). | ||
| ENV HOST=0.0.0.0 \ | ||
| PORT=7080 \ | ||
| NAMESPACE=konveyor-agents | ||
|
|
||
| USER node | ||
| EXPOSE 7080 | ||
| WORKDIR /app/packages/hub-shim | ||
| CMD ["npx", "tsx", "src/server.ts"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| # agentic-gateway: in-cluster stand-in for the future Hub passthrough proxy. | ||
| # Namespace-scoped RBAC — exactly the surface the SHIM API v1 needs. | ||
| --- | ||
| apiVersion: v1 | ||
| kind: ServiceAccount | ||
| metadata: | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| --- | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: Role | ||
| metadata: | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| rules: | ||
| # Run kinds: create/delete but never update (specs are immutable). | ||
| - apiGroups: ["konveyor.io"] | ||
| resources: ["agentruns", "agentplaybookruns"] | ||
| verbs: ["get", "list", "watch", "create", "delete"] | ||
| # Catalog kinds the management UI authors (POST/PUT/DELETE routes). | ||
| - apiGroups: ["konveyor.io"] | ||
| resources: ["agents", "skillcards", "skillcollections", "agentplaybooks"] | ||
| verbs: ["get", "list", "create", "update", "delete"] | ||
| # Providers are cluster-admin-owned — the API surface is read-only. | ||
| # "create" exists ONLY for POST /api/defaults, which seeds the default | ||
| # LLMProvider (create-only; existing providers are never touched). | ||
| - apiGroups: ["konveyor.io"] | ||
| resources: ["llmproviders"] | ||
| verbs: ["get", "list", "create"] | ||
| # get: ACP key Secrets. create/update: the hub-token Secret upsert the | ||
| # defaults seeding performs (ensureHubTokenSecret). | ||
| - apiGroups: [""] | ||
| resources: ["secrets"] | ||
| verbs: ["get", "create", "update"] | ||
| - apiGroups: [""] | ||
| resources: ["pods"] | ||
| verbs: ["get", "list"] | ||
| # Agent-image catalog ConfigMap (GET /api/images, seeded by /api/defaults). | ||
| - apiGroups: [""] | ||
| resources: ["configmaps"] | ||
| verbs: ["get", "create"] | ||
| --- | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: RoleBinding | ||
| metadata: | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| roleRef: | ||
| apiGroup: rbac.authorization.k8s.io | ||
| kind: Role | ||
| name: agentic-gateway | ||
| subjects: | ||
| - kind: ServiceAccount | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| --- | ||
| apiVersion: apps/v1 | ||
| kind: Deployment | ||
| metadata: | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| labels: | ||
| app.kubernetes.io/name: agentic-gateway | ||
| spec: | ||
| replicas: 1 | ||
| selector: | ||
| matchLabels: | ||
| app.kubernetes.io/name: agentic-gateway | ||
| template: | ||
| metadata: | ||
| labels: | ||
| app.kubernetes.io/name: agentic-gateway | ||
| 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 | ||
|
Comment on lines
+73
to
+98
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Missing
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| --- | ||
| apiVersion: v1 | ||
| kind: Service | ||
| metadata: | ||
| name: agentic-gateway | ||
| namespace: konveyor-agents | ||
| labels: | ||
| app.kubernetes.io/name: agentic-gateway | ||
| spec: | ||
| selector: | ||
| app.kubernetes.io/name: agentic-gateway | ||
| ports: | ||
| - name: http | ||
| port: 7080 | ||
| targetPort: http | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # EXAMPLE — not applied by the kustomization. Adapt host/class/TLS to your | ||
| # environment and put SSO in front (oauth2-proxy annotations, or on | ||
| # OpenShift use a Route with an oauth-proxy sidecar instead). | ||
| # | ||
| # Only the UI needs exposing: nginx inside agentic-ui proxies /api (HTTP + | ||
| # WebSocket) to the gateway Service, so one host serves everything | ||
| # same-origin. | ||
| apiVersion: networking.k8s.io/v1 | ||
| kind: Ingress | ||
| metadata: | ||
| name: agentic-ui | ||
| namespace: konveyor-agents | ||
| annotations: | ||
| # WebSocket sessions are long-lived: | ||
| nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" | ||
| nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" | ||
| spec: | ||
| ingressClassName: nginx | ||
| rules: | ||
| - host: agentic.example.com | ||
| http: | ||
| paths: | ||
| - path: / | ||
| pathType: Prefix | ||
| backend: | ||
| service: | ||
| name: agentic-ui | ||
| port: | ||
| number: 80 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| apiVersion: kustomize.config.k8s.io/v1beta1 | ||
| kind: Kustomization | ||
|
|
||
| # In-cluster deployment of the interim agentic UI + gateway. | ||
| # Prereqs: the agentic-controller and Agent Sandbox are already installed | ||
| # (see manifests/controller/install.yaml), and the agentic-gateway:dev / | ||
| # agentic-ui:dev images are loadable by the cluster (minikube image build, | ||
| # or retag + push to a registry and patch the images below). | ||
| resources: | ||
| - gateway.yaml | ||
| - ui.yaml | ||
|
|
||
| # Ingress is environment-specific — see ingress.example.yaml. Put TLS and | ||
| # SSO (oauth2-proxy / OpenShift Route auth) in front: the gateway itself | ||
| # is deliberately auth-less, exactly like the future Hub proxy seat it | ||
| # stands in for is not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚖️ Poor tradeoff
Unrestricted
secretsget/update in the namespace lets the gateway read provider credentials.The comment scopes this rule to per-run ACP key Secrets plus the hub-token upsert, but the rule grants
get/updateon every Secret inkonveyor-agents— includingaws-bedrock-credsfromclients/manifests/goose-bedrock.yaml. Since per-run ACP Secret names are dynamic,resourceNamesonly helps for the fixed hub-token Secret; consider splitting this into a name-restricted rule forupdate(and the known fixed names) and keeping credential Secrets out of this namespace, or accept and document the trust boundary explicitly.🤖 Prompt for AI Agents