From 02280a19159c2d01009524bda50bb82fbfc659b0 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:46:04 +0000 Subject: [PATCH 1/8] feat: add omni/talos-image.yaml version ledger placeholder --- omni/talos-image.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 omni/talos-image.yaml diff --git a/omni/talos-image.yaml b/omni/talos-image.yaml new file mode 100644 index 0000000..9d8cc88 --- /dev/null +++ b/omni/talos-image.yaml @@ -0,0 +1,6 @@ +# Auto-updated by talos-images workflow — do not edit manually +talos_version: v1.9.0 +kubernetes_version: v1.32.3 +schematic_id: "" +oci_image_ocid: "" +updated_at: "" From bb600e3b1599dc5f4a4bfa17a5509c1202ee9e39 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:47:47 +0000 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20add=20spec.installImage=20to=20mach?= =?UTF-8?q?ine=20classes=20(placeholder=20=E2=80=94=20updated=20by=20autom?= =?UTF-8?q?ation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- omni/machine-classes/control-plane.yaml | 1 + omni/machine-classes/worker.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/omni/machine-classes/control-plane.yaml b/omni/machine-classes/control-plane.yaml index 1bf8a62..31071a0 100644 --- a/omni/machine-classes/control-plane.yaml +++ b/omni/machine-classes/control-plane.yaml @@ -4,6 +4,7 @@ metadata: id: oci-cp spec: + installImage: ghcr.io/syscode-labs/talos-images/installer:v1.9.0 matchLabels: # Applied manually in Omni UI after OCI nodes connect via SideroLink. # omnictl machine set-labels role=oci-cp diff --git a/omni/machine-classes/worker.yaml b/omni/machine-classes/worker.yaml index 126b700..ebdfc54 100644 --- a/omni/machine-classes/worker.yaml +++ b/omni/machine-classes/worker.yaml @@ -4,6 +4,7 @@ metadata: id: oci-worker spec: + installImage: ghcr.io/syscode-labs/talos-images/installer:v1.9.0 matchLabels: # Applied manually in Omni UI after OCI nodes connect via SideroLink. # omnictl machine set-labels role=oci-worker From 0d8645961c7627c9b1549fbb1a7895da3a308459 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:49:38 +0000 Subject: [PATCH 3/8] chore: add yamllint config (120 char line limit) --- .yamllint.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .yamllint.yml diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..80f1fca --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,11 @@ +extends: default + +rules: + line-length: + max: 120 + level: warning + truthy: + allowed-values: ["true", "false"] + check-keys: false + comments: + min-spaces-from-content: 1 From 318aefa4ab48251281a67f4d3081ebc82c3324a4 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:50:48 +0000 Subject: [PATCH 4/8] feat: add CI workflow (yamllint, gitleaks, kubeconform, helm lint, pluto, markdownlint) --- .github/workflows/ci.yml | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a3e9bdc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,116 @@ +name: CI + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + yamllint: + name: YAML lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: pip install yamllint --quiet + - run: yamllint -c .yamllint.yml . + + secrets: + name: Secrets detection + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + kubeconform: + name: Kubernetes manifest validation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install kubeconform + run: | + curl -sL https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz \ + | tar -xz -C /usr/local/bin kubeconform + + - name: Validate Kubernetes manifests + run: | + find bootstrap infrastructure clusters -name '*.yaml' -o -name '*.yml' 2>/dev/null \ + | xargs kubeconform \ + -strict \ + -ignore-missing-schemas \ + -summary + + helm-lint: + name: Helm lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: "3.17.0" + + - name: Add chart repositories + run: | + helm repo add cilium https://helm.cilium.io + helm repo add jetstack https://charts.jetstack.io + helm repo add argo https://argoproj.github.io/argo-helm + helm repo update + + - name: Lint Cilium chart + run: | + CHART_VERSION=$(grep 'targetRevision:' infrastructure/cilium/application.yaml | head -1 | awk '{print $2}' | tr -d '"') + helm pull cilium/cilium --version "$CHART_VERSION" --untar --untardir /tmp/charts + helm lint /tmp/charts/cilium --values infrastructure/cilium/values.yaml + + - name: Lint cert-manager chart + run: | + CHART_VERSION=$(grep 'targetRevision:' infrastructure/cert-manager/application.yaml | head -1 | awk '{print $2}' | tr -d '"') + helm pull jetstack/cert-manager --version "$CHART_VERSION" --untar --untardir /tmp/charts + helm lint /tmp/charts/cert-manager --values infrastructure/cert-manager/values.yaml + + pluto: + name: API deprecation check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Read target Kubernetes version + id: k8s + run: | + K8S_VERSION=$(grep '^kubernetes_version:' omni/talos-image.yaml | awk '{print $2}') + echo "version=${K8S_VERSION}" >> "$GITHUB_OUTPUT" + echo "Checking against Kubernetes ${K8S_VERSION}" + + - name: Install pluto + run: | + curl -sL https://github.com/FairwindsOps/pluto/releases/latest/download/pluto_linux_amd64.tar.gz \ + | tar -xz -C /usr/local/bin pluto + + - name: Check for deprecated APIs + run: | + pluto detect-files \ + --directory . \ + --target-versions "k8s=${{ steps.k8s.outputs.version }}" \ + --ignore-deprecations \ + --output wide + + markdownlint: + name: Markdown lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20" + - run: npm install -g markdownlint-cli2 + - run: markdownlint-cli2 "**/*.md" "#node_modules" From a1c464d5f9445e21f4d270905f07d17a2e2e14e6 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:54:38 +0000 Subject: [PATCH 5/8] fix: resolve pluto version dynamically, robust helm chart version extraction Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3e9bdc..40b48a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,13 +68,23 @@ jobs: - name: Lint Cilium chart run: | - CHART_VERSION=$(grep 'targetRevision:' infrastructure/cilium/application.yaml | head -1 | awk '{print $2}' | tr -d '"') + CHART_VERSION=$(python3 -c " + import yaml + doc = yaml.safe_load(open('infrastructure/cilium/application.yaml')) + srcs = doc['spec']['sources'] + print(next(s['targetRevision'] for s in srcs if 'chart' in s)) + ") helm pull cilium/cilium --version "$CHART_VERSION" --untar --untardir /tmp/charts helm lint /tmp/charts/cilium --values infrastructure/cilium/values.yaml - name: Lint cert-manager chart run: | - CHART_VERSION=$(grep 'targetRevision:' infrastructure/cert-manager/application.yaml | head -1 | awk '{print $2}' | tr -d '"') + CHART_VERSION=$(python3 -c " + import yaml + doc = yaml.safe_load(open('infrastructure/cert-manager/application.yaml')) + srcs = doc['spec']['sources'] + print(next(s['targetRevision'] for s in srcs if 'chart' in s)) + ") helm pull jetstack/cert-manager --version "$CHART_VERSION" --untar --untardir /tmp/charts helm lint /tmp/charts/cert-manager --values infrastructure/cert-manager/values.yaml @@ -93,7 +103,9 @@ jobs: - name: Install pluto run: | - curl -sL https://github.com/FairwindsOps/pluto/releases/latest/download/pluto_linux_amd64.tar.gz \ + PLUTO_VERSION=$(curl -sf https://api.github.com/repos/FairwindsOps/pluto/releases/latest \ + | grep '"tag_name"' | cut -d'"' -f4) + curl -sL "https://github.com/FairwindsOps/pluto/releases/download/${PLUTO_VERSION}/pluto_${PLUTO_VERSION#v}_linux_amd64.tar.gz" \ | tar -xz -C /usr/local/bin pluto - name: Check for deprecated APIs From 9b542f6ec5f2e411ed4ff7d1b72a08e122af9386 Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:56:02 +0000 Subject: [PATCH 6/8] fix: guard pluto version resolution, use -f on download curl Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40b48a5..b06de1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,11 @@ jobs: run: | PLUTO_VERSION=$(curl -sf https://api.github.com/repos/FairwindsOps/pluto/releases/latest \ | grep '"tag_name"' | cut -d'"' -f4) - curl -sL "https://github.com/FairwindsOps/pluto/releases/download/${PLUTO_VERSION}/pluto_${PLUTO_VERSION#v}_linux_amd64.tar.gz" \ + if [[ -z "$PLUTO_VERSION" ]]; then + echo "ERROR: failed to resolve pluto version" >&2 + exit 1 + fi + curl -sfL "https://github.com/FairwindsOps/pluto/releases/download/${PLUTO_VERSION}/pluto_${PLUTO_VERSION#v}_linux_amd64.tar.gz" \ | tar -xz -C /usr/local/bin pluto - name: Check for deprecated APIs From c0dcacedde0db14003bfd87120cc25ad34e5e76e Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 02:56:46 +0000 Subject: [PATCH 7/8] chore: add pre-commit config matching CI checks --- .pre-commit-config.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9b4985b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +repos: + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - id: yamllint + args: [-c, .yamllint.yml] + + - repo: https://github.com/gitleaks/gitleaks + rev: v8.21.2 + hooks: + - id: gitleaks + + - repo: https://github.com/yannh/kubeconform + rev: v0.6.7 + hooks: + - id: kubeconform + args: + - -strict + - -ignore-missing-schemas + - -summary + + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.44.0 + hooks: + - id: markdownlint + args: ["--ignore", "node_modules"] From 68bcf872915b21772b7456934a31db12b41e7e2b Mon Sep 17 00:00:00 2001 From: Giovanni Ferri Date: Mon, 16 Mar 2026 12:14:21 +0000 Subject: [PATCH 8/8] fix: gitleaks CLI (no license needed), exclude values.yaml from kubeconform, fix markdownlint --- .github/workflows/ci.yml | 14 ++++++++++---- .markdownlint-cli2.yaml | 2 ++ README.md | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 .markdownlint-cli2.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b06de1d..51cc282 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,14 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: gitleaks/gitleaks-action@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install gitleaks + run: | + GITLEAKS_VERSION=$(curl -sf https://api.github.com/repos/gitleaks/gitleaks/releases/latest \ + | grep '"tag_name"' | cut -d'"' -f4) + curl -sfL "https://github.com/gitleaks/gitleaks/releases/download/${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION#v}_linux_x64.tar.gz" \ + | tar -xz -C /usr/local/bin gitleaks + - name: Detect secrets + run: gitleaks detect --source . --redact kubeconform: name: Kubernetes manifest validation @@ -42,7 +47,8 @@ jobs: - name: Validate Kubernetes manifests run: | - find bootstrap infrastructure clusters -name '*.yaml' -o -name '*.yml' 2>/dev/null \ + find bootstrap infrastructure clusters \( -name '*.yaml' -o -name '*.yml' \) \ + ! -name 'values.yaml' ! -name 'values.yml' 2>/dev/null \ | xargs kubeconform \ -strict \ -ignore-missing-schemas \ diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 0000000..e8270d9 --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,2 @@ +config: + MD013: false # line-length: URLs and long paths make this impractical diff --git a/README.md b/README.md index 52cc4dd..294dc8c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ On first boot, the App-of-Apps in `bootstrap/argocd-app-of-apps.yaml` is applied ## Structure -``` +```text bootstrap/ App-of-Apps + manually bootstrapped apps (Argo CD, Tailscale operator) infrastructure/ Helm charts + values, one directory per app clusters/oci/ Cluster-specific kustomize patches