name: Build Pipeline

on:
  workflow_dispatch:
  push:
    branches:
      - main
    paths-ignore:
      - 'docs/**'
      - 'README.md'
      - 'CHANGELOG.md'
      - '.forgejo/ISSUE_TEMPLATE/**'
      - '**/*.md'

concurrency:
  group: build-${{ gitea.workflow }}-${{ gitea.ref }}
  cancel-in-progress: true

permissions:
  contents: read
  actions: read
  packages: write

env:
  GO_VERSION: '1.25.0'
  ZIG_VERSION: '0.15.2'
  RSYNC_VERSION: '3.3.0'
  REGISTRY: ghcr.io
  IMAGE_NAME: fetchml-worker

jobs:
  build-binaries:
    name: Build Binaries
    runs-on: self-hosted
    timeout-minutes: 30
    strategy:
      matrix:
        build_config:
          - name: "native"
            tags: "native_libs"
            cgo_enabled: "1"
            build_native: "true"
          - name: "cgo-only"
            tags: ""
            cgo_enabled: "1"
            build_native: "false"
          - name: "no-cgo"
            tags: ""
            cgo_enabled: "0"
            build_native: "false"
      fail-fast: false

    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 1

    - name: Set up Go
      run: |
        REQUIRED_GO="1.25.0"
        if command -v go &> /dev/null && go version | grep -q "go${REQUIRED_GO}"; then
          echo "Go ${REQUIRED_GO} already installed - skipping download"
        else
          echo "Installing Go ${REQUIRED_GO}..."
          curl -sL "https://go.dev/dl/go${REQUIRED_GO}.linux-amd64.tar.gz" | sudo tar -C /usr/local -xzf -
          export PATH="/usr/local/go/bin:$PATH"
          echo "/usr/local/go/bin" >> $GITHUB_PATH
          echo "Go ${REQUIRED_GO} installed"
        fi
        go version

    - name: Set up Zig
      run: |
        ZIG_VERSION="${{ env.ZIG_VERSION }}"
        if command -v zig &> /dev/null && zig version | grep -q "${ZIG_VERSION}"; then
          echo "Zig ${ZIG_VERSION} already installed - skipping download"
        else
          echo "Installing Zig ${ZIG_VERSION}..."
          ZIG_DIR="/usr/local/zig-${ZIG_VERSION}"
          if [[ "$OSTYPE" == "linux-gnu"* ]]; then
            curl -fsSL --retry 3 "https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" -o /tmp/zig.tar.xz
            sudo mkdir -p "${ZIG_DIR}"
            sudo tar -C "${ZIG_DIR}" --strip-components=1 -xJf /tmp/zig.tar.xz
            sudo ln -sf "${ZIG_DIR}/zig" /usr/local/bin/zig
          elif [[ "$OSTYPE" == "darwin"* ]]; then
            curl -fsSL --retry 3 "https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-macos-${ZIG_VERSION}.tar.xz" -o /tmp/zig.tar.xz
            sudo mkdir -p "${ZIG_DIR}"
            sudo tar -C "${ZIG_DIR}" --strip-components=1 -xJf /tmp/zig.tar.xz
            sudo ln -sf "${ZIG_DIR}/zig" /usr/local/bin/zig
          fi
          rm -f /tmp/zig.tar.xz
          echo "Zig ${ZIG_VERSION} installed"
        fi
        zig version

    - name: Install build dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y podman build-essential autoconf automake libtool pkg-config musl-tools cmake zlib1g-dev

    - name: Build pinned rsync from official source
      run: |
        make -C cli build-rsync RSYNC_VERSION=${{ env.RSYNC_VERSION }}

    - name: Build SQLite for CLI
      run: |
        make -C cli build-sqlite

    - name: Build CLI binary
      run: |
        cd cli && make tiny

    - name: Build Native Libraries
      if: matrix.build_config.build_native == 'true'
      run: |
        echo "Building native C++ libraries..."
        make native-build 2>&1 || {
          echo "Native build failed!"
          exit 1
        }
        echo "Native libraries built successfully"

    - name: Build Go binaries (${{ matrix.build_config.name }})
      run: |
        echo "Building Go binaries with CGO_ENABLED=${{ matrix.build_config.cgo_enabled }}, tags=${{ matrix.build_config.tags }}"
        CGO_ENABLED=${{ matrix.build_config.cgo_enabled }} make build
        # Tag the binaries with the build config name
        mkdir -p "bin/${{ matrix.build_config.name }}"
        cp bin/* "bin/${{ matrix.build_config.name }}/" 2>/dev/null || true

    - name: Test binaries
      run: |
        ./bin/worker --help || true
        ./cli/zig-out/bin/ml --help || true
        ls -lh ./cli/zig-out/bin/ml

    - name: Upload build artifacts
      uses: actions/upload-artifact@v4
      with:
        name: fetch_ml_binaries_${{ matrix.build_config.name }}
        path: |
          bin/
          cli/zig-out/
        retention-days: 30

  build-docker:
    name: Build Docker Images
    runs-on: self-hosted
    needs: build-binaries
    timeout-minutes: 45

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Download build artifacts
      uses: actions/download-artifact@v4
      with:
        name: fetch_ml_binaries_native
        path: bin/

    - name: Set up Docker
      run: |
        # Check Docker is available
        docker --version || {
          echo "Docker not available, using Podman"
          sudo apt-get install -y podman
        }

    - name: Build Docker image
      run: |
        # Build the Docker image
        docker build -f build/docker/simple.Dockerfile -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} .

    - name: Generate image digest
      run: |
        docker inspect --format='{{index .RepoDigests 0}}' ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} > image-digest.txt
        cat image-digest.txt

    - name: Tag images
      run: |
        # Tag with commit SHA
        docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

        # If this is a version tag, tag with version
        if [[ "${{ gitea.ref }}" == refs/tags/v* ]]; then
          VERSION=$(echo "${{ gitea.ref }}" | sed 's/refs\/tags\///')
          docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}
        fi

    - name: Container image scan (trivy)
      run: |
        # Scan the built image for vulnerabilities
        trivy image --exit-code 1 --severity CRITICAL ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} || {
          echo "CRITICAL vulnerabilities found in container image"
          exit 1
        }

    - name: Save image digest artifact
      uses: actions/upload-artifact@v4
      with:
        name: image-digest
        path: image-digest.txt
        retention-days: 30

    # Note: In Forgejo, you may need to configure a local registry or use external push
    # This section is a placeholder for registry push
    - name: Push to registry (optional)
      run: |
        echo "Image built: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }}"
        echo "Note: Registry push requires proper authentication setup in Forgejo"
        # docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }}
        # docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

  sign-hipaa-config:
    name: Sign HIPAA Config
    runs-on: self-hosted
    needs: build-binaries
    timeout-minutes: 10

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Install cosign (if available)
      run: |
        # Try to install cosign for signing
        if command -v cosign &> /dev/null; then
          echo "cosign already installed"
        else
          echo "Installing cosign..."
          curl -sSfL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 | sudo tee /usr/local/bin/cosign > /dev/null
          sudo chmod +x /usr/local/bin/cosign || {
            echo "cosign installation failed - signing will be skipped"
          }
        fi
        cosign version || echo "cosign not available"

    - name: Sign HIPAA config (placeholder)
      run: |
        echo "HIPAA config signing placeholder"
        echo "To enable signing, configure COSIGN_KEY secret"
        
        # Check if signing key is available
        if [ -n "${{ secrets.COSIGN_KEY }}" ]; then
          echo "Signing HIPAA config..."
          # cosign sign-blob \
          #   --key ${{ secrets.COSIGN_KEY }} \
          #   deployments/configs/worker/docker-hipaa.yaml \
          #   > deployments/configs/worker/docker-hipaa.yaml.sig
          echo "Signing would happen here with real cosign key"
        else
          echo "COSIGN_KEY not set - skipping HIPAA config signing"
          # Create a placeholder signature file for now
          echo "UNSIGNED_PLACEHOLDER" > deployments/configs/worker/docker-hipaa.yaml.sig
        fi

    - name: Upload HIPAA config signature
      uses: actions/upload-artifact@v4
      with:
        name: hipaa-config-signature
        path: deployments/configs/worker/docker-hipaa.yaml.sig
        retention-days: 30

  provenance:
    name: Generate SLSA Provenance
    runs-on: self-hosted
    needs: [build-binaries, build-docker]
    timeout-minutes: 15

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Download build artifacts
      uses: actions/download-artifact@v4
      with:
        path: artifacts/

    - name: Generate provenance
      run: |
        echo "Generating SLSA provenance..."
        
        # Create a basic SLSA provenance file
        cat > provenance.json << 'EOF'
        {
          "_type": "https://in-toto.io/Statement/v0.1",
          "predicateType": "https://slsa.dev/provenance/v0.2",
          "subject": [
            {
              "name": "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}",
              "digest": {
                "sha256": "$(cat artifacts/image-digest/image-digest.txt | cut -d':' -f2 || echo 'unknown')"
              }
            }
          ],
          "predicate": {
            "builder": {
              "id": "https://forgejo.example.com/jfraeysd/fetch_ml/.forgejo/workflows/build.yml"
            },
            "buildType": "https://forgejo.example.com/buildType/docker",
            "invocation": {
              "configSource": {
                "uri": "https://forgejo.example.com/jfraeysd/fetch_ml",
                "digest": {
                  "sha1": "${{ gitea.sha }}"
                },
                "entryPoint": ".forgejo/workflows/build.yml"
              },
              "parameters": {},
              "environment": {
                "gitea_actor": "${{ gitea.actor }}",
                "gitea_ref": "${{ gitea.ref }}"
              }
            },
            "metadata": {
              "buildInvocationId": "${{ gitea.run_id }}",
              "buildStartedOn": "$(date -Iseconds)",
              "completeness": {
                "parameters": false,
                "environment": false,
                "materials": false
              }
            },
            "materials": [
              {
                "uri": "https://forgejo.example.com/jfraeysd/fetch_ml",
                "digest": {
                  "sha1": "${{ gitea.sha }}"
                }
              }
            ]
          }
        }
        EOF

        cat provenance.json

    - name: Upload provenance
      uses: actions/upload-artifact@v4
      with:
        name: slsa-provenance
        path: provenance.json
        retention-days: 30
