diff --git a/README.md b/README.md index 2d17198..4400732 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ Run a read-only health snapshot from the Debian server with: ./jeannie capacity ./jeannie recover-plan ./jeannie recover-power --dry-run +./jeannie scorecard ./jeannie gitops-status ./jeannie cert-check ./jeannie release-snapshot @@ -317,6 +318,10 @@ edge verification. Debian runtime, Gitea, RPi DNS, Pimox workers, Kubernetes, GitOps/apps, and edge/public checks. Use `recover-power --dry-run` to preview the sequence. +`scorecard` rolls up backup readiness, GitOps health, DNS/RPi health, cluster +health, edge health, capacity pressure, security posture, public certificates, +inventory, and docs freshness into a compact pass/warn/fail report. + `gitops-status` prints a focused Argo CD view: application sync and health, out-of-sync or degraded apps, repository secret presence, recent Argo CD events, and recent repo-server/application-controller errors. diff --git a/README.md.tmpl b/README.md.tmpl index 4e5ace8..b1dd343 100644 --- a/README.md.tmpl +++ b/README.md.tmpl @@ -273,6 +273,7 @@ Run a read-only health snapshot from the Debian server with: ./{{ main_script }} capacity ./{{ main_script }} recover-plan ./{{ main_script }} recover-power --dry-run +./{{ main_script }} scorecard ./{{ main_script }} gitops-status ./{{ main_script }} cert-check ./{{ main_script }} release-snapshot @@ -317,6 +318,10 @@ edge verification. Debian runtime, Gitea, RPi DNS, Pimox workers, Kubernetes, GitOps/apps, and edge/public checks. Use `recover-power --dry-run` to preview the sequence. +`scorecard` rolls up backup readiness, GitOps health, DNS/RPi health, cluster +health, edge health, capacity pressure, security posture, public certificates, +inventory, and docs freshness into a compact pass/warn/fail report. + `gitops-status` prints a focused Argo CD view: application sync and health, out-of-sync or degraded apps, repository secret presence, recent Argo CD events, and recent repo-server/application-controller errors. diff --git a/docs/jeannie.1.md b/docs/jeannie.1.md index 663ead2..4cae8e3 100644 --- a/docs/jeannie.1.md +++ b/docs/jeannie.1.md @@ -66,6 +66,11 @@ verification. : Run the post-outage recovery sequence in dependency order: Debian runtime, Gitea, RPi DNS, Pimox workers, Kubernetes, GitOps/apps, and edge/public checks. +`scorecard` +: Roll up backup readiness, GitOps health, DNS/RPi health, cluster health, edge +health, capacity pressure, security posture, public certificates, inventory, and +docs freshness into a compact pass/warn/fail report. + `gitops-status` : Print a focused Argo CD status view with application sync/health, out-of-sync or degraded apps, repository secret presence, recent events, and recent diff --git a/jeannie b/jeannie index 6368a91..29df79a 100755 --- a/jeannie +++ b/jeannie @@ -6022,6 +6022,11 @@ recover_power() { "${REPO_ROOT}/scripts/recover-power" "${@:2}" } +scorecard() { + require_debian_server "scorecard" + "${REPO_ROOT}/scripts/scorecard" +} + workers_manage() { require_debian_server "workers" "${REPO_ROOT}/scripts/workers" "${@:2}" @@ -6102,6 +6107,9 @@ case "${1:-}" in recover-power) recover_power "$@" ;; + scorecard) + scorecard + ;; workers) workers_manage "$@" ;; @@ -6259,7 +6267,7 @@ case "${1:-}" in echo "Log: ${JEANNIE_LOG_FILE}" ;; *) - echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|recover-power [--dry-run]|gitops-status|cert-check|release-snapshot|backup-status|synthetic-checks|resource-budget|artifact-cache {status|up|down|instructions}|golden-ledger {show|check}|route-inventory|workers |change-journal {list|path}|map [--dot]|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}" + echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|recover-power [--dry-run]|scorecard|gitops-status|cert-check|release-snapshot|backup-status|synthetic-checks|resource-budget|artifact-cache {status|up|down|instructions}|golden-ledger {show|check}|route-inventory|workers |change-journal {list|path}|map [--dot]|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}" exit 1 ;; esac diff --git a/scripts/scorecard b/scripts/scorecard new file mode 100755 index 0000000..df2ef03 --- /dev/null +++ b/scripts/scorecard @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +failures=0 +warnings=0 + +score() { + local label="$1" + local severity="$2" + shift 2 + local output + local status + + printf '%-28s ' "$label" + set +e + output="$("$@" 2>&1)" + status=$? + set -e + if [ "$status" -eq 0 ]; then + printf 'pass\n' + return 0 + fi + if [ "$severity" = "fail" ]; then + failures=$((failures + 1)) + printf 'fail' + else + warnings=$((warnings + 1)) + printf 'warn' + fi + if [ -n "$output" ]; then + printf ' - %s' "$(printf '%s' "$output" | grep -v '^+' | head -n 1)" + fi + printf '\n' +} + +docs_fresh() { + "${REPO_ROOT}/scripts/render-docs" --check >/dev/null +} + +inventory_ok() { + "${REPO_ROOT}/scripts/validate-homelab-inventory" "${HOMELAB_INVENTORY_FILE:-${REPO_ROOT}/homelab.yml}" >/dev/null +} + +security_static_ok() { + "${REPO_ROOT}/scripts/validate-tailnet-policy" >/dev/null +} + +printf 'Homelab scorecard\n' +printf '=================\n\n' + +score "Inventory" fail inventory_ok +score "Documentation freshness" warn docs_fresh +score "Backup readiness" fail "${REPO_ROOT}/scripts/backup-status" +score "GitOps health" warn "${REPO_ROOT}/scripts/gitops-status" +score "DNS and RPi health" fail "${REPO_ROOT}/jeannie" doctor-rpi +score "Cluster health" fail "${REPO_ROOT}/jeannie" doctor-cluster +score "Edge health" fail "${REPO_ROOT}/jeannie" doctor-edge +score "Capacity pressure" warn "${REPO_ROOT}/scripts/resource-budget" +score "Security posture" warn security_static_ok +score "Public certificates" warn "${REPO_ROOT}/scripts/cert-check" + +printf '\nSummary: failures=%s warnings=%s\n' "$failures" "$warnings" +if [ "$failures" -gt 0 ]; then + printf 'Focus on the failed categories first, then clear warnings.\n' + exit 1 +fi +if [ "$warnings" -gt 0 ]; then + printf 'No blocking failures, but warnings need cleanup.\n' + exit 0 +fi +printf 'Scorecard passed.\n'