e3c8979e8d
- cmd/fn/doctor.go - cmd/fn/main.go - cpp/apps/primitives_gallery/playground/tables/CMakeLists.txt - cpp/apps/primitives_gallery/playground/tables/data_table.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.h - cpp/apps/primitives_gallery/playground/tables/self_test.cpp - cpp/apps/primitives_gallery/playground/tables/tql.cpp - cpp/apps/primitives_gallery/playground/tables/viz.cpp - cpp/apps/primitives_gallery/playground/tables/viz.h - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
173 lines
4.5 KiB
Bash
173 lines
4.5 KiB
Bash
#!/usr/bin/env bash
|
|
# vault_audit — Full audit pipeline for one or all declared vaults.
|
|
# Runs: layout-ensure → index → profile → dedupe → aggregate → doctor
|
|
#
|
|
# Usage:
|
|
# vault_audit.sh <vault_name>
|
|
# vault_audit.sh --all
|
|
# vault_audit.sh <vault_name> --skip-profilers
|
|
# vault_audit.sh <vault_name> --dry-run-layout
|
|
# vault_audit.sh --all --skip-profilers
|
|
set -euo pipefail
|
|
|
|
# --- locate FN_REGISTRY_ROOT ---
|
|
_find_registry_root() {
|
|
local dir
|
|
dir="$(pwd)"
|
|
while [[ "$dir" != "/" ]]; do
|
|
if [[ -f "$dir/registry.db" ]]; then
|
|
echo "$dir"
|
|
return 0
|
|
fi
|
|
dir="$(dirname "$dir")"
|
|
done
|
|
return 1
|
|
}
|
|
|
|
if [[ -n "${FN_REGISTRY_ROOT:-}" && -f "${FN_REGISTRY_ROOT}/registry.db" ]]; then
|
|
REGISTRY_ROOT="$FN_REGISTRY_ROOT"
|
|
elif REGISTRY_ROOT="$(_find_registry_root 2>/dev/null)"; then
|
|
: # found
|
|
else
|
|
echo "ERROR: Cannot locate registry.db. Set FN_REGISTRY_ROOT or run from registry root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
FN_BIN="${FN_BIN:-${REGISTRY_ROOT}/fn}"
|
|
if [[ ! -x "$FN_BIN" ]]; then
|
|
echo "ERROR: fn binary not found at $FN_BIN. Build with: CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# --- parse args ---
|
|
AUDIT_ALL=0
|
|
SKIP_PROFILERS=0
|
|
DRY_RUN_LAYOUT=0
|
|
VAULT_NAMES=()
|
|
START_TS=$(date +%s)
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--all) AUDIT_ALL=1 ;;
|
|
--skip-profilers) SKIP_PROFILERS=1 ;;
|
|
--dry-run-layout) DRY_RUN_LAYOUT=1 ;;
|
|
-*)
|
|
echo "ERROR: Unknown flag: $1" >&2
|
|
echo "Usage: vault_audit.sh <name> | --all [--skip-profilers] [--dry-run-layout]" >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
VAULT_NAMES+=("$1")
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ $AUDIT_ALL -eq 0 && ${#VAULT_NAMES[@]} -eq 0 ]]; then
|
|
echo "Usage: vault_audit.sh <vault_name> | --all [--skip-profilers] [--dry-run-layout]" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# --- resolve vault list ---
|
|
if [[ $AUDIT_ALL -eq 1 ]]; then
|
|
mapfile -t VAULT_NAMES < <(
|
|
sqlite3 "${REGISTRY_ROOT}/registry.db" "SELECT name FROM vaults ORDER BY name;" 2>/dev/null || true
|
|
)
|
|
if [[ ${#VAULT_NAMES[@]} -eq 0 ]]; then
|
|
echo "No vaults registered in registry.db. Run 'fn index' first." >&2
|
|
exit 1
|
|
fi
|
|
echo "Found ${#VAULT_NAMES[@]} vault(s): ${VAULT_NAMES[*]}"
|
|
fi
|
|
|
|
# --- build fn vault flags ---
|
|
LAYOUT_FLAGS=()
|
|
if [[ $DRY_RUN_LAYOUT -eq 1 ]]; then
|
|
LAYOUT_FLAGS+=(--dry-run)
|
|
fi
|
|
|
|
# --- per-vault audit ---
|
|
PASS_COUNT=0
|
|
FAIL_COUNT=0
|
|
declare -A VAULT_STATUS
|
|
|
|
audit_one() {
|
|
local name="$1"
|
|
local vault_ok=1
|
|
echo ""
|
|
echo "=== vault: $name ==="
|
|
|
|
# Step 1: layout-ensure
|
|
echo " [1/5] layout-ensure"
|
|
if ! "$FN_BIN" vault layout-ensure "$name" "${LAYOUT_FLAGS[@]}" 2>&1 | sed 's/^/ /'; then
|
|
echo " WARN: layout-ensure failed (non-fatal)" >&2
|
|
vault_ok=0
|
|
fi
|
|
|
|
# Step 2: index
|
|
echo " [2/5] index"
|
|
if ! "$FN_BIN" vault index "$name" 2>&1 | sed 's/^/ /'; then
|
|
echo " ERROR: index failed" >&2
|
|
vault_ok=0
|
|
fi
|
|
|
|
# Step 3: profile
|
|
if [[ $SKIP_PROFILERS -eq 0 ]]; then
|
|
echo " [3/5] profile"
|
|
if ! "$FN_BIN" vault profile "$name" 2>&1 | sed 's/^/ /'; then
|
|
echo " WARN: profile had errors (non-fatal)" >&2
|
|
fi
|
|
else
|
|
echo " [3/5] profile (skipped)"
|
|
fi
|
|
|
|
# Step 4: dedupe (informational, non-fatal)
|
|
echo " [4/5] dedupe"
|
|
"$FN_BIN" vault dedupe "$name" 2>&1 | sed 's/^/ /' || true
|
|
|
|
# Step 5 deferred — aggregate runs once at the end
|
|
echo " [5/5] aggregate (deferred)"
|
|
|
|
if [[ $vault_ok -eq 1 ]]; then
|
|
VAULT_STATUS["$name"]="ok"
|
|
PASS_COUNT=$((PASS_COUNT + 1))
|
|
else
|
|
VAULT_STATUS["$name"]="warn"
|
|
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
fi
|
|
}
|
|
|
|
for vault_name in "${VAULT_NAMES[@]}"; do
|
|
audit_one "$vault_name"
|
|
done
|
|
|
|
# --- aggregate (once, after all vaults) ---
|
|
echo ""
|
|
echo "=== aggregate ==="
|
|
"$FN_BIN" vault aggregate 2>&1 | sed 's/^/ /'
|
|
|
|
# --- doctor (read-only health check) ---
|
|
echo ""
|
|
echo "=== doctor ==="
|
|
"$FN_BIN" vault doctor 2>&1 | sed 's/^/ /' || true
|
|
|
|
# --- summary table ---
|
|
END_TS=$(date +%s)
|
|
ELAPSED=$(( END_TS - START_TS ))
|
|
|
|
echo ""
|
|
echo "=== summary ==="
|
|
printf "%-30s %s\n" "VAULT" "STATUS"
|
|
printf "%-30s %s\n" "-----" "------"
|
|
for vault_name in "${VAULT_NAMES[@]}"; do
|
|
status="${VAULT_STATUS[$vault_name]:-unknown}"
|
|
printf "%-30s %s\n" "$vault_name" "$status"
|
|
done
|
|
echo ""
|
|
echo "Done: ${PASS_COUNT} ok, ${FAIL_COUNT} warn (${ELAPSED}s)"
|
|
|
|
if [[ $FAIL_COUNT -gt 0 ]]; then
|
|
exit 4
|
|
fi
|
|
exit 0
|