Initial commit
Label Sync / Label Sync (push) Failing after 1m7s
E2E / reject-invalid (bad-bgp-asn) (push) Skipped
E2E / reject-invalid (bad-mac-address) (push) Skipped
E2E / reject-invalid (bad-repo-url) (push) Skipped
E2E / reject-invalid (bad-vlan-tag) (push) Skipped
E2E / reject-invalid (duplicate-gateway-addrs) (push) Skipped
E2E / reject-invalid (duplicate-node-names) (push) Skipped
E2E / reject-invalid (gateway-node-collision) (push) Skipped
E2E / reject-invalid (missing-dns-token) (push) Skipped
E2E / reject-invalid (nested-cidr-overlap) (push) Skipped
E2E / reject-invalid (node-addr-outside-cidr) (push) Skipped
E2E / reject-invalid (tunnel-without-dns) (push) Skipped
E2E / accept-valid (selfhosted) (push) Skipped
E2E / reject-invalid (missing-known-hosts) (push) Skipped
E2E / reject-invalid (missing-schematic) (push) Skipped
E2E / reject-invalid (partial-bgp) (push) Skipped
E2E / accept-valid (internal) (push) Skipped
E2E / reject-invalid (missing-external-gateway) (push) Skipped
E2E / reject-invalid (node-uses-gateway-addr) (push) Skipped
E2E / reject-invalid (non-canonical-cidr) (push) Skipped
E2E / accept-valid (private) (push) Skipped
E2E / accept-valid (single-node) (push) Skipped
E2E / reject-invalid (overlapping-cidrs) (push) Skipped
E2E / reject-invalid (reserved-node-name) (push) Skipped
E2E / reject-invalid (tiny-svc-cidr) (push) Skipped
E2E / validator-tests (push) Skipped
E2E / accept-valid (direct) (push) Skipped
E2E / accept-valid (multi-controller) (push) Skipped
E2E / accept-valid (no-webhook) (push) Skipped
E2E / accept-valid (public) (push) Skipped

This commit is contained in:
2026-09-15 22:21:43 +03:00
committed by GitHub
commit e502e0ff76
171 changed files with 7520 additions and 0 deletions
+182
View File
@@ -0,0 +1,182 @@
set quiet
set default-list
set default-script
set shell := ['bash', '-euo', 'pipefail', '-c']
set script-interpreter := ['bash', '-euo', 'pipefail']
set working-directory := '..'
bootstrap_dir := justfile_dir() + '/bootstrap'
kubernetes_dir := justfile_dir() + '/kubernetes'
talos_dir := justfile_dir() + '/talos'
private_dir := justfile_dir() + '/.private'
template_dir := justfile_dir() + '/template'
template_resources := template_dir + '/resources'
makejinja_config := justfile_dir() + '/makejinja.toml'
mise_fragment := justfile_dir() + '/.mise/conf.d/template.toml'
config_file := justfile_dir() + '/cluster.toml'
schema_file := justfile_dir() + '/cluster.schema.json'
sample_config_file := justfile_dir() + '/cluster.sample.toml'
validate_script := template_dir + '/scripts/validate.py'
deploy_key := justfile_dir() + '/deploy.key'
webhook_token_file := justfile_dir() + '/flux-webhook-token.txt'
cloudflare_tunnel := justfile_dir() + '/cloudflare-tunnel.json'
[doc('Render and validate configuration files')]
[group('template')]
configure: render encrypt-secrets validate-kubernetes validate-talos
[doc('Check that all prerequisite files exist and cluster.toml validates against the schema')]
[group('template')]
[no-exit-message]
doctor:
rc=0
just log info "just version" version "{{ just_version() }}"
just template doctor-check "cluster.toml" "{{ config_file }}" || rc=1
just template doctor-check "cluster.sample.toml" "{{ sample_config_file }}" || rc=1
config_json="$(just template config-json 2>/dev/null || true)"
if [ "$(jq -r '.ingress.mode' <<< "$config_json" 2>/dev/null)" = "cloudflare-tunnel" ]; then
just template doctor-check "cloudflare-tunnel.json" "{{ cloudflare_tunnel }}" || rc=1
fi
just template doctor-check "age.key" "$SOPS_AGE_KEY_FILE" || rc=1
just template doctor-check "deploy.key" "{{ deploy_key }}" || rc=1
just template doctor-check "flux-webhook-token.txt" "{{ webhook_token_file }}" || rc=1
just template doctor-check "template/" "{{ template_dir }}" || rc=1
just template doctor-check "makejinja.toml" "{{ makejinja_config }}" || rc=1
just template doctor-check "validate.py" "{{ validate_script }}" || rc=1
if [ -f "{{ config_file }}" ] && [ -f "{{ validate_script }}" ]; then
if [ -n "$config_json" ]; then
just log info "ok" check schema
else
just log error "fail" check schema
just log info "diagnose with: uv run --locked --no-dev {{ validate_script }} {{ config_file }}"
rc=1
fi
fi
[ "$rc" = 0 ] && just log info "all good"
exit "$rc"
[doc('Initialize configuration files (cluster.toml, age key, deploy key, webhook token)')]
[group('template')]
init:
[ -f "{{ config_file }}" ] || cp "{{ sample_config_file }}" "{{ config_file }}"
[ -f "$SOPS_AGE_KEY_FILE" ] || age-keygen -pq --output "$SOPS_AGE_KEY_FILE"
[ -f "{{ deploy_key }}" ] || ssh-keygen -t ed25519 -C "deploy-key" -f "{{ deploy_key }}" -q -P ""
[ -f "{{ webhook_token_file }}" ] || openssl rand -hex 16 > "{{ webhook_token_file }}"
# Editors resolve the #:schema directive in cluster.toml against this file;
# the validator tests fail when it drifts from the pydantic model.
[doc('Regenerate the cluster.toml JSON Schema from the validator')]
[group('template')]
schema:
uv run --quiet --locked --no-dev "{{ validate_script }}" --schema > "{{ schema_file }}"
oxfmt "{{ schema_file }}" > /dev/null
[confirm("Remove all templated files and directories — continue? [y/N]")]
[doc('Remove rendered files (bootstrap/, kubernetes/, talos/, .sops.yaml)')]
[group('template')]
reset:
rm -rf "{{ bootstrap_dir }}" "{{ kubernetes_dir }}" "{{ talos_dir }}" "{{ justfile_dir() }}/.sops.yaml"
# tidy-archive moves template/ (this module's source) away, so it runs as a
# subsequent dependency: the tidy script itself must spawn while the module
# directory still exists.
[confirm("All template related config will be archived — continue? [y/N]")]
[doc('Archive all template tooling under .private/<ts>/ (one-way, run after configure works)')]
[group('template')]
tidy: tidy-preconditions tidy-strip && tidy-archive
# Validated, defaulted cluster config as JSON on stdout; fails when the
# config is invalid.
[private]
config-json:
uv run --quiet --locked --no-dev "{{ validate_script }}" "{{ config_file }}"
[no-exit-message]
[private]
doctor-check label path:
if [ -e "{{ path }}" ]; then
just log info "ok" file "{{ label }}"
else
just log error "missing" file "{{ label }}"
exit 1
fi
[private]
encrypt-secrets:
find "{{ bootstrap_dir }}" "{{ kubernetes_dir }}" "{{ talos_dir }}" -type f -name '*.sops.*' -print0 \
| while IFS= read -r -d '' f; do
if ! status="$(sops filestatus "$f" | jq -r '.encrypted')"; then
just log fatal "could not read encryption status" file "$f"
fi
case "$status" in
false) sops encrypt --in-place "$f" ;;
true) : ;;
*) just log fatal "could not determine encryption status" file "$f" ;;
esac
done
[private]
render:
PYTHONDONTWRITEBYTECODE=1 uv run --locked --no-dev makejinja
[private]
tidy-archive:
TIDY_FOLDER="{{ private_dir }}/$(date +%s)"
mkdir -p "$TIDY_FOLDER"
rm -rf "{{ justfile_dir() }}/.github/template-tests" "{{ justfile_dir() }}/.github/workflows"/template-*.yaml
mv \
"{{ template_dir }}" \
"{{ makejinja_config }}" \
"{{ mise_fragment }}" \
"{{ schema_file }}" \
"{{ config_file }}" \
"{{ sample_config_file }}" \
"{{ justfile_dir() }}/pyproject.toml" \
"{{ justfile_dir() }}/uv.lock" \
"$TIDY_FOLDER/"
rmdir "$(dirname "{{ mise_fragment }}")" 2>/dev/null || true
rm -rf "{{ justfile_dir() }}/.venv"
[private]
tidy-preconditions:
test -d "{{ template_dir }}"
test -d "{{ justfile_dir() }}/.github/template-tests"
test -f "{{ makejinja_config }}"
test -f "{{ config_file }}"
test -f "{{ sample_config_file }}"
test -f "{{ justfile_dir() }}/pyproject.toml"
test -f "{{ justfile_dir() }}/uv.lock"
test -f "{{ justfile_dir() }}/justfile"
test -f "{{ mise_fragment }}"
test -f "{{ schema_file }}"
test -f "{{ justfile_dir() }}/.renovaterc.json5"
compgen -G "{{ justfile_dir() }}/.github/workflows/template-*.yaml" > /dev/null
[private]
tidy-strip:
sd '\..\.j2' '' "{{ justfile_dir() }}/.renovaterc.json5"
sd -A '(?ms)^# === template ===$.*' '' "{{ justfile_dir() }}/justfile"
# Renders every bootstrap chart with the rendered values, catching chart or
# values drift that dry runs cannot; needs network access to pull charts.
[doc('Render the bootstrap helmfile charts against the rendered values')]
[group('template')]
test-helmfile:
helmfile --file "{{ bootstrap_dir }}/helmfile/apps.yaml" template --quiet > /dev/null
just log info "bootstrap charts rendered cleanly"
[private]
validate-kubernetes:
bash "{{ template_resources }}/kubeconform.sh" "{{ kubernetes_dir }}"
# Rendering needs the secrets bundle; topf generates and sops-encrypts one
# on first run (--confirm=false so it never prompts mid-pipeline).
[private]
[working-directory('talos')]
validate-talos:
topf render --confirm=false --output "$(mktemp -d)" >/dev/null
if ! sops filestatus secrets.sops.yaml | jq --exit-status '.encrypted == true' >/dev/null; then
just log fatal "Talos secrets bundle is not encrypted"
fi