Major additions: - Community Next.js app (port 18187) for browsing claims with API docs - stemedb-chaos crate: Fault injection, chaos testing, CRDT properties - Latent ingestion system: Reddit/FDA ingesters with ADK-Go agents - Disputed claims handling: Manual review workflows and validation - Aphoria security scanner: New extractors (SQL injection, command injection, weak crypto, TLS version), policy-based ignores, UAT reports - Docker infrastructure: Dockerfile, docker-compose.yml for full stack - VulnBank demo: Intentionally vulnerable multi-language test corpus SDK & API enhancements: - Source registry handlers for tracking data provenance - Metrics endpoint - Skeptic filtering improvements Code quality: - Split 14 large files (>500 lines) into focused modules - All files now under 500-line limit per project guidelines Documentation: - Chaos testing guide, circuit breakers, observability docs - Phase 7 UAT documentation updates - Martin Kleppmann technical writer agent Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
240 lines
6.9 KiB
Bash
Executable File
240 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# StemeDB Validation Script
|
|
#
|
|
# Validates that StemeDB works end-to-end:
|
|
# 1. Builds the API server
|
|
# 2. Starts the server in the background
|
|
# 3. Waits for health check
|
|
# 4. Creates an assertion via curl
|
|
# 5. Queries it back
|
|
# 6. Shuts down the server
|
|
#
|
|
# Usage:
|
|
# ./scripts/validate.sh # Run validation
|
|
# ./scripts/validate.sh --no-build # Skip cargo build (faster)
|
|
#
|
|
# Exit codes:
|
|
# 0 - All checks passed
|
|
# 1 - Validation failed
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
readonly API_HOST="${STEMEDB_BIND_ADDR:-127.0.0.1:18180}"
|
|
readonly API_URL="http://${API_HOST}"
|
|
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
readonly DATA_DIR="${PROJECT_DIR}/tmp/validate-$$"
|
|
readonly PID_FILE="${DATA_DIR}/server.pid"
|
|
readonly LOG_FILE="${DATA_DIR}/server.log"
|
|
|
|
# Colors (if terminal supports it)
|
|
if [[ -t 1 ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
else
|
|
RED=''
|
|
GREEN=''
|
|
YELLOW=''
|
|
BLUE=''
|
|
NC=''
|
|
fi
|
|
|
|
# Logging helpers
|
|
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
success() { echo -e "${GREEN}[PASS]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
|
|
|
|
# Cleanup on exit
|
|
cleanup() {
|
|
if [[ -f "$PID_FILE" ]]; then
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
info "Stopping server (PID $pid)..."
|
|
kill "$pid" 2>/dev/null || true
|
|
wait "$pid" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
if [[ -d "$DATA_DIR" ]]; then
|
|
rm -rf "$DATA_DIR"
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# Parse arguments
|
|
SKIP_BUILD=false
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
--no-build)
|
|
SKIP_BUILD=true
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: $0 [--no-build]"
|
|
echo ""
|
|
echo "Validates StemeDB end-to-end (build, start, assert, query, shutdown)."
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --no-build Skip cargo build (use existing binary)"
|
|
echo " --help Show this help message"
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Main validation
|
|
main() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " StemeDB Validation"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Create temp data directory
|
|
mkdir -p "$DATA_DIR"
|
|
|
|
# Step 1: Build
|
|
if [[ "$SKIP_BUILD" == "false" ]]; then
|
|
info "Building stemedb-api..."
|
|
cd "$PROJECT_DIR"
|
|
if ! cargo build --package stemedb-api --quiet 2>&1; then
|
|
fail "Build failed"
|
|
fi
|
|
success "Build complete"
|
|
else
|
|
info "Skipping build (--no-build)"
|
|
fi
|
|
|
|
# Step 2: Start server
|
|
info "Starting API server..."
|
|
cd "$PROJECT_DIR"
|
|
STEMEDB_WAL_DIR="$DATA_DIR/wal" \
|
|
STEMEDB_DB_DIR="$DATA_DIR/db" \
|
|
STEMEDB_BIND_ADDR="$API_HOST" \
|
|
cargo run --package stemedb-api --quiet > "$LOG_FILE" 2>&1 &
|
|
echo $! > "$PID_FILE"
|
|
|
|
# Step 3: Wait for health
|
|
info "Waiting for server to be ready..."
|
|
local attempts=0
|
|
local max_attempts=30
|
|
while [[ $attempts -lt $max_attempts ]]; do
|
|
if curl -s "${API_URL}/v1/health" > /dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 0.5
|
|
((attempts++))
|
|
done
|
|
|
|
if [[ $attempts -eq $max_attempts ]]; then
|
|
echo ""
|
|
echo "Server log:"
|
|
cat "$LOG_FILE" || true
|
|
fail "Server failed to start within 15 seconds"
|
|
fi
|
|
success "Server is healthy"
|
|
|
|
# Step 4: Health check details
|
|
info "Checking health endpoint..."
|
|
local health_response
|
|
health_response=$(curl -s "${API_URL}/v1/health")
|
|
echo " Response: $health_response"
|
|
|
|
if ! echo "$health_response" | grep -q '"status":"healthy"'; then
|
|
fail "Health check failed"
|
|
fi
|
|
success "Health check passed"
|
|
|
|
# Step 5: Create a properly signed assertion
|
|
info "Creating assertion (with valid Ed25519 signature)..."
|
|
|
|
# Generate a properly signed assertion using the helper binary
|
|
# This creates a fresh keypair and signs "{subject}:{predicate}"
|
|
local assertion_json
|
|
assertion_json=$(cargo run --package stemedb-api --example gen_test_assertion --quiet 2>/dev/null)
|
|
|
|
if [[ -z "$assertion_json" ]]; then
|
|
fail "Failed to generate signed assertion"
|
|
fi
|
|
|
|
local assert_response
|
|
assert_response=$(curl -s -X POST "${API_URL}/v1/assert" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$assertion_json")
|
|
|
|
echo " Response: $assert_response"
|
|
|
|
if ! echo "$assert_response" | grep -q '"status":"created"'; then
|
|
fail "Assertion creation failed"
|
|
fi
|
|
|
|
local assertion_hash
|
|
assertion_hash=$(echo "$assert_response" | grep -o '"hash":"[^"]*"' | cut -d'"' -f4)
|
|
success "Assertion created: ${assertion_hash:0:16}..."
|
|
|
|
# Step 6: Query the assertion back (with retry for ingestion)
|
|
info "Querying assertion..."
|
|
|
|
# Retry loop - ingestion worker needs time to process WAL
|
|
local query_attempts=0
|
|
local query_max_attempts=10
|
|
local query_response=""
|
|
|
|
while [[ $query_attempts -lt $query_max_attempts ]]; do
|
|
query_response=$(curl -s "${API_URL}/v1/query?subject=StemeDB_Validation&predicate=test_status")
|
|
local count
|
|
count=$(echo "$query_response" | grep -o '"total_count":[0-9]*' | cut -d':' -f2)
|
|
|
|
if [[ "$count" -gt 0 ]] 2>/dev/null; then
|
|
break
|
|
fi
|
|
|
|
sleep 0.5
|
|
((query_attempts++))
|
|
done
|
|
|
|
echo " Total count: $(echo "$query_response" | grep -o '"total_count":[0-9]*' | cut -d':' -f2)"
|
|
echo " Ingestion took ~$((query_attempts * 500))ms"
|
|
|
|
if ! echo "$query_response" | grep -q '"StemeDB_Validation"'; then
|
|
echo " Full response: $query_response"
|
|
fail "Query did not return expected subject (tried ${query_attempts} times)"
|
|
fi
|
|
|
|
if ! echo "$query_response" | grep -q '"working"'; then
|
|
fail "Query did not return expected value"
|
|
fi
|
|
success "Query returned correct data"
|
|
|
|
# Step 7: Test query with lens
|
|
info "Testing lens-based query..."
|
|
|
|
local lens_response
|
|
lens_response=$(curl -s "${API_URL}/v1/query?subject=StemeDB_Validation&predicate=test_status&lens=Recency")
|
|
|
|
if ! echo "$lens_response" | grep -q '"working"'; then
|
|
fail "Lens query failed"
|
|
fi
|
|
success "Lens query (Recency) works"
|
|
|
|
# Final summary
|
|
echo ""
|
|
echo "=========================================="
|
|
echo -e " ${GREEN}All validation checks passed!${NC}"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "StemeDB is working correctly. You can now:"
|
|
echo " 1. Start the server: cargo run --package stemedb-api"
|
|
echo " 2. View API docs: http://localhost:18180/swagger-ui"
|
|
echo " 3. Use the Go SDK: cd sdk/go/examples/basic && go run main.go"
|
|
echo ""
|
|
}
|
|
|
|
main "$@"
|