146 lines
3.5 KiB
Bash
146 lines
3.5 KiB
Bash
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
umask 077
|
|
|
|
# ==================================================
|
|
# Configuration
|
|
# ==================================================
|
|
|
|
: "${CACHE_ROOT:=/vuln-cache/vuln-builder}"
|
|
|
|
SOURCES_DIR="${SOURCES_DIR:-$CACHE_ROOT/sources}"
|
|
SOURCES_CONFIG="${SOURCES_CONFIG:-$CACHE_ROOT/sources.json}"
|
|
SOURCE_MANIFEST="$CACHE_ROOT/source-manifest.json"
|
|
RELEASE_DIR="$CACHE_ROOT/releases"
|
|
|
|
# ==================================================
|
|
# Create directories
|
|
# ==================================================
|
|
|
|
mkdir -p "$CACHE_ROOT" "$SOURCES_DIR" "$RELEASE_DIR"
|
|
|
|
# ==================================================
|
|
# Prevent concurrent builds
|
|
# ==================================================
|
|
|
|
exec 9>"$CACHE_ROOT/.build.lock"
|
|
|
|
/usr/bin/flock -w 1800 9 || {
|
|
echo "ERROR: Another builder run is active" >&2
|
|
exit 1
|
|
}
|
|
|
|
# ==================================================
|
|
# Validate configuration
|
|
# ==================================================
|
|
|
|
echo "========================================"
|
|
echo "Vulnerability SQLite Builder"
|
|
echo "========================================"
|
|
|
|
if [ ! -s "$SOURCES_CONFIG" ]; then
|
|
echo "ERROR: sources.json missing: $SOURCES_CONFIG" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -s "$SOURCE_MANIFEST" ]; then
|
|
echo "ERROR: Source manifest missing" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -d "$SOURCES_DIR" ]; then
|
|
echo "ERROR: Source directory missing" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Verify that all sources listed in the manifest
|
|
# exist as local Git repositories.
|
|
python3 - "$SOURCE_MANIFEST" "$SOURCES_DIR" <<'PY'
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
manifest_path = Path(sys.argv[1])
|
|
sources_dir = Path(sys.argv[2])
|
|
|
|
entries = json.loads(
|
|
manifest_path.read_text(encoding="utf-8")
|
|
)
|
|
|
|
if not isinstance(entries, list) or not entries:
|
|
raise SystemExit("ERROR: Empty source manifest")
|
|
|
|
for entry in entries:
|
|
name = entry["repo"]
|
|
expected = entry["commit"]
|
|
repo = sources_dir / name
|
|
|
|
if not (repo / ".git").is_dir():
|
|
raise SystemExit(f"ERROR: Missing repository {name}")
|
|
|
|
actual = subprocess.check_output(
|
|
["git", "-C", str(repo), "rev-parse", "HEAD"],
|
|
text=True
|
|
).strip()
|
|
|
|
if actual != expected:
|
|
raise SystemExit(
|
|
f"ERROR: Commit mismatch in {name}: "
|
|
f"{actual} != {expected}"
|
|
)
|
|
|
|
print(f"OK {name}: {actual[:12]}", flush=True)
|
|
|
|
print(f"Validated {len(entries)} repositories")
|
|
PY
|
|
|
|
# ==================================================
|
|
# Build SQLite
|
|
# ==================================================
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
echo "Starting SQLite build..."
|
|
|
|
python3 scripts/build.py \
|
|
--sources "$SOURCES_DIR" \
|
|
--output "$RELEASE_DIR"
|
|
|
|
# ==================================================
|
|
# Verify release files
|
|
# ==================================================
|
|
|
|
echo "Checking build results..."
|
|
|
|
if [ ! -s "$RELEASE_DIR/master.db.zst" ]; then
|
|
echo "ERROR: master.db.zst missing or empty" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -s "$RELEASE_DIR/manifest.json" ]; then
|
|
echo "ERROR: Release manifest missing" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ==================================================
|
|
# Show results
|
|
# ==================================================
|
|
|
|
echo "========================================"
|
|
echo "Build completed"
|
|
echo "========================================"
|
|
|
|
ls -lh \
|
|
"$RELEASE_DIR/master.db.zst" \
|
|
"$RELEASE_DIR/manifest.json"
|
|
|
|
find "$RELEASE_DIR" \
|
|
-maxdepth 1 \
|
|
-name 'delta-*.zst' \
|
|
-printf '%f %s bytes\n'
|
|
|
|
echo "SQLite build finished successfully"
|
|
|