#!/usr/bin/env bash # Generate partially prefilled release evidence markdown. # # Usage: # bash ops/generate_release_evidence.sh # bash ops/generate_release_evidence.sh --out release-evidence-custom.md # bash ops/generate_release_evidence.sh --sofiia-url http://127.0.0.1:8002 --skip-preflight # # Exit codes: # 0 = file created # 1 = critical error set -euo pipefail SOFIIA_URL="http://127.0.0.1:8002" OUT_FILE="" SKIP_PREFLIGHT=0 SKIP_HEALTH=0 while [ "$#" -gt 0 ]; do case "$1" in --out) OUT_FILE="${2:-}" shift 2 ;; --sofiia-url) SOFIIA_URL="${2:-}" shift 2 ;; --skip-preflight) SKIP_PREFLIGHT=1 shift ;; --skip-health) SKIP_HEALTH=1 shift ;; -h|--help) cat <<'EOF' Usage: bash ops/generate_release_evidence.sh [options] Options: --out Output markdown file path --sofiia-url Sofiia console base URL (default: http://127.0.0.1:8002) --skip-preflight Skip preflight execution --skip-health Skip health/metrics checks EOF exit 0 ;; *) echo "Unknown argument: $1" exit 1 ;; esac done if ! command -v git >/dev/null 2>&1; then echo "ERROR: git is required" exit 1 fi if ! command -v date >/dev/null 2>&1; then echo "ERROR: date is required" exit 1 fi REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)" if [ -z "${REPO_ROOT}" ]; then echo "ERROR: not inside a git repository" exit 1 fi cd "${REPO_ROOT}" TS_TAG="$(date -u '+%Y%m%d-%H%M%S')" if [ -z "${OUT_FILE}" ]; then OUT_FILE="release-evidence-${TS_TAG}.md" fi UTC_TS="$(date -u '+%Y-%m-%d %H:%M:%S UTC')" KYIV_TS="$(TZ=Europe/Kyiv date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')" GIT_SHA="$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")" GIT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")" GIT_MSG="$(git log -1 --pretty=%s 2>/dev/null || echo "unknown")" HOST_NAME="$(hostname 2>/dev/null || echo "unknown")" NODE_ID_VALUE="${NODE_ID:-unset}" OPERATOR_VALUE="${USER:-unknown}" PREFLIGHT_STATUS="SKIPPED" PREFLIGHT_CMD='bash ops/preflight_sofiia_console.sh' if [ "${SKIP_PREFLIGHT}" = "0" ]; then set +e bash ops/preflight_sofiia_console.sh >/dev/null 2>&1 PREFLIGHT_CODE=$? set -e if [ "${PREFLIGHT_CODE}" = "0" ]; then PREFLIGHT_STATUS="PASS" elif [ "${PREFLIGHT_CODE}" = "2" ]; then PREFLIGHT_STATUS="WARN" else PREFLIGHT_STATUS="FAIL" fi fi HEALTH_CODE="SKIPPED" METRICS_CODE="SKIPPED" if [ "${SKIP_HEALTH}" = "0" ]; then set +e HEALTH_CODE="$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "${SOFIIA_URL}/api/health" 2>/dev/null || echo "000")" METRICS_CODE="$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "${SOFIIA_URL}/metrics" 2>/dev/null || echo "000")" set -e fi cat > "${OUT_FILE}" < 401 confirmed: yes / no - with key -> 200 confirmed: yes / no ## 5) Post-release checks - Key metrics deltas (optional): - sofiia_rate_limited_total: - sofiia_idempotency_replays_total: - Audit write/read quick check: OK / FAIL - Retention dry-run: - Command: \`python3 ops/prune_audit_db.py --dry-run\` - candidates= - Notes: ## 6) Rollback plan & outcome - Rollback needed: no / yes - If yes: - reason: - rollback commands used: - result: - Final service state: healthy / degraded ## 7) Sign-off - Reviewer / approver: - Timestamp UTC: - Notes: EOF echo "Release evidence file created: ${OUT_FILE}" exit 0