titan-iac/scripts/ops/hermes_triage_demo.sh
jenkins 35ae4d4bab
Some checks failed
Tests / Declarative: Post Actions failed: 2, passed: 142
refactor(demo): split the two demos into two scripts
One script with a 'fixture' and a 'code' subcommand meant the wrong subcommand
was always one word away, in front of an audience, with different blast radii
behind each: the triage demo touches only a ConfigMap, the code demo pushes to
a repository and deletes issues. Those should not share a command line.

Each demo is now its own driver with the same five verbs - monitor, reset,
preflight, run, status - so knowing one teaches the other. What they genuinely
share (credentials, Jenkins access, the tick reader, the lab-wide preflight
checks) moved to hermes_demo_lib.sh rather than being duplicated, because the
reason to split was clarity at the command line, not two copies of the same
helper drifting apart.

Each reset now covers only its own demo. The triage reset no longer reaches
into a Gitea repository it never writes to, and the code reset owns the
repository cleanup entirely.

The credentials file is now hermes_demo.env since both read it; the old
hermes_triage_demo.env is still sourced as a fallback so a filled-in file
keeps working, and both names stay git-ignored.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 21:59:23 -03:00

99 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Drive and narrate the Hermes automated-triage demo.
#
# This is the autonomous loop: a build fails, Ariadne diagnoses it through
# Hermes, authorizes a predefined repair, performs it, and rebuilds green
# without a human touching anything.
#
# hermes_triage_demo.sh monitor # follow the Test Automation Diagram live
# hermes_triage_demo.sh reset # restore the demo to its pre-run state
# hermes_triage_demo.sh preflight # confirm the lab is ready to demo
# hermes_triage_demo.sh run # arm the failure and narrate the loop
# hermes_triage_demo.sh status # current incident/alert state, no changes
#
# The code-proposal demo is a separate script: hermes_code_demo.sh. They prove
# different halves of the diagram and reset different things, so they are kept
# apart rather than behind one command.
#
# FIRST RUN: copy hermes_demo.env.example to hermes_demo.env in this directory
# and fill it in. That file is git-ignored precisely so it can hold real
# tokens; this script sources it automatically.
#
# Needs kubectl access to the cluster as well. Nothing here mutates the cluster
# directly: the demo only asks Jenkins to run a parameterized build.
set -euo pipefail
# shellcheck source=scripts/ops/hermes_demo_lib.sh
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hermes_demo_lib.sh"
# The fixture is a ConfigMap the demo job reads. Resetting it is the whole
# blast radius of this script: no repository is touched, because the triage
# loop repairs infrastructure rather than source.
cmd_reset() {
say "Reset — restoring the triage demo to its pre-run state"
note "fixture -> healthy"
if kubectl -n "$DEMO_NS" patch cm hermes-triage-demo-fixture \
--type merge -p '{"data":{"state":"healthy"}}' >/dev/null 2>&1; then
note " fixture: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}')"
else
note " fixture patch failed (is the demo namespace present?)"
fi
say "Ready"
note "no repository was touched; this demo repairs infrastructure, not source"
note "run 'preflight' next, then 'run'"
}
cmd_preflight() {
require_jenkins
say "Preflight — triage demo"
note "fixture state: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}' 2>/dev/null || echo MISSING)"
shared_preflight
}
cmd_status() {
shared_status
say "Demo namespace"
kubectl -n "$DEMO_NS" get jobs --no-headers 2>/dev/null | sed 's/^/ /'
}
cmd_run() {
require_jenkins
local start_num next_num
start_num="$(last_build_number "$FIXTURE_JOB")"
next_num=$((start_num + 1))
say "Arming the demo failure (SEED_FAILURE=true) -> build #$next_num"
note "HTTP $(jenkins_post "/job/$FIXTURE_JOB/buildWithParameters?SEED_FAILURE=true")"
note "Only manual step. Everything after this is automatic."
say "Waiting for the seeded build to fail"
note "result: $(wait_for_build "$FIXTURE_JOB" "$next_num")"
say "Ariadne detects, gathers evidence, asks Hermes, authorizes, repairs"
note "the repair is a single in-process ConfigMap patch, so watch the fixture"
for _ in $(seq 1 40); do
sleep 10
if [ "$(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}' 2>/dev/null)" = "healthy" ]; then
note "fixture patched back to healthy"
break
fi
done
ariadne_ticks 400 4
say "Ariadne triggers one rebuild with seeding disabled"
note "result: $(wait_for_build "$FIXTURE_JOB" $((next_num + 1)))"
say "Resolution"
sleep 45
ariadne_ticks 200 3
note "fixture state: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}')"
}
case "${1:-}" in
run|fixture) cmd_run ;;
status) cmd_status ;;
preflight) cmd_preflight ;;
reset) cmd_reset ;;
monitor) run_monitor "$FIXTURE_JOB" ;;
*) sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//' ; exit 1 ;;
esac