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
50 changes: 50 additions & 0 deletions .github/workflows/secrets.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: secrets

# Server-side complement to the gitleaks pre-commit hook in .pre-commit-config.yaml.
# Uses the MIT-licensed gitleaks CLI directly rather than the gitleaks-action
# wrapper (which requires a paid license for org-owned repos as of v2).
#
# Why both pre-commit AND this:
# - Pre-commit runs locally and is bypassable (`git commit --no-verify`),
# skippable (if `pre-commit install` was never run), and doesn't fire for
# commits authored via the GitHub web UI, mobile app, or REST API.
# - This workflow runs in CI on every PR + push, can be enforced via branch
# protection ("required check"), and is the last line before merge.
# - Same engine, same rules — different enforcement surface.
#
# To bump gitleaks: edit GITLEAKS_VERSION below.

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

env:
GITLEAKS_VERSION: "8.30.1"

jobs:
gitleaks:
name: gitleaks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Fetch the full history so gitleaks scans every commit in the PR,
# not just the tip. Catches secrets that were committed and later
# "deleted" without being rotated.
fetch-depth: 0

- name: Install gitleaks
run: |
curl -sfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| sudo tar -xz -C /usr/local/bin gitleaks
gitleaks version

- name: Scan repo history
# --redact : redact secret values in the output (don't leak them into CI logs)
# --verbose : per-commit progress (helpful when something fails)
# --no-banner : skip the ASCII art banner
run: gitleaks detect --redact --verbose --no-banner
58 changes: 58 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: validate

# Pre-merge validation: yamllint, kustomize rendering, kubeconform, shellcheck.
# Calls the same script developers can run locally — see ci/validate.sh and
# the README "Optional, for running CI checks locally" line in Prerequisites.
#
# Tool versions are pinned via env vars below — bump them as needed.

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

env:
KUSTOMIZE_VERSION: "5.8.1"
KUBECONFORM_VERSION: "0.7.0"
HELM_VERSION: "v3.16.0"

jobs:
manifests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.x'
- run: pip install --quiet yamllint

- name: Install kustomize
# Direct download from a pinned release. (The kubernetes-sigs
# `install_kustomize.sh` script does its own discovery and is flaky
# under GitHub API rate limits — we pin instead.) The release tag is
# `kustomize/v<version>`, so the slash is URL-encoded as `%2F`.
run: |
curl -sfL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz" \
| sudo tar -xz -C /usr/local/bin kustomize
kustomize version

# helm is required for kustomize's `--enable-helm` flag (renders the
# helmCharts: block in manifests/quine-enterprise/).
- uses: azure/setup-helm@v4
with:
version: ${{ env.HELM_VERSION }}

- name: Install kubeconform
run: |
curl -sfL "https://github.com/yannh/kubeconform/releases/download/v${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz" \
| sudo tar -xz -C /usr/local/bin kubeconform
kubeconform -v

# shellcheck is pre-installed on ubuntu-latest runners.

- name: Run validation
run: ./ci/validate.sh
27 changes: 27 additions & 0 deletions .yamllint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# yamllint config — relaxed preset, with rules tuned for this repo.
#
# We disable line-length because Kustomize patches, Helm values, and operator
# CRs commonly carry long URLs or composite identifiers. We disable
# `truthy.check-keys` because Kubernetes manifests use `on:` (workflow trigger)
# and similar field names that yamllint would otherwise flag.
#
# What still fires (and should):
# - syntax errors
# - duplicate keys
# - inconsistent indentation
# - trailing whitespace
# - missing document start where required by surrounding context

extends: relaxed

rules:
line-length: disable
truthy:
check-keys: false

ignore: |
charts/
**/charts/
tmp/
temp/
.pre-commit-cache/
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ export THATDOT_REGISTRY_USERNAME="..."
export THATDOT_REGISTRY_PASSWORD="..."
```

Optional — for reproducing the CI validation checks locally before pushing (`./ci/validate.sh` runs the same checks `.github/workflows/validate.yml` runs):

```bash
brew install yamllint shellcheck kustomize helm kubeconform
```

## First-time setup

```bash
Expand Down
82 changes: 82 additions & 0 deletions ci/validate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
set -uo pipefail

# Validates the manifest tree, Kustomize rendering, and helper scripts.
# Same checks the .github/workflows/validate.yml workflow runs — install the
# tools locally and you can reproduce CI before pushing.
#
# Tools required:
# yamllint, shellcheck, kustomize, helm, kubeconform
#
# macOS install:
# brew install yamllint shellcheck kustomize helm kubeconform
#
# Usage: ./ci/validate.sh

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_DIR" || exit 1

# ---- Tool check ----
missing=()
for tool in yamllint shellcheck kustomize helm kubeconform; do
command -v "$tool" >/dev/null 2>&1 || missing+=("$tool")
done
if [[ ${#missing[@]} -gt 0 ]]; then
echo "ERROR: missing required tools: ${missing[*]}"
echo " macOS install: brew install ${missing[*]}"
exit 1
fi

# Run all checks, collecting failures rather than aborting on the first one —
# so the developer sees the full picture in a single run.
failed=()

# Note on `--ignore-missing-schemas`:
# kubeconform validates against built-in Kubernetes schemas only. Custom
# resources (ArgoCD Application, OLM Subscription/OperatorGroup, OpenShift
# Route, CassandraDatacenter, Keycloak, KeycloakRealmImport) are skipped
# rather than failed. To close the gap, pre-download the schemas we want
# from https://github.com/datreeio/CRDs-catalog into ci/schemas/ and add
# --schema-location flags pointing at the local paths. kubeconform v0.7.0
# doesn't expose a `lower` template fn, so the catalog can't be referenced
# by URL directly (datreeio's filenames are lowercase; {{.ResourceKind}}
# renders PascalCase). Future work.

echo "==> yamllint"
yamllint . || failed+=("yamllint")

echo ""
echo "==> shellcheck scripts/*.sh ci/*.sh"
shellcheck scripts/*.sh ci/*.sh || failed+=("shellcheck")

echo ""
echo "==> kubeconform bootstrap/*.yaml"
# argocd-customizations.yaml is a patch payload (no apiVersion/kind/metadata),
# not a complete manifest — kubeconform would correctly reject it. Skip.
for f in bootstrap/*.yaml; do
case "$f" in
bootstrap/argocd-customizations.yaml) continue ;;
esac
echo " --- $f ---"
if ! kubeconform --strict --ignore-missing-schemas --summary "$f"; then
failed+=("$f")
fi
done

echo ""
echo "==> kustomize + kubeconform per leaf"
for leaf in manifests/root manifests/platform manifests/product manifests/cassandra manifests/keycloak manifests/quine-enterprise; do
echo " --- $leaf ---"
if ! kustomize build --enable-helm "$leaf" \
| kubeconform --strict --ignore-missing-schemas --summary; then
failed+=("$leaf")
fi
done

echo ""
if [[ ${#failed[@]} -gt 0 ]]; then
echo "FAILED: ${failed[*]}"
exit 1
fi
echo "All checks passed."
Loading