121 lines
3.7 KiB
Bash
Executable file
121 lines
3.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
source deploy/env.sh
|
|
|
|
AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-$HOME/.config/age/keys.txt}"
|
|
AGE_RECIPIENT="age1hkehkc2rryjl975c2mg5cghmjr54n4wjshncl292h2eg5l394fhs4uydrh"
|
|
|
|
require_cmd() {
|
|
local cmd="$1"
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
echo "Missing required tool: $cmd. Please install it before building." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_docker() {
|
|
if [[ -n "${SKIP_DOCKER_CHECK:-}" ]]; then
|
|
return
|
|
fi
|
|
require_cmd docker
|
|
if ! docker info >/dev/null 2>&1; then
|
|
echo "Docker is installed but the daemon is not reachable. Start Docker Desktop/Engine and try again." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_age_setup() {
|
|
if [[ -n "${SKIP_AGE_CHECK:-}" ]]; then
|
|
return
|
|
fi
|
|
require_cmd sops
|
|
local repo_age_key="$PWD/creds/age-key.txt"
|
|
if [[ ! -f "$AGE_KEY_FILE" ]]; then
|
|
echo "Age key file not found at $AGE_KEY_FILE. Copy creds/age-key.txt or set SOPS_AGE_KEY_FILE." >&2
|
|
exit 1
|
|
fi
|
|
local has_key="0"
|
|
if command -v age-keygen >/dev/null 2>&1; then
|
|
if age-keygen -y "$AGE_KEY_FILE" 2>/dev/null | grep -q "$AGE_RECIPIENT"; then
|
|
has_key="1"
|
|
fi
|
|
else
|
|
# Fallback: best-effort text check for the public key comment
|
|
if grep -q "$AGE_RECIPIENT" "$AGE_KEY_FILE"; then
|
|
has_key="1"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$has_key" != "1" ]]; then
|
|
echo "Age key file at $AGE_KEY_FILE does not contain the expected public key ($AGE_RECIPIENT)." >&2
|
|
if [[ -f "$repo_age_key" ]] && grep -q "$AGE_RECIPIENT" "$repo_age_key"; then
|
|
cat >&2 <<EOF
|
|
Found the repository age key at $repo_age_key.
|
|
Import it with:
|
|
mkdir -p "$(dirname "$AGE_KEY_FILE")"
|
|
cat "$repo_age_key" >> "$AGE_KEY_FILE"
|
|
Or set: SOPS_AGE_KEY_FILE="$repo_age_key"
|
|
EOF
|
|
else
|
|
echo "Ensure your ~/.config/age/keys.txt includes the repo key (see creds/age-key.txt)." >&2
|
|
fi
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
echo "Running pre-flight checks..."
|
|
for tool in git npm; do
|
|
require_cmd "$tool"
|
|
done
|
|
check_docker
|
|
check_age_setup
|
|
|
|
GIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || date +%s)
|
|
BASE_TAG=${BUILD_TAG:-$GIT_SHA}
|
|
|
|
# Optional dev override: set FORCE_DEV_TAG=1 to append a timestamp without committing
|
|
if [[ -n "${FORCE_DEV_TAG:-}" ]]; then
|
|
BASE_TAG="${BASE_TAG}-dev$(date +%s)"
|
|
fi
|
|
|
|
IMAGE_REPO="${REGISTRY}/${REGISTRY_REPO}"
|
|
IMAGE="${IMAGE_REPO}:${BASE_TAG}"
|
|
IMAGE_LATEST="${IMAGE_REPO}:latest"
|
|
|
|
echo "Building image:"
|
|
echo " $IMAGE"
|
|
echo " $IMAGE_LATEST"
|
|
|
|
# npm audit (high severity and above)
|
|
echo "Running npm audit (high)..."
|
|
npm audit --audit-level=high || echo "npm audit reported issues above."
|
|
|
|
# Build
|
|
docker build --build-arg APP_VERSION="$GIT_SHA" -t "$IMAGE" -t "$IMAGE_LATEST" .
|
|
|
|
echo "$IMAGE" > deploy/.last-image
|
|
|
|
echo "Done. Last image: $IMAGE"
|
|
|
|
# Trivy image scan (if available)
|
|
if command -v trivy >/dev/null 2>&1; then
|
|
MIN_TRIVY_VERSION="0.56.0"
|
|
INSTALLED_TRIVY_VERSION="$(trivy --version 2>/dev/null | head -n1 | awk '{print $2}')"
|
|
if [[ -n "$INSTALLED_TRIVY_VERSION" ]] && [[ "$(printf '%s\n%s\n' "$MIN_TRIVY_VERSION" "$INSTALLED_TRIVY_VERSION" | sort -V | head -n1)" != "$MIN_TRIVY_VERSION" ]]; then
|
|
echo "Trivy version $INSTALLED_TRIVY_VERSION is older than recommended $MIN_TRIVY_VERSION."
|
|
echo "Update recommended: brew upgrade trivy # macOS"
|
|
echo "or: sudo apt-get install -y trivy # Debian/Ubuntu (Aqua repo)"
|
|
echo "or: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin"
|
|
fi
|
|
|
|
echo "Running Trivy scan on $IMAGE ..."
|
|
TRIVY_IGNORE_ARGS=()
|
|
if [[ -f ".trivyignore" ]]; then
|
|
TRIVY_IGNORE_ARGS+=(--ignorefile .trivyignore)
|
|
fi
|
|
trivy image --exit-code 0 "${TRIVY_IGNORE_ARGS[@]}" "$IMAGE" || true
|
|
else
|
|
echo "Trivy not installed; skipping image scan."
|
|
fi
|