Files
git.stella-ops.org/docs/modules/zastava/kit/validate-paths.sh
StellaOps Bot 2e70c9fdb6
Some checks failed
LNM Migration CI / build-runner (push) Has been cancelled
Ledger OpenAPI CI / deprecation-check (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Airgap Sealed CI Smoke / sealed-smoke (push) Has been cancelled
Ledger Packs CI / build-pack (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Ledger OpenAPI CI / validate-oas (push) Has been cancelled
Ledger OpenAPI CI / check-wellknown (push) Has been cancelled
Ledger Packs CI / verify-pack (push) Has been cancelled
LNM Migration CI / validate-metrics (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
up
2025-12-14 18:33:02 +02:00

330 lines
9.4 KiB
Bash

#!/usr/bin/env bash
#
# validate-paths.sh - Validates offline kit path structure
#
# Usage: ./validate-paths.sh [--combined] [kit_directory]
#
# Options:
# --combined Expect combined runtime format (combined.runtime.ndjson)
# kit_directory Path to kit directory (default: parent of this script)
#
# Exit codes:
# 0 - All validations passed
# 1 - Missing required files or directories
# 2 - Invalid file format
# 3 - Usage error
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
COMBINED_FORMAT=false
KIT_DIR=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--combined)
COMBINED_FORMAT=true
shift
;;
--help|-h)
echo "Usage: $0 [--combined] [kit_directory]"
echo ""
echo "Validates offline kit path structure and file formats."
echo ""
echo "Options:"
echo " --combined Expect combined runtime format"
echo " kit_directory Path to kit directory (default: parent of this script)"
exit 0
;;
-*)
echo "Unknown option: $1" >&2
exit 3
;;
*)
KIT_DIR="$1"
shift
;;
esac
done
# Default to parent directory if not specified
if [[ -z "$KIT_DIR" ]]; then
KIT_DIR="${SCRIPT_DIR}/.."
fi
# Resolve to absolute path
KIT_DIR="$(cd "$KIT_DIR" && pwd)"
echo "Validating kit at: $KIT_DIR"
ERRORS=0
# Helper functions
check_file() {
local file="$1"
local required="${2:-true}"
local path="$KIT_DIR/$file"
if [[ -f "$path" ]]; then
echo " [OK] $file"
return 0
elif [[ "$required" == "true" ]]; then
echo " [MISSING] $file (required)" >&2
ERRORS=$((ERRORS + 1))
return 1
else
echo " [SKIP] $file (optional)"
return 0
fi
}
check_dir() {
local dir="$1"
local required="${2:-true}"
local path="$KIT_DIR/$dir"
if [[ -d "$path" ]]; then
echo " [OK] $dir/"
return 0
elif [[ "$required" == "true" ]]; then
echo " [MISSING] $dir/ (required)" >&2
ERRORS=$((ERRORS + 1))
return 1
else
echo " [SKIP] $dir/ (optional)"
return 0
fi
}
validate_json() {
local file="$1"
local path="$KIT_DIR/$file"
if [[ ! -f "$path" ]]; then
return 0 # Skip if file doesn't exist (handled by check_file)
fi
if command -v python3 >/dev/null 2>&1; then
if python3 -c "import json; json.load(open('$path'))" 2>/dev/null; then
echo " [VALID JSON] $file"
return 0
else
echo " [INVALID JSON] $file" >&2
ERRORS=$((ERRORS + 1))
return 1
fi
elif command -v jq >/dev/null 2>&1; then
if jq empty "$path" 2>/dev/null; then
echo " [VALID JSON] $file"
return 0
else
echo " [INVALID JSON] $file" >&2
ERRORS=$((ERRORS + 1))
return 1
fi
else
echo " [SKIP] $file (no JSON validator available)"
return 0
fi
}
validate_ndjson() {
local file="$1"
local path="$KIT_DIR/$file"
if [[ ! -f "$path" ]]; then
return 0 # Skip if file doesn't exist
fi
if command -v python3 >/dev/null 2>&1; then
local result
result=$(python3 -c "
import json, sys
path = '$path'
errors = 0
with open(path, 'r') as f:
for i, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
json.loads(line)
except json.JSONDecodeError as e:
print(f'Line {i}: {e}', file=sys.stderr)
errors += 1
if errors >= 5:
print('(truncated after 5 errors)', file=sys.stderr)
break
sys.exit(0 if errors == 0 else 1)
" 2>&1)
if [[ $? -eq 0 ]]; then
echo " [VALID NDJSON] $file"
return 0
else
echo " [INVALID NDJSON] $file" >&2
echo "$result" >&2
ERRORS=$((ERRORS + 1))
return 1
fi
else
echo " [SKIP] $file (python3 required for NDJSON validation)"
return 0
fi
}
# =============================================================================
# Directory Structure Validation
# =============================================================================
echo ""
echo "=== Checking directory structure ==="
check_dir "schemas"
check_dir "exports"
check_dir "kit"
# =============================================================================
# Core Files Validation
# =============================================================================
echo ""
echo "=== Checking core files ==="
check_file "thresholds.yaml"
check_file "thresholds.yaml.dsse"
check_file "SHA256SUMS"
# =============================================================================
# Schema Files Validation
# =============================================================================
echo ""
echo "=== Checking schema files ==="
check_file "schemas/observer_event.schema.json"
check_file "schemas/observer_event.schema.json.dsse"
check_file "schemas/webhook_admission.schema.json"
check_file "schemas/webhook_admission.schema.json.dsse"
# =============================================================================
# Kit Files Validation
# =============================================================================
echo ""
echo "=== Checking kit files ==="
check_file "kit/ed25519.pub"
check_file "kit/verify.sh"
check_file "kit/zastava-kit.tzst" false # Optional - may not be in source tree
check_file "kit/zastava-kit.tzst.dsse" false
# =============================================================================
# Export Files Validation
# =============================================================================
echo ""
echo "=== Checking export files ==="
if [[ "$COMBINED_FORMAT" == "true" ]]; then
# Combined format
echo "(Combined format mode)"
check_file "exports/combined.runtime.ndjson"
check_file "exports/combined.runtime.ndjson.dsse"
# Legacy files are optional in combined mode
check_file "exports/observer_events.ndjson" false
check_file "exports/webhook_admissions.ndjson" false
else
# Legacy format
echo "(Legacy format mode)"
check_file "exports/observer_events.ndjson"
check_file "exports/observer_events.ndjson.dsse"
check_file "exports/webhook_admissions.ndjson"
check_file "exports/webhook_admissions.ndjson.dsse"
# Combined is optional in legacy mode
check_file "exports/combined.runtime.ndjson" false
fi
# =============================================================================
# JSON/NDJSON Format Validation
# =============================================================================
echo ""
echo "=== Validating file formats ==="
validate_json "schemas/observer_event.schema.json"
validate_json "schemas/webhook_admission.schema.json"
if [[ "$COMBINED_FORMAT" == "true" ]] && [[ -f "$KIT_DIR/exports/combined.runtime.ndjson" ]]; then
validate_ndjson "exports/combined.runtime.ndjson"
else
if [[ -f "$KIT_DIR/exports/observer_events.ndjson" ]]; then
validate_ndjson "exports/observer_events.ndjson"
fi
if [[ -f "$KIT_DIR/exports/webhook_admissions.ndjson" ]]; then
validate_ndjson "exports/webhook_admissions.ndjson"
fi
fi
# =============================================================================
# Combined Format Structure Validation
# =============================================================================
if [[ "$COMBINED_FORMAT" == "true" ]] && [[ -f "$KIT_DIR/exports/combined.runtime.ndjson" ]]; then
echo ""
echo "=== Validating combined format structure ==="
if command -v python3 >/dev/null 2>&1; then
python3 - "$KIT_DIR/exports/combined.runtime.ndjson" <<'PYTHON'
import json
import sys
path = sys.argv[1]
errors = []
has_header = False
has_footer = False
record_types = set()
with open(path, 'r') as f:
for i, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
record = json.loads(line)
rtype = record.get("type", "unknown")
record_types.add(rtype)
if rtype == "combined.header":
if has_header:
errors.append(f"Line {i}: duplicate header")
has_header = True
if i != 1:
errors.append(f"Line {i}: header should be first record")
elif rtype == "combined.footer":
has_footer = True
except json.JSONDecodeError as e:
errors.append(f"Line {i}: {e}")
if not has_header:
errors.append("Missing combined.header record")
if not has_footer:
errors.append("Missing combined.footer record")
if errors:
for e in errors:
print(f" [ERROR] {e}", file=sys.stderr)
sys.exit(1)
print(f" [OK] Header and footer present")
print(f" [OK] Record types: {', '.join(sorted(record_types))}")
PYTHON
if [[ $? -ne 0 ]]; then
ERRORS=$((ERRORS + 1))
fi
fi
fi
# =============================================================================
# Summary
# =============================================================================
echo ""
echo "=== Validation Summary ==="
if [[ $ERRORS -eq 0 ]]; then
echo "All validations passed!"
exit 0
else
echo "$ERRORS validation error(s) found" >&2
exit 1
fi