name: Docker Build

# Build and test Docker images on pushes to main and pull requests.
# Note: Release tags (robust-mcp-server-v*) trigger mcp-server-release.yaml
# which handles Docker Hub releases. This workflow is for CI testing only.
on:
  push:
    branches: [main, master]
    paths:
      - "Dockerfile"
      - ".dockerignore"
      - "src/**/*.py"
      - "pyproject.toml"
      - ".github/workflows/docker.yaml"
  pull_request:
    branches: [main, master]
    paths:
      - "Dockerfile"
      - ".dockerignore"
      - "src/**/*.py"
      - "pyproject.toml"
      - ".github/workflows/docker.yaml"
  workflow_dispatch:
  workflow_call:

# Cancel in-progress runs for the same branch
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: freecad-robust-mcp

jobs:
  build:
    name: Build Docker Image
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

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

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix=sha-

      - name: Get version for setuptools-scm
        id: version
        run: |
          # Get version from git describe (matches setuptools-scm behavior)
          # For tagged releases: v1.0.0 -> 1.0.0
          # For dev builds: v1.0.0-5-g1234567 -> 1.0.0.dev5+g1234567
          if git describe --tags --exact-match 2>/dev/null; then
            TAG=$(git describe --tags --exact-match)
            VERSION="${TAG#v}"
          else
            # Get the latest tag or use 0.0.0 if none exists
            LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
            BASE_VERSION="${LATEST_TAG#v}"
            # Count commits since tag
            COMMITS=$(git rev-list "${LATEST_TAG}..HEAD" --count 2>/dev/null || echo "0")
            SHORT_SHA=$(git rev-parse --short HEAD)
            VERSION="${BASE_VERSION}.dev${COMMITS}+g${SHORT_SHA}"
          fi
          echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
          echo "Detected version: $VERSION"

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            VERSION=${{ steps.version.outputs.VERSION }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Test Docker image
        run: |
          # Build for current platform only for testing
          docker build --build-arg VERSION=${{ steps.version.outputs.VERSION }} -t ${{ env.IMAGE_NAME }}:test .

          # Test that the container starts and responds to MCP initialize
          echo '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | \
            timeout 30 docker run --rm -i \
              -e FREECAD_MODE=xmlrpc \
              ${{ env.IMAGE_NAME }}:test 2>&1 | \
            grep -q '"result"' && echo "Container test passed" || echo "Container test completed"

      - name: Cache Trivy vulnerability database
        uses: actions/cache@v4
        with:
          path: .trivy-cache
          # Cache key based on OS and workflow file hash; refreshes when workflow changes
          key: trivy-db-${{ runner.os }}-${{ hashFiles('.github/workflows/docker.yaml') }}
          restore-keys: |
            trivy-db-${{ runner.os }}-

      - name: Scan for HIGH/CRITICAL vulnerabilities (fail build)
        uses: aquasecurity/trivy-action@0.33.1
        with:
          image-ref: ${{ env.IMAGE_NAME }}:test
          severity: "HIGH,CRITICAL"
          exit-code: "1"
          format: "table"
          cache-dir: .trivy-cache

      - name: Scan for MEDIUM/LOW vulnerabilities (warning only)
        uses: aquasecurity/trivy-action@0.33.1
        with:
          image-ref: ${{ env.IMAGE_NAME }}:test
          severity: "MEDIUM,LOW"
          exit-code: "0"
          format: "table"
          cache-dir: .trivy-cache
        continue-on-error: true

      - name: Generate SARIF report for GitHub Security
        if: github.event_name != 'pull_request'
        uses: aquasecurity/trivy-action@0.33.1
        with:
          image-ref: ${{ env.IMAGE_NAME }}:test
          format: "sarif"
          output: "trivy-results.sarif"
          cache-dir: .trivy-cache
        continue-on-error: true

      - name: Upload Trivy scan results
        if: github.event_name != 'pull_request'
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: "trivy-results.sarif"
        continue-on-error: true
