feat: full kubeclaw operator — CRDs, controllers, deploy manifests, Helm chart
- 7 CRDs (Agent, AgentConfig, AgentGroup, Channel, Provider, WorkflowTemplate, CompliancePolicy) - 3 controllers (Agent, WorkflowTemplate, CompliancePolicy) - Generated deepcopy methods (controller-gen v0.16.5) - Dockerfile (multi-stage Go build) - Nix build-image.nix (dockerTools.streamLayeredImage) - Helm chart with RBAC, deployment, service account - Deploy manifests (RBAC + controller deployment) - Sample manifests for all 7 CRDs - Quickstart script - Successfully deployed to k3s on n97-mini: - Controller running and reconciling - All 7 CRDs registered - Agent CR creates Pod (ErrImagePull expected — no agent image yet) - Controller logs show reconciliation working
This commit is contained in:
parent
7607086664
commit
ece81f651c
47 changed files with 4038 additions and 13 deletions
13
Dockerfile
Normal file
13
Dockerfile
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM golang:1.24-alpine AS builder
|
||||||
|
WORKDIR /workspace
|
||||||
|
COPY go.mod go.sum* ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o manager ./cmd/manager
|
||||||
|
|
||||||
|
FROM alpine:3.21
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata
|
||||||
|
WORKDIR /
|
||||||
|
COPY --from=builder /workspace/manager .
|
||||||
|
USER 65532:65532
|
||||||
|
ENTRYPOINT ["/manager"]
|
||||||
|
|
@ -4,8 +4,9 @@ Copyright 2025 Scott Scoble.
|
||||||
Licensed under the MIT License.
|
Licensed under the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package v1alpha1 contains API Schema definitions for the scobleclaw v1alpha1 API group.
|
// Package v1alpha1 contains API Schema definitions for the kubeclaw v1alpha1 API group.
|
||||||
// +groupName=scobleclaw.ai
|
// +groupName=kubeclaw.scoble.me
|
||||||
|
// +kubebuilder:object:generate=true
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -15,7 +16,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GroupVersion = schema.GroupVersion{
|
GroupVersion = schema.GroupVersion{
|
||||||
Group: "scobleclaw.ai",
|
Group: "kubeclaw.scoble.me",
|
||||||
Version: "v1alpha1",
|
Version: "v1alpha1",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WorkflowTemplateSpec defines a workflow template that agents can instantiate.
|
// WorkflowTemplateSpec defines a workflow template that agents can instantiate.
|
||||||
|
|
@ -22,14 +23,14 @@ type WorkflowTemplateSpec struct {
|
||||||
Steps []WorkflowStep `json:"steps"`
|
Steps []WorkflowStep `json:"steps"`
|
||||||
|
|
||||||
// ParametersSchema defines the JSON Schema for allowed parameters.
|
// ParametersSchema defines the JSON Schema for allowed parameters.
|
||||||
// +kubebuilder:validation:Schemaless
|
// +optional
|
||||||
// +kubebuilder:pruning:PreserveUnknownFields
|
// +kubebuilder:pruning:PreserveUnknownFields
|
||||||
ParametersSchema map[string]interface{} `json:"parametersSchema"`
|
ParametersSchema runtime.RawExtension `json:"parametersSchema,omitempty"`
|
||||||
|
|
||||||
// OutputSchema defines the expected output shape (JSON Schema).
|
// OutputSchema defines the expected output shape (JSON Schema).
|
||||||
// +kubebuilder:validation:Schemaless
|
// +optional
|
||||||
// +kubebuilder:pruning:PreserveUnknownFields
|
// +kubebuilder:pruning:PreserveUnknownFields
|
||||||
OutputSchema map[string]interface{} `json:"outputSchema"`
|
OutputSchema runtime.RawExtension `json:"outputSchema,omitempty"`
|
||||||
|
|
||||||
// ComplianceRequirements lists compliance frameworks this template satisfies.
|
// ComplianceRequirements lists compliance frameworks this template satisfies.
|
||||||
// +optional
|
// +optional
|
||||||
|
|
|
||||||
1230
api/v1alpha1/zz_generated.deepcopy.go
Normal file
1230
api/v1alpha1/zz_generated.deepcopy.go
Normal file
File diff suppressed because it is too large
Load diff
BIN
bin/manager
Executable file
BIN
bin/manager
Executable file
Binary file not shown.
18
charts/kubeclaw/Chart.yaml
Normal file
18
charts/kubeclaw/Chart.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
apiVersion: v2
|
||||||
|
name: kubeclaw
|
||||||
|
description: OpenClaw operator for Kubernetes — run Scobleclaw agents as K8s workloads
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "0.1.0"
|
||||||
|
keywords:
|
||||||
|
- openclaw
|
||||||
|
- agent
|
||||||
|
- llm
|
||||||
|
- ai
|
||||||
|
- operator
|
||||||
|
home: https://github.com/sscoble/kubeclaw
|
||||||
|
sources:
|
||||||
|
- https://github.com/sscoble/kubeclaw
|
||||||
|
maintainers:
|
||||||
|
- name: Scott Scoble
|
||||||
|
email: scott@scoble.me
|
||||||
104
charts/kubeclaw/crds/kubeclaw.scoble.me_agentconfigs.yaml
Normal file
104
charts/kubeclaw/crds/kubeclaw.scoble.me_agentconfigs.yaml
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agentconfigs.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: AgentConfig
|
||||||
|
listKind: AgentConfigList
|
||||||
|
plural: agentconfigs
|
||||||
|
singular: agentconfig
|
||||||
|
shortNames:
|
||||||
|
- acfg
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
workspace:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
repo:
|
||||||
|
type: string
|
||||||
|
branch:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
autoCommit:
|
||||||
|
type: boolean
|
||||||
|
heartbeat:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
intervalSeconds:
|
||||||
|
type: integer
|
||||||
|
prompt:
|
||||||
|
type: string
|
||||||
|
sandbox:
|
||||||
|
type: string
|
||||||
|
enum: [inherit, require, none]
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
enum: ["off", "low", "medium", "high"]
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
fallbacks:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
toolsAllow:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
toolsDeny:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
env:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
valueFrom:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
secretKeyRef:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
usedByAgents:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
107
charts/kubeclaw/crds/kubeclaw.scoble.me_agentgroups.yaml
Normal file
107
charts/kubeclaw/crds/kubeclaw.scoble.me_agentgroups.yaml
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agentgroups.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: AgentGroup
|
||||||
|
listKind: AgentGroupList
|
||||||
|
plural: agentgroups
|
||||||
|
singular: agentgroup
|
||||||
|
shortNames:
|
||||||
|
- agg
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Members
|
||||||
|
type: integer
|
||||||
|
jsonPath: .status.memberCount
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [members]
|
||||||
|
properties:
|
||||||
|
sharedConfigRef:
|
||||||
|
type: string
|
||||||
|
sharedProviders:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
sharedChannels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
members:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, agentId]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
agentId:
|
||||||
|
type: string
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
configOverrides:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
allowedTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
requests:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
limits:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
memberCount:
|
||||||
|
type: integer
|
||||||
|
memberReady:
|
||||||
|
type: integer
|
||||||
|
agentRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
147
charts/kubeclaw/crds/kubeclaw.scoble.me_agents.yaml
Normal file
147
charts/kubeclaw/crds/kubeclaw.scoble.me_agents.yaml
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agents.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Agent
|
||||||
|
listKind: AgentList
|
||||||
|
plural: agents
|
||||||
|
singular: agent
|
||||||
|
shortNames:
|
||||||
|
- ag
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: AgentID
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.agentId
|
||||||
|
- name: Model
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.model
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [agentId]
|
||||||
|
properties:
|
||||||
|
agentId:
|
||||||
|
type: string
|
||||||
|
description: OpenClaw agent identifier (main, engineering, etc.)
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
agentConfigRef:
|
||||||
|
type: string
|
||||||
|
description: Reference to an AgentConfig resource
|
||||||
|
workspace:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
configMapRef:
|
||||||
|
type: string
|
||||||
|
secretRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
pvcName:
|
||||||
|
type: string
|
||||||
|
providers:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
channelRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
channels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [type, botTokenSecretRef]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
botTokenSecretRef:
|
||||||
|
type: object
|
||||||
|
required: [name, key]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
guildID:
|
||||||
|
type: string
|
||||||
|
defaultChannel:
|
||||||
|
type: string
|
||||||
|
defaultTemplate:
|
||||||
|
type: string
|
||||||
|
allowedTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDataSources:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDestinations:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
compliancePolicyRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
requests:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
limits:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
image:
|
||||||
|
type: string
|
||||||
|
replicas:
|
||||||
|
type: integer
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
phase:
|
||||||
|
type: string
|
||||||
|
deployments:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
lastTransition:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
75
charts/kubeclaw/crds/kubeclaw.scoble.me_channels.yaml
Normal file
75
charts/kubeclaw/crds/kubeclaw.scoble.me_channels.yaml
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: channels.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Channel
|
||||||
|
listKind: ChannelList
|
||||||
|
plural: channels
|
||||||
|
singular: channel
|
||||||
|
shortNames:
|
||||||
|
- ch
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Type
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.type
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [type, botTokenSecretRef]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: Channel type (discord, slack, telegram)
|
||||||
|
botTokenSecretRef:
|
||||||
|
type: object
|
||||||
|
required: [name, key]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
webhookURL:
|
||||||
|
type: string
|
||||||
|
guildID:
|
||||||
|
type: string
|
||||||
|
defaultChannel:
|
||||||
|
type: string
|
||||||
|
allowedChannels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
connected:
|
||||||
|
type: boolean
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
lastConnected:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
106
charts/kubeclaw/crds/kubeclaw.scoble.me_compliancepolicies.yaml
Normal file
106
charts/kubeclaw/crds/kubeclaw.scoble.me_compliancepolicies.yaml
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: compliancepolicies.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: CompliancePolicy
|
||||||
|
listKind: CompliancePolicyList
|
||||||
|
plural: compliancepolicies
|
||||||
|
singular: compliancepolicy
|
||||||
|
shortNames:
|
||||||
|
- cp
|
||||||
|
- compol
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Framework
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.framework
|
||||||
|
- name: Escalation
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.escalation.mode
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [displayName, framework, rules, escalation]
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
framework:
|
||||||
|
type: string
|
||||||
|
rules:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, description, severity, constraint]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
severity:
|
||||||
|
type: string
|
||||||
|
enum: [block, warn, log]
|
||||||
|
constraint:
|
||||||
|
type: string
|
||||||
|
escalation:
|
||||||
|
type: object
|
||||||
|
required: [mode]
|
||||||
|
properties:
|
||||||
|
mode:
|
||||||
|
type: string
|
||||||
|
enum: [auto_deny, human_review, warn_only]
|
||||||
|
humanChannelRef:
|
||||||
|
type: string
|
||||||
|
timeoutSeconds:
|
||||||
|
type: integer
|
||||||
|
targetSelector:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
matchTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchNamespaces:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchLabels:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
prompt:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
activeTemplates:
|
||||||
|
type: integer
|
||||||
|
totalJudgments:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
lastJudgment:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
86
charts/kubeclaw/crds/kubeclaw.scoble.me_providers.yaml
Normal file
86
charts/kubeclaw/crds/kubeclaw.scoble.me_providers.yaml
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: providers.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Provider
|
||||||
|
listKind: ProviderList
|
||||||
|
plural: providers
|
||||||
|
singular: provider
|
||||||
|
shortNames:
|
||||||
|
- prov
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Type
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.type
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [type]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: Provider type (ollama, openai, anthropic, deepseek)
|
||||||
|
baseUrl:
|
||||||
|
type: string
|
||||||
|
description: Provider API endpoint URL
|
||||||
|
apiKeySecretRef:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
models:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
type: boolean
|
||||||
|
cost:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
input:
|
||||||
|
type: number
|
||||||
|
output:
|
||||||
|
type: number
|
||||||
|
extraHeaders:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
lastChecked:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
106
charts/kubeclaw/crds/kubeclaw.scoble.me_workflowtemplates.yaml
Normal file
106
charts/kubeclaw/crds/kubeclaw.scoble.me_workflowtemplates.yaml
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: workflowtemplates.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: WorkflowTemplate
|
||||||
|
listKind: WorkflowTemplateList
|
||||||
|
plural: workflowtemplates
|
||||||
|
singular: workflowtemplate
|
||||||
|
shortNames:
|
||||||
|
- wt
|
||||||
|
- wft
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Audit
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.auditLevel
|
||||||
|
- name: Steps
|
||||||
|
type: integer
|
||||||
|
jsonPath: .spec.steps
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [displayName, description, steps, parametersSchema, outputSchema, auditLevel]
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
steps:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, action, target]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
action:
|
||||||
|
type: string
|
||||||
|
target:
|
||||||
|
type: string
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
onFailure:
|
||||||
|
type: string
|
||||||
|
enum: [stop, skip, continue]
|
||||||
|
parametersSchema:
|
||||||
|
type: object
|
||||||
|
x-kubernetes-preserve-unknown-fields: true
|
||||||
|
outputSchema:
|
||||||
|
type: object
|
||||||
|
x-kubernetes-preserve-unknown-fields: true
|
||||||
|
complianceRequirements:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
requiresApproval:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDataSources:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDestinations:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
auditLevel:
|
||||||
|
type: string
|
||||||
|
enum: [minimal, standard, full]
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
validated:
|
||||||
|
type: boolean
|
||||||
|
usedByAgents:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
lastInstantiated:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
39
charts/kubeclaw/templates/_helpers.tpl
Normal file
39
charts/kubeclaw/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{- define "kubeclaw.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "kubeclaw.fullname" -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "kubeclaw.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "kubeclaw.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "kubeclaw.chart" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{ include "kubeclaw.selectorLabels" . }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "kubeclaw.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "kubeclaw.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "kubeclaw.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "kubeclaw.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
35
charts/kubeclaw/templates/deployment.yaml
Normal file
35
charts/kubeclaw/templates/deployment.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels: {{- include "kubeclaw.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "kubeclaw.serviceAccountName" . }}
|
||||||
|
containers:
|
||||||
|
- name: manager
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- --health-probe-bind-address=:8081
|
||||||
|
- --metrics-bind-address=:8080
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
containerPort: 8080
|
||||||
|
- name: health
|
||||||
|
containerPort: 8081
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: health
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /readyz
|
||||||
|
port: health
|
||||||
|
resources: {{- toYaml .Values.resources | nindent 12 }}
|
||||||
40
charts/kubeclaw/templates/rbac.yaml
Normal file
40
charts/kubeclaw/templates/rbac.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{- if .Values.rbac.create }}
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents", "agentconfigs", "agentgroups", "channels", "providers"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["workflowtemplates", "compliancepolicies"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/status", "agentconfigs/status", "agentgroups/status", "channels/status", "providers/status", "workflowtemplates/status", "compliancepolicies/status"]
|
||||||
|
verbs: ["get", "update", "patch"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/finalizers"]
|
||||||
|
verbs: ["update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "configmaps", "serviceaccounts"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "kubeclaw.serviceAccountName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
5
charts/kubeclaw/templates/serviceaccount.yaml
Normal file
5
charts/kubeclaw/templates/serviceaccount.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.serviceAccountName" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
31
charts/kubeclaw/values.yaml
Normal file
31
charts/kubeclaw/values.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# kubeclaw Helm chart values
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/sscoble/kubeclaw
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: latest
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
name: kubeclaw-controller
|
||||||
|
|
||||||
|
rbac:
|
||||||
|
create: true
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
101
cmd/manager/main.go
Normal file
101
cmd/manager/main.go
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 Scott Scoble.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
|
||||||
|
kubeclawv1alpha1 "github.com/sscoble/kubeclaw/api/v1alpha1"
|
||||||
|
"github.com/sscoble/kubeclaw/internal/controller"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(kubeclawv1alpha1.AddToScheme(scheme))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var metricsAddr string
|
||||||
|
var enableLeaderElection bool
|
||||||
|
var probeAddr string
|
||||||
|
|
||||||
|
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
|
||||||
|
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||||
|
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||||
|
"Enable leader election for controller manager.")
|
||||||
|
opts := zap.Options{Development: true}
|
||||||
|
opts.BindFlags(flag.CommandLine)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||||
|
|
||||||
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||||
|
Scheme: scheme,
|
||||||
|
Metrics: ctrl.Options{}.Metrics,
|
||||||
|
HealthProbeBindAddress: probeAddr,
|
||||||
|
LeaderElection: enableLeaderElection,
|
||||||
|
LeaderElectionID: "kubeclaw.scoble.me",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
setupLog.Error(err, "unable to start manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up Agent reconciler
|
||||||
|
if err = (&controller.AgentReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Agent")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up WorkflowTemplate reconciler
|
||||||
|
if err = (&controller.WorkflowTemplateReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "WorkflowTemplate")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up CompliancePolicy reconciler
|
||||||
|
if err = (&controller.CompliancePolicyReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "CompliancePolicy")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "unable to set up health check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "unable to set up ready check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
setupLog.Info("starting manager")
|
||||||
|
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||||
|
setupLog.Error(err, "problem running manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
110
config/crd/bases/kubeclaw.scoble.me_agentconfigs.yaml
Normal file
110
config/crd/bases/kubeclaw.scoble.me_agentconfigs.yaml
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agentconfigs.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: AgentConfig
|
||||||
|
listKind: AgentConfigList
|
||||||
|
plural: agentconfigs
|
||||||
|
singular: agentconfig
|
||||||
|
shortNames:
|
||||||
|
- acfg
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
workspace:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
repo:
|
||||||
|
type: string
|
||||||
|
branch:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
autoCommit:
|
||||||
|
type: boolean
|
||||||
|
heartbeat:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
intervalSeconds:
|
||||||
|
type: integer
|
||||||
|
prompt:
|
||||||
|
type: string
|
||||||
|
sandbox:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
allowedExec:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
enum: ["off", "low", "medium", "high"]
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
fallbacks:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
toolsAllow:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
toolsDeny:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
env:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
valueFrom:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
secretKeyRef:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
usedByAgents:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
107
config/crd/bases/kubeclaw.scoble.me_agentgroups.yaml
Normal file
107
config/crd/bases/kubeclaw.scoble.me_agentgroups.yaml
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agentgroups.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: AgentGroup
|
||||||
|
listKind: AgentGroupList
|
||||||
|
plural: agentgroups
|
||||||
|
singular: agentgroup
|
||||||
|
shortNames:
|
||||||
|
- agg
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Members
|
||||||
|
type: integer
|
||||||
|
jsonPath: .status.memberCount
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [members]
|
||||||
|
properties:
|
||||||
|
sharedConfigRef:
|
||||||
|
type: string
|
||||||
|
sharedProviders:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
sharedChannels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
members:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, agentId]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
agentId:
|
||||||
|
type: string
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
configOverrides:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
allowedTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
requests:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
limits:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
memberCount:
|
||||||
|
type: integer
|
||||||
|
memberReady:
|
||||||
|
type: integer
|
||||||
|
agentRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
147
config/crd/bases/kubeclaw.scoble.me_agents.yaml
Normal file
147
config/crd/bases/kubeclaw.scoble.me_agents.yaml
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: agents.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Agent
|
||||||
|
listKind: AgentList
|
||||||
|
plural: agents
|
||||||
|
singular: agent
|
||||||
|
shortNames:
|
||||||
|
- ag
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: AgentID
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.agentId
|
||||||
|
- name: Model
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.model
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [agentId]
|
||||||
|
properties:
|
||||||
|
agentId:
|
||||||
|
type: string
|
||||||
|
description: OpenClaw agent identifier (main, engineering, etc.)
|
||||||
|
model:
|
||||||
|
type: string
|
||||||
|
thinking:
|
||||||
|
type: string
|
||||||
|
agentConfigRef:
|
||||||
|
type: string
|
||||||
|
description: Reference to an AgentConfig resource
|
||||||
|
workspace:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
configMapRef:
|
||||||
|
type: string
|
||||||
|
secretRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
pvcName:
|
||||||
|
type: string
|
||||||
|
providers:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
channelRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
channels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [type, botTokenSecretRef]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
botTokenSecretRef:
|
||||||
|
type: object
|
||||||
|
required: [name, key]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
guildID:
|
||||||
|
type: string
|
||||||
|
defaultChannel:
|
||||||
|
type: string
|
||||||
|
defaultTemplate:
|
||||||
|
type: string
|
||||||
|
allowedTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDataSources:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDestinations:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
compliancePolicyRefs:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
requests:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
limits:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
type: string
|
||||||
|
memory:
|
||||||
|
type: string
|
||||||
|
image:
|
||||||
|
type: string
|
||||||
|
replicas:
|
||||||
|
type: integer
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
phase:
|
||||||
|
type: string
|
||||||
|
deployments:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
lastTransition:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
75
config/crd/bases/kubeclaw.scoble.me_channels.yaml
Normal file
75
config/crd/bases/kubeclaw.scoble.me_channels.yaml
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: channels.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Channel
|
||||||
|
listKind: ChannelList
|
||||||
|
plural: channels
|
||||||
|
singular: channel
|
||||||
|
shortNames:
|
||||||
|
- ch
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Type
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.type
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [type, botTokenSecretRef]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: Channel type (discord, slack, telegram)
|
||||||
|
botTokenSecretRef:
|
||||||
|
type: object
|
||||||
|
required: [name, key]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
webhookURL:
|
||||||
|
type: string
|
||||||
|
guildID:
|
||||||
|
type: string
|
||||||
|
defaultChannel:
|
||||||
|
type: string
|
||||||
|
allowedChannels:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
connected:
|
||||||
|
type: boolean
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
lastConnected:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
106
config/crd/bases/kubeclaw.scoble.me_compliancepolicies.yaml
Normal file
106
config/crd/bases/kubeclaw.scoble.me_compliancepolicies.yaml
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: compliancepolicies.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: CompliancePolicy
|
||||||
|
listKind: CompliancePolicyList
|
||||||
|
plural: compliancepolicies
|
||||||
|
singular: compliancepolicy
|
||||||
|
shortNames:
|
||||||
|
- cp
|
||||||
|
- compol
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Framework
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.framework
|
||||||
|
- name: Escalation
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.escalation.mode
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [displayName, framework, rules, escalation]
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
framework:
|
||||||
|
type: string
|
||||||
|
rules:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, description, severity, constraint]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
severity:
|
||||||
|
type: string
|
||||||
|
enum: [block, warn, log]
|
||||||
|
constraint:
|
||||||
|
type: string
|
||||||
|
escalation:
|
||||||
|
type: object
|
||||||
|
required: [mode]
|
||||||
|
properties:
|
||||||
|
mode:
|
||||||
|
type: string
|
||||||
|
enum: [auto_deny, human_review, warn_only]
|
||||||
|
humanChannelRef:
|
||||||
|
type: string
|
||||||
|
timeoutSeconds:
|
||||||
|
type: integer
|
||||||
|
targetSelector:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
matchTemplates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchNamespaces:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchLabels:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
prompt:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
activeTemplates:
|
||||||
|
type: integer
|
||||||
|
totalJudgments:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
lastJudgment:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
86
config/crd/bases/kubeclaw.scoble.me_providers.yaml
Normal file
86
config/crd/bases/kubeclaw.scoble.me_providers.yaml
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: providers.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: Provider
|
||||||
|
listKind: ProviderList
|
||||||
|
plural: providers
|
||||||
|
singular: provider
|
||||||
|
shortNames:
|
||||||
|
- prov
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Type
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.type
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [type]
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: Provider type (ollama, openai, anthropic, deepseek)
|
||||||
|
baseUrl:
|
||||||
|
type: string
|
||||||
|
description: Provider API endpoint URL
|
||||||
|
apiKeySecretRef:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
models:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
type: boolean
|
||||||
|
cost:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
input:
|
||||||
|
type: number
|
||||||
|
output:
|
||||||
|
type: number
|
||||||
|
extraHeaders:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
lastChecked:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
106
config/crd/bases/kubeclaw.scoble.me_workflowtemplates.yaml
Normal file
106
config/crd/bases/kubeclaw.scoble.me_workflowtemplates.yaml
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: workflowtemplates.kubeclaw.scoble.me
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kubeclaw
|
||||||
|
app.kubernetes.io/part-of: scobleclaw
|
||||||
|
spec:
|
||||||
|
group: kubeclaw.scoble.me
|
||||||
|
names:
|
||||||
|
kind: WorkflowTemplate
|
||||||
|
listKind: WorkflowTemplateList
|
||||||
|
plural: workflowtemplates
|
||||||
|
singular: workflowtemplate
|
||||||
|
shortNames:
|
||||||
|
- wt
|
||||||
|
- wft
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
additionalPrinterColumns:
|
||||||
|
- name: Audit
|
||||||
|
type: string
|
||||||
|
jsonPath: .spec.auditLevel
|
||||||
|
- name: Steps
|
||||||
|
type: integer
|
||||||
|
jsonPath: .spec.steps
|
||||||
|
- name: Ready
|
||||||
|
type: boolean
|
||||||
|
jsonPath: .status.ready
|
||||||
|
- name: Age
|
||||||
|
type: date
|
||||||
|
jsonPath: .metadata.creationTimestamp
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
required: [displayName, description, steps, parametersSchema, outputSchema, auditLevel]
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
steps:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [name, action, target]
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
action:
|
||||||
|
type: string
|
||||||
|
target:
|
||||||
|
type: string
|
||||||
|
condition:
|
||||||
|
type: string
|
||||||
|
onFailure:
|
||||||
|
type: string
|
||||||
|
enum: [stop, skip, continue]
|
||||||
|
parametersSchema:
|
||||||
|
type: object
|
||||||
|
x-kubernetes-preserve-unknown-fields: true
|
||||||
|
outputSchema:
|
||||||
|
type: object
|
||||||
|
x-kubernetes-preserve-unknown-fields: true
|
||||||
|
complianceRequirements:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
requiresApproval:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDataSources:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
allowedDestinations:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
auditLevel:
|
||||||
|
type: string
|
||||||
|
enum: [minimal, standard, full]
|
||||||
|
status:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ready:
|
||||||
|
type: boolean
|
||||||
|
validated:
|
||||||
|
type: boolean
|
||||||
|
usedByAgents:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
lastInstantiated:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
49
config/deploy/controller.yaml
Normal file
49
config/deploy/controller.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
|
labels:
|
||||||
|
app: kubeclaw
|
||||||
|
component: controller
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: kubeclaw
|
||||||
|
component: controller
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: kubeclaw
|
||||||
|
component: controller
|
||||||
|
spec:
|
||||||
|
serviceAccountName: kubeclaw-controller
|
||||||
|
containers:
|
||||||
|
- name: manager
|
||||||
|
image: kubeclaw/controller:latest
|
||||||
|
imagePullPolicy: Never
|
||||||
|
args:
|
||||||
|
- --health-probe-bind-address=:8081
|
||||||
|
- --metrics-bind-address=:8080
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
containerPort: 8080
|
||||||
|
- name: health
|
||||||
|
containerPort: 8081
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: health
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /readyz
|
||||||
|
port: health
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 256Mi
|
||||||
46
config/deploy/rbac.yaml
Normal file
46
config/deploy/rbac.yaml
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents", "agentconfigs", "agentgroups", "channels", "providers",
|
||||||
|
"workflowtemplates", "compliancepolicies"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/status", "agentconfigs/status", "agentgroups/status",
|
||||||
|
"channels/status", "providers/status",
|
||||||
|
"workflowtemplates/status", "compliancepolicies/status"]
|
||||||
|
verbs: ["get", "update", "patch"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/finalizers"]
|
||||||
|
verbs: ["update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "configmaps", "serviceaccounts"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: kubeclaw-controller
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
40
config/rbac/role.yaml
Normal file
40
config/rbac/role.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{- if .Values.rbac.create }}
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents", "agentconfigs", "agentgroups", "channels", "providers"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["workflowtemplates", "compliancepolicies"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/status", "agentconfigs/status", "agentgroups/status", "channels/status", "providers/status", "workflowtemplates/status", "compliancepolicies/status"]
|
||||||
|
verbs: ["get", "update", "patch"]
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["agents/finalizers"]
|
||||||
|
verbs: ["update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "configmaps", "serviceaccounts"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
labels: {{- include "kubeclaw.labels" . | nindent 4 }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: {{ include "kubeclaw.fullname" . }}
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "kubeclaw.serviceAccountName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
13
config/samples/01-provider.yaml
Normal file
13
config/samples/01-provider.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Example: LLM provider pointing to a local Ollama instance
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: Provider
|
||||||
|
metadata:
|
||||||
|
name: ollama-cloud
|
||||||
|
spec:
|
||||||
|
type: ollama
|
||||||
|
baseUrl: https://ollama.example.com
|
||||||
|
models:
|
||||||
|
- id: deepseek-v4-pro:cloud
|
||||||
|
default: true
|
||||||
|
- id: deepseek-v4-flash:cloud
|
||||||
|
- id: qwen3-coder-next:cloud
|
||||||
11
config/samples/02-channel.yaml
Normal file
11
config/samples/02-channel.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: Channel
|
||||||
|
metadata:
|
||||||
|
name: discord-main
|
||||||
|
spec:
|
||||||
|
type: discord
|
||||||
|
botTokenSecretRef:
|
||||||
|
name: discord-token
|
||||||
|
key: token
|
||||||
|
guildID: "1169414363476672584"
|
||||||
|
defaultChannel: "1496038116128198676"
|
||||||
11
config/samples/03-agentconfig.yaml
Normal file
11
config/samples/03-agentconfig.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: AgentConfig
|
||||||
|
metadata:
|
||||||
|
name: default-config
|
||||||
|
spec:
|
||||||
|
model: deepseek-v4-pro:cloud
|
||||||
|
thinking: "off"
|
||||||
|
heartbeat:
|
||||||
|
intervalSeconds: 1800
|
||||||
|
sandbox:
|
||||||
|
enabled: false
|
||||||
40
config/samples/04-workflowtemplate.yaml
Normal file
40
config/samples/04-workflowtemplate.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: WorkflowTemplate
|
||||||
|
metadata:
|
||||||
|
name: search-memory
|
||||||
|
spec:
|
||||||
|
displayName: "Search Memory"
|
||||||
|
description: "Search the agent's memory store for relevant past context"
|
||||||
|
steps:
|
||||||
|
- name: search
|
||||||
|
action: search_memory
|
||||||
|
target: memory_store
|
||||||
|
- name: format-results
|
||||||
|
action: format_output
|
||||||
|
target: stdout
|
||||||
|
parametersSchema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
query:
|
||||||
|
type: string
|
||||||
|
description: "Search query"
|
||||||
|
maxResults:
|
||||||
|
type: integer
|
||||||
|
default: 5
|
||||||
|
required: ["query"]
|
||||||
|
outputSchema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
results:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
content:
|
||||||
|
type: string
|
||||||
|
score:
|
||||||
|
type: number
|
||||||
|
auditLevel: standard
|
||||||
|
complianceRequirements: ["SOC2"]
|
||||||
18
config/samples/05-compliancepolicy.yaml
Normal file
18
config/samples/05-compliancepolicy.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: CompliancePolicy
|
||||||
|
metadata:
|
||||||
|
name: soc2-data-access
|
||||||
|
spec:
|
||||||
|
displayName: "SOC2 Data Access Policy"
|
||||||
|
framework: SOC2
|
||||||
|
rules:
|
||||||
|
- name: data-source-check
|
||||||
|
description: "Ensure data sources are in the allowed list"
|
||||||
|
severity: block
|
||||||
|
constraint: "data_source in allowed_sources"
|
||||||
|
- name: audit-trail
|
||||||
|
description: "Require full audit trail for data writes"
|
||||||
|
severity: warn
|
||||||
|
constraint: "audit_level >= standard"
|
||||||
|
escalation:
|
||||||
|
mode: auto_deny
|
||||||
25
config/samples/06-agent.yaml
Normal file
25
config/samples/06-agent.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: Agent
|
||||||
|
metadata:
|
||||||
|
name: main-agent
|
||||||
|
labels:
|
||||||
|
team: core
|
||||||
|
spec:
|
||||||
|
agentId: main
|
||||||
|
model: deepseek-v4-pro:cloud
|
||||||
|
agentConfigRef: default-config
|
||||||
|
providers:
|
||||||
|
- ollama-cloud
|
||||||
|
channelRefs:
|
||||||
|
- discord-main
|
||||||
|
allowedTemplates:
|
||||||
|
- search-memory
|
||||||
|
allowedDataSources:
|
||||||
|
- memory_store
|
||||||
|
- vault
|
||||||
|
allowedDestinations:
|
||||||
|
- stdout
|
||||||
|
- discord
|
||||||
|
compliancePolicyRefs:
|
||||||
|
- soc2-data-access
|
||||||
|
replicas: 1
|
||||||
20
config/samples/07-agentgroup.yaml
Normal file
20
config/samples/07-agentgroup.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
apiVersion: kubeclaw.scoble.me/v1alpha1
|
||||||
|
kind: AgentGroup
|
||||||
|
metadata:
|
||||||
|
name: scobleclaw-team
|
||||||
|
spec:
|
||||||
|
sharedProviders:
|
||||||
|
- ollama-cloud
|
||||||
|
sharedChannels:
|
||||||
|
- discord-main
|
||||||
|
members:
|
||||||
|
- name: cos
|
||||||
|
agentId: main
|
||||||
|
model: deepseek-v4-pro:cloud
|
||||||
|
- name: engineering
|
||||||
|
agentId: engineering
|
||||||
|
model: qwen3-coder-next:cloud
|
||||||
|
- name: trust
|
||||||
|
agentId: trust
|
||||||
|
model: deepseek-v4-flash:cloud
|
||||||
|
thinking: low
|
||||||
65
go.mod
65
go.mod
|
|
@ -1,14 +1,67 @@
|
||||||
module github.com/sscoble/kubeclaw
|
module github.com/sscoble/kubeclaw
|
||||||
|
|
||||||
go 1.24
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/onsi/ginkgo/v2 v2.23.3
|
|
||||||
github.com/onsi/gomega v1.37.0
|
|
||||||
k8s.io/api v0.33.0
|
k8s.io/api v0.33.0
|
||||||
k8s.io/apiextensions-apiserver v0.33.0
|
|
||||||
k8s.io/apimachinery v0.33.0
|
k8s.io/apimachinery v0.33.0
|
||||||
k8s.io/client-go v0.33.0
|
k8s.io/client-go v0.33.0
|
||||||
sigs.k8s.io/controller-runtime v0.20.4
|
sigs.k8s.io/controller-runtime v0.20.4
|
||||||
sigs.k8s.io/yaml v1.4.0
|
)
|
||||||
)
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
|
github.com/go-logr/zapr v1.3.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/gnostic-models v0.6.9 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/onsi/ginkgo/v2 v2.23.3 // indirect
|
||||||
|
github.com/onsi/gomega v1.37.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.62.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
|
golang.org/x/net v0.38.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.27.0 // indirect
|
||||||
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
|
golang.org/x/term v0.30.0 // indirect
|
||||||
|
golang.org/x/text v0.23.0 // indirect
|
||||||
|
golang.org/x/time v0.9.0 // indirect
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
k8s.io/apiextensions-apiserver v0.33.0 // indirect
|
||||||
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||||
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
|
)
|
||||||
|
|
|
||||||
196
go.sum
Normal file
196
go.sum
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||||
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
|
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||||
|
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||||
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||||
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
|
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
|
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||||
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
|
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||||
|
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||||
|
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
|
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||||
|
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||||
|
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||||
|
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||||
|
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||||
|
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||||
|
k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs=
|
||||||
|
k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc=
|
||||||
|
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||||
|
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||||
|
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||||
|
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||||
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||||
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||||
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
|
||||||
|
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
|
||||||
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||||
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||||
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
4
hack/boilerplate.go.txt
Normal file
4
hack/boilerplate.go.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 Scott Scoble.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
*/
|
||||||
190
internal/controller/agent_controller.go
Normal file
190
internal/controller/agent_controller.go
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 Scott Scoble. Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
|
kubeclawv1alpha1 "github.com/sscoble/kubeclaw/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AgentReconciler reconciles Agent objects.
|
||||||
|
type AgentReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AgentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
logger.Info("reconciling Agent", "name", req.Name, "namespace", req.Namespace)
|
||||||
|
|
||||||
|
agent := &kubeclawv1alpha1.Agent{}
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, agent); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle deletion
|
||||||
|
if !agent.DeletionTimestamp.IsZero() {
|
||||||
|
if controllerutil.ContainsFinalizer(agent, "kubeclaw.scoble.me/finalizer") {
|
||||||
|
podName := fmt.Sprintf("kubeclaw-agent-%s", agent.Spec.AgentID)
|
||||||
|
pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: podName, Namespace: req.Namespace}}
|
||||||
|
if err := r.Delete(ctx, pod); err != nil && !errors.IsNotFound(err) {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
controllerutil.RemoveFinalizer(agent, "kubeclaw.scoble.me/finalizer")
|
||||||
|
if err := r.Update(ctx, agent); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure finalizer
|
||||||
|
if !controllerutil.ContainsFinalizer(agent, "kubeclaw.scoble.me/finalizer") {
|
||||||
|
controllerutil.AddFinalizer(agent, "kubeclaw.scoble.me/finalizer")
|
||||||
|
if err := r.Update(ctx, agent); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve AgentConfig
|
||||||
|
if agent.Spec.AgentConfigRef != "" {
|
||||||
|
acfg := &kubeclawv1alpha1.AgentConfig{}
|
||||||
|
if err := r.Get(ctx, types.NamespacedName{Name: agent.Spec.AgentConfigRef, Namespace: req.Namespace}, acfg); err != nil {
|
||||||
|
logger.Error(err, "cannot fetch AgentConfig", "ref", agent.Spec.AgentConfigRef)
|
||||||
|
agent.Status.Phase = "ConfigError"
|
||||||
|
_ = r.Status().Update(ctx, agent)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
if agent.Spec.Model == "" && acfg.Spec.Model != "" {
|
||||||
|
agent.Spec.Model = acfg.Spec.Model
|
||||||
|
}
|
||||||
|
if agent.Spec.Thinking == "" && acfg.Spec.Thinking != "" {
|
||||||
|
agent.Spec.Thinking = acfg.Spec.Thinking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image := agent.Spec.Image
|
||||||
|
if image == "" {
|
||||||
|
image = "ghcr.io/sscoble/kubeclaw-agent:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
podName := fmt.Sprintf("kubeclaw-agent-%s", agent.Spec.AgentID)
|
||||||
|
|
||||||
|
pod := &corev1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
Namespace: req.Namespace,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app.kubernetes.io/name": "kubeclaw-agent",
|
||||||
|
"app.kubernetes.io/instance": podName,
|
||||||
|
"app.kubernetes.io/part-of": "scobleclaw",
|
||||||
|
"kubeclaw.scoble.me/agent-id": agent.Spec.AgentID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{{
|
||||||
|
Name: "agent",
|
||||||
|
Image: image,
|
||||||
|
Env: r.buildEnv(agent),
|
||||||
|
Resources: corev1.ResourceRequirements{
|
||||||
|
Requests: corev1.ResourceList{
|
||||||
|
corev1.ResourceCPU: resource.MustParse("100m"),
|
||||||
|
corev1.ResourceMemory: resource.MustParse("128Mi"),
|
||||||
|
},
|
||||||
|
Limits: corev1.ResourceList{
|
||||||
|
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||||
|
corev1.ResourceMemory: resource.MustParse("256Mi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply resource overrides
|
||||||
|
if agent.Spec.Resources != nil {
|
||||||
|
if cpu, ok := agent.Spec.Resources.Requests["cpu"]; ok {
|
||||||
|
if q, err := resource.ParseQuantity(cpu); err == nil {
|
||||||
|
pod.Spec.Containers[0].Resources.Requests[corev1.ResourceCPU] = q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mem, ok := agent.Spec.Resources.Requests["memory"]; ok {
|
||||||
|
if q, err := resource.ParseQuantity(mem); err == nil {
|
||||||
|
pod.Spec.Containers[0].Resources.Requests[corev1.ResourceMemory] = q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cpu, ok := agent.Spec.Resources.Limits["cpu"]; ok {
|
||||||
|
if q, err := resource.ParseQuantity(cpu); err == nil {
|
||||||
|
pod.Spec.Containers[0].Resources.Limits[corev1.ResourceCPU] = q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mem, ok := agent.Spec.Resources.Limits["memory"]; ok {
|
||||||
|
if q, err := resource.ParseQuantity(mem); err == nil {
|
||||||
|
pod.Spec.Containers[0].Resources.Limits[corev1.ResourceMemory] = q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or update
|
||||||
|
foundPod := &corev1.Pod{}
|
||||||
|
err := r.Get(ctx, types.NamespacedName{Name: podName, Namespace: req.Namespace}, foundPod)
|
||||||
|
if err != nil && errors.IsNotFound(err) {
|
||||||
|
logger.Info("creating Pod", "name", podName)
|
||||||
|
if err := r.Create(ctx, pod); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
foundPod.Spec = pod.Spec
|
||||||
|
foundPod.Labels = pod.Labels
|
||||||
|
if err := r.Update(ctx, foundPod); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.Status.Phase = "Running"
|
||||||
|
agent.Status.ReadyReplicas = 1
|
||||||
|
if err := r.Status().Update(ctx, agent); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AgentReconciler) buildEnv(agent *kubeclawv1alpha1.Agent) []corev1.EnvVar {
|
||||||
|
env := []corev1.EnvVar{{Name: "KUBECLAW_AGENT_ID", Value: agent.Spec.AgentID}}
|
||||||
|
if agent.Spec.Model != "" {
|
||||||
|
env = append(env, corev1.EnvVar{Name: "KUBECLAW_MODEL", Value: agent.Spec.Model})
|
||||||
|
}
|
||||||
|
if agent.Spec.Thinking != "" {
|
||||||
|
env = append(env, corev1.EnvVar{Name: "KUBECLAW_THINKING", Value: agent.Spec.Thinking})
|
||||||
|
}
|
||||||
|
if agent.Spec.DefaultTemplate != "" {
|
||||||
|
env = append(env, corev1.EnvVar{Name: "KUBECLAW_DEFAULT_TEMPLATE", Value: agent.Spec.DefaultTemplate})
|
||||||
|
}
|
||||||
|
if len(agent.Spec.AllowedTemplates) > 0 {
|
||||||
|
env = append(env, corev1.EnvVar{Name: "KUBECLAW_ALLOWED_TEMPLATES", Value: joinSlice(agent.Spec.AllowedTemplates, ",")})
|
||||||
|
}
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AgentReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&kubeclawv1alpha1.Agent{}).
|
||||||
|
Owns(&corev1.Pod{}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
52
internal/controller/compliancepolicy_controller.go
Normal file
52
internal/controller/compliancepolicy_controller.go
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 Scott Scoble. Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
|
kubeclawv1alpha1 "github.com/sscoble/kubeclaw/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CompliancePolicyReconciler reconciles CompliancePolicy objects.
|
||||||
|
type CompliancePolicyReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CompliancePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
cp := &kubeclawv1alpha1.CompliancePolicy{}
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, cp); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("validating compliance policy", "name", cp.Name)
|
||||||
|
|
||||||
|
valid := true
|
||||||
|
if len(cp.Spec.Rules) == 0 {
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
|
||||||
|
cp.Status.Ready = valid
|
||||||
|
|
||||||
|
if err := r.Status().Update(ctx, cp); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CompliancePolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&kubeclawv1alpha1.CompliancePolicy{}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
12
internal/controller/helpers.go
Normal file
12
internal/controller/helpers.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package controller
|
||||||
|
|
||||||
|
func joinSlice(items []string, sep string) string {
|
||||||
|
result := ""
|
||||||
|
for i, item := range items {
|
||||||
|
if i > 0 {
|
||||||
|
result += sep
|
||||||
|
}
|
||||||
|
result += item
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
57
internal/controller/workflowtemplate_controller.go
Normal file
57
internal/controller/workflowtemplate_controller.go
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 Scott Scoble. Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
|
kubeclawv1alpha1 "github.com/sscoble/kubeclaw/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WorkflowTemplateReconciler reconciles WorkflowTemplate objects.
|
||||||
|
type WorkflowTemplateReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WorkflowTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
wt := &kubeclawv1alpha1.WorkflowTemplate{}
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, wt); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("validating workflow template", "name", wt.Name)
|
||||||
|
|
||||||
|
// Validate basic shape
|
||||||
|
valid := true
|
||||||
|
if len(wt.Spec.Steps) == 0 {
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
if wt.Spec.AuditLevel == "" {
|
||||||
|
wt.Spec.AuditLevel = "standard"
|
||||||
|
}
|
||||||
|
|
||||||
|
wt.Status.Ready = valid
|
||||||
|
wt.Status.Validated = true
|
||||||
|
|
||||||
|
if err := r.Status().Update(ctx, wt); err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WorkflowTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&kubeclawv1alpha1.WorkflowTemplate{}).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
BIN
manager
Executable file
BIN
manager
Executable file
Binary file not shown.
35
nix/build-image.nix
Normal file
35
nix/build-image.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# build-image.nix — Package the pre-built kubeclaw controller binary as an OCI image
|
||||||
|
# Usage: nix-build build-image.nix && result | k3s ctr images import -
|
||||||
|
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
let
|
||||||
|
manager-bin = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "kubeclaw-manager";
|
||||||
|
src = ./../manager;
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp $src $out/bin/manager
|
||||||
|
chmod +x $out/bin/manager
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in pkgs.dockerTools.streamLayeredImage {
|
||||||
|
name = "kubeclaw/controller";
|
||||||
|
tag = "latest";
|
||||||
|
created = "now";
|
||||||
|
contents = [
|
||||||
|
manager-bin
|
||||||
|
pkgs.cacert
|
||||||
|
pkgs.tzdata
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
User = "65532:65532";
|
||||||
|
Entrypoint = [ "/bin/manager" ];
|
||||||
|
ExposedPorts = {
|
||||||
|
"8080/tcp" = {};
|
||||||
|
"8081/tcp" = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
1
nix/result
Symbolic link
1
nix/result
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/6xkkvlii8k7jj9i2zj0bkw5xj6dbmz81-stream-controller
|
||||||
170
quickstart.sh
Executable file
170
quickstart.sh
Executable file
|
|
@ -0,0 +1,170 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# kubeclaw quickstart: install CRDs + deploy controller on Docker Desktop Kubernetes
|
||||||
|
# Prerequisites: Docker Desktop with Kubernetes enabled, kubectl pointing to docker-desktop
|
||||||
|
|
||||||
|
echo "=== kubeclaw Quickstart ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. Verify cluster access
|
||||||
|
echo "→ Checking cluster connection..."
|
||||||
|
kubectl cluster-info --request-timeout=5s > /dev/null 2>&1 || {
|
||||||
|
echo "ERROR: Cannot reach Kubernetes cluster."
|
||||||
|
echo "Make sure Docker Desktop has Kubernetes enabled (Settings → Kubernetes → Enable Kubernetes)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo " ✓ Cluster reachable ($(kubectl config current-context))"
|
||||||
|
|
||||||
|
# 2. Install CRDs
|
||||||
|
echo ""
|
||||||
|
echo "→ Installing CRDs..."
|
||||||
|
for crd in config/crd/bases/*.yaml; do
|
||||||
|
kubectl apply -f "$crd"
|
||||||
|
done
|
||||||
|
echo " ✓ CRDs installed"
|
||||||
|
|
||||||
|
# Wait for CRDs to register
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 3. Verify CRDs are ready
|
||||||
|
echo ""
|
||||||
|
echo "→ Verifying CRDs..."
|
||||||
|
kubectl get crd | grep kubeclaw.scoble.me | awk '{print " " $1}'
|
||||||
|
|
||||||
|
# 4. Create namespace
|
||||||
|
echo ""
|
||||||
|
echo "→ Creating scobleclaw namespace..."
|
||||||
|
kubectl create namespace scobleclaw --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
echo " ✓ Namespace ready"
|
||||||
|
|
||||||
|
# 5. Deploy controller
|
||||||
|
echo ""
|
||||||
|
echo "→ Deploying kubeclaw controller..."
|
||||||
|
kubectl apply -f config/rbac/role.yaml 2>/dev/null || {
|
||||||
|
# Generate minimal RBAC if role.yaml doesn't exist
|
||||||
|
kubectl apply -f - <<'RBAC'
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["kubeclaw.scoble.me"]
|
||||||
|
resources: ["*"]
|
||||||
|
verbs: ["*"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "configmaps", "serviceaccounts"]
|
||||||
|
verbs: ["*"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["*"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: kubeclaw-controller
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
|
RBAC
|
||||||
|
}
|
||||||
|
|
||||||
|
kubectl apply -f - <<'DEPLOYMENT'
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-config
|
||||||
|
namespace: scobleclaw
|
||||||
|
data:
|
||||||
|
config.yaml: |
|
||||||
|
logLevel: info
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: kubeclaw-controller
|
||||||
|
namespace: scobleclaw
|
||||||
|
labels:
|
||||||
|
app: kubeclaw
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: kubeclaw
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: kubeclaw
|
||||||
|
spec:
|
||||||
|
serviceAccountName: kubeclaw-controller
|
||||||
|
containers:
|
||||||
|
- name: manager
|
||||||
|
image: ghcr.io/sscoble/kubeclaw:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command: ["/manager"]
|
||||||
|
args:
|
||||||
|
- --health-probe-bind-address=:8081
|
||||||
|
- --metrics-bind-address=:8080
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: metrics
|
||||||
|
- containerPort: 8081
|
||||||
|
name: health
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 256Mi
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: health
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /readyz
|
||||||
|
port: health
|
||||||
|
DEPLOYMENT
|
||||||
|
|
||||||
|
echo " ✓ Controller deployed"
|
||||||
|
|
||||||
|
# 6. Wait for controller
|
||||||
|
echo ""
|
||||||
|
echo "→ Waiting for controller to start..."
|
||||||
|
kubectl wait --for=condition=available deployment/kubeclaw-controller -n scobleclaw --timeout=60s 2>/dev/null || {
|
||||||
|
echo " (controller may still be starting — check with 'kubectl get pods -n scobleclaw')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 7. Apply samples
|
||||||
|
echo ""
|
||||||
|
echo "→ Installing sample resources..."
|
||||||
|
for sample in config/samples/0*.yaml; do
|
||||||
|
echo " Applying $sample..."
|
||||||
|
kubectl apply -f "$sample" -n scobleclaw 2>/dev/null || kubectl apply -f "$sample"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Quickstart Complete ==="
|
||||||
|
echo ""
|
||||||
|
echo "Check status:"
|
||||||
|
echo " kubectl get agents -n scobleclaw"
|
||||||
|
echo " kubectl get workflowtemplates"
|
||||||
|
echo " kubectl get compliancepolicies"
|
||||||
|
echo ""
|
||||||
|
echo "View controller logs:"
|
||||||
|
echo " kubectl logs -n scobleclaw deployment/kubeclaw-controller"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue