Repository navigation
feat: CUE GitOps template with Flux/Argo delivery and alpha-01 Talos cluster - #19
Merged
Merged
Conversation
…setup Remove argocd, crossplane, gitops and generated cue.mod definitions, trim the devshell to the tools in use and switch pre-commit hooks from the stale hercules-ci flakeModule branch to cachix/git-hooks.nix, which provides the cue-fmt and zizmor hooks.
Talos v1.14 multi-document config patches and a gen.sh that renders controlplane.yaml/talosconfig into .secrets/talos/alpha-01: - install to the SATA SSD via UnattendedInstallConfig, EPHEMERAL capped at 64GiB, the rest of the disk as the local-storage user volume - dual-stack (IPv6 primary): node IP and API endpoint on the Starlink ULA prefix, IPv4 stays on DHCP - no Flannel, kube-proxy or discovery; workloads on the control plane - Cilium 1.20 values: native routing, netkit, BPF host routing and masquerade, kube-proxy replacement, node IPAM LoadBalancer
Components are defined once in apps/base and rendered either as a Flux
source + HelmRelease or as an Argo CD Application; apps/bundles wires
them with flex (Renovate) and stable version channels, clusters/<name>
picks a channel, pins and overrides.
Each cluster renders a bootstrap project plus flux and argo artifacts.
A committed release layer (releases.json -> release/{flux,argo}) pins
the artifacts by digest and is what the FluxInstance syncs, so no
cluster follows latest. SOPS-encrypted secrets ship in the flux
artifact. alpha-01's Talos config moves under clusters/alpha-01/talos.
Components live in apps/<x> and each cluster lists what it runs. Versions come from apps/registry/latest.json (channel fast) with clusters/<name>/pins.json on top, or from pins only (channel stable).
- integration: nix checks, cue vet, release-layer sync, Talos validation, per-project manifest diff comments, final-check gate - publish: content-addressed artifacts to GHCR, cosign keyless signing, release PR per cluster with optional auto-merge - flake updates and Renovate with auto-merge, Pin workflow for stable-channel clusters, weekly GHCR cleanup keeping pinned digests
- cue cmd versions exposes what each cluster resolves; scripts/promote.sh and the Promote workflow copy versions from latest.json or another cluster into a target's pins.json (replaces the Pin workflow) - config.publish: clusters without it are rendered and diffed in PRs but get no artifacts or release PRs - beta-01: different component set, IPv4-only, stable channel with older pinned versions
#Cluster carries version resolution, rendering, the release layer and projects; #Core (flux-operator, Cilium, Argo CD) and #Homelab (+ cert- manager, local-path, whoami) are reusable component sets. Clusters unify one with config, pins and releases and add or override on top.
Promotion now lives next to version resolution in CUE: it reads the source versions (latest.json or another cluster) and the target's pins, writes pins.json keeping key order and prints what changed. An explicit component list can add pins the target does not have yet.
Like etherno-infra projects: config.sets defines the sets of a cluster, each rendered and published as its own artifact <cluster>-<set> with its own releases.json entry, release and rollback. A set's controller decides the wrapper of its components (replaces the per-component controller); set dependsOn becomes Kustomization dependsOn, and Argo sets wait for the Flux sets they need. Defaults: system (Flux) and apps (Argo, after system). SOPS secrets move to secrets/<set>/ and are limited to Flux sets.
Owner
Author
|
retrigger |
Contributor
Manifests diff:
|
Contributor
Manifests diff:
|
Contributor
Manifests diff:
|
Contributor
Manifests diff:
|
Contributor
Manifests diff:
|
Contributor
Manifests diff:
|
- nix/overlay.nix pins CUE v0.18.0-rc.1 from the upstream release tarball (devshell, CI, treefmt and pre-commit) until v0.18.0 reaches nixpkgs - language.version v0.18.0: aliasv2 and explicitopen are stable, their attributes go; try is unused, so no file needs an experiment - tree reformatted by the v0.18 cue fmt (formatv2) - ext_tool.cue marshals each object instead of copying them into a list for yaml.MarshalStream (CUE never structure-shares a list comprehension body), as in etherno-infra Every (cluster, project) render is the same set of objects as on v0.17.1; the release layer is byte-identical.
…jects - each branch renders with its own devshell (its CUE) and scripts, so a CUE upgrade in a PR never evaluates the base with the new binary - .github/split-manifests.py (from etherno-infra) lays out only the objects that differ, one normalized file per <namespace>/<kind>/<name> with sorted keys; Python + PyYAML join the CI devshell - every workflow runs on ubuntu-26.04
- cue-expert rewritten for this repo: status of every CUE experiment at v0.18, which would help here, v0.18 pitfalls, scope traps, manifest typing, comparing renders as objects - crd-generation: no experiment header, strip-matchn step - scripts/crd/strip-matchn.py from etherno-infra for future CRDs - CLAUDE.md: experiment rules, CUE pin, render comparison
…etherno-infra) - integration: narrow the diff matrix to the clusters whose inputs changed (shared inputs keep the full matrix, docs/Talos/release layer render nothing); run on merge_group in render-only mode; GOGC=200 - publish: SLSA provenance attestation next to the cosign signature; GHCR cleanup keeps .att tags with their artifact - cue-compat: manual vet + render of every project on another CUE release before moving the pin - renovate: hourly limit, timestamp-optional soak, immediate security PRs, assignee - .github/CLAUDE.md: CI context and workflow security rules
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebuilds the repo as a reusable CUE GitOps template for Talos clusters: manifests are rendered in CI, published to GHCR as signed OCI artifacts and delivered by Flux (platform) and Argo CD (user apps). Old ArgoCD/Crossplane/gitops manifests are removed.
Layout
apps/<category>/<component>: each component defined once (chart, values, manifests). Initial set: flux-operator + FluxInstance, Cilium, cert-manager, local-path-provisioner, headless Argo CD (no UI/Dex/notifications/ApplicationSet), whoami example.clusters/defaults.cue: shared cluster definitions#Core/#Homelab(version resolution, rendering, release layer).clusters/<cluster>/: config, extra components and overrides,pins.json,releases.json, generatedrelease/, SOPSsecrets/<set>/, Talos config.alpha-01: the Beelink single-node cluster (dual-stack, IPv6 primary, Cilium native routing + netkit, nodeIPAM).beta-01: manifest-only example (publish: false) with a different component set, IPv4-only, stable channel with older pins.Sets, versions, releases
system(Flux) andapps(Argo, aftersystem) by default. Each set is its own artifact<cluster>-<set>, release and rollback.apps/registry/latest.json(Renovate) → per-clusterpins.json. Channelfast= latest with pins on top,stable= pins only.cue cmd promote -t to=… -t from=<latest|cluster>and the Promote workflow move versions between clusters.latestanywhere: content-addressed artifacts, a committed release layer pins them by digest (cosign-verified by Flux); publishing opens a release PR per cluster (auto-merge for alpha-01); rollback = revert.CI
final-checkgate.flake.lock.Before/after merge
See
docs/bootstrap.md: GitHub App (APP_CLIENT_ID/APP_PRIVATE_KEY), Renovate app, auto-merge + ruleset requiringfinal-check, make GHCR packages public after the first publish, then bootstrap the cluster (sops-age secret, flux-operator,cue cmd dump -t project=bootstrap).Not yet verified live: helm-controller adopting the hand-installed Cilium release, Argo CD accepting a digest
targetRevisionfor OCI sources.🤖 Generated with Claude Code