Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions api/v1alpha1/deco_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,33 @@ type DecoSpec struct {
// Admin adds entries to Previews.Active on PR open and removes on PR close.
// +optional
Previews *DecoPreviewPolicy `json:"previews,omitempty"`

// FastDeploy enables and configures git-driven, KV-first content fast-deploy
// for this site. When Enabled, content-only pushes (touching only
// .deco/blocks/**) sync to Cloudflare KV via a Decofile CR instead of a full
// build/deploy. This is the per-site config the webhook's DeploymentTarget
// reads to decide whether and how to fast-deploy.
// +optional
FastDeploy *DecoFastDeploy `json:"fastDeploy,omitempty"`
}

// DecoFastDeploy configures KV-first content fast-deploy for a site.
// +kubebuilder:validation:XValidation:rule="!self.enabled || (has(self.kvNamespaceId) && size(self.kvNamespaceId) > 0)",message="kvNamespaceId is required when fastDeploy is enabled"
type DecoFastDeploy struct {
// Enabled gates the fast-deploy content path. When false, content pushes take
// the normal build/deploy path.
// +optional
Enabled bool `json:"enabled,omitempty"`

// KVNamespaceID is the Cloudflare KV namespace id for this site (one per site).
// Required when enabled (enforced via the XValidation rule on this struct).
// +optional
KVNamespaceID string `json:"kvNamespaceId,omitempty"`

// SiteOrigin is the deployed site origin used for cache purge after a sync
// (e.g. https://www.example.com). Optional.
// +optional
SiteOrigin string `json:"siteOrigin,omitempty"`
}

// DecoEnvVar is a plain environment variable injected into the build Job.
Expand Down
48 changes: 48 additions & 0 deletions api/v1alpha1/decofile_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,24 @@ import (
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// Decofile source kinds (DecofileSpec.Source).
const (
SourceInline = "inline"
SourceGitHub = "github"
)

// Decofile delivery targets (DecofileSpec.Target) — selects the FastDeployment
// strategy that reconciles the CR.
const (
// TargetConfigMap writes a ConfigMap + notifies Knative pods (default).
TargetConfigMap = "configmap"
// TargetTanstackKV runs a Job that pushes the decofile to Cloudflare KV.
TargetTanstackKV = "tanstack-kv"
)

// DecofileSpec defines the desired state of Decofile.
// +kubebuilder:validation:XValidation:rule="self.target != 'tanstack-kv' || has(self.tanstackKV)",message="spec.tanstackKV is required when target is tanstack-kv"
// +kubebuilder:validation:XValidation:rule="self.target != 'tanstack-kv' || self.source == 'github'",message="source must be 'github' when target is tanstack-kv"
type DecofileSpec struct {
// Source specifies where to get the configuration data
// +kubebuilder:validation:Required
Expand All @@ -43,6 +60,33 @@ type DecofileSpec struct {
// Pods are queried using the app.deco/deploymentId label
// +optional
DeploymentId string `json:"deploymentId,omitempty"`

// Target selects how this Decofile is delivered (the FastDeployment strategy).
// "configmap" (default) writes a ConfigMap and notifies Knative pods.
// "tanstack-kv" runs a self-cleaning Job that pushes the decofile to Cloudflare
// KV — the fast-deploy content path for TanStack/Workers sites.
// +kubebuilder:validation:Enum=configmap;tanstack-kv
// +kubebuilder:default=configmap
// +optional
Target string `json:"target,omitempty"`

// TanstackKV configures the tanstack-kv target. Required when target=tanstack-kv.
// The repo/commit to sync come from spec.github (source=github).
// +optional
TanstackKV *TanstackKVTarget `json:"tanstackKV,omitempty"`
}

// TanstackKVTarget configures Cloudflare KV fast-deploy for a TanStack/Workers site.
type TanstackKVTarget struct {
// KVNamespaceID is the Cloudflare KV namespace id for this site (one per site).
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
KVNamespaceID string `json:"kvNamespaceId"`
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

// SiteOrigin is the deployed site origin used to POST /_cache/purge after the
// sync (e.g. https://www.example.com). Optional — purge is skipped when empty.
// +optional
SiteOrigin string `json:"siteOrigin,omitempty"`
}

// InlineSource contains direct JSON configuration data
Expand Down Expand Up @@ -98,6 +142,10 @@ type DecofileStatus struct {
// GitHubCommit stores the commit SHA if using GitHub source
// +optional
GitHubCommit string `json:"githubCommit,omitempty"`

// JobName is the K8s Job name for the current tanstack-kv sync (target=tanstack-kv).
// +optional
JobName string `json:"jobName,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
40 changes: 40 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion chart/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v2
name: deco-operator
description: Kubernetes operator for Deco CMS that manages Decofile resources and automatically injects configuration into Knative Services
type: application
version: 0.2.6
version: 0.3.0
appVersion: "0.2.6"
keywords:
- operator
Expand Down
2 changes: 2 additions & 0 deletions chart/templates/clusterrole-operator-manager-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ rules:
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- cert-manager.io
Expand Down
38 changes: 38 additions & 0 deletions chart/templates/customresourcedefinition-decofiles.deco.sites.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,43 @@ spec:
- inline
- github
type: string
tanstackKV:
description: |-
TanstackKV configures the tanstack-kv target. Required when target=tanstack-kv.
The repo/commit to sync come from spec.github (source=github).
properties:
kvNamespaceId:
description: KVNamespaceID is the Cloudflare KV namespace id for
this site (one per site).
minLength: 1
type: string
siteOrigin:
description: |-
SiteOrigin is the deployed site origin used to POST /_cache/purge after the
sync (e.g. https://www.example.com). Optional — purge is skipped when empty.
type: string
required:
- kvNamespaceId
type: object
target:
default: configmap
description: |-
Target selects how this Decofile is delivered (the FastDeployment strategy).
"configmap" (default) writes a ConfigMap and notifies Knative pods.
"tanstack-kv" runs a self-cleaning Job that pushes the decofile to Cloudflare
KV — the fast-deploy content path for TanStack/Workers sites.
enum:
- configmap
- tanstack-kv
type: string
required:
- source
type: object
x-kubernetes-validations:
- message: spec.tanstackKV is required when target is tanstack-kv
rule: self.target != 'tanstack-kv' || has(self.tanstackKV)
- message: source must be 'github' when target is tanstack-kv
rule: self.target != 'tanstack-kv' || self.source == 'github'
status:
description: DecofileStatus defines the observed state of Decofile.
properties:
Expand Down Expand Up @@ -160,6 +194,10 @@ spec:
githubCommit:
description: GitHubCommit stores the commit SHA if using GitHub source
type: string
jobName:
description: JobName is the K8s Job name for the current tanstack-kv
sync (target=tanstack-kv).
type: string
lastUpdated:
description: LastUpdated is the timestamp of the last update
format: date-time
Expand Down
28 changes: 28 additions & 0 deletions chart/templates/customresourcedefinition-decos.deco.sites.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,34 @@ spec:
required:
- source
type: object
fastDeploy:
description: |-
FastDeploy enables and configures git-driven, KV-first content fast-deploy
for this site. When Enabled, content-only pushes (touching only
.deco/blocks/**) sync to Cloudflare KV via a Decofile CR instead of a full
build/deploy. This is the per-site config the webhook's DeploymentTarget
reads to decide whether and how to fast-deploy.
properties:
enabled:
description: |-
Enabled gates the fast-deploy content path. When false, content pushes take
the normal build/deploy path.
type: boolean
kvNamespaceId:
description: |-
KVNamespaceID is the Cloudflare KV namespace id for this site (one per site).
Required when enabled (enforced via the XValidation rule on this struct).
type: string
siteOrigin:
description: |-
SiteOrigin is the deployed site origin used for cache purge after a sync
(e.g. https://www.example.com). Optional.
type: string
type: object
x-kubernetes-validations:
- message: kvNamespaceId is required when fastDeploy is enabled
rule: '!self.enabled || (has(self.kvNamespaceId) && size(self.kvNamespaceId)
> 0)'
framework:
description: Framework is the site framework. deno | tanstack | next
| remix | static
Expand Down
15 changes: 13 additions & 2 deletions chart/templates/deployment-operator-controller-manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ spec:
command:
- /manager
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
{{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) .Values.operatorApi.existingSecret (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.region .Values.s3.logsBucket .Values.s3.stateBucket .Values.build.serviceAccount .Values.build.roleArn .Values.build.nodeSelector .Values.build.tolerations }}
{{- if or (and .Values.github (or .Values.github.token .Values.github.existingSecret)) .Values.operatorApi.existingSecret (and .Values.valkey (get .Values.valkey "sentinelUrls")) .Values.cfworkers.existingSecret .Values.cfworkers.builderImage .Values.cfworkers.artifactsBucket .Values.s3.region .Values.s3.logsBucket .Values.s3.stateBucket .Values.build.serviceAccount .Values.build.roleArn .Values.build.nodeSelector .Values.build.tolerations (and .Values.fastDeploy .Values.fastDeploy.syncerImage) }}
env:
{{- if and .Values.github .Values.github.existingSecret }}
- name: GITHUB_TOKEN
Expand Down Expand Up @@ -131,19 +131,30 @@ spec:
value: {{ .tolerations | toJson | quote }}
{{- end }}
{{- end }}
{{- if and .Values.fastDeploy .Values.fastDeploy.syncerImage }}
- name: DECOFILE_SYNCER_IMAGE
value: {{ .Values.fastDeploy.syncerImage | quote }}
{{- end }}
{{- if .Values.operatorApi.existingSecret }}
{{- if .Values.operatorApi.addr }}
- name: OPERATOR_API_ADDR
value: {{ .Values.operatorApi.addr | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.operatorApi.existingSecret }}
{{- if or .Values.secretEnv.existingSecret .Values.operatorApi.existingSecret }}
envFrom:
{{- if .Values.secretEnv.existingSecret }}
- secretRef:
name: {{ .Values.secretEnv.existingSecret | quote }}
optional: true
{{- end }}
{{- if .Values.operatorApi.existingSecret }}
- secretRef:
name: {{ .Values.operatorApi.existingSecret | quote }}
optional: true
{{- end }}
{{- end }}
livenessProbe:
httpGet:
path: /healthz
Expand Down
18 changes: 18 additions & 0 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ build:
nodeSelector: {} # Default nodeSelector for build pods (overridable per-site via spec.build.nodeSelector)
tolerations: [] # Default tolerations for build pods (overridable per-site via spec.build.tolerations)

# ── Unified secret env ───────────────────────────────────────────────────────
# A single Secret whose KEYS ARE THE ENV VAR NAMES (e.g. CLOUDFLARE_API_WORKERS_TOKEN,
# CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_KV_API_TOKEN, GITHUB_TOKEN, GITHUB_APP_ID,
# GITHUB_APP_PRIVATE_KEY, GITHUB_WEBHOOK_SECRET, DECO_PURGE_TOKEN). Injected
# wholesale via envFrom, so adding a new secret env is just a new key on the
# backing ExternalSecret — no chart change. Preferred over the per-feature
# existingSecret knobs above; those still work when set (and win, being explicit env).
secretEnv:
existingSecret: ""

# ── Fast deploy (KV-first content) ───────────────────────────────────────────
# Git-webhook → Decofile CR → self-cleaning KV-sync Job. The webhook/KV/GitHub-App
# secrets come from secretEnv above (GITHUB_WEBHOOK_SECRET enables the endpoint;
# the operator-api controller must also be enabled). Only the non-secret syncer
# image lives here.
fastDeploy:
syncerImage: "" # decofile-syncer image (repository:tag) → DECOFILE_SYNCER_IMAGE

# ── Operator Management API ──────────────────────────────────────────────────
# General HTTP API for managing operator resources (DecoRedirects, etc.).
# Enabled when username+password (or existingSecret) are set.
Expand Down
Loading
Loading