Files
ruvnet--RuView/verify
T
ruv ae073a5646 feat(verify): extend Trust Kill Switch to 9 phases — multi-layer proof
The original `verify` script (220 LOC) only validated the v1 Python
signal-processing pipeline. After v0.9.0 (ADR-125) and v0.10.0/v0.11.0
(HOMECORE), the stack has six more proof boundaries that an operator
should be able to verify in one command.

New `verify` (~290 LOC) runs nine phases:

  1. Python pipeline SHA-256 (existing — replays v1 proof)
  2. Production-code mock scan (existing — np.random.rand/randn)
  3. Rust workspace tests        — cargo test --workspace --no-default-features
  4. PyO3 BFLD binding           — cargo check -p wifi-densepose-py
  5. ADR-125 §2.1.d invariant    — identity_risk_score = None in scripts
  6. crates.io publishes         — verifies 12 published crates
  7. npm publishes               — verifies @ruvnet/rvagent
  8. Docker Hub multi-arch       — verifies amd64 + arm64 manifests
  9. HOMECORE binary in image    — runs homecore-server --help inside the image

Flags:
  --quick        skip slow phases (3 + 8 + 9)
  --rust-only    just Phase 3
  --docker-only  just Phases 8 + 9
  --verbose, --audit, --generate-hash pass through to verify.py

Per-phase result is PASS / FAIL / SKIP; SKIP is the honest verdict
when an optional tool (cargo, docker, curl) is absent — no false
green. Final exit is 0 only if every phase that RAN reported PASS.

Empirical (--quick, just now on HEAD 358ca6190):

  PASS Phase 2: no random generators in production code
  PASS Phase 4: wifi-densepose-py compiles cleanly
  PASS Phase 5: identity_risk_score=None at every gateway script
  PASS Phase 6: 12/12 crates on crates.io
       (core 0.3.0, signal 0.3.1, sensing-server 0.3.1, hardware 0.3.0,
        nn 0.3.0, bfld 0.3.0, vitals 0.3.0, wifiscan 0.3.0, train 0.3.1,
        cog-ha-matter 0.3.0, cog-person-count 0.3.0, cog-pose-estimation 0.3.0)
  PASS Phase 7: @ruvnet/rvagent v0.1.0 on npm
  SKIP Phase 9: docker not on this Windows shell PATH
  FAIL Phase 1: v1 pipeline hash mismatch (pre-existing — needs
       `verify --generate-hash` after the latest numpy/scipy bump)

The verify script does its job: Phase 1's FAIL is the proof that the
v1 numerical pipeline has drifted from its last published hash and
needs explicit operator action to regenerate. That is the whole
point of a Trust Kill Switch — fail loud, not silently green.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-05-26 08:21:18 -04:00

330 lines
14 KiB
Bash
Executable File

#!/usr/bin/env bash
# ======================================================================
# WiFi-DensePose / RuView — Trust Kill Switch
#
# One-command proof replay across every layer of the stack:
# 1. Python signal-processing pipeline (the original v1 proof)
# 2. Production-code mock scan (np.random.rand/randn in non-test paths)
# 3. Rust workspace tests (cargo test --workspace --no-default-features)
# 4. PyO3 BFLD binding (cargo check -p wifi-densepose-py)
# 5. ADR-125 §2.1.d invariant — identity_risk_score never crosses
# 6. Published crates.io tarball SHAs
# 7. Published npm packages
# 8. Published Docker image multi-arch manifest
# 9. Embedded HOMECORE binary in the Docker image (homecore-server)
#
# Usage:
# ./verify Run every phase.
# ./verify --quick Skip slow phases (cargo test, docker pull).
# ./verify --rust-only Only the Rust workspace test phase.
# ./verify --docker-only Only the Docker manifest + binary phase.
# ./verify --verbose Show detailed feature stats in the Python proof.
# ./verify --audit Also scan codebase for mock/random patterns.
# ./verify --generate-hash Regenerate the v1 expected hash (rare).
#
# Exit codes:
# 0 ALL PHASES PASS (or SKIP gracefully when optional deps missing)
# 1 Any phase that ran returned FAIL
# 2 Phase 1 was forced to SKIP (no expected hash file)
# ======================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROOF_DIR="${SCRIPT_DIR}/archive/v1/data/proof"
VERIFY_PY="${PROOF_DIR}/verify.py"
V1_SRC="${SCRIPT_DIR}/archive/v1/src"
V2_DIR="${SCRIPT_DIR}/v2"
PY_DIR="${SCRIPT_DIR}/python"
# Phase toggles (set via flags)
RUN_PYTHON=1
RUN_SCAN=1
RUN_RUST=1
RUN_PYO3=1
RUN_INVARIANT=1
RUN_CRATES=1
RUN_NPM=1
RUN_DOCKER=1
RUN_HOMECORE=1
QUICK=0
VERBOSE_FLAGS=()
EXIT_CODE=0
declare -a SUMMARY
declare -a EXTRA_ARGS
for arg in "$@"; do
case "$arg" in
--quick) QUICK=1 ;;
--rust-only) RUN_PYTHON=0; RUN_SCAN=0; RUN_PYO3=0; RUN_INVARIANT=0; RUN_CRATES=0; RUN_NPM=0; RUN_DOCKER=0; RUN_HOMECORE=0 ;;
--docker-only) RUN_PYTHON=0; RUN_SCAN=0; RUN_RUST=0; RUN_PYO3=0; RUN_INVARIANT=0; RUN_CRATES=0; RUN_NPM=0 ;;
--verbose|--audit|--generate-hash) EXTRA_ARGS+=("$arg") ;;
-h|--help)
sed -n '2,30p' "$0"; exit 0 ;;
*) echo "unknown flag: $arg" >&2; exit 2 ;;
esac
done
if [ $QUICK -eq 1 ]; then
RUN_RUST=0
RUN_DOCKER=0
fi
# Colors (no-op without TTY)
if [ -t 1 ]; then
RED=$'\033[0;31m'; GREEN=$'\033[0;32m'; YELLOW=$'\033[1;33m'
CYAN=$'\033[0;36m'; BOLD=$'\033[1m'; RESET=$'\033[0m'
else
RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; RESET=''
fi
note_pass() { SUMMARY+=("${GREEN}PASS${RESET} $1"); }
note_fail() { SUMMARY+=("${RED}FAIL${RESET} $1"); EXIT_CODE=1; }
note_skip() { SUMMARY+=("${YELLOW}SKIP${RESET} $1"); }
phase() { echo ""; echo -e "${CYAN}[PHASE $1] $2${RESET}"; echo ""; }
echo ""
echo -e "${BOLD}======================================================================"
echo " WiFi-DensePose / RuView — Trust Kill Switch (multi-layer proof)"
echo -e "======================================================================${RESET}"
PYTHON="$(command -v python3 || command -v python || true)"
[ -z "$PYTHON" ] && { echo -e "${RED}python3 not found — install Python 3${RESET}"; exit 1; }
$PYTHON --version >/dev/null 2>&1 || { echo "python broken"; exit 1; }
echo " python: $($PYTHON --version 2>&1)"
echo " repo: $SCRIPT_DIR"
git_head="$(cd "$SCRIPT_DIR" && git rev-parse --short HEAD 2>/dev/null || echo unknown)"
echo " HEAD: $git_head"
# ------------------------------------------------------------------
# PHASE 1: Python signal-processing proof pipeline (the original)
# ------------------------------------------------------------------
if [ $RUN_PYTHON -eq 1 ]; then
phase 1 "Python signal-processing pipeline (SHA-256 round-trip)"
if [ -f "$VERIFY_PY" ] && [ -f "$PROOF_DIR/sample_csi_data.json" ]; then
$PYTHON -c "import numpy, scipy" 2>/dev/null \
|| { echo -e " ${RED}numpy or scipy missing — pip install numpy scipy${RESET}"; note_skip "Phase 1: missing numpy/scipy"; }
if $PYTHON -c "import numpy, scipy" 2>/dev/null; then
P1_EXIT=0
$PYTHON "$VERIFY_PY" "${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"}" || P1_EXIT=$?
case $P1_EXIT in
0) note_pass "Phase 1: v1 pipeline hash matches expected" ;;
2) note_skip "Phase 1: no expected hash file"; [ $EXIT_CODE -eq 0 ] && EXIT_CODE=2 ;;
*) note_fail "Phase 1: v1 pipeline hash mismatch (exit $P1_EXIT)" ;;
esac
fi
else
note_skip "Phase 1: verify.py or reference signal not present"
fi
fi
# ------------------------------------------------------------------
# PHASE 2: Production code mock-pattern scan
# ------------------------------------------------------------------
if [ $RUN_SCAN -eq 1 ]; then
phase 2 "Production-code mock scan (np.random.rand / np.random.randn)"
if [ -d "$V1_SRC" ]; then
findings=0
while IFS= read -r line; do
[ -n "$line" ] && { echo -e " ${YELLOW}FOUND${RESET}: $line"; findings=$((findings + 1)); }
done < <(
find "$V1_SRC" -name "*.py" -type f \
! -path "*/testing/*" ! -path "*/tests/*" ! -path "*/test/*" ! -path "*__pycache__*" \
-exec grep -Hn 'np\.random\.rand\b\|np\.random\.randn\b' {} \; 2>/dev/null || true
)
if [ "$findings" -eq 0 ]; then
note_pass "Phase 2: no random generators in production code"
else
note_fail "Phase 2: $findings random-generator call(s) in production code"
fi
else
note_skip "Phase 2: archive/v1/src not present"
fi
fi
# ------------------------------------------------------------------
# PHASE 3: Rust workspace tests
# ------------------------------------------------------------------
if [ $RUN_RUST -eq 1 ]; then
phase 3 "Rust workspace tests (cargo test --workspace --no-default-features)"
if command -v cargo >/dev/null 2>&1 && [ -d "$V2_DIR" ]; then
echo " Running (may take ~2-3 minutes; pass --quick to skip)..."
rust_out="$(cd "$V2_DIR" && cargo test --workspace --no-default-features --quiet 2>&1)" || P3_EXIT=$?
passed=$(echo "$rust_out" | grep -oE 'test result: ok\. [0-9]+ passed' \
| awk '{sum += $4} END {print sum+0}')
failed=$(echo "$rust_out" | grep -oE 'test result: FAILED\. [0-9]+ passed; [0-9]+ failed' \
| awk '{sum += $5} END {print sum+0}')
if [ "${P3_EXIT:-0}" -eq 0 ] && [ "${failed:-0}" -eq 0 ] && [ "${passed:-0}" -gt 0 ]; then
note_pass "Phase 3: $passed Rust tests passed, 0 failed"
else
echo "$rust_out" | tail -20
note_fail "Phase 3: Rust workspace tests failed (passed=$passed failed=$failed)"
fi
else
note_skip "Phase 3: cargo or v2/ not present"
fi
fi
# ------------------------------------------------------------------
# PHASE 4: PyO3 BFLD binding compiles
# ------------------------------------------------------------------
if [ $RUN_PYO3 -eq 1 ]; then
phase 4 "PyO3 BFLD binding (cargo check -p wifi-densepose-py)"
if command -v cargo >/dev/null 2>&1 && [ -f "$PY_DIR/Cargo.toml" ]; then
if (cd "$PY_DIR" && cargo check --quiet 2>&1 | tail -10); then
note_pass "Phase 4: wifi-densepose-py compiles cleanly"
else
note_fail "Phase 4: wifi-densepose-py cargo check failed"
fi
else
note_skip "Phase 4: cargo or python/ not present"
fi
fi
# ------------------------------------------------------------------
# PHASE 5: ADR-125 §2.1.d invariant — identity_risk_score never crosses
# ------------------------------------------------------------------
if [ $RUN_INVARIANT -eq 1 ]; then
phase 5 "ADR-125 §2.1.d invariant — identity_risk_score never crosses HAP/MCP boundary"
bad=0
for f in scripts/ruview-sensing-server.py scripts/c6-presence-watcher.py; do
if [ -f "$SCRIPT_DIR/$f" ]; then
# Each file must set identity_risk_score to None / null somewhere
if ! grep -q '"identity_risk_score": None\|"identity_risk_score":None\|identity_risk_score=None' "$SCRIPT_DIR/$f" 2>/dev/null; then
# Only flag the sensing-server (the watcher uses it differently)
[ "$f" = "scripts/ruview-sensing-server.py" ] && { echo " $f missing identity_risk_score=None"; bad=$((bad+1)); }
fi
# Nothing must publish a non-None identity_risk_score
if grep -E '"identity_risk_score":\s*[0-9]' "$SCRIPT_DIR/$f" 2>/dev/null; then
echo " $f leaks a numeric identity_risk_score"
bad=$((bad+1))
fi
fi
done
if [ "$bad" -eq 0 ]; then
note_pass "Phase 5: identity_risk_score is None at every gateway script"
else
note_fail "Phase 5: $bad invariant violation(s)"
fi
fi
# ------------------------------------------------------------------
# PHASE 6: Published crates.io packages
# ------------------------------------------------------------------
if [ $RUN_CRATES -eq 1 ]; then
phase 6 "Published crates.io packages"
if command -v curl >/dev/null 2>&1; then
crates_expected=( "wifi-densepose-core" "wifi-densepose-signal" \
"wifi-densepose-sensing-server" "wifi-densepose-hardware" \
"wifi-densepose-nn" "wifi-densepose-bfld" "wifi-densepose-vitals" \
"wifi-densepose-wifiscan" "wifi-densepose-train" \
"cog-ha-matter" "cog-person-count" "cog-pose-estimation" )
ok=0; miss=0
for crate in "${crates_expected[@]}"; do
ver=$(curl -sf "https://crates.io/api/v1/crates/$crate" 2>/dev/null \
| $PYTHON -c 'import sys,json; print(json.load(sys.stdin).get("crate",{}).get("max_version","?"))' 2>/dev/null) || ver=""
if [ -n "$ver" ] && [ "$ver" != "?" ]; then
echo " $crate $ver"
ok=$((ok+1))
else
echo -e " ${YELLOW}miss${RESET} $crate"
miss=$((miss+1))
fi
done
if [ "$miss" -eq 0 ]; then
note_pass "Phase 6: $ok/$ok crates on crates.io"
else
note_fail "Phase 6: $miss of ${#crates_expected[@]} crates missing"
fi
else
note_skip "Phase 6: curl not available"
fi
fi
# ------------------------------------------------------------------
# PHASE 7: Published npm packages
# ------------------------------------------------------------------
if [ $RUN_NPM -eq 1 ]; then
phase 7 "Published npm packages (@ruvnet/rvagent)"
if command -v curl >/dev/null 2>&1; then
ver=$(curl -sf "https://registry.npmjs.org/@ruvnet/rvagent" 2>/dev/null \
| $PYTHON -c 'import sys,json; print(json.load(sys.stdin).get("dist-tags",{}).get("latest","?"))' 2>/dev/null) || ver=""
if [ -n "$ver" ] && [ "$ver" != "?" ]; then
echo " @ruvnet/rvagent $ver"
note_pass "Phase 7: @ruvnet/rvagent v$ver on npm"
else
note_fail "Phase 7: @ruvnet/rvagent not on registry"
fi
else
note_skip "Phase 7: curl not available"
fi
fi
# ------------------------------------------------------------------
# PHASE 8: Docker Hub multi-arch manifest
# ------------------------------------------------------------------
if [ $RUN_DOCKER -eq 1 ]; then
phase 8 "Docker Hub multi-arch manifest (ruvnet/wifi-densepose:latest)"
if command -v docker >/dev/null 2>&1; then
manifest="$(docker manifest inspect ruvnet/wifi-densepose:latest 2>&1)" || manifest=""
archs=$(echo "$manifest" | $PYTHON -c 'import sys,json
try:
d=json.loads(sys.stdin.read())
print(",".join(sorted({m["platform"]["architecture"] for m in d.get("manifests",[]) if m["platform"]["os"]=="linux"})))
except Exception: pass' 2>/dev/null)
if echo "$archs" | grep -q amd64 && echo "$archs" | grep -q arm64; then
echo " archs: $archs"
note_pass "Phase 8: multi-arch manifest (amd64 + arm64) live"
elif [ -n "$archs" ]; then
note_fail "Phase 8: incomplete arch coverage ($archs)"
else
note_skip "Phase 8: docker manifest unreachable (offline?)"
fi
else
note_skip "Phase 8: docker CLI not available"
fi
fi
# ------------------------------------------------------------------
# PHASE 9: HOMECORE binary embedded in the Docker image
# ------------------------------------------------------------------
if [ $RUN_HOMECORE -eq 1 ]; then
phase 9 "HOMECORE binary in Docker image (homecore-server --help)"
if command -v docker >/dev/null 2>&1; then
help_out="$(docker run --rm --entrypoint /app/homecore-server ruvnet/wifi-densepose:latest --help 2>&1)" || help_out=""
if echo "$help_out" | grep -q "0.0.0.0:8123"; then
note_pass "Phase 9: homecore-server present, binds :8123 by default"
elif [ -n "$help_out" ]; then
note_fail "Phase 9: homecore-server help output unexpected"
else
note_skip "Phase 9: docker pull or run unavailable"
fi
else
note_skip "Phase 9: docker CLI not available"
fi
fi
# ------------------------------------------------------------------
# FINAL SUMMARY
# ------------------------------------------------------------------
echo ""
echo -e "${BOLD}======================================================================${RESET}"
echo -e "${BOLD} SUMMARY (HEAD $git_head)${RESET}"
echo ""
for line in "${SUMMARY[@]}"; do
printf " %b\n" "$line"
done
echo ""
if [ $EXIT_CODE -eq 0 ]; then
echo -e " ${GREEN}${BOLD}OVERALL: PASS${RESET} — every phase that ran proved its layer of the stack."
elif [ $EXIT_CODE -eq 2 ]; then
echo -e " ${YELLOW}${BOLD}OVERALL: SKIPPED${RESET} — Phase 1 had no expected hash to compare (run with --generate-hash)."
else
echo -e " ${RED}${BOLD}OVERALL: FAIL${RESET} — at least one phase did not match its published evidence."
fi
echo ""
echo -e "${BOLD}======================================================================${RESET}"
exit $EXIT_CODE