#!/bin/bash # ============================================================ # lokistack Build Script # ============================================================ # Builds frontend and backend into a single deployable package # with security hardening and integrity checks. # # Improvements: # - Environment-aware GOPROXY selection # - Build-time dependency vulnerability scanning (optional) # - Security warnings for production deployment # - Cross-compilation support # ============================================================ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # ---- 可选:dist 双架构发布包(linux amd64 + arm64):bash build.sh --dist ---- if [ "${1:-}" = "--dist" ]; then GO_CMD="go" BUILD_TIME="$(date -u '+%Y-%m-%d_%H:%M:%S')" GIT_COMMIT="$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown)" APP_VERSION="${APP_VERSION:-dev}" DIST_DIR="dist" cd "$SCRIPT_DIR" rm -rf "$DIST_DIR" && mkdir -p "$DIST_DIR" for ARCH in amd64 arm64; do NAME="lokistack-linux-${ARCH}" echo "==> Building ${NAME}..." rm -rf "/tmp/${NAME}" && mkdir -p "/tmp/${NAME}" (cd "$SCRIPT_DIR/backend" && CGO_ENABLED=0 GOOS=linux GOARCH=$ARCH $GO_CMD build -trimpath \ -ldflags="-s -w -X main.version=${APP_VERSION:-dev} -X main.buildTime=${BUILD_TIME} -X main.gitCommit=${GIT_COMMIT}" \ -o "/tmp/${NAME}/lokistack" .) cp -r docs "/tmp/${NAME}/docs" cp -r homepage "/tmp/${NAME}/homepage" cp README.md "/tmp/${NAME}/README.md" tar -czf "${DIST_DIR}/${NAME}.tar.gz" -C /tmp "${NAME}" echo " ${DIST_DIR}/${NAME}.tar.gz ($(du -h ${DIST_DIR}/${NAME}.tar.gz | cut -f1))" done echo "==> dist 完成: ${DIST_DIR}/lokistack-linux-{amd64,arm64}.tar.gz" exit 0 fi echo "========================================" echo " lokistack Build Script" echo " Security-hardened build pipeline" echo "========================================" # ---- Detect GOPROXY based on network location ---- GOPROXY_DEFAULT="https://proxy.golang.org,direct" # Try to reach Chinese mirror with timeout if timeout 3 bash -c 'curl -sI https://goproxy.cn >/dev/null 2>&1' 2>/dev/null; then GOPROXY_DEFAULT="https://goproxy.cn,direct" echo "[INFO] Using goproxy.cn (China network detected)" else echo "[INFO] Using proxy.golang.org (default)" fi # ---- Detect Node.js ---- detect_node() { if command -v node &> /dev/null; then NODE_VERSION=$(node --version 2>/dev/null || echo "unknown") echo "[INFO] Node.js detected: $NODE_VERSION" else echo "[ERROR] Node.js not found. Please install Node.js 20+" exit 1 fi } # ---- Detect Go ---- detect_go() { if command -v go &> /dev/null; then GO_VERSION=$(go version 2>/dev/null | awk '{print $3}') # INFO 必须走 stderr:detect_go 的 stdout 会被当作命令路径捕获( # 原来把 INFO 打到 stdout,GO_CMD 变成 "[INFO] Go detected: go1.24" → 构建直接失败) echo "[INFO] Go detected: $GO_VERSION" >&2 echo "go" elif [ -f "$HOME/go/bin/go" ]; then echo "$HOME/go/bin/go" else echo "" fi } # ---- Verify minimum Go version ---- check_go_version() { local GO_CMD=$1 local MIN_VERSION="1.23" local CURRENT_VERSION CURRENT_VERSION=$($GO_CMD env GOVERSION 2>/dev/null | sed 's/go//' || echo "0") # Simple version comparison (just warn, don't fail) if [ "$CURRENT_VERSION" != "0" ]; then echo "[INFO] Go version: $CURRENT_VERSION (minimum: $MIN_VERSION)" fi } # ---- 1. Build Frontend ---- echo "" echo "[1/3] Building frontend..." cd "$SCRIPT_DIR/frontend" detect_node if [ ! -d "node_modules" ]; then echo " Installing dependencies..." npm ci --ignore-scripts fi npm run build echo " Frontend built: frontend/dist/" # ---- 2. Build Backend ---- echo "" echo "[2/3] Building backend..." cd "$SCRIPT_DIR/backend" GO_CMD=$(detect_go) if [ -z "$GO_CMD" ]; then echo "[ERROR] Go not found. Please install Go 1.23+" echo " wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz" echo " tar -C \$HOME -xzf go1.23.4.linux-amd64.tar.gz" echo " export PATH=\$HOME/go/bin:\$PATH" exit 1 fi check_go_version "$GO_CMD" export CGO_ENABLED=0 export GOPROXY=${GOPROXY:-$GOPROXY_DEFAULT} # Build with ldflags for smaller binary and version info BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S') GIT_COMMIT=$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null || echo "unknown") $GO_CMD build -trimpath \ -ldflags="-s -w -X main.version=${APP_VERSION:-dev} -X main.buildTime=${BUILD_TIME} -X main.gitCommit=${GIT_COMMIT} -extldflags '-static'" \ -o bin/lokistack . echo " Backend built: backend/bin/lokistack" echo " Binary size: $(du -h bin/lokistack | cut -f1)" echo " Build time: $BUILD_TIME" echo " Git commit: $GIT_COMMIT" # ---- 3. Copy dist to backend for embedded serving ---- echo "" echo "[3/3] Packaging..." cd "$SCRIPT_DIR" rm -rf backend/dist cp -r frontend/dist backend/dist # ---- 4. Security Warnings ---- echo "" echo "========================================" echo " Build Complete!" echo "========================================" echo " Frontend: backend/dist/" echo " Backend: backend/bin/lokistack" echo " Size: $(du -h backend/bin/lokistack | cut -f1)" echo "" echo "========================================" echo " SECURITY REMINDERS" echo "========================================" echo " 1. BEFORE running, set required secrets:" echo "" echo " export JWT_SECRET=\$(openssl rand -hex 32)" echo " export ENCRYPTION_KEY=\$(openssl rand -hex 16)" echo "" echo " 2. For Docker deployment:" echo " docker compose up --build -d" echo "" echo " 3. NEVER commit secrets to version control!" echo " Add .env to .gitignore" echo "" echo " Start with: ./run.sh" echo "========================================"