.PHONY: help doctor validate validate-strict validate-changed ci-local source-lint mylar-source-check komga-source-check komga-worker-check hooks-install hooks-install-site mirror-sync prepare-audit metadata-audit hygiene-audit docs-generate docs-check pages-generate pages-check site-test-syntax site-test secrets secrets-files monitoring-validate monitoring-reload monitoring-smoke-check monitoring-iterate monitoring-quick monitoring-sync-blackbox JAVA_HOME_21 ?= $(JAVA_HOME_21_X64) MYLAR_PYTHON ?= python3 PUBLICATION_HOST_PYTHON ?= python3 SOURCE_LINT_TOOLING ?= ARCHIVING_UTILS_ROOT ?= /opt/archiving-utils PUBLICATION_AUTH_BACKEND ?= host export ARCHIVING_UTILS_ROOT help: @echo "Homelab repository targets:" @echo " doctor Read-only host and repository checks" @echo " validate Python, Compose YAML, and shell validation" @echo " validate-strict Validate and require every lint dependency" @echo " validate-changed Validate changed stacks; requires BASE=" @echo " ci-local Run source, pre-commit and candidate-history secret checks" @echo " source-lint Run pinned shared lint; requires SOURCE_LINT_TOOLING" @echo " mylar-source-check Run Mylar recovery/archive source controls without Docker" @echo " komga-source-check Run the Komga source/compile gate; requires JAVA_HOME_21" @echo " komga-worker-check Run the full worker suite with the checked archive SDK" @echo " hooks-install Install repository pre-commit hooks" @echo " hooks-install-site Opt in to Pages browser tests before push" @echo " mirror-sync Fast-forward Gitea from authoritative GitHub" @echo " prepare-audit Audit stack preparation scripts and prerequisites" @echo " metadata-audit Validate stack.yaml catalog metadata" @echo " hygiene-audit Validate examples, docs, and cross-file basics" @echo " docs-generate Regenerate topology and stack catalog documents" @echo " docs-check Fail when generated documentation is stale" @echo " pages-generate Regenerate the public application reference" @echo " pages-check Validate generated Pages content and links" @echo " site-test-syntax Check browser-test and server syntax" @echo " site-test Run browser accessibility and behavior tests" @echo " secrets Scan the full Git history with Gitleaks" @echo " secrets-files Scan files on disk, including ignored runtime files" @echo " monitoring-iterate Validate, reload, and smoke-test monitoring" @echo " monitoring-quick Reload and smoke-test monitoring" doctor: bash scripts/homelab-doctor.sh validate: bash scripts/validate-repo.sh validate-strict: bash scripts/validate-repo.sh --strict validate-changed: @test -n "$(BASE)" || (echo "Usage: make validate-changed BASE=" >&2; exit 2) bash scripts/validate-repo.sh --strict --changed-base "$(BASE)" ci-local: @node --input-type=module -e "import.meta.resolve('markdownlint/promise')" >/dev/null 2>&1 || { echo "FAIL: locked Markdown tools are unavailable; run npm ci with the repository Node toolchain." >&2; exit 1; } $(MAKE) nodepad-source-check $(MAKE) openai-oauth-source-check $(MAKE) source-lint $(MAKE) mylar-source-check $(MAKE) komga-worker-check $(MAKE) komga-source-check pre-commit run --all-files bash scripts/scan-secrets-gitleaks.sh git --log-opts=HEAD source-lint: python3 scripts/source-lint-local.py "$(SOURCE_LINT_TOOLING)" .PHONY: openai-oauth-source-check openai-oauth-source-check: @set -eu; task_dir=$$(mktemp -d -t homelab-oauth-source.XXXXXXXX); \ trap 'rm -rf -- "$$task_dir"' EXIT; \ cp stacks/openai-oauth/package.json stacks/openai-oauth/package-lock.json stacks/openai-oauth/test-runtime.mjs "$$task_dir/"; \ cd "$$task_dir"; \ npm ci --omit=dev --ignore-scripts --no-audit --no-fund; \ node --test test-runtime.mjs; \ ./node_modules/.bin/openai-oauth --help > /dev/null mylar-source-check: @test -f "$(ARCHIVING_UTILS_ROOT)/lib/archive_backend.py" || { echo "The complete publication gate requires ARCHIVING_UTILS_ROOT pointing to the checked archive SDK." >&2; exit 1; } @$(PUBLICATION_HOST_PYTHON) -c "import fcntl, os, sys; sys.exit(0 if hasattr(os, 'memfd_create') and all(hasattr(fcntl, name) for name in ('F_ADD_SEALS', 'F_GET_SEALS', 'F_SEAL_WRITE', 'F_SEAL_GROW', 'F_SEAL_SHRINK', 'F_SEAL_SEAL')) else 'Authenticated host controls require Linux memfd and seal support')" $(MYLAR_PYTHON) -B -m unittest discover -s stacks/mylar3/config -p test_workflow.py $(MYLAR_PYTHON) -B stacks/mylar3/config/test_health.py $(MYLAR_PYTHON) -B stacks/mylar3/config/test_pack_records.py $(MYLAR_PYTHON) -I -B stacks/mylar3/config/test_verify_status_routing.py $(MYLAR_PYTHON) -I -B stacks/mylar3/config/test_publication_launch_auth.py # Tagging host controls share real admission; three executable cases remain image-only. $(MYLAR_PYTHON) -B -m unittest discover -s stacks/mylar3/config -p test_publication_tagging.py $(MYLAR_PYTHON) -B -m unittest discover -s stacks/mylar3/config -p 'test_tagging_stage*.py' # Match the image's owning portable suites, including complete recovery controls. $(MYLAR_PYTHON) -B stacks/mylar3/config/run_publication_reader_controls.py $(MYLAR_PYTHON) -B stacks/mylar3/config/test_publication_archive_adoption.py $(MYLAR_PYTHON) -B stacks/mylar3/config/test_publication_archive_nfs.py $(MYLAR_PYTHON) -B stacks/mylar3/config/run_import_api_controls.py --family all $(MYLAR_PYTHON) -B stacks/mylar3/config/run_standalone_controls.py --family all $(PUBLICATION_HOST_PYTHON) -B stacks/mylar3/config/run_authenticated_standalone_controls.py --backend "$(PUBLICATION_AUTH_BACKEND)" komga-source-check: @test -n "$(JAVA_HOME_21)" || (echo "JDK 21 is required: set JAVA_HOME_21=/path/to/jdk-21 (or JAVA_HOME_21_X64)." >&2; exit 2) $(MYLAR_PYTHON) -B stacks/komga/normalizer/test_naming_worker.py $(MYLAR_PYTHON) -B stacks/komga/normalizer/test_retained_pack_control.py $(MYLAR_PYTHON) -B stacks/komga/normalizer/test_archive_terminal_observation.py python3 -I -B stacks/komga/effective_scope/run_source_tests.py --java-home "$(JAVA_HOME_21)" komga-worker-check: $(MYLAR_PYTHON) -B scripts/run-private-comic-controls.py local-worker hooks-install: pre-commit install --install-hooks hooks-install-site: hooks-install pre-commit install --hook-type pre-push mirror-sync: bash scripts/sync-gitea-mirrors.local.sh prepare-audit: python3 scripts/audit-prepare-scripts.py metadata-audit: python3 scripts/audit-stack-metadata.py hygiene-audit: python3 scripts/audit-repo-hygiene.py docs-generate: python3 scripts/build-stack-catalog.py python3 scripts/build-topology.py --in-place docs-check: python3 scripts/build-stack-catalog.py --check python3 scripts/build-topology.py --check pages-generate: python3 scripts/build-pages-site.py pages-check: python3 scripts/build-pages-site.py --check python3 scripts/validate-pages-site.py node --check site/public/search.js site-test-syntax: node --check playwright.config.js node --check tests/site/site.spec.js python3 -m py_compile scripts/serve-pages-site.py site-test: site-test-syntax npm run test:site secrets: bash scripts/scan-secrets-gitleaks.sh git secrets-files: bash scripts/scan-secrets-gitleaks.sh dir monitoring-validate: bash scripts/validate-monitoring-config.sh monitoring-reload: docker exec prometheus wget -qO- --post-data='' http://localhost:9090/-/reload docker exec alertmanager wget -qO- --post-data='' http://localhost:9093/-/reload monitoring-smoke-check: bash scripts/monitoring-smoke-check.sh # Full inner loop while tuning monitoring config. monitoring-iterate: monitoring-validate monitoring-reload monitoring-smoke-check # Fast path during query/rule tuning: reload + smoke only. monitoring-quick: monitoring-reload monitoring-smoke-check # Rebuild blackbox_nonalert + blackbox_http_paths_nonalert from documents/MONITORING-TARGETS.md (example.com only). monitoring-sync-blackbox: python3 scripts/sync-blackbox-targets-from-monitoring.py stacks/prometheus/prometheus.yml.example .PHONY: nodepad-source-check nodepad-source-check: python3 scripts/check-nodepad-source.py