Skip to content

Commit 8aa496f

Browse files
committed
fix: clean up .gitignore and implement report writing
1 parent e51ea17 commit 8aa496f

14 files changed

Lines changed: 744 additions & 7 deletions

File tree

cmd/validate.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,20 @@ func runValidate() error {
182182
}
183183
}
184184

185-
// Output for CI (GITHUB_OUTPUT)
186-
// We can write to a file or stdout?
187-
// The validation pipeline expects 'diff_output' and 'has_drift' outputs.
188-
// Ideally this command outputs the report to stdout?
189-
// But we are also logging info.
190-
// Maybe we write the REPORT to a file if requested? --output-file?
191-
// For now, let's print the usage instruction for the user.
185+
// Output Report
186+
if validateReportFile != "" {
187+
if totalDiff == "" {
188+
totalDiff = "No drift detected."
189+
}
190+
if err := os.WriteFile(validateReportFile, []byte(totalDiff), 0644); err != nil {
191+
fmt.Fprintf(os.Stderr, "ERROR: Failed to write report: %v\n", err)
192+
}
193+
} else {
194+
// If no file, print report to stdout (if not empty)
195+
if totalDiff != "" {
196+
fmt.Println(totalDiff)
197+
}
198+
}
192199

193200
if hasDrift {
194201
return fmt.Errorf("Validation failed: Drift detected.")

demos/gitops-validation/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# GitOps Validation Demos
2+
3+
This directory contains step-by-step tutorials for implementing **GitOps Validation** using Kalco.
4+
5+
**Philosophy**: These demos are designed to be "Drop-in". They assume you want validation *without* maintaining a persistent "Reality Repo". The pipeline creates a temporary snapshot during the check.
6+
7+
## Scenarios
8+
9+
1. **[Raw Resources](./raw-resources/README.md)**
10+
* **Best for:** Deployments using plain Kubernetes YAML manifests (Deployment, Service, etc.).
11+
* **How to use:** Copy the folder contents (`manifests`, `.github`) to your repo.
12+
13+
2. **[Helm Charts](./helm/README.md)**
14+
* **Best for:** Deployments managed via Helm Charts.
15+
* **How to use:** Copy the folder contents (`chart`, `.github`) to your repo.
16+
17+
All you need is to set the `KUBECONFIG` secret in your repository.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Kalco Helm Validation
2+
3+
on:
4+
pull_request:
5+
branches: [ master ]
6+
paths:
7+
- 'chart/**'
8+
9+
jobs:
10+
validate-drift:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
pull-requests: write
15+
steps:
16+
- name: Checkout Source Code
17+
uses: actions/checkout@v3
18+
19+
- name: Install Tools
20+
run: |
21+
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
22+
# Install Kalco
23+
curl -sL https://github.com/graz-dev/kalco/releases/download/v0.1.19/kalco_Linux_x86_64.tar.gz | tar xz
24+
sudo mv kalco /usr/local/bin/
25+
26+
- name: Configure Kalco
27+
env:
28+
KUBECONFIG_DATA: ${{ secrets.KUBECONFIG }}
29+
run: |
30+
# Configure Git for Kalco's internal git operations
31+
git config --global user.email "ci-bot@kalco.dev"
32+
git config --global user.name "Kalco CI Bot"
33+
34+
mkdir -p ~/.kube
35+
echo "$KUBECONFIG_DATA" | base64 -d > ~/.kube/config
36+
37+
mkdir -p tmp-snapshot
38+
39+
kalco context set validation-ctx \
40+
--kubeconfig ~/.kube/config \
41+
--output $(pwd)/tmp-snapshot
42+
43+
kalco context use validation-ctx
44+
45+
- name: Snapshot Live State
46+
run: |
47+
kalco export
48+
49+
- name: Render & Diff
50+
id: kalco-diff
51+
run: |
52+
# Fetch base branch for comparison
53+
git fetch origin ${{ github.base_ref }}
54+
55+
mkdir -p generated-manifests
56+
57+
# 1. Render PR version (Chart at current state)
58+
helm template my-release chart --namespace guestbook-helm > generated-manifests/pr-all.yaml
59+
60+
# 2. Render Base version (Chart at base branch state)
61+
# We need to extract the chart files from the base branch to a temp dir?
62+
# Or easier: checkout base to temp dir and render there.
63+
mkdir -p base-chart-source
64+
git archive origin/${{ github.base_ref }} chart | tar -x -C base-chart-source
65+
66+
# Check if chart existed in base
67+
IGNORE_BASE_FLAG=""
68+
if [ -d "base-chart-source/chart" ]; then
69+
helm template my-release base-chart-source/chart --namespace guestbook-helm > generated-manifests/base-all.yaml
70+
if [ -s generated-manifests/base-all.yaml ]; then
71+
IGNORE_BASE_FLAG="--ignore-base generated-manifests/base-all.yaml"
72+
fi
73+
fi
74+
75+
TOTAL_DIFF=""
76+
HAS_DRIFT="false"
77+
78+
echo "Comparing generated manifests against snapshot..."
79+
80+
# Use Kalco Diff directly on the multi-doc generated file
81+
# Pass --ignore-base pointing to the base render
82+
OUTPUT=$(kalco --no-color diff --target generated-manifests/pr-all.yaml --snapshot-dir tmp-snapshot --format markdown $IGNORE_BASE_FLAG --ignore-extra-fields || true)
83+
84+
if [ -n "$OUTPUT" ]; then
85+
echo "Diff Output for all.yaml:"
86+
echo "$OUTPUT"
87+
88+
TOTAL_DIFF+=$'\n'"#### Helm Difference Report"$'\n'"$OUTPUT"$'\n'
89+
90+
if echo "$OUTPUT" | grep -q "Drift Detected"; then
91+
HAS_DRIFT="true"
92+
echo "!!! CRITICAL: DRIFT DETECTED !!!"
93+
fi
94+
fi
95+
96+
echo "has_drift=$HAS_DRIFT" >> $GITHUB_OUTPUT
97+
98+
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
99+
echo "diff_output<<$EOF" >> $GITHUB_OUTPUT
100+
echo "$TOTAL_DIFF" >> $GITHUB_OUTPUT
101+
echo "$EOF" >> $GITHUB_OUTPUT
102+
103+
- name: Comment PR & Label
104+
uses: actions/github-script@v6
105+
env:
106+
DIFF_OUTPUT: ${{ steps.kalco-diff.outputs.diff_output }}
107+
HAS_DRIFT: ${{ steps.kalco-diff.outputs.has_drift }}
108+
with:
109+
github-token: ${{ secrets.GITHUB_TOKEN }}
110+
script: |
111+
const output = process.env.DIFF_OUTPUT;
112+
const hasDrift = process.env.HAS_DRIFT === 'true';
113+
114+
if (!output || output.trim() === "") {
115+
console.log("No output to comment.");
116+
return;
117+
}
118+
119+
const labelAdd = hasDrift ? 'kalco/deny' : 'kalco/approve';
120+
const labelRemove = hasDrift ? 'kalco/approve' : 'kalco/deny';
121+
122+
await github.rest.issues.createComment({
123+
issue_number: context.issue.number,
124+
owner: context.repo.owner,
125+
repo: context.repo.repo,
126+
body: `### 🛡️ Kalco Helm Validation Report\n\n${output}`
127+
});
128+
129+
try {
130+
await github.rest.issues.removeLabel({
131+
issue_number: context.issue.number,
132+
owner: context.repo.owner,
133+
repo: context.repo.repo,
134+
name: labelRemove
135+
});
136+
} catch (e) {}
137+
138+
await github.rest.issues.addLabels({
139+
issue_number: context.issue.number,
140+
owner: context.repo.owner,
141+
repo: context.repo.repo,
142+
labels: [labelAdd]
143+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# GitOps Validation with Kalco: Helm Charts
2+
3+
This tutorial shows how to validate Helm Chart changes against your live cluster using Kalco.
4+
5+
## Prerequisites
6+
7+
- [ ] Kubernetes Cluster & ArgoCD.
8+
- [ ] **One GitHub Repository**: This contains your chart and pipeline.
9+
- [ ] **Secrets** configured: `KUBECONFIG`.
10+
11+
## Setup
12+
13+
### 1. Install ArgoCD (if not installed)
14+
15+
```bash
16+
kubectl create namespace argocd
17+
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
18+
19+
# Wait for ArgoCD to be ready
20+
kubectl wait --for=condition=available deployment -l "app.kubernetes.io/name=argocd-server" -n argocd --timeout=300s
21+
```
22+
23+
### 2. Copy Files
24+
Copy the contents of this folder (`chart/`, `.github/`, `argocd/`) to the **root** of your repository.
25+
26+
### 3. Configure Secret
27+
Add `KUBECONFIG` to your repo secrets.
28+
29+
### 4. Deploy App
30+
Apply `argocd/application.yaml` (edit the repoURL first!).
31+
32+
## Workflow Overview
33+
34+
1. **Snapshot**: Kalco exports the live state to a temporary directory (`./tmp-snapshot`).
35+
2. **Render**: `helm template` generates manifests from your local chart code.
36+
3. **Split & Diff**: The rendered manifests are split and compared against the temporary snapshot.
37+
38+
## Command Reference
39+
40+
```bash
41+
# Workflow logic roughly equivalent to:
42+
kalco context set validation-ctx --output ./tmp-snapshot --kubeconfig ...
43+
kalco export
44+
helm template . > all.yaml
45+
kalco diff --target <split-file> --snapshot-dir ./tmp-snapshot
46+
```
47+
48+
## Usage
49+
50+
1. Change a value in `chart/values.yaml` (e.g., replica count).
51+
2. Open a PR.
52+
3. The pipeline will detect if your change conflicts with the live state.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: argoproj.io/v1alpha1
2+
kind: Application
3+
metadata:
4+
name: guestbook-helm
5+
namespace: argocd
6+
spec:
7+
project: default
8+
source:
9+
repoURL: https://github.com/YOUR_USERNAME/gitops-validation-demo # Users will update this
10+
targetRevision: HEAD
11+
path: chart
12+
helm:
13+
valueFiles:
14+
- values.yaml
15+
destination:
16+
server: https://kubernetes.default.svc
17+
namespace: guestbook-helm
18+
syncPolicy:
19+
automated:
20+
selfHeal: false
21+
prune: true
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v2
2+
name: guestbook
3+
description: A Helm chart for the Guestbook application
4+
type: application
5+
version: 0.1.0
6+
appVersion: "1.16.0"

0 commit comments

Comments
 (0)