Compare commits

..
Author SHA1 Message Date
forust 5f9354b9a8 fix(edu): deploy reviewed application release with Redis authentication
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 14s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 13s
ci / lint-prettier (push) Successful in 19s
ci / lint-ruff (push) Successful in 9s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 10s
ci / build (push) Successful in 30s
2026-10-06 22:56:02 +02:00
forust fcd16f6128 Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.140.0' (#96) from renovate/renovate-self-update into main
renovate-ci / validate-renovate (push) Successful in 1m25s
ci / lint-compose (push) Successful in 12s
ci / lint-actionlint (push) Successful in 7s
ci / lint-shellcheck (push) Successful in 16s
ci / lint-prettier (push) Successful in 23s
ci / lint-ruff (push) Successful in 9s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 6s
ci / build (push) Successful in 25s
Reviewed-on: #96
2026-10-06 17:51:40 +00:00
renovate-bot 2ac2a94bb4 chore(deps): update renovate/renovate docker tag to v44.140.0 2026-10-06 17:51:40 +00:00
forust 3c7e358dd5 Merge pull request 'chore(deps): update lscr.io/linuxserver/qbittorrent docker tag to v20' (#97) from renovate/lscr.io-linuxserver-qbittorrent-20.x into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 16s
ci / lint-actionlint (push) Successful in 7s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-prettier (push) Successful in 20s
ci / lint-ruff (push) Successful in 9s
ci / lint-yaml (push) Successful in 14s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 8s
ci / build (push) Successful in 24s
Reviewed-on: #97
2026-10-06 17:51:25 +00:00
renovate-bot 9be8fb6c69 chore(deps): update lscr.io/linuxserver/qbittorrent docker tag to v20 2026-10-06 17:51:25 +00:00
forust 7fdeacffb8 feat(monitoring): stand down Prometheus server during VM trial
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 13s
ci / lint-actionlint (push) Successful in 5s
ci / lint-shellcheck (push) Successful in 10s
ci / lint-prettier (push) Successful in 14s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 19s
vmagent scrapes and remote-writes to VictoriaMetrics, so the Prometheus server scales to 0. Encoded as prometheusSpec.replicas in values instead of a kubectl patch, so helm keeps owning spec.replicas and Helm 4 server-side apply stops conflicting with the kubectl-patch field manager.
2026-10-06 19:29:30 +02:00
forust cef499de73 fix(deploy): skip VMAgent in secrets check before CRD install
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 12s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-ruff (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 6s
ci / lint-prettier (push) Successful in 21s
ci / lint-yaml (push) Successful in 10s
ci / validate (push) Successful in 8s
ci / build (push) Successful in 21s
check_referenced_secrets ran kubectl create on vmagent.yaml even when the VMAgent CRD is not installed yet, failing validate with 'no matches for kind VMAgent'. Apply the same skip_uninstalled_vmagent_crd guard used by both dry-run loops.
2026-10-06 19:19:47 +02:00
forust 1b70a55300 fix(ci): handle malformed push before SHA
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 10s
ci / lint-actionlint (push) Successful in 7s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-prettier (push) Failing after 22s
ci / lint-ruff (push) Failing after 2s
ci / lint-yaml (push) Failing after 2s
ci / lint-dockerfiles (push) Failing after 3s
ci / validate (push) Failing after 2s
ci / build (push) Skipped
2026-10-06 18:21:19 +02:00
forust 3f2b4e9acf fix(deploy): skip VMAgent preflight before CRD install
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 11s
ci / lint-actionlint (push) Successful in 5s
ci / lint-shellcheck (push) Successful in 10s
ci / lint-prettier (push) Successful in 15s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 10s
ci / build (push) Successful in 25s
2026-10-06 18:18:25 +02:00
forust 6057734a4f fix(renovate): sync generated configmap
renovate-ci / validate-renovate (push) Successful in 9s
ci / lint-compose (push) Successful in 9s
ci / lint-actionlint (push) Successful in 4s
ci / lint-shellcheck (push) Successful in 10s
ci / lint-prettier (push) Successful in 19s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 18s
2026-10-06 18:08:17 +02:00
forust 8eedf8b74b Merge pull request 'feat(monitoring): add VictoriaMetrics trial stack' (#95) from feat/victoria-metrics-migration into main
ci / lint-compose (push) Successful in 11s
ci / lint-actionlint (push) Successful in 2m36s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-prettier (push) Successful in 19s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Successful in 10s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 7s
renovate-ci / validate-renovate (push) Failing after 9s
ci / build (push) Successful in 19s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/95
2026-10-06 16:05:46 +00:00
forust 8c0e36a5c0 feat(monitoring): replace scrape dump with vmagent
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
ci / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (pull_request) Successful in 11s
ci / lint-actionlint (pull_request) Successful in 6s
ci / lint-shellcheck (pull_request) Successful in 16s
ci / lint-dockerfiles (pull_request) Successful in 6s
ci / lint-prettier (pull_request) Successful in 16s
ci / lint-ruff (pull_request) Successful in 7s
ci / lint-yaml (pull_request) Successful in 10s
ci / validate (pull_request) Successful in 7s
ci / build (pull_request) Skipped
renovate-ci / validate-renovate (pull_request) Failing after 1m40s
2026-10-06 18:03:59 +02:00
forust 78cd15f12c chore(monitoring): remove vmctl backfill job
renovate-ci / validate-renovate (pull_request) Skipped
ci / lint-compose (pull_request) Successful in 11s
ci / lint-yaml (pull_request) Successful in 11s
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
ci / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-actionlint (pull_request) Successful in 5s
ci / lint-shellcheck (pull_request) Successful in 16s
ci / lint-prettier (pull_request) Successful in 15s
ci / lint-ruff (pull_request) Successful in 6s
ci / lint-dockerfiles (pull_request) Successful in 7s
ci / validate (pull_request) Successful in 7s
ci / build (pull_request) Skipped
One-shot Prometheus history backfill is complete; drop the Job and clean up related comments.
2026-10-06 17:53:24 +02:00
forust 18c633c242 feat(monitoring): add VictoriaMetrics trial stack
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
ci / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
renovate-ci / validate-renovate (pull_request) Skipped
ci / lint-compose (pull_request) Successful in 12s
ci / lint-actionlint (pull_request) Successful in 6s
ci / lint-shellcheck (pull_request) Successful in 13s
ci / lint-prettier (pull_request) Successful in 21s
ci / lint-ruff (pull_request) Successful in 7s
ci / lint-yaml (pull_request) Successful in 12s
ci / lint-dockerfiles (pull_request) Successful in 7s
ci / validate (pull_request) Successful in 7s
ci / build (pull_request) Skipped
2026-10-06 17:45:44 +02:00
forust 4510394531 Merge pull request 'chore(deps): update renovate/renovate docker tag to v44.139.0' (#81) from renovate/renovate-self-update into main
ci / lint-compose (push) Successful in 11s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-prettier (push) Successful in 19s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 9s
renovate-ci / validate-renovate (push) Successful in 13s
ci / build (push) Successful in 20s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/81
2026-10-06 15:33:45 +00:00
renovate-bot 2545312db1 chore(deps): update renovate/renovate docker tag to v44.139.0 2026-10-06 15:33:45 +00:00
forust 8ce0b809c0 Merge pull request 'chore(deps): update all minor updates' (#77) from renovate/all-minor into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Canceled after 0s
ci / lint-actionlint (push) Canceled after 0s
ci / lint-shellcheck (push) Canceled after 0s
ci / lint-prettier (push) Canceled after 0s
ci / lint-ruff (push) Canceled after 0s
ci / lint-yaml (push) Canceled after 0s
ci / lint-dockerfiles (push) Canceled after 0s
ci / validate (push) Canceled after 0s
ci / build (push) Canceled after 0s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/77
2026-10-06 15:33:28 +00:00
renovate-bot 506c04e15c chore(deps): update all minor updates 2026-10-06 15:33:28 +00:00
forust bdcbb3d5af Merge pull request 'chore(deps): update all patch updates' (#82) from renovate/all-patch into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Canceled after 0s
ci / lint-actionlint (push) Canceled after 0s
ci / lint-shellcheck (push) Canceled after 0s
ci / lint-prettier (push) Canceled after 0s
ci / lint-ruff (push) Canceled after 0s
ci / lint-yaml (push) Canceled after 0s
ci / lint-dockerfiles (push) Canceled after 0s
ci / validate (push) Canceled after 0s
ci / build (push) Canceled after 0s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/82
2026-10-06 15:33:09 +00:00
renovate-bot faac6febb8 chore(deps): update all patch updates 2026-10-06 15:33:09 +00:00
forust 695da1308c Merge pull request 'fix(renovate): restore custom extraction and update groups' (#93) from fix/renovate-extraction-groups into main
ci / lint-compose (push) Successful in 10s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 17s
ci / lint-prettier (push) Successful in 18s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 12s
ci / lint-dockerfiles (push) Successful in 8s
ci / validate (push) Successful in 8s
renovate-ci / validate-renovate (push) Successful in 11s
ci / build (push) Successful in 37s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/93
2026-10-06 15:31:25 +00:00
forust 552b22cb66 fix(renovate): include self-update Compose filename 2026-10-06 15:31:25 +00:00
forust 3756e60c95 fix(renovate): restore custom extraction and update groups 2026-10-06 15:31:25 +00:00
forust d0d217ddf4 Merge pull request 'fix(deploy): skip verify and smoke when deployment is disabled' (#94) from fix/deploy-skip-when-disabled into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Canceled after 0s
ci / lint-actionlint (push) Canceled after 0s
ci / lint-shellcheck (push) Canceled after 0s
ci / lint-prettier (push) Canceled after 0s
ci / lint-ruff (push) Canceled after 0s
ci / lint-yaml (push) Canceled after 0s
ci / lint-dockerfiles (push) Canceled after 0s
ci / validate (push) Canceled after 0s
ci / build (push) Canceled after 0s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/94
2026-10-06 15:24:17 +00:00
forust 24f84bab2f fix(deploy): skip verification when deployment is disabled
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
ci / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
renovate-ci / validate-renovate (pull_request) Skipped
ci / lint-compose (pull_request) Canceled after 0s
ci / lint-actionlint (pull_request) Canceled after 0s
ci / lint-shellcheck (pull_request) Canceled after 0s
ci / lint-prettier (pull_request) Canceled after 0s
ci / lint-ruff (pull_request) Canceled after 0s
ci / lint-yaml (pull_request) Canceled after 0s
ci / lint-dockerfiles (pull_request) Canceled after 0s
ci / validate (pull_request) Canceled after 0s
ci / build (pull_request) Canceled after 0s
2026-10-06 15:24:06 +00:00
forust 0b8a3c16a7 Merge pull request 'fix(glance): mount CSS from the correct ConfigMap' (#87) from fix/glance-assets into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Canceled after 0s
ci / lint-actionlint (push) Canceled after 0s
ci / lint-shellcheck (push) Canceled after 0s
ci / lint-prettier (push) Canceled after 0s
ci / lint-ruff (push) Canceled after 0s
ci / lint-yaml (push) Canceled after 0s
ci / lint-dockerfiles (push) Canceled after 0s
ci / validate (push) Canceled after 0s
ci / build (push) Canceled after 0s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/87
2026-10-06 15:17:47 +00:00
forust e9a68aae77 fix(glance): mount CSS from the assets ConfigMap 2026-10-06 15:17:47 +00:00
forust 5359df5ed6 Merge pull request 'fix(postgres): include the required NetBox database password' (#88) from fix/postgres-env-example into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 14s
ci / lint-actionlint (push) Successful in 8s
ci / lint-shellcheck (push) Successful in 17s
ci / lint-prettier (push) Successful in 24s
ci / lint-ruff (push) Successful in 9s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 11s
ci / build (push) Canceled after 0s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/88
2026-10-06 15:17:19 +00:00
forust 8aea0f0d13 fix(postgres): include required NetBox password in Compose env example 2026-10-06 15:17:19 +00:00
forust 65d4f2d482 Merge pull request 'fix(traefik): correct AdGuard and SearXNG Compose rules' (#90) from fix/compose-router-rules into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 12s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 13s
ci / lint-prettier (push) Successful in 16s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 10s
ci / build (push) Successful in 23s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/90
2026-10-06 15:10:49 +00:00
forust 2fe9b7632f fix(traefik): correct AdGuard and SearXNG Compose router expressions 2026-10-06 15:10:49 +00:00
forust e436d89eef Merge pull request 'fix(netbird): restore Compose setup and runtime renderer' (#86) from fix/netbird-compose-runtime into main
renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 11s
ci / lint-actionlint (push) Successful in 4s
ci / lint-shellcheck (push) Successful in 15s
ci / lint-prettier (push) Successful in 21s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Successful in 11s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 20s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/86
2026-10-06 15:10:12 +00:00
forust 8729cb5062 fix(netbird): restore Compose setup and server entrypoint
ci / validate (push) Skipped
ci / lint-prettier (push) Skipped
ci / lint-ruff (push) Skipped
ci / lint-yaml (push) Skipped
ci / lint-dockerfiles (push) Skipped
renovate-ci / validate-renovate (push) Skipped
renovate-ci / validate-renovate (pull_request) Skipped
ci / lint-compose (pull_request) Successful in 12s
ci / lint-actionlint (pull_request) Successful in 8s
ci / lint-shellcheck (pull_request) Successful in 21s
ci / lint-prettier (pull_request) Successful in 17s
ci / lint-ruff (pull_request) Successful in 6s
ci / lint-yaml (pull_request) Successful in 9s
ci / lint-dockerfiles (pull_request) Successful in 5s
ci / validate (pull_request) Successful in 6s
ci / build (pull_request) Skipped
2026-10-06 15:08:46 +00:00
forust f1e4a1088d Merge pull request 'fix(ci): deduplicate PR checks and filter deploy triggers' (#92) from fix/ci-trigger-dedup into main
renovate-ci / validate-renovate (push) Successful in 9s
ci / lint-compose (push) Successful in 10s
ci / lint-actionlint (push) Successful in 6s
ci / lint-shellcheck (push) Successful in 12s
ci / lint-prettier (push) Successful in 19s
ci / lint-ruff (push) Successful in 8s
ci / lint-yaml (push) Successful in 12s
ci / lint-dockerfiles (push) Successful in 7s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 19s
Reviewed-on: https://gitea.forust.xyz/forust/homelab/pulls/92
2026-10-06 15:06:47 +00:00
43 changed files with 860 additions and 127 deletions

No files matched your search

+14
View File
@@ -73,6 +73,20 @@ fi
grep -q 'MISSING OR UNREADABLE: app/credentials' "$scratch/secrets.log" grep -q 'MISSING OR UNREADABLE: app/credentials' "$scratch/secrets.log"
# API/rendering errors must not produce an empty reference list and pass. # API/rendering errors must not produce an empty reference list and pass.
kubectl() { return 1; } kubectl() { return 1; }
if ! skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/vmagent.yaml"; then
echo 'VMAgent preflight did not skip an uninstalled CRD' >&2
exit 1
fi
kubectl() { return 0; }
if skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/vmagent.yaml"; then
echo 'VMAgent preflight skipped an installed CRD' >&2
exit 1
fi
if skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/victoria.yaml"; then
echo 'VMAgent preflight skipped an unrelated manifest' >&2
exit 1
fi
kubectl() { return 1; }
if check_referenced_secrets >"$scratch/secrets.log"; then if check_referenced_secrets >"$scratch/secrets.log"; then
echo 'Secret check accepted a failed manifest render' >&2 echo 'Secret check accepted a failed manifest render' >&2
exit 1 exit 1
+23 -32
View File
@@ -142,6 +142,7 @@ jobs:
export PATH="$tools_dir:$PATH" export PATH="$tools_dir:$PATH"
ruff check . ruff check .
ruff format --check . ruff format --check .
python3 -m unittest discover -s tests -v
lint-yaml: lint-yaml:
runs-on: [self-hosted, linux, arch, homelab] runs-on: [self-hosted, linux, arch, homelab]
@@ -293,6 +294,11 @@ jobs:
echo "server-side dry-run: ${#manifests[@]} manifests, ${#kustomize_apps[@]} kustomize apps" echo "server-side dry-run: ${#manifests[@]} manifests, ${#kustomize_apps[@]} kustomize apps"
failed=0 failed=0
for m in ${manifests[@]+"${manifests[@]}"}; do for m in ${manifests[@]+"${manifests[@]}"}; do
if [[ "$m" == "prometheus-stack/k8s/vmagent.yaml" ]] \
&& ! kubectl get crd vmagents.operator.victoriametrics.com >/dev/null 2>&1; then
echo "skip server-side dry-run until the VictoriaMetrics Operator CRD is installed: $m"
continue
fi
if ! out="$(kubectl apply --dry-run=server -f "$m" 2>&1)"; then if ! out="$(kubectl apply --dry-run=server -f "$m" 2>&1)"; then
failed=1 failed=1
echo "::error file=${m}::$(printf '%s' "$out" | head -1)" echo "::error file=${m}::$(printf '%s' "$out" | head -1)"
@@ -332,11 +338,20 @@ jobs:
- name: Detect changed docker-built services - name: Detect changed docker-built services
id: services id: services
shell: bash shell: bash
env:
PUSH_BEFORE: ${{ github.event.before }}
run: | run: |
set -euo pipefail set -euo pipefail
base="${{ github.event.before }}" base="${PUSH_BEFORE:-}"
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then empty_tree="$(git hash-object -t tree /dev/null)"
base="$(git rev-list --max-parents=0 HEAD)" if [[ "$base" =~ ^0{40}$ ]]; then
base="$empty_tree"
elif [[ ! "$base" =~ ^[0-9a-fA-F]{40}$ ]] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then
# Some Gitea push payloads expose `before` as multiple root commits
# joined by newlines. It is not a usable diff base; use this push's
# first parent so image changes in the current commit are still built.
base="$(git rev-parse "${GITHUB_SHA}^" 2>/dev/null || printf '%s' "$empty_tree")"
echo "::warning::invalid push-before value; comparing against ${base}"
fi fi
# A failed diff used to leave changed_files empty, which reads exactly # A failed diff used to leave changed_files empty, which reads exactly
@@ -372,9 +387,6 @@ jobs:
homepages/*) homepages/*)
add_service homepages add_service homepages
;; ;;
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
add_service edu_master
;;
esac esac
done done
@@ -481,32 +493,6 @@ jobs:
done done
done done
;; ;;
edu_master)
for variant in session-keeper webinar-checker; do
case "$variant" in
session-keeper)
context="edu_master/phpsessid-bot"
image="${REGISTRY}/forust/session-keeper"
;;
webinar-checker)
context="edu_master/webinar-checker"
image="${REGISTRY}/forust/webinar-checker"
;;
esac
set_tags
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build \
--cache-from "type=registry,ref=${image}:buildcache" \
--cache-to "type=registry,ref=${image}:buildcache,mode=max" \
"${build_args[@]}" "$context"
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
esac esac
done done
@@ -537,6 +523,11 @@ jobs:
fi fi
echo "pinning ${#repos[@]} image(s) to $commit_tag" echo "pinning ${#repos[@]} image(s) to $commit_tag"
for repo in "${repos[@]}"; do for repo in "${repos[@]}"; do
# EDU images are released by the application repository and pinned
# directly by digest in edu_master manifests. Never retag them here.
case "$repo" in
*/session-keeper|*/webinar-checker) continue ;;
esac
if docker buildx imagetools inspect "$repo:$commit_tag" >/dev/null 2>&1; then if docker buildx imagetools inspect "$repo:$commit_tag" >/dev/null 2>&1; then
echo " already built by this push: ${repo##*/}" echo " already built by this push: ${repo##*/}"
continue continue
+23
View File
@@ -546,6 +546,7 @@ rollback_workloads() {
# have to be declared as custom.regex managers in renovate/renovate.json. # have to be declared as custom.regex managers in renovate/renovate.json.
HELM_RELEASES=( HELM_RELEASES=(
"prometheus-stack|prometheus-community/kube-prometheus-stack|prometheus|86.2.3|prometheus-stack/k8s/grafana-values.yaml|prometheus-stack/k8s/active" "prometheus-stack|prometheus-community/kube-prometheus-stack|prometheus|86.2.3|prometheus-stack/k8s/grafana-values.yaml|prometheus-stack/k8s/active"
"victoria-operator|victoriametrics/victoria-metrics-operator|prometheus|0.68.1|prometheus-stack/k8s/victoria-operator-values.yaml|prometheus-stack/k8s/active"
"loki|grafana/loki|prometheus|7.3.0|loki/k8s/loki-values.yaml|loki/k8s/active" "loki|grafana/loki|prometheus|7.3.0|loki/k8s/loki-values.yaml|loki/k8s/active"
"alloy|grafana/alloy|prometheus|1.12.1|loki/k8s/alloy-values.yaml|loki/k8s/active" "alloy|grafana/alloy|prometheus|1.12.1|loki/k8s/alloy-values.yaml|loki/k8s/active"
"reloader|stakater/reloader|reloader|2.2.17|reloader/k8s/reloader-values.yaml|reloader/k8s/active" "reloader|stakater/reloader|reloader|2.2.17|reloader/k8s/reloader-values.yaml|reloader/k8s/active"
@@ -557,6 +558,7 @@ helm_repo_for() {
prometheus-community/*) echo "prometheus-community https://prometheus-community.github.io/helm-charts" ;; prometheus-community/*) echo "prometheus-community https://prometheus-community.github.io/helm-charts" ;;
grafana/*) echo "grafana https://grafana.github.io/helm-charts" ;; grafana/*) echo "grafana https://grafana.github.io/helm-charts" ;;
stakater/*) echo "stakater https://stakater.github.io/stakater-charts" ;; stakater/*) echo "stakater https://stakater.github.io/stakater-charts" ;;
victoriametrics/*) echo "victoriametrics https://victoriametrics.github.io/helm-charts" ;;
esac esac
} }
@@ -703,6 +705,9 @@ check_referenced_secrets() {
local missing=() local missing=()
refs="" refs=""
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
if skip_uninstalled_vmagent_crd "$m"; then
continue
fi
objects="$(kubectl create --dry-run=client --validate=false -f "$m" -o json)" || return 1 objects="$(kubectl create --dry-run=client --validate=false -f "$m" -o json)" || return 1
extracted="$(printf '%s' "$objects" | jq -r -f "$REPO/.gitea/workflows/secret-references.jq")" || return 1 extracted="$(printf '%s' "$objects" | jq -r -f "$REPO/.gitea/workflows/secret-references.jq")" || return 1
refs+="$extracted"$'\n' refs+="$extracted"$'\n'
@@ -729,6 +734,18 @@ check_referenced_secrets() {
fi fi
} }
# The VMAgent CRD is installed by the VictoriaMetrics Operator Helm release in
# stage_apply_k8s, after this preflight stage. Skip only its dry-run until then.
skip_uninstalled_vmagent_crd() {
local manifest="$1"
if [[ "$manifest" == "$REPO/prometheus-stack/k8s/vmagent.yaml" ]] \
&& ! kubectl get crd vmagents.operator.victoriametrics.com >/dev/null 2>&1; then
echo " skip: VMAgent CRD is installed by Helm during apply: ${manifest#"$REPO"/}"
return 0
fi
return 1
}
stage_validate() { stage_validate() {
check_prune_mode || return 1 check_prune_mode || return 1
cd "$REPO" cd "$REPO"
@@ -746,6 +763,9 @@ stage_validate() {
done done
log "Validate k8s manifests (kubectl dry-run=client)" log "Validate k8s manifests (kubectl dry-run=client)"
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
if skip_uninstalled_vmagent_crd "$m"; then
continue
fi
kubectl apply --dry-run=client -f "$m" >/dev/null kubectl apply --dry-run=client -f "$m" >/dev/null
done done
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
@@ -753,6 +773,9 @@ stage_validate() {
done done
log "Validate k8s manifests (kubectl dry-run=server)" log "Validate k8s manifests (kubectl dry-run=server)"
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
if skip_uninstalled_vmagent_crd "$m"; then
continue
fi
kubectl apply --dry-run=server -f "$m" >/dev/null kubectl apply --dry-run=server -f "$m" >/dev/null
done done
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
+7 -3
View File
@@ -138,9 +138,10 @@ jobs:
# lets it start after a failed dependency; the needs on apply-compose are a # lets it start after a failed dependency; the needs on apply-compose are a
# barrier, so verification begins only once both applies are done. # barrier, so verification begins only once both applies are done.
verify-k8s: verify-k8s:
needs: [apply-k8s, apply-compose] needs: [preflight, apply-k8s, apply-compose]
if: >- if: >-
always() && always() &&
needs.preflight.result == 'success' &&
needs.apply-k8s.result != 'skipped' && needs.apply-k8s.result != 'skipped' &&
needs.apply-compose.result != 'skipped' needs.apply-compose.result != 'skipped'
runs-on: [self-hosted, linux, arch, homelab, prod] runs-on: [self-hosted, linux, arch, homelab, prod]
@@ -183,8 +184,11 @@ jobs:
# suppressing them on a rollback would hide the one run where the answer # suppressing them on a rollback would hide the one run where the answer
# matters most. # matters most.
smoke: smoke:
needs: [verify-k8s] needs: [preflight, verify-k8s]
if: always() && needs.verify-k8s.result != 'skipped' if: >-
always() &&
needs.preflight.result == 'success' &&
needs.verify-k8s.result != 'skipped'
runs-on: [self-hosted, linux, arch, homelab, prod] runs-on: [self-hosted, linux, arch, homelab, prod]
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
+1 -1
View File
@@ -31,7 +31,7 @@ services:
- "traefik.http.routers.adguard-dev.entrypoints=websecure" - "traefik.http.routers.adguard-dev.entrypoints=websecure"
- "traefik.http.routers.adguard-dev.tls=true" - "traefik.http.routers.adguard-dev.tls=true"
# DoH Router # DoH Router
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))" - "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`)"
- "traefik.http.routers.dns-over-https.entrypoints=websecure" - "traefik.http.routers.dns-over-https.entrypoints=websecure"
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt" - "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
+1 -1
View File
@@ -20,7 +20,7 @@ spec:
spec: spec:
containers: containers:
- name: cloudflared - name: cloudflared
image: cloudflare/cloudflared:2026.9.3 image: cloudflare/cloudflared:2026.10.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
args: args:
- tunnel - tunnel
+14
View File
@@ -0,0 +1,14 @@
# EDU deployment ownership
Application source and release builds: `forust/edu-master`.
The homelab pipeline deploys `edu_master/k8s` and preserves explicit image digests.
The application copies in this directory are legacy and are not build inputs.
Do not publish EDU `prod` images from homelab or resolve releases from moving tags.
For an EDU release, validate both images, select their digests in the keeper and
checker manifests, and run the existing homelab validation/apply/verification
helpers against this service. Keep the existing Secret and Redis PVC.
Coordinate Redis authentication changes with both clients and all init/probes;
keep a pre-rollout Redis backup and both previous compatible image references.
The current HTTP checker does not depend on Playwright; check other consumers
before removing the separate browser service.
+31 -12
View File
@@ -50,7 +50,36 @@ spec:
severity: critical severity: critical
annotations: annotations:
summary: "Webinar checker failing consecutively" summary: "Webinar checker failing consecutively"
description: 'edu-master/webinar-checker: {{ $value }} consecutive webinar check failures (timeout / playwright error / page error). Check pod logs (Loki: {namespace="edu-master", container="webinar-checker"}).' description: 'edu-master/webinar-checker: {{ $value }} consecutive webinar check failures (timeout / http error / page error). Check pod logs (Loki: {namespace="edu-master", container="webinar-checker"}).'
- alert: WebinarCheckerNeverStarted
expr: |
(time() - edu_process_start > 120)
and (webinar_check_last_run_timestamp_seconds == 0)
for: 2m
labels:
severity: critical
annotations:
summary: "Webinar checker job has not started"
description: "The process exposes metrics but its webinar job has never started."
- alert: WebinarDeliveryPending
expr: edu_delivery_pending > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Webinar notifications await delivery"
description: "Telegram delivery has pending recipients. Check delivery failures and retry status."
- alert: EduRedisUnavailable
expr: edu_redis_connected == 0
for: 2m
labels:
severity: critical
annotations:
summary: "EDU checker cannot reach Redis"
description: "Redis health checks are failing; checker commands and delivery may be unavailable."
# Metrics endpoint not scraped for 10m: pod down, metrics server dead, or ServiceMonitor broken. # Metrics endpoint not scraped for 10m: pod down, metrics server dead, or ServiceMonitor broken.
- alert: WebinarCheckerScrapeDown - alert: WebinarCheckerScrapeDown
@@ -74,7 +103,7 @@ spec:
summary: "EDU_PHPSESSID missing" summary: "EDU_PHPSESSID missing"
description: "edu-master: EDU_PHPSESSID absent from redis for 10m. Webinar/diari/schedule checks are all skipped. Check session-keeper logs and EDU credentials." description: "edu-master: EDU_PHPSESSID absent from redis for 10m. Webinar/diari/schedule checks are all skipped. Check session-keeper logs and EDU credentials."
# Hard deps: checker and playwright deployments unavailable. # Hard deps: checker deployment unavailable.
- alert: WebinarCheckerDeploymentDown - alert: WebinarCheckerDeploymentDown
expr: | expr: |
kube_deployment_status_replicas_unavailable{deployment="webinar-checker", namespace="edu-master"} > 0 kube_deployment_status_replicas_unavailable{deployment="webinar-checker", namespace="edu-master"} > 0
@@ -84,13 +113,3 @@ spec:
annotations: annotations:
summary: "Webinar checker deployment unavailable" summary: "Webinar checker deployment unavailable"
description: "edu-master/webinar-checker deployment has {{ $value }} unavailable replica(s) for 10m." description: "edu-master/webinar-checker deployment has {{ $value }} unavailable replica(s) for 10m."
- alert: PlaywrightServiceDown
expr: |
kube_deployment_status_replicas_unavailable{deployment="playwright-service", namespace="edu-master"} > 0
for: 10m
labels:
severity: critical
annotations:
summary: "Playwright service unavailable"
description: "edu-master/playwright-service deployment has {{ $value }} unavailable replica(s) for 10m. All webinar/diari/schedule checks fail without it."
+22
View File
@@ -0,0 +1,22 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: redis-clients-only
namespace: edu-master
spec:
podSelector:
matchLabels:
app: edu-master-redis
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: edu-master-session-keeper
- podSelector:
matchLabels:
app: edu-master-webinar-checker
ports:
- protocol: TCP
port: 6379
+21
View File
@@ -20,6 +20,27 @@ spec:
- name: redis - name: redis
image: redis:8.10.2-alpine image: redis:8.10.2-alpine
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: edu-master-secrets
key: REDIS_PASSWORD
- name: REDISCLI_AUTH
valueFrom:
secretKeyRef:
name: edu-master-secrets
key: REDIS_PASSWORD
command:
- /bin/sh
- -ec
- |
case "$REDIS_PASSWORD" in *[!0-9a-fA-F]*|'') echo 'REDIS_PASSWORD must be 64 hex characters' >&2; exit 1;; esac
[ "${#REDIS_PASSWORD}" -eq 64 ] || { echo 'REDIS_PASSWORD must be 64 hex characters' >&2; exit 1; }
umask 077
printf 'requirepass "%s"\n' "$REDIS_PASSWORD" > /tmp/redis-auth.conf
chown redis:redis /tmp/redis-auth.conf
exec docker-entrypoint.sh redis-server /tmp/redis-auth.conf
ports: ports:
- containerPort: 6379 - containerPort: 6379
volumeMounts: volumeMounts:
+15 -1
View File
@@ -16,12 +16,20 @@ spec:
type: Recreate type: Recreate
template: template:
metadata: metadata:
annotations:
edu.forust.xyz/source-commit: "90829d6c8080b9928f9da23587678e640939e10a"
labels: labels:
app: edu-master-session-keeper app: edu-master-session-keeper
spec: spec:
initContainers: initContainers:
- name: wait-redis - name: wait-redis
image: redis:8.10.2-alpine image: redis:8.10.2-alpine
env:
- name: REDISCLI_AUTH
valueFrom:
secretKeyRef:
name: edu-master-secrets
key: REDIS_PASSWORD
command: command:
- /bin/sh - /bin/sh
- -ec - -ec
@@ -35,10 +43,16 @@ spec:
echo "redis is ready" echo "redis is ready"
containers: containers:
- name: session-keeper - name: session-keeper
image: gcr.forust.xyz/forust/session-keeper:prod image: gcr.forust.xyz/forust/session-keeper@sha256:49285e87cc5bc4cf4ffe190813d87927916c2df8a206daac0aeb7d227c636450
envFrom: envFrom:
- secretRef: - secretRef:
name: edu-master-secrets name: edu-master-secrets
env:
- name: REDISCLI_AUTH
valueFrom:
secretKeyRef:
name: edu-master-secrets
key: REDIS_PASSWORD
resources: resources:
requests: requests:
cpu: 25m cpu: 25m
+18 -8
View File
@@ -16,14 +16,22 @@ spec:
type: Recreate type: Recreate
template: template:
metadata: metadata:
annotations:
edu.forust.xyz/source-commit: "90829d6c8080b9928f9da23587678e640939e10a"
labels: labels:
app: edu-master-webinar-checker app: edu-master-webinar-checker
spec: spec:
# Enforces dependency order like compose depends_on: # Enforces dependency order like compose depends_on:
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started # redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID)
initContainers: initContainers:
- name: wait-deps - name: wait-deps
image: redis:8.10.2-alpine image: redis:8.10.2-alpine
env:
- name: REDISCLI_AUTH
valueFrom:
secretKeyRef:
name: edu-master-secrets
key: REDIS_PASSWORD
command: command:
- /bin/sh - /bin/sh
- -ec - -ec
@@ -41,15 +49,9 @@ spec:
sleep 2 sleep 2
done done
echo "PHPSESSID ok" echo "PHPSESSID ok"
until nc -z playwright-service 3000; do
i=$((i+1))
[ "$i" -ge 300 ] && echo "TIMEOUT: playwright-service not reachable" && exit 1
sleep 2
done
echo "playwright ok"
containers: containers:
- name: webinar-checker - name: webinar-checker
image: gcr.forust.xyz/forust/webinar-checker:prod image: gcr.forust.xyz/forust/webinar-checker@sha256:66c146f7b43cb9f0dc31ba9aa36d217e01df42ddafba5971b79c12ec215b2c01
ports: ports:
- name: metrics - name: metrics
containerPort: 8000 containerPort: 8000
@@ -62,6 +64,14 @@ spec:
timeoutSeconds: 3 timeoutSeconds: 3
failureThreshold: 12 failureThreshold: 12
initialDelaySeconds: 10 initialDelaySeconds: 10
livenessProbe:
httpGet:
path: /live
port: metrics
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 4
envFrom: envFrom:
- secretRef: - secretRef:
name: edu-master-secrets name: edu-master-secrets
+1 -1
View File
@@ -1,4 +1,4 @@
FROM python:3.11-slim FROM python:3.14-slim
WORKDIR /app WORKDIR /app
+1 -1
View File
@@ -1,4 +1,4 @@
FROM python:3.11-slim FROM python:3.14-slim
WORKDIR /app WORKDIR /app
+1 -1
View File
@@ -71,7 +71,7 @@ spec:
name: glance-config name: glance-config
- name: glance-assets - name: glance-assets
configMap: configMap:
name: glance-config name: glance-assets
- name: docker-socket - name: docker-socket
hostPath: hostPath:
path: /var/run/docker.sock path: /var/run/docker.sock
+1 -1
View File
@@ -1,7 +1,7 @@
services: services:
homarr: homarr:
container_name: homarr container_name: homarr
image: ghcr.io/homarr-labs/homarr:v2.1.2 image: ghcr.io/homarr-labs/homarr:v2.2.0
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./appdata:/appdata - ./appdata:/appdata
+1 -1
View File
@@ -32,7 +32,7 @@ spec:
serviceAccountName: homarr serviceAccountName: homarr
containers: containers:
- name: homarr - name: homarr
image: ghcr.io/homarr-labs/homarr:v2.1.2 image: ghcr.io/homarr-labs/homarr:v2.2.0
envFrom: envFrom:
- configMapRef: - configMapRef:
name: homarr-config name: homarr-config
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
n8n: n8n:
image: docker.n8n.io/n8nio/n8n:2.42.3 image: docker.n8n.io/n8nio/n8n:2.43.0
container_name: n8n container_name: n8n
restart: unless-stopped restart: unless-stopped
environment: environment:
+1 -1
View File
@@ -31,7 +31,7 @@ spec:
spec: spec:
containers: containers:
- name: n8n - name: n8n
image: docker.n8n.io/n8nio/n8n:2.42.3 image: docker.n8n.io/n8nio/n8n:2.43.0
envFrom: envFrom:
- configMapRef: - configMapRef:
name: n8n-config name: n8n-config
+109
View File
@@ -0,0 +1,109 @@
#!/bin/sh
set -eu
umask 077
TEMPLATE_PATH=/opt/netbird/config.template.yaml
RENDERED_PATH=/run/netbird/config.yaml
RELAY_SECRET_PATH=/run/secrets/relay_auth_secret
ENCRYPTION_KEY_PATH=/run/secrets/datastore_encryption_key
is_valid_proxy_subnet() {
candidate="$1"
case "$candidate" in
0.0.0.0/0)
return 1
;;
*/*)
address="${candidate%%/*}"
prefix="${candidate#*/}"
;;
*)
return 1
;;
esac
case "$prefix" in
0|[1-9]|[1-2][0-9]|3[0-2]) ;;
*)
return 1
;;
esac
old_ifs="$IFS"
IFS=.
# shellcheck disable=SC2086
set -- $address
IFS="$old_ifs"
[ "$#" -eq 4 ] || return 1
for octet do
case "$octet" in
0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ;;
*)
return 1
;;
esac
done
}
read_secret() {
secret_path="$1"
if [ ! -r "$secret_path" ]; then
echo "Required secret is not readable: $secret_path" >&2
exit 1
fi
secret_value="$(cat "$secret_path")"
if [ -z "$secret_value" ]; then
echo "Required secret is empty: $secret_path" >&2
exit 1
fi
printf '%s' "$secret_value"
}
if [ -z "${NETBIRD_DOMAIN:-}" ]; then
echo "NETBIRD_DOMAIN must be set" >&2
exit 1
fi
case "$NETBIRD_DOMAIN" in
*[!A-Za-z0-9.-]*)
echo "NETBIRD_DOMAIN contains unsupported characters" >&2
exit 1
;;
esac
if [ -z "${NETBIRD_PROXY_SUBNET:-}" ] || [ "$NETBIRD_PROXY_SUBNET" = "auto" ]; then
echo "NETBIRD_PROXY_SUBNET must be an explicit IPv4 CIDR; run netbird/setup.sh first" >&2
exit 1
fi
if ! is_valid_proxy_subnet "$NETBIRD_PROXY_SUBNET"; then
echo "NETBIRD_PROXY_SUBNET must be a non-default IPv4 CIDR, for example 172.20.0.0/16" >&2
exit 1
fi
if [ "$#" -ne 2 ] || [ "$1" != "--config" ] || [ "$2" != "$RENDERED_PATH" ]; then
echo "Expected: --config $RENDERED_PATH" >&2
exit 1
fi
relay_secret="$(read_secret "$RELAY_SECRET_PATH")"
encryption_key="$(read_secret "$ENCRYPTION_KEY_PATH")"
mkdir -p "$(dirname "$RENDERED_PATH")"
sed \
-e "s|__NETBIRD_DOMAIN__|${NETBIRD_DOMAIN}|g" \
-e "s|__NETBIRD_AUTH_SECRET__|${relay_secret}|g" \
-e "s|__NETBIRD_ENCRYPTION_KEY__|${encryption_key}|g" \
-e "s|__NETBIRD_PROXY_SUBNET__|${NETBIRD_PROXY_SUBNET}|g" \
"$TEMPLATE_PATH" >"$RENDERED_PATH"
if grep -q '__NETBIRD_' "$RENDERED_PATH"; then
echo "Rendered NetBird configuration still contains unresolved placeholders" >&2
exit 1
fi
exec /go/bin/netbird-server "$@"
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Prepare local Compose configuration without replacing existing credentials.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
umask 077
if [ ! -f .env ]; then
cp .env.example .env
fi
if grep -q '^NETBIRD_PROXY_SUBNET=auto$' .env; then
subnet="$(docker network inspect proxy --format '{{range .IPAM.Config}}{{println .Subnet}}{{end}}' | awk '/^[0-9]+\./ { print; exit }')"
if [ -z "$subnet" ]; then
echo "No IPv4 subnet found on the Docker proxy network. Set NETBIRD_PROXY_SUBNET in .env." >&2
exit 1
fi
# The detected value must be safe to substitute into the env file.
if [[ ! "$subnet" =~ ^[0-9.]+/[0-9]+$ ]]; then
echo "Unexpected Docker network subnet: $subnet" >&2
exit 1
fi
sed -i "s|^NETBIRD_PROXY_SUBNET=auto$|NETBIRD_PROXY_SUBNET=$subnet|" .env
fi
mkdir -p secrets
chmod 700 secrets
for name in relay-auth-secret datastore-encryption-key; do
path="secrets/$name"
if [ -e "$path" ]; then
if [ ! -s "$path" ]; then
echo "Existing secret is empty: $path. Restore it before continuing." >&2
exit 1
fi
else
openssl rand -base64 32 >"$path"
fi
chmod 600 "$path"
done
printf '%s\n' 'Local files are ready. Review .env, then run docker compose config --quiet.'
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
netronome: netronome:
image: ghcr.io/autobrr/netronome:v0.15.0 image: ghcr.io/autobrr/netronome:v0.16.0
restart: unless-stopped restart: unless-stopped
container_name: netronome container_name: netronome
ports: ports:
+1 -1
View File
@@ -34,7 +34,7 @@ spec:
spec: spec:
containers: containers:
- name: netronome - name: netronome
image: ghcr.io/autobrr/netronome:v0.15.0 image: ghcr.io/autobrr/netronome:v0.16.0
ports: ports:
- name: netronome-port - name: netronome-port
protocol: TCP protocol: TCP
+1
View File
@@ -1,6 +1,7 @@
POSTGRES_ADMIN_PASSWORD= POSTGRES_ADMIN_PASSWORD=
AUTHENTIK_DB_PASSWORD= AUTHENTIK_DB_PASSWORD=
GITEA_DB_PASSWORD= GITEA_DB_PASSWORD=
NETBOX_DB_PASSWORD=
NETRONOME_DB_PASSWORD= NETRONOME_DB_PASSWORD=
PENPOT_DB_PASSWORD= PENPOT_DB_PASSWORD=
STATUSPAGE_DB_PASSWORD= STATUSPAGE_DB_PASSWORD=
+17
View File
@@ -0,0 +1,17 @@
# VictoriaMetrics
The `victoria-operator` Helm release converts Prometheus Operator
`ServiceMonitor` resources into owned `VMServiceScrape` resources. The
`VMAgent` selects converted scrapes labeled `release: prometheus-stack` in all
namespaces and writes them to the existing single-node VictoriaMetrics
instance. Changes to selected `ServiceMonitor` resources are reconciled
automatically; there is no copied Prometheus scrape-config blob to regenerate.
The agent drops targets for the Prometheus server service to avoid duplicating
its self-scrape. `scraper: victoria` identifies the samples ingested by this
VMAgent.
The VictoriaMetrics Operator chart and its CRDs are installed before the
Kubernetes manifests by the normal deploy workflow. On a cluster where the
operator CRDs are not installed yet, CI skips the server-side dry-run of the
`VMAgent` resource; the deploy installs the chart before applying that resource.
+11
View File
@@ -38,6 +38,8 @@ grafana:
# One block covers both the dashboards and datasources sidecars (p95 91M / 80M). # One block covers both the dashboards and datasources sidecars (p95 91M / 80M).
sidecar: sidecar:
datasources:
defaultDatasourceEnabled: false
resources: resources:
requests: requests:
memory: "96Mi" memory: "96Mi"
@@ -50,9 +52,18 @@ grafana:
type: loki type: loki
url: http://loki-gateway.prometheus.svc.cluster.local url: http://loki-gateway.prometheus.svc.cluster.local
access: proxy access: proxy
- name: VictoriaMetrics
type: prometheus
url: http://victoria-metrics.prometheus.svc.cluster.local:8428
access: proxy
isDefault: true
prometheus: prometheus:
prometheusSpec: prometheusSpec:
# VM trial: vmagent scrapes and remote-writes to VictoriaMetrics, so the
# Prometheus server itself stands down. Encoded here (not a kubectl patch)
# so helm keeps owning spec.replicas and upgrades do not conflict on it.
replicas: 0
retention: 60d retention: 60d
retentionSize: 32GB retentionSize: 32GB
storageSpec: storageSpec:
+102
View File
@@ -31,3 +31,105 @@ spec:
port: 80 port: 80
tls: tls:
secretName: internal-wildcard-tls secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: prometheus-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`prom.workstation.internal`) || Host(`prom.gigaforust.internal`)
kind: Rule
services:
- name: prometheus-stack-kube-prom-prometheus
port: 9090
tls:
secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: alertmanager-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`am.workstation.internal`) || Host(`am.gigaforust.internal`)
kind: Rule
services:
- name: prometheus-stack-kube-prom-alertmanager
port: 9093
tls:
secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: loki-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`loki.workstation.internal`) || Host(`loki.gigaforust.internal`)
kind: Rule
services:
- name: loki-gateway
port: 80
tls:
secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: alloy-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`alloy.workstation.internal`) || Host(`alloy.gigaforust.internal`)
kind: Rule
services:
- name: alloy
port: 12345
tls:
secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: victoria-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`victoria.workstation.internal`) || Host(`victoria.gigaforust.internal`)
kind: Rule
services:
- name: victoria-metrics
port: 8428
tls:
secretName: internal-wildcard-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: vmalert-local
namespace: prometheus
spec:
entryPoints:
- websecure
routes:
- match: Host(`vmalert.workstation.internal`) || Host(`vmalert.gigaforust.internal`)
kind: Rule
services:
- name: vmalert
port: 8880
tls:
secretName: internal-wildcard-tls
@@ -0,0 +1,12 @@
nameOverride: victoria-operator
operator:
enable_converter_ownership: true
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 200m
memory: 256Mi
+79
View File
@@ -0,0 +1,79 @@
apiVersion: v1
kind: Service
metadata:
name: victoria-metrics
namespace: prometheus
spec:
selector:
app: victoria-metrics
ports:
- port: 8428
targetPort: 8428
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: victoria-pvc
namespace: prometheus
spec:
resources:
requests:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: victoria-deployment
namespace: prometheus
spec:
replicas: 1
selector:
matchLabels:
app: victoria-metrics
strategy:
type: Recreate
template:
metadata:
labels:
app: victoria-metrics
spec:
containers:
- name: victoria
image: victoriametrics/victoria-metrics:v1.153.0-scratch
args:
- -storageDataPath=/vmdata
- -retentionPeriod=30d
- -httpListenAddr=:8428
ports:
- containerPort: 8428
readinessProbe:
httpGet:
path: /health
port: 8428
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 6
livenessProbe:
httpGet:
path: /health
port: 8428
initialDelaySeconds: 60
periodSeconds: 30
failureThreshold: 3
volumeMounts:
- name: vmdata
mountPath: /vmdata
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
volumes:
- name: vmdata
persistentVolumeClaim:
claimName: victoria-pvc
+29
View File
@@ -0,0 +1,29 @@
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
name: vmagent
namespace: prometheus
spec:
image:
tag: v1.153.0
scrapeInterval: 30s
externalLabels:
scraper: victoria
serviceScrapeNamespaceSelector: {}
serviceScrapeSelector:
matchLabels:
release: prometheus-stack
globalScrapeRelabelConfigs:
- action: drop
source_labels:
- __meta_kubernetes_service_name
regex: prometheus-stack-kube-prom-prometheus
remoteWrite:
- url: http://victoria-metrics.prometheus.svc.cluster.local:8428/api/v1/write
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1000m"
memory: 1Gi
+70
View File
@@ -0,0 +1,70 @@
apiVersion: v1
kind: Service
metadata:
name: vmalert
namespace: prometheus
spec:
selector:
app: vmalert
ports:
- port: 8880
targetPort: 8880
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vmalert-deployment
namespace: prometheus
spec:
replicas: 1
selector:
matchLabels:
app: vmalert
strategy:
type: Recreate
template:
metadata:
labels:
app: vmalert
spec:
containers:
- name: vmalert
image: victoriametrics/vmalert:v1.153.0
args:
- -datasource.url=http://victoria-metrics.prometheus.svc.cluster.local:8428
- -remoteWrite.url=http://victoria-metrics.prometheus.svc.cluster.local:8428
- -notifier.url=http://prometheus-stack-kube-prom-alertmanager.prometheus.svc.cluster.local:9093
- -rule=/etc/vm/rules/*.yaml
- -evaluationInterval=60s
- -httpListenAddr=:8880
ports:
- containerPort: 8880
readinessProbe:
httpGet:
path: /metrics
port: 8880
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 6
livenessProbe:
httpGet:
path: /metrics
port: 8880
initialDelaySeconds: 60
periodSeconds: 30
failureThreshold: 3
volumeMounts:
- name: rules
mountPath: /etc/vm/rules
readOnly: true
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "256Mi"
volumes:
- name: rules
configMap:
name: prometheus-prometheus-stack-kube-prom-prometheus-rulefiles-0
+48 -25
View File
@@ -19,6 +19,9 @@ data:
"dependencyDashboard": true, "dependencyDashboard": true,
"prCreation": "immediate", "prCreation": "immediate",
"labels": ["dependencies", "automated"], "labels": ["dependencies", "automated"],
"docker-compose": {
"managerFilePatterns": ["renovate/renovate-compose.yaml"]
},
"helm-values": { "helm-values": {
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"] "managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
}, },
@@ -29,7 +32,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)", "description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
"managerFilePatterns": ["^edu_master/k8s/playwright\\.yaml$", "^edu_master/compose\\.yaml$"], "managerFilePatterns": ["edu_master/k8s/playwright.yaml", "edu_master/compose.yaml"],
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"], "matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
"datasourceTemplate": "npm", "datasourceTemplate": "npm",
"depNameTemplate": "playwright" "depNameTemplate": "playwright"
@@ -37,24 +40,42 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "singlesource: PLAYWRIGHT_VERSION file", "description": "singlesource: PLAYWRIGHT_VERSION file",
"managerFilePatterns": ["^edu_master/PLAYWRIGHT_VERSION$"], "managerFilePatterns": ["edu_master/PLAYWRIGHT_VERSION"],
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)$"], "matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n)?$"],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "playwright" "depNameTemplate": "playwright"
}, },
{
"customType": "regex",
"description": "singlesource: playwright Python client version pinned in Dockerfile ARG",
"managerFilePatterns": ["edu_master/webinar-checker/Dockerfile"],
"matchStrings": ["(?:^|\\n)ARG PLAYWRIGHT_VERSION=(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n|$)"],
"datasourceTemplate": "pypi",
"depNameTemplate": "playwright",
"versioningTemplate": "pep440"
},
{ {
"customType": "regex", "customType": "regex",
"description": "kube-prometheus-stack chart version pinned in the deploy workflow", "description": "kube-prometheus-stack chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "kube-prometheus-stack", "depNameTemplate": "kube-prometheus-stack",
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts" "registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
}, },
{
"customType": "regex",
"description": "VictoriaMetrics Operator chart version pinned in the deploy workflow",
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|victoriametrics/victoria-metrics-operator\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm",
"depNameTemplate": "victoria-metrics-operator",
"registryUrlTemplate": "https://victoriametrics.github.io/helm-charts"
},
{ {
"customType": "regex", "customType": "regex",
"description": "grafana/loki chart version pinned in the deploy workflow", "description": "grafana/loki chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "loki", "depNameTemplate": "loki",
@@ -63,7 +84,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "grafana/alloy chart version pinned in the deploy workflow", "description": "grafana/alloy chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "alloy", "depNameTemplate": "alloy",
@@ -72,7 +93,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "actionlint version used by the ci workflow", "description": "actionlint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "rhysd/actionlint" "depNameTemplate": "rhysd/actionlint"
@@ -80,7 +101,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "shellcheck version used by the ci workflow", "description": "shellcheck version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "koalaman/shellcheck" "depNameTemplate": "koalaman/shellcheck"
@@ -88,7 +109,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "kubeconform version used by the ci workflow", "description": "kubeconform version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "yannh/kubeconform" "depNameTemplate": "yannh/kubeconform"
@@ -96,7 +117,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "uv version used to build the pytest venv", "description": "uv version used to build the pytest venv",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "astral-sh/uv" "depNameTemplate": "astral-sh/uv"
@@ -104,7 +125,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "prettier version used by the ci workflow", "description": "prettier version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "npm", "datasourceTemplate": "npm",
"depNameTemplate": "prettier" "depNameTemplate": "prettier"
@@ -112,7 +133,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "ruff version used by the ci workflow", "description": "ruff version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "ruff" "depNameTemplate": "ruff"
@@ -120,7 +141,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "pip-audit version used by the ci workflow", "description": "pip-audit version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "pip-audit" "depNameTemplate": "pip-audit"
@@ -128,7 +149,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "yamllint version used by the ci workflow", "description": "yamllint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "yamllint" "depNameTemplate": "yamllint"
@@ -136,7 +157,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "hadolint version used by the ci workflow", "description": "hadolint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "hadolint/hadolint" "depNameTemplate": "hadolint/hadolint"
@@ -144,7 +165,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "node version the ci workflow runs npm with", "description": "node version the ci workflow runs npm with",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "node", "datasourceTemplate": "node",
"depNameTemplate": "node" "depNameTemplate": "node"
@@ -152,7 +173,7 @@ data:
{ {
"customType": "regex", "customType": "regex",
"description": "stakater/reloader chart version pinned in the deploy workflow", "description": "stakater/reloader chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "reloader", "depNameTemplate": "reloader",
@@ -161,7 +182,7 @@ data:
], ],
"packageRules": [ "packageRules": [
{ {
"description": "Automerge digest and patch updates - safe by definition, review adds nothing, keeps the renovate queue and the deploy line short. Specific no-automerge rules below still override this for playwright, helm and majors.", "description": "Automerge ordinary digest and patch updates after successful checks; specific manual-review rules below override this.",
"matchUpdateTypes": ["digest", "patch"], "matchUpdateTypes": ["digest", "patch"],
"automerge": true "automerge": true
}, },
@@ -172,6 +193,12 @@ data:
"groupSlug": "all-minor", "groupSlug": "all-minor",
"automerge": false "automerge": false
}, },
{
"description": "Group ordinary patch updates; the specific groups and manual-review rules below take precedence",
"matchUpdateTypes": ["patch"],
"groupName": "all patch updates",
"groupSlug": "all-patch"
},
{ {
"description": "Keep private homelab images unchanged", "description": "Keep private homelab images unchanged",
"matchDatasources": ["docker"], "matchDatasources": ["docker"],
@@ -196,7 +223,7 @@ data:
"automerge": false "automerge": false
}, },
{ {
"description": "CI runs npm on the node the panel image is built from - the NODE_VERSION pin in tool-versions.env and node:22-alpine in the Dockerfile are the same dependency and move as one", "description": "Keep CI Node runtime updates in a separate, manually reviewed group",
"matchPackageNames": ["node"], "matchPackageNames": ["node"],
"groupName": "node runtime", "groupName": "node runtime",
"groupSlug": "node", "groupSlug": "node",
@@ -205,6 +232,8 @@ data:
{ {
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable", "description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
"matchDatasources": ["helm"], "matchDatasources": ["helm"],
"groupName": "Helm chart {{depName}}",
"groupSlug": "helm-{{depName}}",
"automerge": false "automerge": false
}, },
{ {
@@ -213,12 +242,6 @@ data:
"dependencyDashboardApproval": true, "dependencyDashboardApproval": true,
"automerge": false "automerge": false
}, },
{
"description": "Group patch updates from all sources - automerge still applies via the digest/patch rule above (helm/playwright stay manual via their own rules)",
"matchUpdateTypes": ["patch"],
"groupName": "all patch updates",
"groupSlug": "all-patch"
},
{ {
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.", "description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
"matchDatasources": ["docker"], "matchDatasources": ["docker"],
+1 -1
View File
@@ -19,7 +19,7 @@ spec:
restartPolicy: Never restartPolicy: Never
containers: containers:
- name: renovate - name: renovate
image: renovate/renovate:44.136.0 image: renovate/renovate:44.140.0
env: env:
- name: RENOVATE_PLATFORM - name: RENOVATE_PLATFORM
value: gitea value: gitea
+1 -1
View File
@@ -2,7 +2,7 @@ services:
renovate: renovate:
# Kept in step with renovate/k8s/cronjob.yaml by the "renovate self-update" # Kept in step with renovate/k8s/cronjob.yaml by the "renovate self-update"
# package rule in renovate/renovate.json. # package rule in renovate/renovate.json.
image: renovate/renovate:44.115.9 image: renovate/renovate:44.136.0
container_name: renovate container_name: renovate
restart: "no" restart: "no"
env_file: env_file:
+48 -25
View File
@@ -8,6 +8,9 @@
"dependencyDashboard": true, "dependencyDashboard": true,
"prCreation": "immediate", "prCreation": "immediate",
"labels": ["dependencies", "automated"], "labels": ["dependencies", "automated"],
"docker-compose": {
"managerFilePatterns": ["renovate/renovate-compose.yaml"]
},
"helm-values": { "helm-values": {
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"] "managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
}, },
@@ -18,7 +21,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)", "description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
"managerFilePatterns": ["^edu_master/k8s/playwright\\.yaml$", "^edu_master/compose\\.yaml$"], "managerFilePatterns": ["edu_master/k8s/playwright.yaml", "edu_master/compose.yaml"],
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"], "matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
"datasourceTemplate": "npm", "datasourceTemplate": "npm",
"depNameTemplate": "playwright" "depNameTemplate": "playwright"
@@ -26,24 +29,42 @@
{ {
"customType": "regex", "customType": "regex",
"description": "singlesource: PLAYWRIGHT_VERSION file", "description": "singlesource: PLAYWRIGHT_VERSION file",
"managerFilePatterns": ["^edu_master/PLAYWRIGHT_VERSION$"], "managerFilePatterns": ["edu_master/PLAYWRIGHT_VERSION"],
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)$"], "matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n)?$"],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "playwright" "depNameTemplate": "playwright"
}, },
{
"customType": "regex",
"description": "singlesource: playwright Python client version pinned in Dockerfile ARG",
"managerFilePatterns": ["edu_master/webinar-checker/Dockerfile"],
"matchStrings": ["(?:^|\\n)ARG PLAYWRIGHT_VERSION=(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n|$)"],
"datasourceTemplate": "pypi",
"depNameTemplate": "playwright",
"versioningTemplate": "pep440"
},
{ {
"customType": "regex", "customType": "regex",
"description": "kube-prometheus-stack chart version pinned in the deploy workflow", "description": "kube-prometheus-stack chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "kube-prometheus-stack", "depNameTemplate": "kube-prometheus-stack",
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts" "registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
}, },
{
"customType": "regex",
"description": "VictoriaMetrics Operator chart version pinned in the deploy workflow",
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|victoriametrics/victoria-metrics-operator\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm",
"depNameTemplate": "victoria-metrics-operator",
"registryUrlTemplate": "https://victoriametrics.github.io/helm-charts"
},
{ {
"customType": "regex", "customType": "regex",
"description": "grafana/loki chart version pinned in the deploy workflow", "description": "grafana/loki chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "loki", "depNameTemplate": "loki",
@@ -52,7 +73,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "grafana/alloy chart version pinned in the deploy workflow", "description": "grafana/alloy chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "alloy", "depNameTemplate": "alloy",
@@ -61,7 +82,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "actionlint version used by the ci workflow", "description": "actionlint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "rhysd/actionlint" "depNameTemplate": "rhysd/actionlint"
@@ -69,7 +90,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "shellcheck version used by the ci workflow", "description": "shellcheck version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "koalaman/shellcheck" "depNameTemplate": "koalaman/shellcheck"
@@ -77,7 +98,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "kubeconform version used by the ci workflow", "description": "kubeconform version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "yannh/kubeconform" "depNameTemplate": "yannh/kubeconform"
@@ -85,7 +106,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "uv version used to build the pytest venv", "description": "uv version used to build the pytest venv",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "astral-sh/uv" "depNameTemplate": "astral-sh/uv"
@@ -93,7 +114,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "prettier version used by the ci workflow", "description": "prettier version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "npm", "datasourceTemplate": "npm",
"depNameTemplate": "prettier" "depNameTemplate": "prettier"
@@ -101,7 +122,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "ruff version used by the ci workflow", "description": "ruff version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "ruff" "depNameTemplate": "ruff"
@@ -109,7 +130,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "pip-audit version used by the ci workflow", "description": "pip-audit version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "pip-audit" "depNameTemplate": "pip-audit"
@@ -117,7 +138,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "yamllint version used by the ci workflow", "description": "yamllint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "pypi", "datasourceTemplate": "pypi",
"depNameTemplate": "yamllint" "depNameTemplate": "yamllint"
@@ -125,7 +146,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "hadolint version used by the ci workflow", "description": "hadolint version used by the ci workflow",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "github-tags", "datasourceTemplate": "github-tags",
"depNameTemplate": "hadolint/hadolint" "depNameTemplate": "hadolint/hadolint"
@@ -133,7 +154,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "node version the ci workflow runs npm with", "description": "node version the ci workflow runs npm with",
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"], "managerFilePatterns": [".gitea/workflows/tool-versions.env"],
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""], "matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
"datasourceTemplate": "node", "datasourceTemplate": "node",
"depNameTemplate": "node" "depNameTemplate": "node"
@@ -141,7 +162,7 @@
{ {
"customType": "regex", "customType": "regex",
"description": "stakater/reloader chart version pinned in the deploy workflow", "description": "stakater/reloader chart version pinned in the deploy workflow",
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"], "managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"], "matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
"datasourceTemplate": "helm", "datasourceTemplate": "helm",
"depNameTemplate": "reloader", "depNameTemplate": "reloader",
@@ -150,7 +171,7 @@
], ],
"packageRules": [ "packageRules": [
{ {
"description": "Automerge digest and patch updates - safe by definition, review adds nothing, keeps the renovate queue and the deploy line short. Specific no-automerge rules below still override this for playwright, helm and majors.", "description": "Automerge ordinary digest and patch updates after successful checks; specific manual-review rules below override this.",
"matchUpdateTypes": ["digest", "patch"], "matchUpdateTypes": ["digest", "patch"],
"automerge": true "automerge": true
}, },
@@ -161,6 +182,12 @@
"groupSlug": "all-minor", "groupSlug": "all-minor",
"automerge": false "automerge": false
}, },
{
"description": "Group ordinary patch updates; the specific groups and manual-review rules below take precedence",
"matchUpdateTypes": ["patch"],
"groupName": "all patch updates",
"groupSlug": "all-patch"
},
{ {
"description": "Keep private homelab images unchanged", "description": "Keep private homelab images unchanged",
"matchDatasources": ["docker"], "matchDatasources": ["docker"],
@@ -185,7 +212,7 @@
"automerge": false "automerge": false
}, },
{ {
"description": "CI runs npm on the node the panel image is built from - the NODE_VERSION pin in tool-versions.env and node:22-alpine in the Dockerfile are the same dependency and move as one", "description": "Keep CI Node runtime updates in a separate, manually reviewed group",
"matchPackageNames": ["node"], "matchPackageNames": ["node"],
"groupName": "node runtime", "groupName": "node runtime",
"groupSlug": "node", "groupSlug": "node",
@@ -194,6 +221,8 @@
{ {
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable", "description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
"matchDatasources": ["helm"], "matchDatasources": ["helm"],
"groupName": "Helm chart {{depName}}",
"groupSlug": "helm-{{depName}}",
"automerge": false "automerge": false
}, },
{ {
@@ -202,12 +231,6 @@
"dependencyDashboardApproval": true, "dependencyDashboardApproval": true,
"automerge": false "automerge": false
}, },
{
"description": "Group patch updates from all sources - automerge still applies via the digest/patch rule above (helm/playwright stay manual via their own rules)",
"matchUpdateTypes": ["patch"],
"groupName": "all patch updates",
"groupSlug": "all-patch"
},
{ {
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.", "description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
"matchDatasources": ["docker"], "matchDatasources": ["docker"],
+2 -2
View File
@@ -12,11 +12,11 @@ services:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.services.searxng.loadbalancer.server.port=8080" - "traefik.http.services.searxng.loadbalancer.server.port=8080"
# Prod Router # Prod Router
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `search.forust.xyz`)" - "traefik.http.routers.searxng.rule=Host(`s.forust.xyz`) || Host(`search.forust.xyz`)"
- "traefik.http.routers.searxng.entrypoints=websecure" - "traefik.http.routers.searxng.entrypoints=websecure"
- "traefik.http.routers.searxng.tls.certresolver=letsencrypt" - "traefik.http.routers.searxng.tls.certresolver=letsencrypt"
# Local Router # Local Router
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)" - "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal`) || Host(`searxng.workstation.internal`)"
- "traefik.http.routers.searxng-local.entrypoints=websecure" - "traefik.http.routers.searxng-local.entrypoints=websecure"
- "traefik.http.routers.searxng-local.tls=true" - "traefik.http.routers.searxng-local.tls=true"
# Dev Router # Dev Router
+1 -1
View File
@@ -19,7 +19,7 @@ services:
- streaming - streaming
qbittorrent: qbittorrent:
image: lscr.io/linuxserver/qbittorrent:5.2.4 image: lscr.io/linuxserver/qbittorrent:20.04.1
container_name: qbittorrent container_name: qbittorrent
restart: unless-stopped restart: unless-stopped
environment: environment:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
termix: termix:
image: ghcr.io/lukegus/termix:2.9.1 image: ghcr.io/lukegus/termix:2.9.2
container_name: termix container_name: termix
restart: unless-stopped restart: unless-stopped
# ports: # ports:
+1 -1
View File
@@ -31,7 +31,7 @@ spec:
spec: spec:
containers: containers:
- name: termix - name: termix
image: ghcr.io/lukegus/termix:2.9.1 image: ghcr.io/lukegus/termix:2.9.2
envFrom: envFrom:
- configMapRef: - configMapRef:
name: termix-config name: termix-config
+87
View File
@@ -0,0 +1,87 @@
"""Exercise local setup and config rendering without a Docker daemon."""
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
class NetbirdRuntimeTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
self.stack = self.root / 'netbird'
self.stack.mkdir()
for name in ('setup.sh', '.env.example', 'config.template.yaml'):
shutil.copy(ROOT / 'netbird' / name, self.stack / name)
binary = self.root / 'bin'
binary.mkdir()
docker = binary / 'docker'
docker.write_text('#!/bin/sh\nprintf "%s\\n" 172.20.0.0/16\n')
docker.chmod(0o755)
self.env = dict(os.environ, PATH=f'{binary}:{os.environ["PATH"]}')
def setup(self):
return subprocess.run( # noqa: S603 - executes the repository script copied into this test's temp dir
['/bin/bash', str(self.stack / 'setup.sh')], env=self.env, capture_output=True, check=False
)
def test_setup_preserves_existing_secrets_and_env(self):
self.assertEqual(self.setup().returncode, 0)
paths = [self.stack / '.env', *sorted((self.stack / 'secrets').iterdir())]
before = [p.read_bytes() for p in paths]
self.assertIn(b'NETBIRD_PROXY_SUBNET=172.20.0.0/16', before[0])
self.assertEqual(self.setup().returncode, 0)
self.assertEqual(before, [p.read_bytes() for p in paths])
for p in paths[1:]:
self.assertEqual(p.stat().st_mode & 0o777, 0o600)
def test_setup_rejects_empty_existing_secret(self):
(self.stack / 'secrets').mkdir()
secret = self.stack / 'secrets/datastore-encryption-key'
secret.touch()
self.assertNotEqual(self.setup().returncode, 0)
self.assertEqual(secret.read_bytes(), b'')
def render(self, subnet):
self.assertEqual(self.setup().returncode, 0)
rendered = self.root / 'run/config.yaml'
script = (ROOT / 'netbird/entrypoint.sh').read_text()
replacements = {
'/opt/netbird/config.template.yaml': str(self.stack / 'config.template.yaml'),
'/run/netbird/config.yaml': str(rendered),
'/run/secrets/relay_auth_secret': str(self.stack / 'secrets/relay-auth-secret'),
'/run/secrets/datastore_encryption_key': str(self.stack / 'secrets/datastore-encryption-key'),
'/go/bin/netbird-server': '/bin/true',
}
for original, local in replacements.items():
script = script.replace(original, local)
result = subprocess.run( # noqa: S603 - repository renderer, with test-local paths
['/bin/sh', '-c', script, 'entrypoint', '--config', str(rendered)],
env=dict(self.env, NETBIRD_DOMAIN='nb.example.com', NETBIRD_PROXY_SUBNET=subnet),
capture_output=True,
check=False,
)
return result, rendered
def test_renderer_replaces_placeholders_and_restricts_file_permissions(self):
result, rendered = self.render('172.20.0.0/16')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertNotIn('__NETBIRD_', rendered.read_text())
self.assertIn('nb.example.com', rendered.read_text())
self.assertEqual(rendered.stat().st_mode & 0o777, 0o600)
def test_renderer_rejects_auto_and_default_route(self):
for subnet in ('auto', '0.0.0.0/0', '999.1.1.1/24'):
with self.subTest(subnet=subnet):
result, _ = self.render(subnet)
self.assertNotEqual(result.returncode, 0)
if __name__ == '__main__':
unittest.main()
+1 -1
View File
@@ -1,7 +1,7 @@
services: services:
server: server:
container_name: vaultwarden-server container_name: vaultwarden-server
image: vaultwarden/server:1.37.3 image: vaultwarden/server:1.37.4
restart: unless-stopped restart: unless-stopped
ports: ports:
- 9993:80 - 9993:80
+1 -1
View File
@@ -31,7 +31,7 @@ spec:
spec: spec:
containers: containers:
- name: vaultwarden - name: vaultwarden
image: vaultwarden/server:1.37.3 image: vaultwarden/server:1.37.4
ports: ports:
- containerPort: 80 - containerPort: 80
envFrom: envFrom:
+1 -1
View File
@@ -38,7 +38,7 @@ spec:
spec: spec:
containers: containers:
- name: xui - name: xui
image: ghcr.io/mhsanaei/3x-ui:v3.8.5 image: ghcr.io/mhsanaei/3x-ui:v3.9.0
envFrom: envFrom:
- configMapRef: - configMapRef:
name: xui-config name: xui-config