feat: Add Workbench and WorkbenchTool CRDs#3217
feat: Add Workbench and WorkbenchTool CRDs#3217maciaszczykm wants to merge 40 commits intomasterfrom
Workbench and WorkbenchTool CRDs#3217Conversation
Wokbench and WorkbenchTool CRDsWorkbench and WorkbenchTool CRDs
…d tool references
8c6c6ec to
267bece
Compare
267bece to
198d0b6
Compare
This reverts commit 198d0b6.
…rkbench-operator-support
Greptile SummaryAdds two new Kubernetes CRDs —
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| go/controller/api/v1alpha1/workbench_types.go | New Workbench CRD type definitions with spec, configuration, skills, and attribute conversion methods. Follows established patterns well. |
| go/controller/api/v1alpha1/workbenchtool_types.go | New WorkbenchTool CRD type definitions. Has a nil pointer dereference risk in Attributes() when InputSchema is nil, and Required vs omitempty tag inconsistencies. |
| go/controller/internal/controller/workbench_controller.go | New Workbench reconciler following established controller patterns (Project controller). Handles CRUD, finalizers, read-only mode, and references to tools/repos/runtimes. |
| go/controller/internal/controller/workbench_tool_controller.go | New WorkbenchTool reconciler following the same patterns as the Workbench controller. Clean implementation with proper finalizer and sync logic. |
| go/controller/internal/controller/workbench_controller_test.go | Workbench controller tests with incorrect agent runtime mock setup: wrong format for agentRuntimeName, missing GetClusterByHandle mock, and wrong argument count for GetAgentRuntime. |
| go/controller/internal/client/workbench.go | Console client methods for Workbench CRUD operations. Standard implementation matching other resources. |
| go/controller/internal/client/workbenchtool.go | Console client methods for WorkbenchTool CRUD operations. Standard implementation matching other resources. |
| go/controller/internal/client/agentruntime.go | New GetAgentRuntime client method that fetches runtime by name and cluster ID with standard error handling. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Workbench CR created/updated] --> B[WorkbenchReconciler.Reconcile]
B --> C{Already exists in API?}
C -->|Yes, read-only| D[handleExistingWorkbench - sync ID]
C -->|No| E[addOrRemoveFinalizer]
E --> F{Being deleted?}
F -->|Yes| G[Delete from Console API & remove finalizer]
F -->|No| H[Compute SHA diff]
H --> I[Resolve ProjectRef]
I --> J[Resolve RepositoryRef]
J --> K[Resolve AgentRuntime - clusterHandle/runtimeName]
K --> L[Resolve WorkbenchTool refs - collect IDs]
L --> M[sync - Create or Update via Console API]
M --> N[Update status: ID, SHA, conditions]
O[WorkbenchTool CR created/updated] --> P[WorkbenchToolReconciler.Reconcile]
P --> Q{Already exists in API?}
Q -->|Yes, read-only| R[handleExistingWorkbenchTool - sync ID]
Q -->|No| S[addOrRemoveFinalizer]
S --> T{Being deleted?}
T -->|Yes| U[Delete from Console API & remove finalizer]
T -->|No| V[Compute SHA diff]
V --> W[Resolve ProjectRef]
W --> X[sync - Create or Update via Console API]
X --> Y[Update status: ID, SHA, conditions]
L -.->|owner ref| O
Last reviewed commit: 03068f8
| } | ||
| }), | ||
| Body: c.Body, | ||
| InputSchema: lo.ToPtr(string(c.InputSchema.Raw)), |
There was a problem hiding this comment.
Nil pointer dereference on InputSchema
InputSchema is a *runtime.RawExtension (pointer type). If it is nil, accessing c.InputSchema.Raw will panic at runtime. While the field is annotated +kubebuilder:validation:Required, the JSON tag uses omitempty, which creates an inconsistency — and the kubebuilder validation only applies at admission time, not when the struct is used programmatically (e.g., in tests or internal logic).
Add a nil guard before accessing .Raw:
| InputSchema: lo.ToPtr(string(c.InputSchema.Raw)), | |
| InputSchema: lo.Ternary(c.InputSchema != nil, lo.ToPtr(string(c.InputSchema.Raw)), nil), |
| workbenchName = "test" | ||
| namespace = "default" | ||
| id = "123" | ||
| agentRuntimeName = "test-agent-runtime" |
There was a problem hiding this comment.
Agent runtime test format mismatch
agentRuntimeName is set to "test-agent-runtime", but the controller's handleAgentRuntime method (workbench_controller.go:288-291) expects the format "clusterHandle/runtimeName" and splits on "/". With this value, strings.Split produces a single-element slice, causing the controller to return fmt.Errorf("invalid agent runtime reference: %s", ref).
Additionally, the controller calls GetClusterByHandle before GetAgentRuntime, but the test doesn't mock GetClusterByHandle. And the GetAgentRuntime mock on line 156 only provides 2 matcher arguments (mock.Anything, agentRuntimeName) while the actual signature requires 3 (ctx, name, clusterId).
The test likely passes only because the reconcile fails at the agent runtime step and the error is handled by common.HandleRequeue (which sets a condition and returns a requeue result without propagating the error). This means the "create" path assertion succeeds coincidentally — the workbench is created without an agent runtime, which may not be the intended behavior to test.
| // +kubebuilder:validation:Required | ||
| // +kubebuilder:validation:Enum:=GET;POST;PUT;DELETE;PATCH | ||
| Method console.WorkbenchToolHTTPMethod `json:"method,omitempty"` |
There was a problem hiding this comment.
Required field uses omitempty JSON tag
Method is annotated +kubebuilder:validation:Required but the JSON struct tag is json:"method,omitempty". For a required field, the tag should be json:"method" (without omitempty) to ensure it is always serialized. The same inconsistency applies to the InputSchema field on line 177.
| // +kubebuilder:validation:Required | |
| // +kubebuilder:validation:Enum:=GET;POST;PUT;DELETE;PATCH | |
| Method console.WorkbenchToolHTTPMethod `json:"method,omitempty"` | |
| Method console.WorkbenchToolHTTPMethod `json:"method"` |
There was a problem hiding this comment.
Pull request overview
This PR adds support for Workbench and WorkbenchTool CRDs to the Plural Console controller. These CRDs enable users to define AI workbenches with associated tools, system prompts, configuration, and skills. The implementation follows the existing controller patterns in the codebase and includes complete CRUD operations with drift detection support.
Changes:
- Added Workbench and WorkbenchTool CRD definitions with comprehensive configuration options for AI agent runs
- Implemented reconcilers for both resources following established patterns (read-only mode, finalizers, drift detection)
- Extended Console API client with workbench and workbench tool operations, plus agent runtime retrieval
Reviewed changes
Copilot reviewed 25 out of 30 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| go/controller/api/v1alpha1/workbench_types.go | Defines Workbench CRD structure with system prompt, configuration, skills, and tool references |
| go/controller/api/v1alpha1/workbenchtool_types.go | Defines WorkbenchTool CRD for HTTP tools with input schema, headers, and methods |
| go/controller/internal/controller/workbench_controller.go | Implements reconciliation logic for Workbench resources, handling project/repository/agent runtime refs |
| go/controller/internal/controller/workbench_tool_controller.go | Implements reconciliation logic for WorkbenchTool resources |
| go/controller/internal/client/workbench.go | Client methods for Workbench CRUD operations |
| go/controller/internal/client/workbenchtool.go | Client methods for WorkbenchTool CRUD operations |
| go/controller/internal/client/agentruntime.go | Adds GetAgentRuntime method to fetch agent runtime by name and cluster ID |
| go/controller/internal/test/mocks/ConsoleClient_mock.go | Auto-generated mock updates for new console client methods |
| go/controller/Makefile | Modified test command - appears to be debugging code |
| go/client/graph/*.graphql | Updated GraphQL queries to accept both ID and name parameters |
| go/client/client.go | Updated generated GraphQL client code |
| config/crd/bases/*.yaml | Generated CRD manifests for Workbench and WorkbenchTool |
| config/rbac/role.yaml | Added RBAC permissions for new resources |
| cmd/register.go | Registered both new reconcilers |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
go/controller/Makefile
Outdated
| test: TOOL = envtest controller-gen mockery | ||
| test: --tool manifests generate genmock fmt vet ## run tests | ||
| @KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(BINARIES_DIR) -p path)" go test -p 1 $$(go list ./... | grep -vE '/e2e|/benchmark') -v | ||
| KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(BINARIES_DIR) -p path)" echo ${KUBEBUILDER_ASSETS} |
There was a problem hiding this comment.
The test command has been replaced with an echo statement, which means tests are no longer being executed. This appears to be a debugging change that was accidentally committed. The original command should be restored to ensure tests run properly.
| KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(BINARIES_DIR) -p path)" echo ${KUBEBUILDER_ASSETS} | |
| KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(BINARIES_DIR) -p path)" go test ./... |
Built based on the project controller logic.
I had to make workbench tool input schema required, otherwise API was returning
input_schema can't be blank.Test Plan
Checklist
Plural Flow: console