name: Publish Linux VM guest agents + kernel

# Builds and distributes the Nucleic **Linux VM** guest artifacts (docs/LINUX_VM.md,
# docs/LINUX_VM_SEMANTIC_AGENT.md) — the pieces the macOS-host base build bakes into the guest image:
#
#   • nucleic-linux-agent   — static-C control agent (vsock 2035: ping/exec)
#   • nucleic-a11y-agent    — Rust AT-SPI semantic agent (vsock 2036: ax_*)
#   • pre-unwrapped kernel  — the Ubuntu arm64 kernel unwrapped from EFI-zboot to a raw Image, so the
#                             base build needs no host-side zstd (see scripts/publish-linux-vm-kernel.sh)
#
# The agents are arm64 Linux binaries, built natively on an arm64 runner. Each artifact is (a) uploaded
# as a workflow artifact (download + commit into guest/<agent>/build/, the path the base build reads —
# same committed-binary model the C agent already uses) and (b) pushed to GHCR as a single-blob OCI
# artifact (the project's distribution channel, mirroring kernel-image.yml / ProjectSandbox.kernelImage).
#
# Manual + on-change. After the FIRST publish, set each GHCR package to Public (GitHub → Packages) so it
# can be pulled anonymously while the repo stays private, exactly like nucleic-kernel / nucleic-sandbox.

on:
  workflow_dispatch:
    inputs:
      tag:
        description: "GHCR tag for the agent artifacts"
        required: true
        default: "latest"
      publish:
        description: "Push to GHCR (else just build + upload workflow artifacts)"
        type: boolean
        default: true
  push:
    paths:
      - "guest/nucleic-linux-agent/**"
      - "guest/nucleic-a11y-agent/**"
      - "scripts/publish-linux-vm-kernel.sh"
      - ".github/workflows/linux-vm-agents.yml"

jobs:
  agents:
    runs-on: ubuntu-24.04-arm # native arm64 — the guest binaries are arm64
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Toolchain (C static + Rust)
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends build-essential
      - uses: dtolnay/rust-toolchain@stable

      - name: Build nucleic-linux-agent (static C)
        run: bash guest/nucleic-linux-agent/build.sh

      - name: Build nucleic-a11y-agent (Rust)
        run: bash guest/nucleic-a11y-agent/build.sh

      - name: Sanity-check the binaries are arm64 ELF
        run: |
          file guest/nucleic-linux-agent/build/nucleic-linux-agent
          file guest/nucleic-a11y-agent/build/nucleic-a11y-agent

      - name: Upload workflow artifacts
        uses: actions/upload-artifact@v4
        with:
          name: nucleic-linux-vm-agents-arm64
          path: |
            guest/nucleic-linux-agent/build/nucleic-linux-agent
            guest/nucleic-a11y-agent/build/nucleic-a11y-agent
          if-no-files-found: error

      - name: Resolve GHCR owner
        id: ref
        run: echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"

      - uses: oras-project/setup-oras@v1
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
      - name: Log in to GHCR
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
        run: oras login ghcr.io -u '${{ github.actor }}' -p '${{ secrets.GITHUB_TOKEN }}'
      - name: Push agents as OCI artifacts
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
        working-directory: guest
        run: |
          T='${{ inputs.tag }}'
          O='${{ steps.ref.outputs.owner }}'
          oras push "ghcr.io/$O/nucleic-linux-agent:$T" \
            --artifact-type application/vnd.nucleic.agent \
            nucleic-linux-agent/build/nucleic-linux-agent:application/octet-stream
          oras push "ghcr.io/$O/nucleic-a11y-agent:$T" \
            --artifact-type application/vnd.nucleic.agent \
            nucleic-a11y-agent/build/nucleic-a11y-agent:application/octet-stream

  kernel:
    # The kernel unwrap is arch-agnostic (it downloads the arm64 vmlinuz and decompresses it), so any
    # runner works; it needs zstd + ar + curl + python3.
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - name: Tools
        run: sudo apt-get update && sudo apt-get install -y --no-install-recommends zstd binutils curl python3
      - name: Unwrap the pinned Ubuntu kernel → raw Image
        run: OUT="$PWD/vmlinux-arm64" bash scripts/publish-linux-vm-kernel.sh resolute 26.04
      - name: Upload workflow artifact
        uses: actions/upload-artifact@v4
        with:
          name: nucleic-linux-vm-kernel-arm64
          path: vmlinux-arm64
          if-no-files-found: error
      - name: Resolve GHCR owner
        id: ref
        run: echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
      - uses: oras-project/setup-oras@v1
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
      - name: Log in to GHCR
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
        run: oras login ghcr.io -u '${{ github.actor }}' -p '${{ secrets.GITHUB_TOKEN }}'
      - name: Push kernel as an OCI artifact
        if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
        run: |
          oras push "ghcr.io/${{ steps.ref.outputs.owner }}/nucleic-linux-vm-kernel:26.04-${{ inputs.tag }}" \
            --artifact-type application/vnd.nucleic.kernel \
            vmlinux-arm64:application/octet-stream
