Files
home-network-k3s-impl/platform/homepage/configmap.yaml
T
jakman85andClaude Opus 5 02c58aae15 fix(homepage): the C2 root hid a running service — Crafty had no tile
The R-C2-01 check added in the previous commit is RED on main for a real reason.
platform/crafty/httproute.yaml serves crafty.${BASE_DOMAIN} on the shared Gateway,
clusters/base/crafty.yaml reconciles it (dependsOn platform-config, wait:false), the web
UI is Keycloak-gated by a per-pod oauth2-proxy sidecar — and nothing on the operator's
front door linked to it. The service was running and the root did not admit it existed.

R-C2-01: "The root `home.keithjackson.dev` MUST serve a UI that surfaces the services
running in the cluster and links to them." An unsurfaced route is a requirement gap, not
a missing nicety, and it is the exact failure mode nothing else in the gate notices: every
cluster test stays green, the apex answers 200, and the estate is one service larger than
the dashboard says.

This is the SAME defect the unmerged 49c160d found on 2026-09-07 (feat/coverage-debt-
paydown, ~107 commits behind main). That branch was never merged, so the gap survived —
re-fixed here against today's tree, in token form (`crafty.${BASE_DOMAIN}`, not the
literal hostname that branch predated).

Grouped under Media because Crafty manages game servers; Platform would be equally
defensible and purely cosmetic. The tile also does duty for the L4 game ports
(crafty-mc.${BASE_DOMAIN}, TCP 25565-25567 / UDP 19132-19134), which have no browsable URL
of their own — the check reports those as an advisory rather than requiring a link.

ALSO: clusters/base/homepage.yaml's postBuild comment claimed "Homepage references no
${VARS} today; the substitution is retained for parity". That is no longer true and the
claim is dangerous, because it invites someone to delete the substitution as dead weight.
This component now references ${BASE_DOMAIN} in httproute.yaml's apex hostname AND in every
tile href; without substitution the token is applied literally, the apex route binds a host
matching no listener, every link on the root is dead, and Flux still reports Ready. Comment
corrected, and the property is asserted by c2-root-surface (5) so it cannot rot back.

Verified: conformance/tests/l0-static/c2-root-surface -> check OK, 49 assertions.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-13 16:28:21 -05:00

156 lines
5.6 KiB
YAML

---
# Homepage configuration (gethomepage). Each key is mounted read-only into /app/config via a subPath
# (deployment.yaml) — the exact file set the app expects (services/settings/bookmarks/widgets +
# docker/kubernetes/proxmox + custom.css/js). Plain link tiles only: NO service-widget API keys are wired
# here (that needs per-service secrets — flagged as a follow-up), so nothing sensitive lives in this
# ConfigMap. Icons use the app-BUNDLED Material Design set (`mdi-*`) so no icon CDN is fetched and the
# pod's egress stays DNS-only (networkpolicy.yaml). Brand icons (selfh.st/dashboard-icons) would need
# world:443 egress — deliberately not used.
apiVersion: v1
kind: ConfigMap
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage
data:
settings.yaml: |
---
title: Home Network
headerStyle: clean
theme: dark
color: slate
hideVersion: true
layout:
Platform:
style: row
columns: 3
Media:
style: row
columns: 3
Network & Infra:
style: row
columns: 3
services.yaml: |
---
- Platform:
- Headlamp:
href: https://headlamp.${BASE_DOMAIN}
description: Kubernetes dashboard (per-user OIDC RBAC)
icon: mdi-kubernetes
- Grafana:
href: https://grafana.${BASE_DOMAIN}
description: Metrics, logs & dashboards (fronts Prometheus/Loki/Alertmanager)
icon: mdi-chart-areaspline
- Semaphore:
href: https://semaphore.${BASE_DOMAIN}
description: Ansible automation & CI
icon: mdi-cog-play
- Gitea:
href: https://gitea.${BASE_DOMAIN}
description: Git hosting & Actions (GitOps source of truth)
icon: mdi-git
- Keycloak:
href: https://keycloak.${BASE_DOMAIN}
description: Identity provider (SSO / OIDC)
icon: mdi-account-key
- Media:
- Plex:
href: https://plex.${BASE_DOMAIN}
description: Media streaming
icon: mdi-plex
- Seerr:
href: https://seerr.${BASE_DOMAIN}
description: Media requests
icon: mdi-play-box-multiple
- Sonarr:
href: https://sonarr.${BASE_DOMAIN}
description: TV library manager
icon: mdi-television-classic
- Radarr:
href: https://radarr.${BASE_DOMAIN}
description: Movie library manager
icon: mdi-movie-open
- Jackett:
href: https://jackett.${BASE_DOMAIN}
description: Indexer proxy
icon: mdi-magnify
- qBittorrent:
href: https://qbittorrent.${BASE_DOMAIN}
description: Download client (VPN egress)
icon: mdi-download-network
# Crafty Controller — a running, north-south-exposed web UI (platform/crafty/httproute.yaml,
# reconciled by clusters/base/crafty.yaml) that this dashboard did NOT surface until
# 2026-09-13. R-C2-01 says the root MUST surface "the services running in the cluster and
# links to them", so an unsurfaced route is a requirement gap, not a styling preference —
# conformance/tests/l0-static/c2-root-surface fails on one now. Grouped under Media because
# it manages game servers; regrouping it under Platform would be purely cosmetic. The game
# ports themselves (crafty-mc.${BASE_DOMAIN}, TCP 25565-25567 / UDP 19132-19134) are an L4
# LoadBalancer with no browsable URL, so this tile is how they are surfaced.
- Crafty:
href: https://crafty.${BASE_DOMAIN}
description: Minecraft server manager (Keycloak-gated)
icon: mdi-minecraft
- Network & Infra:
- Pi-hole:
href: https://pihole.${BASE_DOMAIN}
description: Network-wide DNS & ad-blocking
icon: mdi-shield-check
- UniFi:
href: https://unifi.${BASE_DOMAIN}:11443
description: Network controller (UOS)
icon: mdi-router-network
- Nextcloud:
href: https://nextcloud.${BASE_DOMAIN}
description: Files, calendar & contacts
icon: mdi-cloud
bookmarks.yaml: |
---
- Operations:
- Gitea (external):
- abbr: GT
href: https://gitea.keithjackson.dev
- Auth portal:
- abbr: SSO
href: https://auth.${BASE_DOMAIN}
- Reference:
- Homepage docs:
- abbr: HP
href: https://gethomepage.dev
widgets.yaml: |
---
- datetime:
text_size: xl
format:
dateStyle: long
timeStyle: short
hour12: false
- search:
provider: duckduckgo
target: _blank
# No Docker integration (Homepage does not reach the Docker socket in-cluster).
docker.yaml: |
---
# No Kubernetes integration (no SA / cluster RBAC granted — avoids scope creep; the kubernetes
# widget would need a read-only ServiceAccount. Left empty deliberately).
kubernetes.yaml: |
---
# No Proxmox integration. Homepage v2.1.2 treats proxmox.yaml as a REQUIRED config file (it is in
# the image skeleton dir /app/src/skeleton) and copies a default skeleton into /app/config when it
# is missing — which EACCES-crashes the pod because the config dir is a read-only subPath mount.
# Provide it here (empty) so Homepage finds it and never writes at runtime. A live PVE widget would
# need pve url/token/secret in a Secret — deliberately not wired.
proxmox.yaml: |
---
custom.css: ""
custom.js: ""