feat: Deco CRD and BuildReconciler for cfworkers#5
Conversation
- DecoBuild CRD: represents a cfworkers build request; operator creates K8s Jobs - BuildReconciler: watches DecoBuild, generates S3 presigned URLs, creates Job - build/job.go: Job spec builder (cfworkers-builder image, env vars, TTL 24h) - build/s3presign.go: generates presigned URLs for logs/cache using aws-sdk-go-v2 - RBAC: batch/jobs + deco.sites/decobuilds permissions - Chart bumped to v0.3.0; cfworkers env vars injected from ExternalSecret
- Add deco.sites_decobuilds.yaml to config/crd/kustomization.yaml so helm-generator picks it up - Add cfworkers env vars block to helm-generator addEnvVarsToDeployment - Regenerate chart templates via make manifests helm
…views Replaces the per-build DecoBuild CRD with a site-scoped Deco CR that owns both production and preview builds. The operator reconciles spec.build.source for production deploys and spec.previews.active[] for concurrent PR previews, fixing the concurrent PR overwrite bug. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…builder images Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
10 issues found across 19 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="api/v1alpha1/deco_types.go">
<violation number="1" location="api/v1alpha1/deco_types.go:9">
P2: Add enum validation for string fields that are documented as closed sets to prevent invalid CRs from being admitted.</violation>
<violation number="2" location="api/v1alpha1/deco_types.go:21">
P2: Add enum validation for `spec.framework` to match the documented allowed values.</violation>
<violation number="3" location="api/v1alpha1/deco_types.go:73">
P2: Add CRD enum validation for `spec.serving.type` to enforce the documented supported runtimes.</violation>
</file>
<file name="config/crd/kustomization.yaml">
<violation number="1" location="config/crd/kustomization.yaml:5">
P1: The new DecoBuild CRD base file exists but is not included in CRD kustomization, so `decobuilds.deco.sites` will not be applied.</violation>
</file>
<file name="config/crd/bases/deco.sites_decobuilds.yaml">
<violation number="1" location="config/crd/bases/deco.sites_decobuilds.yaml:20">
P2: Restrict `.spec.build.type` with an enum to enforce the only supported value at CRD validation time.</violation>
<violation number="2" location="config/crd/bases/deco.sites_decobuilds.yaml:20">
P1: Add enum validation for `.spec.target.type` so unsupported target platforms are rejected by the API server.</violation>
</file>
<file name="config/crd/bases/deco.sites_decos.yaml">
<violation number="1" location="config/crd/bases/deco.sites_decos.yaml:63">
P2: `spec.build.type` is documented as only `k8s-job` but is not validated; add an `enum` to prevent unsupported values.</violation>
<violation number="2" location="config/crd/bases/deco.sites_decos.yaml:90">
P2: `spec.serving.type` should use an `enum` to enforce the supported runtime values documented in the CRD.</violation>
</file>
<file name="chart/templates/deployment-operator-controller-manager.yaml">
<violation number="1" location="chart/templates/deployment-operator-controller-manager.yaml:34">
P2: The `env:` gate is too strict for cfworkers and can skip `S3_REGION` when `cfworkers.existingSecret` is unset.</violation>
</file>
<file name="chart/templates/customresourcedefinition-decos.deco.sites.yaml">
<violation number="1" location="chart/templates/customresourcedefinition-decos.deco.sites.yaml:20">
P2: Add CRD enum validation for `spec.serving.type` so unsupported runtime values are rejected early.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| # since it depends on service name and namespace that are out of this kustomize package. | ||
| # It should be run by config/default | ||
| resources: | ||
| - bases/deco.sites_decos.yaml |
There was a problem hiding this comment.
P1: The new DecoBuild CRD base file exists but is not included in CRD kustomization, so decobuilds.deco.sites will not be applied.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/crd/kustomization.yaml, line 5:
<comment>The new DecoBuild CRD base file exists but is not included in CRD kustomization, so `decobuilds.deco.sites` will not be applied.</comment>
<file context>
@@ -2,6 +2,7 @@
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
+- bases/deco.sites_decos.yaml
- bases/deco.sites_decofiles.yaml
# +kubebuilder:scaffold:crdkustomizeresource
</file context>
| - bases/deco.sites_decos.yaml | |
| - bases/deco.sites_decos.yaml | |
| - bases/deco.sites_decobuilds.yaml |
|
|
||
| // Framework is the site framework. deno | tanstack | next | remix | static | ||
| // +optional | ||
| Framework string `json:"framework,omitempty"` |
There was a problem hiding this comment.
P2: Add enum validation for spec.framework to match the documented allowed values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/v1alpha1/deco_types.go, line 21:
<comment>Add enum validation for `spec.framework` to match the documented allowed values.</comment>
<file context>
@@ -0,0 +1,189 @@
+
+ // Framework is the site framework. deno | tanstack | next | remix | static
+ // +optional
+ Framework string `json:"framework,omitempty"`
+
+ // Build describes the production build pipeline.
</file context>
| // Type is the serving runtime. Drives both serving and build job selection. | ||
| // Supported: cloudflare-worker | knative | deployment | ||
| // +kubebuilder:validation:Required | ||
| Type string `json:"type"` |
There was a problem hiding this comment.
P2: Add CRD enum validation for spec.serving.type to enforce the documented supported runtimes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/v1alpha1/deco_types.go, line 73:
<comment>Add CRD enum validation for `spec.serving.type` to enforce the documented supported runtimes.</comment>
<file context>
@@ -0,0 +1,189 @@
+ // Type is the serving runtime. Drives both serving and build job selection.
+ // Supported: cloudflare-worker | knative | deployment
+ // +kubebuilder:validation:Required
+ Type string `json:"type"`
+}
+
</file context>
| description: Build describes the build pipeline. | ||
| properties: | ||
| type: | ||
| description: Type is the build mechanism. Currently only k8s-job is supported. |
There was a problem hiding this comment.
P2: spec.build.type is documented as only k8s-job but is not validated; add an enum to prevent unsupported values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/crd/bases/deco.sites_decos.yaml, line 63:
<comment>`spec.build.type` is documented as only `k8s-job` but is not validated; add an `enum` to prevent unsupported values.</comment>
<file context>
@@ -0,0 +1,189 @@
+ description: Build describes the build pipeline.
+ properties:
+ type:
+ description: Type is the build mechanism. Currently only k8s-job is supported.
+ type: string
+ builder:
</file context>
| description: Serving describes the runtime serving configuration. Also drives build job selection. | ||
| properties: | ||
| type: | ||
| description: 'Type is the serving runtime. Supported: cloudflare-worker | knative | deployment' |
There was a problem hiding this comment.
P2: spec.serving.type should use an enum to enforce the supported runtime values documented in the CRD.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/crd/bases/deco.sites_decos.yaml, line 90:
<comment>`spec.serving.type` should use an `enum` to enforce the supported runtime values documented in the CRD.</comment>
<file context>
@@ -0,0 +1,189 @@
+ description: Serving describes the runtime serving configuration. Also drives build job selection.
+ properties:
+ type:
+ description: 'Type is the serving runtime. Supported: cloudflare-worker | knative | deployment'
+ type: string
+ required:
</file context>
| type DecoSpec struct { | ||
| // Type is the workload type. site | server | admin | preview | ||
| // +optional | ||
| Type string `json:"type,omitempty"` |
There was a problem hiding this comment.
P2: Add enum validation for string fields that are documented as closed sets to prevent invalid CRs from being admitted.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/v1alpha1/deco_types.go, line 9:
<comment>Add enum validation for string fields that are documented as closed sets to prevent invalid CRs from being admitted.</comment>
<file context>
@@ -0,0 +1,189 @@
+type DecoSpec struct {
+ // Type is the workload type. site | server | admin | preview
+ // +optional
+ Type string `json:"type,omitempty"`
+
+ // Site is the site/repository name.
</file context>
| - additionalPrinterColumns: | ||
| - jsonPath: .spec.site | ||
| name: Site | ||
| type: string |
There was a problem hiding this comment.
P2: Add CRD enum validation for spec.serving.type so unsupported runtime values are rejected early.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At chart/templates/customresourcedefinition-decos.deco.sites.yaml, line 20:
<comment>Add CRD enum validation for `spec.serving.type` so unsupported runtime values are rejected early.</comment>
<file context>
@@ -0,0 +1,129 @@
+ - additionalPrinterColumns:
+ - jsonPath: .spec.site
+ name: Site
+ type: string
+ - jsonPath: .spec.serving.type
+ name: Serving
</file context>
…ilds Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The DecoReconciler no longer holds cfworkers-specific credentials (CfApiToken, CfAccountId, S3Config). A JobFactory function type is injected at startup, keeping the reconciler platform-agnostic. Future serving types just need a new factory wired in main.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="internal/controller/deco_controller.go">
<violation number="1" location="internal/controller/deco_controller.go:235">
P1: Serving type is no longer validated before job creation, so non-`cloudflare-worker` workloads can be reconciled into the Cloudflare build job path.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
|
|
||
| // createJob creates a K8s Job for either a production or preview build. | ||
| func (r *DecoReconciler) createJob(ctx context.Context, deco *decositesv1alpha1.Deco, jobName string, source decositesv1alpha1.DecoSpecBuildSource) error { | ||
| job, err := r.JobFactory(ctx, deco, jobName, source) |
There was a problem hiding this comment.
P1: Serving type is no longer validated before job creation, so non-cloudflare-worker workloads can be reconciled into the Cloudflare build job path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/controller/deco_controller.go, line 235:
<comment>Serving type is no longer validated before job creation, so non-`cloudflare-worker` workloads can be reconciled into the Cloudflare build job path.</comment>
<file context>
@@ -232,25 +232,11 @@ func (r *DecoReconciler) reconcilePreviewBuilds(ctx context.Context, log logr.Lo
- }
-
- presignedURLs, err := build.GeneratePresignedURLs(ctx, r.S3Config, deco.Spec.Site, jobName)
+ job, err := r.JobFactory(ctx, deco, jobName, source)
if err != nil {
- return fmt.Errorf("generating presigned URLs: %w", err)
</file context>
Tip: Review your code locally with the cubic CLI to iterate faster.
BuilderImage, TTLSeconds, LogsBucket and CacheBucket are now fields on JobOpts/S3Config instead of hardcoded constants. The cfworkers factory in main.go owns these values. spec.build.builder in the CR still takes precedence over the platform default for BuilderImage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace single JobFactory field with Factories map[string]JobFactory keyed by spec.serving.type. createJob looks up the factory by type and returns an error for unknown types. A new platform just registers its factory in main.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="cmd/main.go">
<violation number="1" location="cmd/main.go:369">
P2: Use a pinned builder image tag (or digest) instead of `:latest` to keep builds reproducible and auditable.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
| CfAccountId: cfAccountId, | ||
| PresignedURLs: presignedURLs, | ||
| SourceOverride: &source, | ||
| BuilderImage: "ghcr.io/decocms/infra_applications/cfworkers-builder:latest", |
There was a problem hiding this comment.
P2: Use a pinned builder image tag (or digest) instead of :latest to keep builds reproducible and auditable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmd/main.go, line 369:
<comment>Use a pinned builder image tag (or digest) instead of `:latest` to keep builds reproducible and auditable.</comment>
<file context>
@@ -364,12 +366,16 @@ func main() {
CfAccountId: cfAccountId,
PresignedURLs: presignedURLs,
SourceOverride: &source,
+ BuilderImage: "ghcr.io/decocms/infra_applications/cfworkers-builder:latest",
+ TTLSeconds: 24 * 60 * 60,
}), nil
</file context>
| BuilderImage: "ghcr.io/decocms/infra_applications/cfworkers-builder:latest", | |
| BuilderImage: getEnvOrDefault("CFWORKERS_BUILDER_IMAGE", "ghcr.io/decocms/infra_applications/cfworkers-builder:v0.3.0"), |
Tip: Review your code locally with the cubic CLI to iterate faster.
Makes the cfworkers-specific types explicit in the build package so future platforms can add their own types alongside without ambiguity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move serving-type dispatch out of the controller into build.Registry. The controller now holds a *build.Registry and calls registry.NewJob() without knowing about platforms. New platforms register via registry.Register() in main.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clarifies that this file is cfworkers-specific. Generic build helpers (registry, s3presign) stay at the package level; platform-specific implementations get their own file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix goconst: extract Succeeded/Failed as constants - Fix prealloc: pre-allocate newStatuses slice - Fix lll: break long factory func signature in cmd/main.go - Fix helm-generator to emit S3_REGION as secretKeyRef (key: s3-region) - Regenerate CRD template (alphabetical field ordering from controller-gen) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this annotation controller-gen auto-pluralises 'Deco' as 'decoes', creating a second deco.sites_decoes.yaml alongside the committed deco.sites_decos.yaml. envtest loads every yaml in config/crd/bases/ so both CRDs were registered, causing the BeforeSuite context deadline timeout. Also regenerates deco.sites_decos.yaml from current types (updated schema, alphabetical field ordering, adds previews/branchRef fields). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…os.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: DecoBuild CRD and BuildReconciler for cfworkers
Related: decocms/infra_applications feat/cfworkers-builder, deco-sites/admin feat/cfworkers-tanstack