CVE-2026-109618 and CVE-2026-109619 (BSI BITS-H 2026-297981-1132) allow
unauthenticated RCE on every PHP before 8.5.12/8.4.27/8.3.36/8.2.35;
mod_php is the highest-risk variant. The running pod reports PHP 8.3.35
and www.renner.uno serves / to the internet without the Authentik gate.
Switch to the php8.5-apache variant of the same WordPress release,
pinned to the index digest rebuilt on 2026-10-22 after the PHP fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flux source URL, flux-git rotator verify repo, review-bot REPOS, pipeline API,
clone and push URLs, the heating-can source label and the review-bot and
kuma-sync Go module paths. Merge right after the transfer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Switches apps/hermes to gitea.renner.uno/gitea_admin/hermes, which
carries talosctl, kubectl, flux, bao, tea and jq in /usr/local/bin. The
image-automation policy now tracks its build.<unix-ts> tags instead of
upstream nousresearch/hermes-agent; .woodpecker/hermes-image.yml follows
upstream releases.
Drops the kubectl init container and its emptyDir: the binary sat in
/opt/data/.local/bin, which the agent's terminal does not have on PATH.
One group per own service with application-level checks (json-query on
health/API endpoints where ungated, keyword otherwise) and a Third-party
group with plain checks. Endpoints verified from the Kuma VPS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner placed hermes-bot's API token at OpenBao apps/hermes/gitea
(api-token). ExternalSecret hermes-gitea mounts it as a file at
/var/run/secrets/gitea/api-token.
git is configured through GIT_CONFIG_* env on the container, so nothing
lives on the PVC: a credential helper for https://gitea.renner.uno that
answers with hermes-bot and the token read from the file, plus the
commit identity hermes-bot <hermes-bot@konstantin-renner.de>. Hermes'
subprocess env scrub only strips its own provider/messaging secrets, so
GIT_* reaches the terminal tool.
SOUL.md drops "no write access" and tells the agent how to use git and
the REST API (no tea in the image) without printing the token; the
existing feature-branch/PR/no-self-merge rules apply.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apps/hermes sets namespaces per resource, not in the kustomization, so
configMapGenerator emitted hermes-soul and hermes-skills without one and
the Flux apply failed ("namespace not specified"). The earlier
server-side dry-run masked it by defaulting to the current namespace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SOUL.md comes from git (ConfigMap hermes-soul, subPath over the PVC
copy): the stock persona plus the homelab's working rules distilled
from Claude Code's global CLAUDE.md and feedback memory — wiki first,
the verification ladder, the network/DNS/placement/secret design rules,
operational change discipline and how to work with the owner. Claude
Code harness specifics (Bash allowlisting, subagent sizing, worktrees,
claude-bot identities) are left out.
The homelab-wiki skill (ConfigMap hermes-skills, mounted at
/opt/hermes-skills and registered via skills.external_dirs) wraps the
wiki service API in a stdlib Python client, since the image has no
bash or jq. Hermes calls the in-cluster service directly with its own
API key, identity `hermes`:
- apps/hermes/wiki -> Secret hermes-wiki, mounted as a file (optional,
so the pod starts before it is seeded; reads are anonymous)
- apps/ai/wiki-api-key-hermes -> Auth__ApiKeys__hermes on the wiki. A
separate path rather than a field in apps/ai/wiki-api-keys, because
claude-bot's OpenBao policy is write-only and a put on the shared path
would drop the workstation key.
- CNPs: hermes egress to ai/wiki:8080, wiki ingress from hermes
- hermes added to the openbao ClusterSecretStore allowlist
The built-in memory store (2200/1375 chars, agent-rewritten) is left to
the agent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nousresearch/hermes-agent still carries v2026.4.3..v2026.9.24 from the
old date-based scheme. As semver they sort above 0.x, so '>=0.22.2'
picked v2026.9.24 (2026-09-24) and rolled the pod back from v0.22.2.
Cap the range below 1.0.0 and pin the manifests back to v0.22.2.
Add a blackbox-http probe of kuma.renner.uno with a dedicated critical
UptimeKumaUnreachable rule (excluded from BlackboxProbeFailing), scrape
Kuma /metrics with the API key from OpenBao, and alert on sustained slow
monitor response times. No egress policy exists in the monitoring
namespace, so no CNP change is needed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hermes Agent as a pod in its own `hermes` namespace: gateway (messaging
platforms, cron, OpenAI-compatible API) and dashboard, supervised by the
image's s6-overlay, state on a 10Gi ceph-block PVC.
- hermes.renner.uno (LAN): dashboard and Hermes Desktop remote gateway.
Plain Traefik plus the dashboard's own Authentik OIDC login (public PKCE
client, Hermes Users group) — a forward-auth gate would break Desktop's
Bearer-token calls.
- hermes-api.renner.uno (LAN): API server, Bearer key generated in-cluster
by an ESO Password generator.
- Read-only kubectl via the built-in `view` ClusterRole.
- CNPs: world 443/80, kube-apiserver, Traefik for LAN hostnames, and
Prometheus/Alertmanager/Loki (with the matching monitoring-side grant).
- Image automation for nousresearch/hermes-agent v-tags.
After deploy: log in to Anthropic inside the pod
(`hermes auth add anthropic --type oauth --no-browser`, then `hermes model`);
platform and Home Assistant tokens go in via the dashboard.
Not yet covered: a Velero schedule for the PVC.
Last smoke-test step: Flux prunes the KumaMonitor and the controller's
finalizer deletes Kuma monitor 9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keyword check on https://www.renner.uno/ (page title "Familie Renner")
with certificate-expiry notification. Exercises create, tagging,
restart adoption and deletion against the live Kuma; removed from git
again as the last smoke-test step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Namespace, CRD (Flux prune disabled so a prune never cascades into
deleting every Kuma monitor via finalizers), cluster RBAC matching the
controller-gen role, Recreate Deployment of the first master build
(2026-10-19-0545) under image automation, and a default-deny
CiliumNetworkPolicy allowing only DNS, the kube-apiserver and
kuma.renner.uno:443 out, kubelet probes in.
The Kuma login comes from its own OpenBao path infrastructure/kuma-sync
(a copy of the single Kuma admin account) rather than reading
infrastructure/uptime-kuma.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AutoKuma 2.0.0 never applied its ownership tag against Uptime Kuma 2.5.6, so a pod restart with empty /data duplicated every managed monitor (pilot step 5). Replaced by an in-house controller under a separate plan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The flux-image-automation Alert forwarded every info event from
ImageUpdateAutomation (i.e. each successful bump commit) to Alertmanager,
which emailed it as FluxImageUpdateAutomationSucceeded. A success is not
a problem and must not be an alert; the commits are in git history.
Image-automation failures still alert: flux-failures covers
ImageUpdateAutomation at error severity. The Alertmanager source="flux"
route stays for those; its comment now says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
additionalProperties: true makes the API server prune nested objects under
spec.config to {}; x-kubernetes-preserve-unknown-fields (as in upstream
master) keeps the free-form contract. Add ingress: [{}] so the policy
default-denies ingress as named.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AutoKuma 2.0.0 (Kubernetes source) syncs KumaEntity objects to Uptime Kuma
at https://kuma.renner.uno. Ships no KumaEntity objects. Image pinned, not
under Flux automation: Kuma's internal API is unofficial, so Kuma and
AutoKuma are bumped together.
ClusterRole is cluster-wide because the controller lists/watches
KumaEntity across all namespaces. The openbao ClusterSecretStore
namespace allowlist gains autokuma. FILES and DOCKER sources are
disabled; /data and /tmp are emptyDirs for readOnlyRootFilesystem.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chart's KubeJobFailed fires while a failed Job object exists, so it
clears only on Job GC (TTL, history limit, Velero's keep-latest), not on
recovery. On 2026-10-18 this held 10 alerts open for runs that had already
been superseded: renovate recovered 2026-10-13 but alerted until its 7d
TTL; registry-bot-secret-rotate-init2 succeeded 9 min after init failed,
the alert started 7 min after that and stayed 11h.
Replace it with a rule that drops a failed Job once a later Job of the
same series completes: series = owning CronJob, or velero.io/repo-name
for kopia maintenance Jobs (exposed via KSM metricLabelsAllowlist).
Failed Jobs without a series alert as before.
KubeContainerWaiting fired for the never-started main container of a pod
whose init container failed. Exclude Failed/Succeeded pods; KubeJobFailed
covers those.
Verified against live Prometheus: the new expression returns nothing now
(chart rule: 2), returns the 30 Velero maintenance failures at 16:40Z
2026-10-18, and returns nothing at the renovate/registry-bot timestamps
after their successful re-runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge right after the repo transfer. Gitea API writes do not survive the
old-path redirect, so the config-sync sidecar (live -> main PR) and review-bot
(posting reviews) must address the new path.
- config-sync GITEA_REPO = konairius/homeassistant (pod restarts, the remote is
reset on start).
- ha-config-sync rotator verifies against konairius/homeassistant.
- review-bot REPOS lists konairius/homeassistant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sidecar took its git remote, Gitea API base and token from a URL with an
embedded PAT stored on the config PVC. That state was invisible to git,
unrotated, and would break on the repo transfer to konairius: the live -> main
PR is opened with an API POST, and Gitea API writes do not survive the old-path
redirect (seen with the wiki on notes).
- ha-config-sync: dedicated Gitea account, write collaborator on homeassistant.
CronJob openbao/ha-config-sync-secret-rotate (quarterly) mints its
write:repository PAT, verifies pull+push on homeassistant and stores it at
infrastructure/ha-config-sync#token. Policy/role applied and the path seeded
on 2026-10-18. Netpol halves gitea-allow-ha-config-sync-rotator and
rotator-ha-config-sync-egress.
- ExternalSecret home-assistant-config-sync-gitea, mounted as a file (not
subPath) so a rotation lands in place without restarting Home Assistant.
- config-sync.sh: GITEA_URL/GITEA_REPO/GITEA_USER/GITEA_TOKEN_FILE from the
manifest; the remote is reset to the credential-free URL on every start; git
gets the token as an http.extraHeader through GIT_CONFIG_* env, re-read every
loop; the PR call uses the same token.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repo moved to the konairius org. Its webhooks now carry
konairius/authentik-samba-bridge, which REPOS did not list, so the bot
ignored them, and the sweep would post through the old path, where Gitea
API writes do not survive the redirect (seen with the wiki on notes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
authentik-samba-bridge moved to the konairius org and publishes as
registry-bot (konairius/authentik-samba-bridge#7, pipeline #42):
gitea.renner.uno/konairius/authentik-samba-bridge-{server,ldap-outpost}
:2026.8.3-9dd92dd. Between the deployed 872f754 and 9dd92dd only CI, OCI
labels and pyproject URLs changed; the bridge code is the same.
- HelmRelease: server image repository + tag 2026.8.3-9dd92dd.
- LDAP outpost blueprint: container_image 2026.8.3-9dd92dd.
- Repo URLs in the comments follow.
Restarts the authentik server and worker pods and redeploys the LDAP outpost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both repos moved from k.renner to the konairius org on 2026-10-18. The old
paths still resolve through Gitea's redirect (the preset API read of
k.renner/renovate-config returns 200), so nothing is broken; this removes the
dependency on the redirect.
- wiki: Wiki__NoteStore__Gitea__Repository = konairius/notes.
- renovate.json extends local>konairius/renovate-config; the runner comments follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>