ops: refine komodo stack hygiene check

- Hash drift now requires actual file changes inside the stack's
  compose-dir between deployed_hash and latest_hash. Komodo's
  deployed_hash bumps only on redeploy while latest_hash tracks master
  HEAD, which produced six false-positive "Pending Update" warnings
  for stacks whose own files never changed.
- Add EXPECTED_NOT_IN_KOMODO env (default: hermes-agent) for compose
  files intentionally not Komodo-managed (work-in-progress, build/dev
  compose).

End-to-end run on host: 0 critical, 0 warnings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:23:52 +02:00
parent baedf9f932
commit d933d3cee8
+42 -3
View File
@@ -24,6 +24,10 @@ INLINE_ALLOWLIST="${INLINE_ALLOWLIST:-komodo,grafana}"
# (Beispiele, Archive, Submodule). # (Beispiele, Archive, Submodule).
COMPOSE_EXCLUDE_PATTERN="${COMPOSE_EXCLUDE_PATTERN:-/archive/|/examples/|/.git/}" COMPOSE_EXCLUDE_PATTERN="${COMPOSE_EXCLUDE_PATTERN:-/archive/|/examples/|/.git/}"
# Compose-Dir-Namen, die bewusst NICHT als Komodo-Stack laufen sollen
# (Work-in-progress, Build-/Dev-Compose, manuell deployed). Komma-separiert.
EXPECTED_NOT_IN_KOMODO="${EXPECTED_NOT_IN_KOMODO:-hermes-agent}"
TMP_DIR="${TMP_DIR:-/tmp/kallilab-komodo-stack-hygiene}" TMP_DIR="${TMP_DIR:-/tmp/kallilab-komodo-stack-hygiene}"
mkdir -p "$TMP_DIR" mkdir -p "$TMP_DIR"
RESULTS_FILE="$TMP_DIR/results.$$" RESULTS_FILE="$TMP_DIR/results.$$"
@@ -48,6 +52,34 @@ is_inline_allowed() {
return 1 return 1
} }
is_expected_not_in_komodo() {
local name="$1"
local IFS=,
for entry in $EXPECTED_NOT_IN_KOMODO; do
[ "$name" = "$entry" ] && return 0
done
return 1
}
# True drift: do files inside this stack's compose-dir actually differ
# between deployed_hash and latest_hash? Komodo's deployed_hash bumps only
# on redeploy, while latest_hash tracks master HEAD - that produces a noisy
# "Pending Update" even when the stack itself wasn't touched.
stack_files_changed() {
local name="$1" deployed="$2" latest="$3"
local dir
# Locate the stack's compose dir (case-insensitive, same as Mode 3).
dir="$(find "$REPO_ROOT" -type d -iname "$name" -not -path "*/.git/*" 2>/dev/null | head -1)"
[ -n "$dir" ] || return 0 # No dir -> can't tell, treat as drift to be safe
( cd "$REPO_ROOT" && git rev-parse --verify --quiet "$deployed" >/dev/null ) || return 0
( cd "$REPO_ROOT" && git rev-parse --verify --quiet "$latest" >/dev/null ) || return 0
local rel="${dir#$REPO_ROOT/}"
if ( cd "$REPO_ROOT" && git diff --quiet "$deployed".."$latest" -- "$rel" ); then
return 1 # no change
fi
return 0 # real change
}
# Komodo-API-Credentials laden und Stack-Liste holen. # Komodo-API-Credentials laden und Stack-Liste holen.
if [ ! -r "$KOMODO_ENV_FILE" ]; then if [ ! -r "$KOMODO_ENV_FILE" ]; then
add_result "warning" "komodo-api" "Komodo env file not readable: $KOMODO_ENV_FILE" add_result "warning" "komodo-api" "Komodo env file not readable: $KOMODO_ENV_FILE"
@@ -108,10 +140,14 @@ if [ -s "$STACKS_FILE" ]; then
add_result "warning" "$name" "Stack name does not match any compose directory in repo" add_result "warning" "$name" "Stack name does not match any compose directory in repo"
fi fi
# Failure-Mode 4: Deployed-Hash hinkt latest hinterher. # Failure-Mode 4: Deployed-Hash hinkt latest hinterher UND der Stack-Dir
# hat tatsaechlich File-Aenderungen dazwischen. Reine Komodo-Hash-Bewegung
# ohne Stack-Inhalt aendert nichts und ist kein echter Drift.
# "-" = unbekannt (z.B. gitea self-host edge case), nicht als Drift werten. # "-" = unbekannt (z.B. gitea self-host edge case), nicht als Drift werten.
if [ "$deployed_hash" != "-" ] && [ "$latest_hash" != "-" ] && [ "$deployed_hash" != "$latest_hash" ]; then if [ "$deployed_hash" != "-" ] && [ "$latest_hash" != "-" ] \
add_result "warning" "$name" "deployed_hash $deployed_hash != latest_hash $latest_hash" && [ "$deployed_hash" != "$latest_hash" ] \
&& stack_files_changed "$name" "$deployed_hash" "$latest_hash"; then
add_result "warning" "$name" "deployed_hash $deployed_hash != latest_hash $latest_hash (stack files changed)"
fi fi
# Failure-Mode 5: Stack ist down. # Failure-Mode 5: Stack ist down.
@@ -145,6 +181,9 @@ if [ -s "$STACKS_FILE" ]; then
if is_inline_allowed "$dir_name"; then if is_inline_allowed "$dir_name"; then
continue continue
fi fi
if is_expected_not_in_komodo "$dir_name"; then
continue
fi
# Case-insensitive, weil z.B. host-services/Adguard <-> Komodo-Stack adguard # Case-insensitive, weil z.B. host-services/Adguard <-> Komodo-Stack adguard
# legitim als gematched gilt. # legitim als gematched gilt.
if ! printf '%s\n' "$known_names" | grep -Fixq "$dir_name"; then if ! printf '%s\n' "$known_names" | grep -Fixq "$dir_name"; then