#!/usr/bin/env bash
# tests/clientdocs-skill/run-tests.sh -- content gate for the tenant AI-assistant
# skill package (clientdocs/tenant-skill/). Read-only; mutates nothing.
#
# Gates, in order:
# T1 layout: SKILL.md + references/ exist
# T2 frontmatter present and parses (name: omega-cloud-tenant, description)
# T3 zero internal-term leakage (identifiers, tooling names, component code
# names, internal hosts/CIDRs) across every skill file
# T4 placeholder inventory is EXACTLY the documented set (clientdocs/README.md)
# T5 routing: every references/*.md is reachable from SKILL.md, and every
# references/ path mentioned anywhere in the skill exists
# T6 ASCII + LF (belt and braces; repo lint L1 also covers this)
# T7 expected-refusal table present in troubleshooting.md
# T8 starter-script references: every *.sh named in the skill/guide exists
# in clientdocs/scripts/, and every starter script parses (bash -n)
# Exit: 0 all pass | 1 any case failed. ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
SKILL="$REPO/clientdocs/tenant-skill"
PASS=0; FAIL=0
ok() { echo " PASS $1"; PASS=$((PASS+1)); }
bad() { echo " FAIL $1"; shift; for l in "$@"; do echo " $l"; done; FAIL=$((FAIL+1)); }
# ---- T1 layout ----
if [[ -f "$SKILL/SKILL.md" && -d "$SKILL/references" ]]; then
ok "T1 layout: SKILL.md + references/ present"
else
bad "T1 layout missing (SKILL.md or references/)"; echo; echo "RESULT: PASS=$PASS FAIL=$FAIL"; exit 1
fi
mapfile -t FILES < <(find "$SKILL" -name '*.md' | sort)
# ---- T2 frontmatter ----
FM_OUT="$(python3 - "$SKILL/SKILL.md" <<'PY' 2>&1
import sys
t = open(sys.argv[1], encoding="ascii").read()
if not t.startswith("---\n"):
raise SystemExit("no opening frontmatter fence")
end = t.find("\n---\n", 4)
if end < 0:
raise SystemExit("no closing frontmatter fence")
fm = t[4:end]
fields = {}
for ln in fm.splitlines():
if ":" in ln:
k, v = ln.split(":", 1)
fields[k.strip()] = v.strip().strip('"')
if fields.get("name") != "omega-cloud-tenant":
raise SystemExit("name is %r, want omega-cloud-tenant" % fields.get("name"))
if len(fields.get("description", "")) < 80:
raise SystemExit("description missing or too short to trigger on")
print("frontmatter ok")
PY
)"
if [[ "$FM_OUT" == "frontmatter ok" ]]; then
ok "T2 frontmatter parses (name=omega-cloud-tenant, description present)"
else
bad "T2 frontmatter" "$FM_OUT"
fi
# ---- T3 internal-term leakage: must return NOTHING ----
# Internal identifiers, operator tooling, component code names, internal
# hosts/CIDRs. No sanctioned exceptions inside the skill package. The
# client-facing usage page for the skill is scanned too.
LEAK_RX='D-0[0-9]{2}|DOCFIX|BUNDLEFIX|juju|charm|maas|vault|ceph|ovn[^a-z]|magnum|octavia|barbican|keystone|horizon|glance|cinder|neutron|nova[^a-z]|amphora|capi|caracal|runbook|10\.12\.|baldurkeep|vopenstack|neumatrix|jumphost'
LEAK_FILES=("${FILES[@]}")
[[ -f "$REPO/clientdocs/ai-assistant-guide.md" ]] && LEAK_FILES+=("$REPO/clientdocs/ai-assistant-guide.md")
for s in "$REPO"/clientdocs/scripts/*.sh; do [[ -f "$s" ]] && LEAK_FILES+=("$s"); done
LEAKS="$(grep -rniE "$LEAK_RX" "${LEAK_FILES[@]}" 2>/dev/null)"
if [[ -z "$LEAKS" ]]; then
ok "T3 zero internal-term leakage"
else
bad "T3 internal-term LEAK(s):" "$(echo "$LEAKS" | head -5)"
fi
# ---- T4 placeholder inventory ----
# Documented set (clientdocs/README.md). {{THIS}} is the TEMPLATE NOTE
# meta-token shared with the other clientdocs templates, not a placeholder.
WANT="ACCOUNT_CONTACT AUTH_URL DASHBOARD_URL REGION TENANT_SHORT_NAME"
GOT="$(grep -ohE '\{\{[A-Za-z0-9_]+\}\}' "${FILES[@]}" | tr -d '{}' | grep -v '^THIS$' | sort -u | tr '\n' ' ' | sed 's/ $//')"
if [[ "$GOT" == "$WANT" ]]; then
ok "T4 placeholder inventory matches documented set"
else
bad "T4 placeholder inventory drift" "want: $WANT" "got: $GOT"
fi
# ---- T5 routing reachability ----
T5_FAILS=()
for f in "$SKILL"/references/*.md; do
b="references/$(basename "$f")"
grep -q "$b" "$SKILL/SKILL.md" || T5_FAILS+=("MISS $b not referenced from SKILL.md")
done
while read -r ref; do
[[ -f "$SKILL/$ref" ]] || T5_FAILS+=("MISS $ref referenced but absent")
done < <(grep -ohE 'references/[a-z0-9-]+\.md' "${FILES[@]}" | sort -u)
if [[ "${#T5_FAILS[@]}" -eq 0 ]]; then
ok "T5 routing table reachability (SKILL.md <-> references/)"
else
bad "T5 routing gaps:" "${T5_FAILS[@]}"
fi
# ---- T6 ASCII + LF ----
T6_FAILS=()
for f in "${FILES[@]}"; do
if LC_ALL=C grep -q $'\r' "$f"; then T6_FAILS+=("CR bytes in ${f#$REPO/}"); fi
if LC_ALL=C grep -qP '[^\x00-\x7F]' "$f"; then T6_FAILS+=("non-ASCII in ${f#$REPO/}"); fi
done
if [[ "${#T6_FAILS[@]}" -eq 0 ]]; then
ok "T6 ASCII + LF clean"
else
bad "T6 encoding:" "${T6_FAILS[@]}"
fi
# ---- T7 expected-refusal table ----
TS="$SKILL/references/troubleshooting.md"
if grep -qi 'expected refusal' "$TS" && grep -q '| Operation attempted |' "$TS"; then
ok "T7 expected-refusal table present in troubleshooting.md"
else
bad "T7 expected-refusal table missing from troubleshooting.md"
fi
# ---- T8 starter-script references + syntax ----
T8_FAILS=()
GUIDE="$REPO/clientdocs/ai-assistant-guide.md"
while read -r sh; do
[[ -f "$REPO/clientdocs/scripts/$sh" ]] || T8_FAILS+=("MISS clientdocs/scripts/$sh referenced but absent")
done < <(grep -ohE 'scripts/[a-z0-9-]+\.sh' "${FILES[@]}" "$GUIDE" 2>/dev/null | sed 's|^scripts/||' | sort -u)
for s in "$REPO"/clientdocs/scripts/*.sh; do
[[ -f "$s" ]] || continue
bash -n "$s" 2>/dev/null || T8_FAILS+=("SYNTAX ${s#$REPO/} fails bash -n")
done
if [[ "${#T8_FAILS[@]}" -eq 0 ]]; then
ok "T8 starter-script references exist and parse (bash -n)"
else
bad "T8 starter-script gaps:" "${T8_FAILS[@]}"
fi
echo; echo "RESULT: PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]] && { echo "ALL PASS"; exit 0; } || exit 1