diff --git a/.github/.env.base b/.github/.env.base index 01d60c2..53fed8b 100644 --- a/.github/.env.base +++ b/.github/.env.base @@ -36,6 +36,11 @@ GO_PRIMARY_VERSION=1.24.x # Set to same as primary to test with single version only GO_SECONDARY_VERSION=1.24.x +# Govulncheck-specific Go version for vulnerability scanning +# Uses newer Go version for accurate standard library vulnerability detection +# Override this in .env.custom if needed for compatibility +GOVULNCHECK_GO_VERSION=1.25.x + # ================================================================================================ # ๐Ÿ“ฆ GO MODULE CONFIGURATION # ================================================================================================ @@ -73,6 +78,7 @@ PREFERRED_GITHUB_TOKEN=GH_PAT_TOKEN # Core Features ENABLE_BENCHMARKS=true # Run benchmark tests +ENABLE_CACHE_WARMING=true # Warm Go module and build caches ENABLE_CODE_COVERAGE=true # Generate coverage reports via go-coverage ENABLE_FUZZ_TESTING=true # Run fuzz tests (Go 1.18+) ENABLE_RACE_DETECTION=true # Enable Go race detector @@ -225,14 +231,15 @@ REDIS_CACHE_FORCE_PULL=false # Force pull Redis images even when cache # ๐Ÿช„ MAGE-X CONFIGURATION # ================================================================================================ -MAGE_X_VERSION=v1.7.6 # https://github.com/mrz1836/mage-x/releases +MAGE_X_VERSION=v1.7.9 # https://github.com/mrz1836/mage-x/releases +MAGE_X_USE_LOCAL=false # Use local version for development MAGE_X_AUTO_DISCOVER_BUILD_TAGS=true # Enable auto-discovery of build tags MAGE_X_AUTO_DISCOVER_BUILD_TAGS_EXCLUDE=race,custom # Comma-separated list of tags to exclude MAGE_X_FORMAT_EXCLUDE_PATHS=vendor,node_modules,.git,.idea # Format exclusion paths (comma-separated directories to exclude from formatting) MAGE_X_GITLEAKS_VERSION=8.28.0 # https://github.com/gitleaks/gitleaks/releases MAGE_X_GOFUMPT_VERSION=v0.9.1 # https://github.com/mvdan/gofumpt/releases MAGE_X_GOLANGCI_LINT_VERSION=v2.5.0 # https://github.com/golangci/golangci-lint/releases -MAGE_X_GORELEASER_VERSION=v2.12.2 # https://github.com/goreleaser/goreleaser/releases +MAGE_X_GORELEASER_VERSION=v2.12.7 # https://github.com/goreleaser/goreleaser/releases MAGE_X_GOVULNCHECK_VERSION=v1.1.4 # https://pkg.go.dev/golang.org/x/vuln MAGE_X_GO_SECONDARY_VERSION=1.24.x # Secondary Go version for MAGE-X (also our secondary) MAGE_X_GO_VERSION=1.24.x # Primary Go version for MAGE-X (also our primary) diff --git a/.github/actions/setup-magex/action.yml b/.github/actions/setup-magex/action.yml index 68f9646..9f002d5 100644 --- a/.github/actions/setup-magex/action.yml +++ b/.github/actions/setup-magex/action.yml @@ -31,6 +31,10 @@ inputs: runner-os: description: "Runner OS for cache key (e.g., ubuntu-latest, windows-latest)" required: true + use-local: + description: "Build from local source instead of downloading release" + required: false + default: 'false' outputs: cache-hit: @@ -48,6 +52,7 @@ runs: # -------------------------------------------------------------------- - name: ๐Ÿ’พ Restore magex binary cache id: magex-cache + if: inputs.use-local != 'true' uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: path: | @@ -55,30 +60,57 @@ runs: key: ${{ inputs.runner-os }}-magex-${{ inputs.magex-version }} # -------------------------------------------------------------------- - # Make cached magex usable by copying to GOPATH/bin and adding to PATH + # Install cached binary to PATH when remote cache hits # -------------------------------------------------------------------- - - name: ๐Ÿ› ๏ธ Make cached magex usable + - name: ๐Ÿ“ฆ Install cached MAGE-X to PATH (remote mode) + if: inputs.use-local != 'true' && steps.magex-cache.outputs.cache-hit == 'true' shell: bash run: | - set -euo pipefail - BIN_DIR="$HOME/.cache/magex-bin" - MAGEX_BIN="$BIN_DIR/magex" - - # If we restored a cache, copy/link it into GOPATH/bin. - if [[ -f "$MAGEX_BIN" ]]; then - echo "โœ… Using cached magex binary" - mkdir -p "$(go env GOPATH)/bin" - cp "$MAGEX_BIN" "$(go env GOPATH)/bin/" - fi + echo "๐Ÿ“ฆ Installing cached MAGE-X binary to PATH..." - # Make sure the binary location is on PATH for *all* subsequent steps. + # Copy cached binary to GOPATH and add to PATH + mkdir -p "$(go env GOPATH)/bin" + cp ~/.cache/magex-bin/magex "$(go env GOPATH)/bin/magex" + chmod +x "$(go env GOPATH)/bin/magex" echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + echo "โœ… Cached MAGE-X binary installed to PATH" + # -------------------------------------------------------------------- - # Detect platform and download MAGE-X binary *only* when the cache was empty. + # Restore local build cache (commit-specific for local builds) # -------------------------------------------------------------------- - - name: โœ… Download MAGE-X binary (cache miss) - if: steps.magex-cache.outputs.cache-hit != 'true' + - name: ๐Ÿ’พ Restore magex binary cache (local) + id: magex-local-cache + if: inputs.use-local == 'true' + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: | + ~/.cache/magex-local + key: ${{ inputs.runner-os }}-local-magex-${{ github.sha }} + # No restore-keys: local builds are commit-specific only to prevent stale cache issues + + # -------------------------------------------------------------------- + # Install cached binary to PATH when local cache hits + # -------------------------------------------------------------------- + - name: ๐Ÿ“ฆ Install cached MAGE-X to PATH (local mode) + if: inputs.use-local == 'true' && steps.magex-local-cache.outputs.cache-hit == 'true' + shell: bash + run: | + echo "๐Ÿ“ฆ Installing cached MAGE-X binary to PATH..." + + # Copy cached binary to GOPATH and add to PATH + mkdir -p "$(go env GOPATH)/bin" + cp ~/.cache/magex-local/magex "$(go env GOPATH)/bin/magex" + chmod +x "$(go env GOPATH)/bin/magex" + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + + echo "โœ… Cached MAGE-X binary installed to PATH" + + # -------------------------------------------------------------------- + # Download MAGE-X binary for remote mode when cache misses + # -------------------------------------------------------------------- + - name: โœ… Download MAGE-X binary (remote mode only) + if: inputs.use-local != 'true' && steps.magex-cache.outputs.cache-hit != 'true' shell: bash run: | echo "โฌ‡๏ธ Cache miss โ€“ downloading MAGE-X binary..." @@ -142,21 +174,60 @@ runs: echo "โœ… Found magex binary at: $MAGEX_BINARY" - # Make it executable and copy to GOPATH/bin + # Make it executable and copy to cache directory chmod +x "$MAGEX_BINARY" - mkdir -p "$(go env GOPATH)/bin" - cp "$MAGEX_BINARY" "$(go env GOPATH)/bin/magex" - - # Copy to cache directory for future runs mkdir -p ~/.cache/magex-bin cp "$MAGEX_BINARY" ~/.cache/magex-bin/magex + # Copy to GOPATH and add to PATH for subsequent steps + mkdir -p "$(go env GOPATH)/bin" + cp ~/.cache/magex-bin/magex "$(go env GOPATH)/bin/magex" + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + # Cleanup cd / rm -rf "$TEMP_DIR" echo "โœ… MAGE-X binary downloaded and cached" + # -------------------------------------------------------------------- + # Build MAGE-X from local source (when use-local is true) + # -------------------------------------------------------------------- + - name: ๐Ÿ”จ Build MAGE-X from local source + id: build-local + if: inputs.use-local == 'true' && steps.magex-local-cache.outputs.cache-hit != 'true' + shell: bash + run: | + echo "๐Ÿ“ฆ Building local development version of MAGE-X" + cd "$GITHUB_WORKSPACE" + + # Check if source directory exists (we're in mage-x repo with full checkout) + if [ ! -d "./cmd/magex" ]; then + echo "โŒ ERROR: ./cmd/magex directory not found" + echo "โŒ use-local=true requires mage-x repository with full checkout" + echo "โŒ Either set use-local=false or ensure full repository checkout" + exit 1 + fi + + # Build from local source + echo "๐Ÿ”จ Building magex from ./cmd/magex..." + go build -v -o /tmp/magex ./cmd/magex + chmod +x /tmp/magex + + # Show version for debugging + /tmp/magex --version || echo "โš ๏ธ Version check skipped" + + # Copy to local cache for future runs + mkdir -p ~/.cache/magex-local + cp /tmp/magex ~/.cache/magex-local/magex + + # Add magex to PATH for subsequent steps + mkdir -p "$(go env GOPATH)/bin" + cp ~/.cache/magex-local/magex "$(go env GOPATH)/bin/magex" + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + + echo "โœ… MAGE-X built from local source and cached" + # -------------------------------------------------------------------- # Verify MAGE-X installation and set outputs # -------------------------------------------------------------------- @@ -167,19 +238,29 @@ runs: echo "๐Ÿ” Verifying MAGE-X installation..." # Test that magex is available and working - if command -v magex >/dev/null 2>&1; then - MAGEX_VERSION=$(magex --version 2>/dev/null | grep -E '^\s+Version:' | awk '{print $2}' || echo "unknown") - echo "โœ… MAGE-X is available: $MAGEX_VERSION" + if ! command -v magex >/dev/null 2>&1; then + echo "โŒ ERROR: MAGE-X is not available in PATH" >&2 + exit 1 + fi - # Determine installation method - if [[ "${{ steps.magex-cache.outputs.cache-hit }}" == "true" ]]; then + MAGEX_VERSION=$(magex --version 2>/dev/null | grep -E '^\s+Version:' | awk '{print $2}' || echo "unknown") + echo "โœ… MAGE-X $MAGEX_VERSION is available" + + # Determine installation method based on mode and cache status + if [[ "${{ inputs.use-local }}" == "true" ]]; then + if [[ "${{ steps.magex-local-cache.outputs.cache-hit }}" == "true" ]]; then echo "method=cached" >> $GITHUB_OUTPUT - echo "๐Ÿ“‹ Installation method: Restored from cache" + echo "๐Ÿ“‹ Installation method: Cached (local build)" else - echo "method=fresh" >> $GITHUB_OUTPUT - echo "๐Ÿ“‹ Installation method: Fresh binary download" + echo "method=fresh-build" >> $GITHUB_OUTPUT + echo "๐Ÿ“‹ Installation method: Fresh build from source" fi else - echo "โŒ ERROR: MAGE-X is not available in PATH" >&2 - exit 1 + if [[ "${{ steps.magex-cache.outputs.cache-hit }}" == "true" ]]; then + echo "method=cached" >> $GITHUB_OUTPUT + echo "๐Ÿ“‹ Installation method: Cached (remote download)" + else + echo "method=fresh-download" >> $GITHUB_OUTPUT + echo "๐Ÿ“‹ Installation method: Fresh download from releases" + fi fi diff --git a/.github/actions/warm-cache/action.yml b/.github/actions/warm-cache/action.yml index 2331e0c..3ffe7c3 100644 --- a/.github/actions/warm-cache/action.yml +++ b/.github/actions/warm-cache/action.yml @@ -223,14 +223,14 @@ runs: if [ -n "$GO_MODULE_DIR" ]; then echo "๐Ÿ”ง Running build commands from directory: $GO_MODULE_DIR" # Use configured parallelism to avoid OOM on GitHub Actions runners - (cd "$GO_MODULE_DIR" && magex build:prebuild p="$PARALLEL_JOBS" strategy=smart) + (cd "$GO_MODULE_DIR" && magex build:prebuild p="$PARALLEL_JOBS" strategy="${MAGE_X_BUILD_STRATEGY:-smart}" batch_size="${MAGE_X_BUILD_BATCH_SIZE:-20}" batch_delay="${MAGE_X_BUILD_BATCH_DELAY_MS:-0}" exclude="${MAGE_X_BUILD_EXCLUDE_PATTERN:-}") echo "๐Ÿ—๏ธ Building stdlib for host platform..." (cd "$GO_MODULE_DIR" && magex install:stdlib) else echo "๐Ÿ”ง Running build commands from repository root" # Use configured parallelism to avoid OOM on GitHub Actions runners - magex build:prebuild p="$PARALLEL_JOBS" strategy=smart + magex build:prebuild p="$PARALLEL_JOBS" strategy="${MAGE_X_BUILD_STRATEGY:-smart}" batch_size="${MAGE_X_BUILD_BATCH_SIZE:-20}" batch_delay="${MAGE_X_BUILD_BATCH_DELAY_MS:-0}" exclude="${MAGE_X_BUILD_EXCLUDE_PATTERN:-}" echo "๐Ÿ—๏ธ Building stdlib for host platform..." magex install:stdlib diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b7a4441..97724b4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/init@5fe9434cd24fe243e33e7f3305f8a5b519b70280 # v4.31.1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -58,7 +58,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/autobuild@5fe9434cd24fe243e33e7f3305f8a5b519b70280 # v4.31.1 # โ„น๏ธ Command-line programs to run using the OS shell. # ๐Ÿ“š https://git.io/JvXDl @@ -68,4 +68,4 @@ jobs: # uses a compiled language - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/analyze@5fe9434cd24fe243e33e7f3305f8a5b519b70280 # v4.31.1 diff --git a/.github/workflows/fortress-benchmarks.yml b/.github/workflows/fortress-benchmarks.yml index 175540d..cfdaf0a 100644 --- a/.github/workflows/fortress-benchmarks.yml +++ b/.github/workflows/fortress-benchmarks.yml @@ -159,6 +159,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ matrix.os }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Setup Redis service using composite action with caching diff --git a/.github/workflows/fortress-code-quality.yml b/.github/workflows/fortress-code-quality.yml index 3669bff..2b18ef9 100644 --- a/.github/workflows/fortress-code-quality.yml +++ b/.github/workflows/fortress-code-quality.yml @@ -109,6 +109,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Run go vet with sequential execution to avoid memory issues @@ -231,16 +232,6 @@ jobs: echo "GOMODCACHE=$HOME/go/pkg/mod" >> $GITHUB_ENV echo "GOLANGCI_LINT_CACHE=$HOME/.cache/golangci-lint" >> $GITHUB_ENV - # -------------------------------------------------------------------- - # Extract golangci-lint version (MAGE-X managed) - # -------------------------------------------------------------------- - - name: ๐Ÿ” Use MAGE-X managed golangci-lint version - id: golangci-lint-version - run: | - # MAGE-X handles golangci-lint version automatically - echo "โœ… Using MAGE-X managed golangci-lint version" - echo "version=${{ env.MAGE_X_GOLANGCI_LINT_VERSION }}" >> $GITHUB_OUTPUT - # -------------------------------------------------------------------- # Setup Go with caching and version management # -------------------------------------------------------------------- @@ -270,6 +261,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Restore Cache golangci-lint @@ -279,7 +271,7 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.GOLANGCI_LINT_CACHE }} - key: ${{ inputs.primary-runner }}-golangci-lint-analysis-${{ hashFiles('.golangci.json', env.GO_SUM_FILE) }}-${{ steps.golangci-lint-version.outputs.version }} + key: ${{ inputs.primary-runner }}-golangci-lint-analysis-${{ hashFiles('.golangci.json', env.GO_SUM_FILE) }} - name: ๐Ÿ” Debug cache usage run: | @@ -409,6 +401,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Get yamlfmt version from MAGE-X diff --git a/.github/workflows/fortress-release.yml b/.github/workflows/fortress-release.yml index 80ef1d7..0f98a46 100644 --- a/.github/workflows/fortress-release.yml +++ b/.github/workflows/fortress-release.yml @@ -138,6 +138,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Extract GoReleaser version from environment diff --git a/.github/workflows/fortress-security-scans.yml b/.github/workflows/fortress-security-scans.yml index 6f7b5c3..afb2ec2 100644 --- a/.github/workflows/fortress-security-scans.yml +++ b/.github/workflows/fortress-security-scans.yml @@ -204,12 +204,14 @@ jobs: # -------------------------------------------------------------------- # Setup Go with caching and version management + # Uses GOVULNCHECK_GO_VERSION if set, otherwise falls back to primary version + # This allows govulncheck to use a newer Go version for accurate stdlib vulnerability detection # -------------------------------------------------------------------- - name: ๐Ÿ—๏ธ Setup Go with Cache id: setup-govulncheck uses: ./.github/actions/setup-go-with-cache with: - go-version: ${{ inputs.go-primary-version }} + go-version: ${{ env.GOVULNCHECK_GO_VERSION || inputs.go-primary-version }} matrix-os: ${{ inputs.primary-runner }} go-primary-version: ${{ inputs.go-primary-version }} go-secondary-version: ${{ inputs.go-primary-version }} @@ -231,6 +233,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Restore (and later save) a compact cache for the govulncheck binary diff --git a/.github/workflows/fortress-setup-config.yml b/.github/workflows/fortress-setup-config.yml index 156b656..8423089 100644 --- a/.github/workflows/fortress-setup-config.yml +++ b/.github/workflows/fortress-setup-config.yml @@ -62,6 +62,9 @@ on: coverage-provider: description: "Coverage service provider (internal or codecov)" value: ${{ jobs.setup-config.outputs.coverage-provider }} + cache-warming-enabled: + description: "Whether cache warming is enabled" + value: ${{ jobs.setup-config.outputs.cache-warming-enabled }} fuzz-testing-enabled: description: "Whether fuzz testing is enabled" value: ${{ jobs.setup-config.outputs.fuzz-testing-enabled }} @@ -179,6 +182,7 @@ jobs: benchmark-matrix: ${{ steps.matrix.outputs.matrix }} code-coverage-enabled: ${{ steps.config.outputs.code-coverage-enabled }} coverage-provider: ${{ steps.config.outputs.coverage-provider }} + cache-warming-enabled: ${{ steps.config.outputs.cache-warming-enabled }} fuzz-testing-enabled: ${{ steps.config.outputs.fuzz-testing-enabled }} go-primary-version: ${{ steps.config.outputs.go-primary-version }} go-secondary-version: ${{ steps.config.outputs.go-secondary-version }} @@ -421,6 +425,7 @@ jobs: # Feature flags echo "benchmarks-enabled=${{ env.ENABLE_BENCHMARKS }}" >> $GITHUB_OUTPUT + echo "cache-warming-enabled=${{ env.ENABLE_CACHE_WARMING }}" >> $GITHUB_OUTPUT echo "code-coverage-enabled=${{ env.ENABLE_CODE_COVERAGE }}" >> $GITHUB_OUTPUT echo "coverage-provider=${{ env.GO_COVERAGE_PROVIDER }}" >> $GITHUB_OUTPUT @@ -592,6 +597,7 @@ jobs: echo "| Feature | Status | Impact |" >> $GITHUB_STEP_SUMMARY echo "|---------|--------|--------|" >> $GITHUB_STEP_SUMMARY echo "| **Benchmarks** | $([ "${{ env.ENABLE_BENCHMARKS }}" == "true" ] && echo "โœ… Enabled" || echo "โŒ Disabled") | Performance benchmarks will $([ "${{ env.ENABLE_BENCHMARKS }}" == "true" ] && echo "run in **${{ env.BENCHMARK_MODE }}** mode" || echo "be skipped") |" >> $GITHUB_STEP_SUMMARY + echo "| **Cache Warming** | $([ "${{ env.ENABLE_CACHE_WARMING }}" == "true" ] && echo "โœ… Enabled" || echo "โŒ Disabled") | Go module and build caches will $([ "${{ env.ENABLE_CACHE_WARMING }}" == "true" ] && echo "be pre-warmed for faster test execution" || echo "not be pre-warmed (saves memory)") |" >> $GITHUB_STEP_SUMMARY echo "| **Code Coverage** | $([ "${{ env.ENABLE_CODE_COVERAGE }}" == "true" ] && echo "โœ… Enabled" || echo "โŒ Disabled") | Coverage will $([ "${{ env.ENABLE_CODE_COVERAGE }}" == "true" ] && echo "use $([ "${{ env.GO_COVERAGE_PROVIDER }}" == "codecov" ] && echo "**Codecov**" || echo "**go-coverage**") (${{ env.GO_COVERAGE_THRESHOLD }}% threshold)" || echo "be skipped") |" >> $GITHUB_STEP_SUMMARY echo "| **Fuzz Testing** | $([ "${{ env.ENABLE_FUZZ_TESTING }}" == "true" ] && echo "โœ… Enabled" || echo "โŒ Disabled") | Fuzz tests will $([ "${{ env.ENABLE_FUZZ_TESTING }}" == "true" ] && echo "run in parallel job on Linux with primary Go version" || echo "be skipped") |" >> $GITHUB_STEP_SUMMARY echo "| **Gitleaks (Secret Scan)** | $([ "${{ env.ENABLE_SECURITY_SCAN_GITLEAKS }}" == "true" ] && echo "โœ… Enabled" || echo "โŒ Disabled") | Gitleaks will $([ "${{ env.ENABLE_SECURITY_SCAN_GITLEAKS }}" == "true" ] && echo "scan for leaked secrets" || echo "be skipped") |" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/fortress-test-fuzz.yml b/.github/workflows/fortress-test-fuzz.yml index 13b6569..01319a6 100644 --- a/.github/workflows/fortress-test-fuzz.yml +++ b/.github/workflows/fortress-test-fuzz.yml @@ -105,6 +105,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Start fuzz test timer diff --git a/.github/workflows/fortress-test-magex.yml b/.github/workflows/fortress-test-magex.yml index 63c0148..99330d2 100644 --- a/.github/workflows/fortress-test-magex.yml +++ b/.github/workflows/fortress-test-magex.yml @@ -47,9 +47,18 @@ jobs: done # -------------------------------------------------------------------- - # Checkout code (sparse checkout) + # Checkout code (conditional: full or sparse based on MAGE_X_USE_LOCAL) # -------------------------------------------------------------------- - - name: ๐Ÿ“ฅ Checkout (sparse) + # Full checkout when using local build (needs cmd/magex directory) + - name: ๐Ÿ“ฅ Checkout (full - local build) + if: env.MAGE_X_USE_LOCAL == 'true' + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + + # Sparse checkout when using remote build (optimization) + - name: ๐Ÿ“ฅ Checkout (sparse - remote build) + if: env.MAGE_X_USE_LOCAL == 'false' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 # Required for sparse checkout @@ -69,6 +78,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ inputs.primary-runner }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Validate MAGE-X version matches requested version @@ -81,29 +91,46 @@ jobs: # Get the actual version from the binary ACTUAL_VERSION=$(magex --version 2>/dev/null | grep -E '^\s+Version:' | awk '{print $2}' || echo "unknown") REQUESTED_VERSION="${{ env.MAGE_X_VERSION }}" + USE_LOCAL="${{ env.MAGE_X_USE_LOCAL }}" + echo "๐Ÿ“‹ Build mode: $([ "$USE_LOCAL" == "true" ] && echo "local (development)" || echo "remote (release)")" echo "๐Ÿ“‹ Requested version: $REQUESTED_VERSION" echo "๐Ÿ“‹ Actual version: $ACTUAL_VERSION" - # Strip 'v' prefix from both versions for comparison - REQUESTED_CLEAN=$(echo "$REQUESTED_VERSION" | sed 's/^v//') - ACTUAL_CLEAN=$(echo "$ACTUAL_VERSION" | sed 's/^v//') - if [[ "$ACTUAL_VERSION" == "unknown" ]]; then echo "โŒ Failed: Could not determine magex version from binary" echo "โŒ This indicates a problem with version detection or binary corruption" echo "validation-result=failed" >> $GITHUB_OUTPUT exit 1 - elif [[ "$ACTUAL_CLEAN" == "$REQUESTED_CLEAN" ]]; then - echo "โœ… Version validation passed: $ACTUAL_VERSION matches $REQUESTED_VERSION" - echo "validation-result=success" >> $GITHUB_OUTPUT + fi + + # Local builds should have "dev" version + if [[ "$USE_LOCAL" == "true" ]]; then + if [[ "$ACTUAL_VERSION" == "dev" ]]; then + echo "โœ… Version validation passed: local build has expected 'dev' version" + echo "validation-result=success" >> $GITHUB_OUTPUT + else + echo "โš ๏ธ Warning: Local build has version '$ACTUAL_VERSION', expected 'dev'" + echo "โš ๏ธ This might indicate the version file hasn't been updated" + echo "โœ… Accepting anyway since this is a local development build" + echo "validation-result=success-with-warning" >> $GITHUB_OUTPUT + fi else - echo "โŒ Version mismatch detected!" - echo "โŒ Requested: $REQUESTED_VERSION (clean: $REQUESTED_CLEAN)" - echo "โŒ Actual: $ACTUAL_VERSION (clean: $ACTUAL_CLEAN)" - echo "โŒ This indicates a cache corruption or installation failure" - echo "validation-result=failed" >> $GITHUB_OUTPUT - exit 1 + # Remote builds should match the requested version + REQUESTED_CLEAN=$(echo "$REQUESTED_VERSION" | sed 's/^v//') + ACTUAL_CLEAN=$(echo "$ACTUAL_VERSION" | sed 's/^v//') + + if [[ "$ACTUAL_CLEAN" == "$REQUESTED_CLEAN" ]]; then + echo "โœ… Version validation passed: $ACTUAL_VERSION matches $REQUESTED_VERSION" + echo "validation-result=success" >> $GITHUB_OUTPUT + else + echo "โŒ Version mismatch detected!" + echo "โŒ Requested: $REQUESTED_VERSION (clean: $REQUESTED_CLEAN)" + echo "โŒ Actual: $ACTUAL_VERSION (clean: $ACTUAL_CLEAN)" + echo "โŒ This indicates a cache corruption or installation failure" + echo "validation-result=failed" >> $GITHUB_OUTPUT + exit 1 + fi fi # -------------------------------------------------------------------- diff --git a/.github/workflows/fortress-test-matrix.yml b/.github/workflows/fortress-test-matrix.yml index 7249c86..d72efaf 100644 --- a/.github/workflows/fortress-test-matrix.yml +++ b/.github/workflows/fortress-test-matrix.yml @@ -164,6 +164,7 @@ jobs: with: magex-version: ${{ env.MAGE_X_VERSION }} runner-os: ${{ matrix.os }} + use-local: ${{ env.MAGE_X_USE_LOCAL }} # -------------------------------------------------------------------- # Start test timer diff --git a/.github/workflows/fortress-warm-cache.yml b/.github/workflows/fortress-warm-cache.yml new file mode 100644 index 0000000..902517b --- /dev/null +++ b/.github/workflows/fortress-warm-cache.yml @@ -0,0 +1,118 @@ +# ------------------------------------------------------------------------------------ +# Cache Warming (Reusable Workflow) (GoFortress) +# +# Purpose: Warm Go module and Redis caches across multiple Go versions and operating +# systems to optimize subsequent workflow performance. +# +# Maintainer: @mrz1836 +# +# ------------------------------------------------------------------------------------ + +name: GoFortress (Cache Warming) + +on: + workflow_call: + inputs: + env-json: + description: "JSON string of environment variables" + required: true + type: string + warm-cache-matrix: + description: "Cache warming matrix JSON" + required: true + type: string + go-primary-version: + description: "Primary Go version" + required: true + type: string + go-secondary-version: + description: "Secondary Go version" + required: true + type: string + redis-enabled: + description: "Whether Redis service is enabled" + required: false + type: string + default: "false" + redis-version: + description: "Redis Docker image version" + required: false + type: string + default: "7-alpine" + redis-cache-force-pull: + description: "Force pull Redis image instead of using cache" + required: false + type: string + default: "false" + go-sum-file: + description: "Path to go.sum file for dependency verification" + required: true + type: string + +# Security: Restrictive default permissions with job-level overrides for least privilege access +permissions: + contents: read + +jobs: + # ---------------------------------------------------------------------------------- + # Warm Cache Matrix (Parallel) + # ---------------------------------------------------------------------------------- + warm-cache-matrix: + name: ๐Ÿ’พ Warm Cache (${{ matrix.name }}) + strategy: + fail-fast: true + matrix: ${{ fromJSON(inputs.warm-cache-matrix) }} + runs-on: ${{ matrix.os }} + steps: + # -------------------------------------------------------------------- + # Parse environment variables + # -------------------------------------------------------------------- + - name: ๐Ÿ”ง Parse environment variables + env: + ENV_JSON: ${{ inputs.env-json }} + run: | + echo "๐Ÿ“‹ Setting environment variables..." + echo "$ENV_JSON" | jq -r 'to_entries | .[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do + echo "$key=$value" >> $GITHUB_ENV + done + + # -------------------------------------------------------------------- + # Checkout code to access local action + # -------------------------------------------------------------------- + - name: ๐Ÿ“ฅ Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + sparse-checkout: | + .github/actions/warm-cache + .github/actions/warm-redis-cache + .github/actions/cache-redis-image + .github/.env.base + go.mod + ${{ env.GO_SUM_FILE }} + .mage.yaml + + # -------------------------------------------------------------------- + # Extract verbose flag from env-json + # -------------------------------------------------------------------- + - name: ๐Ÿ” Extract ENABLE_VERBOSE + id: extract + run: | + echo "enable_verbose=$(echo '${{ inputs.env-json }}' | jq -r '.ENABLE_VERBOSE_TEST_OUTPUT')" >> "$GITHUB_OUTPUT" + + # -------------------------------------------------------------------- + # Warm the Go and Redis caches using local action + # -------------------------------------------------------------------- + - name: ๐Ÿ”ฅ Warm Go and Redis Caches + uses: ./.github/actions/warm-cache + with: + go-version: ${{ matrix.go-version }} + matrix-os: ${{ matrix.os }} + matrix-name: ${{ matrix.name }} + enable-verbose: ${{ steps.extract.outputs.enable_verbose }} + go-primary-version: ${{ inputs.go-primary-version }} + go-secondary-version: ${{ inputs.go-secondary-version }} + env-json: ${{ inputs.env-json }} + redis-enabled: ${{ inputs.redis-enabled }} + redis-versions: ${{ inputs.redis-version }} + redis-cache-force-pull: ${{ inputs.redis-cache-force-pull }} + go-sum-file: ${{ inputs.go-sum-file }} diff --git a/.github/workflows/fortress.yml b/.github/workflows/fortress.yml index bbcfc2c..54b1b84 100644 --- a/.github/workflows/fortress.yml +++ b/.github/workflows/fortress.yml @@ -126,74 +126,32 @@ jobs: # Warm Go Caches # ---------------------------------------------------------------------------------- warm-cache: - name: ๐Ÿ’พ Warm Cache (${{ matrix.name }}) + name: ๐Ÿ’พ Warm Cache needs: [load-env, setup, test-magex] + if: needs.setup.outputs.cache-warming-enabled == 'true' permissions: contents: read # Read repository content for cache warming - strategy: - fail-fast: true - matrix: ${{ fromJSON(needs.setup.outputs.warm-cache-matrix) }} - runs-on: ${{ matrix.os }} - steps: - # -------------------------------------------------------------------- - # Parse environment variables - # -------------------------------------------------------------------- - - name: ๐Ÿ”ง Parse environment variables - env: - ENV_JSON: ${{ needs.load-env.outputs.env-json }} - run: | - echo "๐Ÿ“‹ Setting environment variables..." - echo "$ENV_JSON" | jq -r 'to_entries | .[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do - echo "$key=$value" >> $GITHUB_ENV - done - - # -------------------------------------------------------------------- - # Checkout code to access local action - # -------------------------------------------------------------------- - - name: ๐Ÿ“ฅ Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - sparse-checkout: | - .github/actions/warm-cache - .github/actions/warm-redis-cache - .github/actions/cache-redis-image - .github/.env.base - go.mod - ${{ env.GO_SUM_FILE }} - .mage.yaml - - # -------------------------------------------------------------------- - # Extract verbose flag from env-json - # -------------------------------------------------------------------- - - name: ๐Ÿ” Extract ENABLE_VERBOSE - id: extract - run: | - echo "enable_verbose=$(echo '${{ needs.load-env.outputs.env-json }}' | jq -r '.ENABLE_VERBOSE_TEST_OUTPUT')" >> "$GITHUB_OUTPUT" - - # -------------------------------------------------------------------- - # Warm the Go and Redis caches using local action - # -------------------------------------------------------------------- - - name: ๐Ÿ”ฅ Warm Go and Redis Caches - uses: ./.github/actions/warm-cache # Might not resolve as it's a composite action - with: - go-version: ${{ matrix.go-version }} - matrix-os: ${{ matrix.os }} - matrix-name: ${{ matrix.name }} - enable-verbose: ${{ steps.extract.outputs.enable_verbose }} - go-primary-version: ${{ needs.setup.outputs.go-primary-version }} - go-secondary-version: ${{ needs.setup.outputs.go-secondary-version }} - env-json: ${{ needs.load-env.outputs.env-json }} - redis-enabled: ${{ needs.setup.outputs.redis-enabled }} - redis-versions: ${{ needs.setup.outputs.redis-version }} - redis-cache-force-pull: ${{ needs.setup.outputs.redis-cache-force-pull }} - go-sum-file: ${{ needs.setup.outputs.go-sum-file }} + uses: ./.github/workflows/fortress-warm-cache.yml + with: + env-json: ${{ needs.load-env.outputs.env-json }} + warm-cache-matrix: ${{ needs.setup.outputs.warm-cache-matrix }} + go-primary-version: ${{ needs.setup.outputs.go-primary-version }} + go-secondary-version: ${{ needs.setup.outputs.go-secondary-version }} + redis-enabled: ${{ needs.setup.outputs.redis-enabled }} + redis-version: ${{ needs.setup.outputs.redis-version }} + redis-cache-force-pull: ${{ needs.setup.outputs.redis-cache-force-pull }} + go-sum-file: ${{ needs.setup.outputs.go-sum-file }} # ---------------------------------------------------------------------------------- # Security Scans # ---------------------------------------------------------------------------------- security: name: ๐Ÿ”’ Security Scans - needs: [load-env, setup, warm-cache, test-magex] - if: needs.setup.outputs.security-scans-enabled == 'true' + needs: [load-env, setup, test-magex, warm-cache] + if: | + !cancelled() && + needs.warm-cache.result != 'failure' && + needs.warm-cache.result != 'cancelled' && + needs.setup.outputs.security-scans-enabled == 'true' permissions: contents: read # Read repository content for security scanning uses: ./.github/workflows/fortress-security-scans.yml @@ -215,7 +173,11 @@ jobs: # ---------------------------------------------------------------------------------- code-quality: name: ๐Ÿ“Š Code Quality - needs: [load-env, setup, warm-cache, test-magex] + needs: [load-env, setup, test-magex, warm-cache] + if: | + !cancelled() && + needs.warm-cache.result != 'failure' && + needs.warm-cache.result != 'cancelled' permissions: contents: read # Read repository content for code quality checks uses: ./.github/workflows/fortress-code-quality.yml @@ -234,8 +196,12 @@ jobs: # ---------------------------------------------------------------------------------- pre-commit: name: ๐Ÿช Pre-commit Checks - needs: [load-env, setup, warm-cache, test-magex] - if: needs.setup.outputs.pre-commit-enabled == 'true' + needs: [load-env, setup, test-magex, warm-cache] + if: | + !cancelled() && + needs.warm-cache.result != 'failure' && + needs.warm-cache.result != 'cancelled' && + needs.setup.outputs.pre-commit-enabled == 'true' permissions: contents: read # Read repository content for pre-commit checks uses: ./.github/workflows/fortress-pre-commit.yml @@ -250,7 +216,11 @@ jobs: # ---------------------------------------------------------------------------------- test-suite: name: ๐Ÿงช Test Suite - needs: [load-env, setup, warm-cache, test-magex] + needs: [load-env, setup, test-magex, warm-cache] + if: | + !cancelled() && + needs.warm-cache.result != 'failure' && + needs.warm-cache.result != 'cancelled' permissions: contents: write # Write repository content and push to gh-pages branch for test execution pull-requests: write # Required: Coverage workflow needs to create PR comments @@ -286,8 +256,12 @@ jobs: # ---------------------------------------------------------------------------------- benchmarks: name: ๐Ÿƒ Benchmarks - needs: [load-env, setup, warm-cache, test-magex] - if: needs.setup.outputs.benchmarks-enabled == 'true' + needs: [load-env, setup, test-magex, warm-cache] + if: | + !cancelled() && + needs.warm-cache.result != 'failure' && + needs.warm-cache.result != 'cancelled' && + needs.setup.outputs.benchmarks-enabled == 'true' permissions: contents: read # Read repository content for benchmarking uses: ./.github/workflows/fortress-benchmarks.yml @@ -315,7 +289,7 @@ jobs: status-check: name: ๐ŸŽฏ All Tests Passed if: ${{ always() }} - needs: [setup, test-magex, security, code-quality, pre-commit, test-suite, benchmarks] + needs: [setup, test-magex, warm-cache, security, code-quality, pre-commit, test-suite, benchmarks] permissions: contents: read # Read repository content for status checking runs-on: ${{ needs.setup.outputs.primary-runner }} @@ -332,6 +306,7 @@ jobs: echo "|-----------|--------|--------|" echo "| ๐ŸŽฏ Setup | ${{ needs.setup.result }} | Required |" echo "| ๐Ÿช„ MAGE-X | ${{ needs.test-magex.result }} | Required |" + echo "| ๐Ÿ’พ Warm Cache | ${{ needs.warm-cache.result }} | ${{ needs.setup.outputs.cache-warming-enabled == 'true' && 'Optional' || 'Skipped' }} |" echo "| ๐Ÿ”’ Security | ${{ needs.security.result }} | Required |" echo "| ๐Ÿ“Š Code Quality | ${{ needs.code-quality.result }} | Required |" echo "| ๐Ÿช Pre-commit | ${{ needs.pre-commit.result }} | ${{ needs.setup.outputs.pre-commit-enabled == 'true' && 'Required' || 'Skipped' }} |" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a7b6c45..7aec89c 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -12,7 +12,7 @@ on: schedule: - cron: "0 8 * * 1" # Every Monday at 08:00 UTC push: - branches: ["master","main"] + branches: ["master", "main"] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -78,6 +78,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable the upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/upload-sarif@5fe9434cd24fe243e33e7f3305f8a5b519b70280 # v4.31.1 with: sarif_file: results.sarif diff --git a/codecov.yml b/codecov.yml index 7de2c61..2fd4ea6 100644 --- a/codecov.yml +++ b/codecov.yml @@ -31,6 +31,7 @@ ignore: - ".mage-cache/**" - ".vscode/**" - "bin/**" + - "example/**" - "examples/**" - "mocks/**" - "testing/**"