name: publish-canvas-image

# Builds and pushes the canvas Docker image to GHCR whenever a commit lands
# on main that touches canvas code. Previously canvas changes were visible in
# CI (npm run build passed) but the live container was never updated —
# operators had to manually run `docker compose build canvas` each time.
#
# Mirror of publish-platform-image.yml, adapted for the Next.js canvas layer.
# See that workflow for inline notes on macOS Keychain isolation and QEMU.

on:
  push:
    branches: [main]
    paths:
      # Only rebuild when canvas source changes — saves GHA minutes on
      # platform-only / docs-only / MCP-only merges.
      - 'canvas/**'
      - '.github/workflows/publish-canvas-image.yml'
  # Manual trigger: use after a non-canvas merge that still needs a fresh
  # image (e.g. a Dockerfile change lives outside the canvas/ tree).
  workflow_dispatch:
    inputs:
      platform_url:
        description: 'NEXT_PUBLIC_PLATFORM_URL baked into the bundle (default: http://localhost:8080)'
        required: false
        default: ''
      ws_url:
        description: 'NEXT_PUBLIC_WS_URL baked into the bundle (default: ws://localhost:8080/ws)'
        required: false
        default: ''

permissions:
  contents: read
  packages: write  # required to push to ghcr.io/${{ github.repository_owner }}/*

env:
  IMAGE_NAME: ghcr.io/molecule-ai/canvas

jobs:
  build-and-push:
    name: Build & push canvas image
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

      - name: Log in to GHCR
        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

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

      - name: Compute tags
        id: tags
        shell: bash
        run: |
          echo "sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"

      - name: Resolve build args
        id: build_args
        # Priority: workflow_dispatch input > repo secret > hardcoded default.
        # NEXT_PUBLIC_* env vars are baked into the JS bundle at build time by
        # Next.js — they cannot be changed at runtime without a full rebuild.
        # For local docker-compose deployments the defaults (localhost:8080)
        # work as-is; production deployments should set CANVAS_PLATFORM_URL
        # and CANVAS_WS_URL as repository secrets.
        #
        # Inputs are passed via env vars (not direct ${{ }} interpolation) to
        # prevent shell injection from workflow_dispatch string inputs.
        shell: bash
        env:
          INPUT_PLATFORM_URL: ${{ github.event.inputs.platform_url }}
          SECRET_PLATFORM_URL: ${{ secrets.CANVAS_PLATFORM_URL }}
          INPUT_WS_URL: ${{ github.event.inputs.ws_url }}
          SECRET_WS_URL: ${{ secrets.CANVAS_WS_URL }}
        run: |
          PLATFORM_URL="${INPUT_PLATFORM_URL:-${SECRET_PLATFORM_URL:-http://localhost:8080}}"
          WS_URL="${INPUT_WS_URL:-${SECRET_WS_URL:-ws://localhost:8080/ws}}"

          echo "platform_url=${PLATFORM_URL}" >> "$GITHUB_OUTPUT"
          echo "ws_url=${WS_URL}" >> "$GITHUB_OUTPUT"

      - name: Build & push canvas image to GHCR
        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
        with:
          context: ./canvas
          file: ./canvas/Dockerfile
          platforms: linux/amd64
          push: true
          build-args: |
            NEXT_PUBLIC_PLATFORM_URL=${{ steps.build_args.outputs.platform_url }}
            NEXT_PUBLIC_WS_URL=${{ steps.build_args.outputs.ws_url }}
          tags: |
            ${{ env.IMAGE_NAME }}:latest
            ${{ env.IMAGE_NAME }}:sha-${{ steps.tags.outputs.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          labels: |
            org.opencontainers.image.source=https://github.com/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.description=Molecule AI canvas (Next.js 15 + React Flow)
