Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
610b39e0fb | ||
|
|
fbc1aaef21 | ||
|
|
3c5c04d4a5 | ||
|
|
f73cc54705 | ||
|
|
9d0707c1aa | ||
|
|
74db40710e | ||
|
|
368dc24add | ||
|
|
dfb2f71c85 | ||
|
|
6b78f4cb5b | ||
|
|
2b1016bd4a |
@@ -0,0 +1,29 @@
|
||||
# Builds ci/images/hermes (nousresearch/hermes-agent plus the agent's CLIs) as
|
||||
# gitea.renner.uno/konairius/hermes:build.<unix-ts> and :latest.
|
||||
when:
|
||||
- event: push
|
||||
branch: master
|
||||
path:
|
||||
- "ci/images/hermes/**"
|
||||
- ".woodpecker/hermes-image.yml"
|
||||
- event: manual
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: registry.gitlab.com/gitlab-ci-utils/container-images/kaniko:v1.25.19-debug@sha256:7795cec509a50a71378cc2c365f55c555ee3a05834d8eb1cd2552df5e66d44d8
|
||||
directory: ci/images/hermes
|
||||
environment:
|
||||
# registry-bot write:package PAT (konairius org secret).
|
||||
GITEA_TOKEN:
|
||||
from_secret: registry_bot_token
|
||||
commands:
|
||||
- mkdir -p /kaniko/.docker
|
||||
- AUTH=$(printf '%s:%s' registry-bot "$GITEA_TOKEN" | base64 | tr -d '\n')
|
||||
- printf '{"auths":{"gitea.renner.uno":{"auth":"%s"}}}' "$AUTH" > /kaniko/.docker/config.json
|
||||
- TAG="build.$(date +%s)"
|
||||
- |
|
||||
/kaniko/executor \
|
||||
--context . \
|
||||
--dockerfile Containerfile \
|
||||
--destination gitea.renner.uno/konairius/hermes:$TAG \
|
||||
--destination gitea.renner.uno/konairius/hermes:latest
|
||||
@@ -0,0 +1,20 @@
|
||||
FROM nousresearch/hermes-agent:v0.22.2@sha256:36099926da316742423544e055d4734777105ffe6341873af5459b957d0c2919
|
||||
|
||||
USER root
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends jq \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=ghcr.io/siderolabs/talosctl:v1.13.10@sha256:3116f64c97ddffb53bd3c5bf87c8614d99f04df4326177dbbb7702b5087f0e4d /talosctl /usr/local/bin/talosctl
|
||||
COPY --from=alpine/kubectl:1.36.3@sha256:dae261106d5555008acede256b7102c8a6decde7209198434f5999f051460f57 /usr/local/bin/kubectl /usr/local/bin/kubectl
|
||||
COPY --from=ghcr.io/fluxcd/flux-cli:v2.9.5@sha256:704d5529535570a495249b643159c93a9aa88ffca07813c974a54b7ba6edbd86 /usr/local/bin/flux /usr/local/bin/flux
|
||||
COPY --from=quay.io/openbao/openbao:2.7.1@sha256:6d2b93856e3fcf7b18ad855a0b51eaba474dc8b79cf554379ea32034797d2acf /usr/bin/bao /usr/local/bin/bao
|
||||
COPY --from=gitea/tea:0.16.0@sha256:af50a2060ce4d8fd76b7ebe75a3d6db4bb0c615c5bc8f2bdfd8ea83207c4752d /usr/bin/tea /usr/local/bin/tea
|
||||
|
||||
RUN talosctl version --client \
|
||||
&& kubectl version --client \
|
||||
&& flux version --client \
|
||||
&& bao version \
|
||||
&& tea --version \
|
||||
&& jq --version
|
||||
@@ -9,7 +9,9 @@ When you use a pronoun for someone whose pronouns haven't been stated, use they/
|
||||
- The homelab wiki through the `homelab-wiki` skill (read, and deposit facts).
|
||||
- The web (HTTPS) and LAN hostnames under `renner.uno` through Traefik.
|
||||
|
||||
All state of record lives in git (`gitea.renner.uno`): infrastructure in the `homelab` repo (Kubernetes/Flux, Ansible, OpenTofu, ESPHome), Home Assistant config in the `homeassistant` repo. You have no write access to either; when a change is needed, describe it (files, diff) for the owner or Claude Code to land as a PR.
|
||||
- Gitea (`https://gitea.renner.uno`) as `hermes-bot`: `git` over HTTPS authenticates and sets the commit identity on its own. For the API, send `Authorization: token <contents of /var/run/secrets/gitea/api-token>` (read it inside the command, never print it). There is no `tea`; use the REST API (`/api/v1`). You write only to repos where `hermes-bot` is a collaborator.
|
||||
|
||||
All state of record lives in git: infrastructure in the `homelab` repo (Kubernetes/Flux, Ansible, OpenTofu, ESPHome), Home Assistant config in the `homeassistant` repo. Changes land as a feature branch plus a PR for the owner's review (see below).
|
||||
|
||||
# Ask the wiki first. Always.
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Gitea API token of hermes-bot, mounted as a file for git and the API.
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: hermes-gitea
|
||||
namespace: hermes
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: openbao
|
||||
target:
|
||||
name: hermes-gitea
|
||||
data:
|
||||
- secretKey: api-token
|
||||
remoteRef:
|
||||
key: apps/hermes/gitea
|
||||
property: api-token
|
||||
@@ -73,7 +73,7 @@ spec:
|
||||
mountPath: /opt/data
|
||||
# Skills from git (ConfigMap hermes-skills) beside the PVC's skills/.
|
||||
- name: skills-config
|
||||
image: nousresearch/hermes-agent:v2026.9.24 # {"$imagepolicy": "flux-system:hermes"}
|
||||
image: nousresearch/hermes-agent:v0.22.2 # {"$imagepolicy": "flux-system:hermes"}
|
||||
command:
|
||||
- /opt/hermes/.venv/bin/hermes
|
||||
- config
|
||||
@@ -130,6 +130,21 @@ spec:
|
||||
value: "true"
|
||||
- name: API_SERVER_HOST
|
||||
value: 0.0.0.0
|
||||
# git as hermes-bot: the credential helper reads the mounted token.
|
||||
- name: GIT_CONFIG_COUNT
|
||||
value: "3"
|
||||
- name: GIT_CONFIG_KEY_0
|
||||
value: credential.https://gitea.renner.uno.helper
|
||||
- name: GIT_CONFIG_VALUE_0
|
||||
value: '!f() { test "$1" = get && echo username=hermes-bot && echo "password=$(cat /var/run/secrets/gitea/api-token)"; }; f'
|
||||
- name: GIT_CONFIG_KEY_1
|
||||
value: user.name
|
||||
- name: GIT_CONFIG_VALUE_1
|
||||
value: hermes-bot
|
||||
- name: GIT_CONFIG_KEY_2
|
||||
value: user.email
|
||||
- name: GIT_CONFIG_VALUE_2
|
||||
value: hermes-bot@konstantin-renner.de
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: hermes-api-key
|
||||
@@ -179,6 +194,9 @@ spec:
|
||||
- name: wiki-key
|
||||
mountPath: /var/run/secrets/wiki
|
||||
readOnly: true
|
||||
- name: gitea-token
|
||||
mountPath: /var/run/secrets/gitea
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
@@ -200,6 +218,9 @@ spec:
|
||||
secret:
|
||||
secretName: hermes-wiki
|
||||
optional: true
|
||||
- name: gitea-token
|
||||
secret:
|
||||
secretName: hermes-gitea
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
@@ -4,6 +4,7 @@ resources:
|
||||
- rbac.yaml
|
||||
- api-key.yaml
|
||||
- wiki-externalsecret.yaml
|
||||
- gitea-externalsecret.yaml
|
||||
- hermes.yaml
|
||||
- ingress.yaml
|
||||
configMapGenerator:
|
||||
|
||||
@@ -30,7 +30,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: controller
|
||||
image: gitea.renner.uno/gitea_admin/kuma-sync:2026-10-19-0615 # {"$imagepolicy": "flux-system:kuma-sync"}
|
||||
image: gitea.renner.uno/gitea_admin/kuma-sync:2026-10-19-0646 # {"$imagepolicy": "flux-system:kuma-sync"}
|
||||
env:
|
||||
- name: KUMA_URL
|
||||
value: https://kuma.renner.uno
|
||||
|
||||
@@ -5,3 +5,4 @@ resources:
|
||||
- externalsecret.yaml
|
||||
- rbac.yaml
|
||||
- deployment.yaml
|
||||
- monitors
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: audiobooks
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Audiobooks
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: audiobooks-health
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: keyword
|
||||
displayName: Audiobookshelf Health
|
||||
parentRef:
|
||||
name: audiobooks
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
url: https://audiobooks.renner.uno/healthcheck
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
keyword:
|
||||
keyword: OK
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: audiobooks-status
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: json-query
|
||||
displayName: Audiobookshelf Server
|
||||
parentRef:
|
||||
name: audiobooks
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
# initialized-server flag from the unauthenticated status endpoint
|
||||
url: https://audiobooks.renner.uno/status
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
jsonQuery:
|
||||
expression: isInit
|
||||
operator: ==
|
||||
expected: "true"
|
||||
@@ -0,0 +1,48 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: auth
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Authentik
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: auth-live
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: Authentik Live
|
||||
parentRef:
|
||||
name: auth
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
# ungated health endpoint, empty body
|
||||
url: https://auth.renner.uno/-/health/live/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: auth-ready
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: Authentik Ready
|
||||
parentRef:
|
||||
name: auth
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
# ungated readiness endpoint (database and cache), empty body
|
||||
url: https://auth.renner.uno/-/health/ready/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
@@ -0,0 +1,30 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: docs
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Documents
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: docs-gate
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: keyword
|
||||
displayName: Documents Login
|
||||
parentRef:
|
||||
name: docs
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 20
|
||||
http:
|
||||
# Paperless is fully behind the Authentik gate; asserts the login page the redirect chain ends on
|
||||
url: https://docs.renner.uno/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
keyword:
|
||||
keyword: <title>authentik</title>
|
||||
@@ -0,0 +1,53 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: home
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Home Assistant
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: home-api
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: json-query
|
||||
displayName: Home Assistant API
|
||||
parentRef:
|
||||
name: home
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
# unauthenticated login-provider list, served by the HA core backend
|
||||
url: https://home.renner.uno/auth/providers
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
jsonQuery:
|
||||
expression: providers[type="homeassistant"].name
|
||||
operator: ==
|
||||
expected: Home Assistant Local
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: home-web
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: keyword
|
||||
displayName: Home Assistant Web
|
||||
parentRef:
|
||||
name: home
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
url: https://home.renner.uno/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
keyword:
|
||||
keyword: <title>Home Assistant</title>
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: immich
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Immich
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: immich-api
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: json-query
|
||||
displayName: Immich API
|
||||
parentRef:
|
||||
name: immich
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
url: https://immich.renner.uno/api/server/ping
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
jsonQuery:
|
||||
expression: res
|
||||
operator: ==
|
||||
expected: pong
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- renner-uno.yaml
|
||||
- home.yaml
|
||||
- immich.yaml
|
||||
- auth.yaml
|
||||
- docs.yaml
|
||||
- audiobooks.yaml
|
||||
- third-party.yaml
|
||||
@@ -0,0 +1,51 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: renner-uno
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Renner.uno Website
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: renner-uno-www
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: keyword
|
||||
displayName: www.renner.uno
|
||||
parentRef:
|
||||
name: renner-uno
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
url: https://www.renner.uno/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
keyword:
|
||||
keyword: Familie Renner
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: renner-uno-apex
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: keyword
|
||||
displayName: renner.uno
|
||||
parentRef:
|
||||
name: renner-uno
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 10
|
||||
http:
|
||||
# 301 to www, followed
|
||||
url: https://renner.uno/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
keyword:
|
||||
keyword: Familie Renner
|
||||
@@ -0,0 +1,87 @@
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: third-party
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: group
|
||||
displayName: Third-party
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: mcb-portal
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: MCB Portal
|
||||
parentRef:
|
||||
name: third-party
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 15
|
||||
http:
|
||||
# root 302s to / to set a session cookie; Kuma keeps no cookies, so do not follow
|
||||
url: https://portal.multi-circuit-boards.eu/
|
||||
acceptedStatusCodes: ["200-299", "302"]
|
||||
maxRedirects: 0
|
||||
expiryNotification: true
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: mcb-tech
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: MCB Technician Portal
|
||||
parentRef:
|
||||
name: third-party
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 15
|
||||
http:
|
||||
url: https://tech.multi-circuit-boards.eu/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: mcb-www
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: MCB Website
|
||||
parentRef:
|
||||
name: third-party
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 15
|
||||
http:
|
||||
# 301 to /index.html, followed
|
||||
url: https://www.multi-circuit-boards.eu/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
---
|
||||
apiVersion: uptime.renner.uno/v1alpha1
|
||||
kind: KumaMonitor
|
||||
metadata:
|
||||
name: turm1388
|
||||
namespace: kuma-sync
|
||||
spec:
|
||||
type: http
|
||||
displayName: Wohnen im Turm
|
||||
parentRef:
|
||||
name: third-party
|
||||
interval: 60
|
||||
retryInterval: 60
|
||||
maxRetries: 1
|
||||
timeout: 15
|
||||
http:
|
||||
url: https://turm1388.de/
|
||||
acceptedStatusCodes: ["200-299"]
|
||||
expiryNotification: true
|
||||
@@ -215,6 +215,24 @@
|
||||
"lscr.io/linuxserver/beets"
|
||||
],
|
||||
"versioning": "regex:^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)-ls(?<build>\\d+)$"
|
||||
},
|
||||
{
|
||||
"description": "Hermes image (ci/images/hermes): its merge rolls out to the cluster via Flux image automation, so it is not CI-only. One PR of its own.",
|
||||
"matchFileNames": [
|
||||
"ci/images/hermes/**"
|
||||
],
|
||||
"groupName": "hermes image",
|
||||
"groupSlug": "hermes-image"
|
||||
},
|
||||
{
|
||||
"description": "nousresearch/hermes-agent also carries the retired date-versioned tags (v2026.x), which sort above v0.x.",
|
||||
"matchDatasources": [
|
||||
"docker"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"nousresearch/hermes-agent"
|
||||
],
|
||||
"allowedVersions": "/^v0\\./"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user