name: Build CLI and prepare release

on:
  workflow_dispatch:
    inputs:
      ref:
        type: string
        description: "Git ref to checkout"
        required: false
      pushContainers:
        type: boolean
        description: "Push containers pinned in the cli to container registry"
        required: false
        default: false
      registry:
        description: "Container registry to use"
        type: string
        default: ghcr.io
      key:
        description: "Key to use for signing. Set to 'release' to use release key, set to 'dev' to use the dev key."
        type: string
        required: true
  workflow_call:
    inputs:
      ref:
        type: string
        description: "Git ref to checkout"
        required: true
      pushContainers:
        type: boolean
        description: "Push containers pinned in the cli to container registry"
        required: false
        default: false
      registry:
        description: "Container registry to use"
        type: string
        default: ghcr.io
      key:
        description: "Key to use for signing. Set to 'release' to use release key, set to 'dev' to use the dev key."
        type: string
        required: true

jobs:
  build-cli:
    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - arch: amd64
            os: linux

          - arch: amd64
            os: darwin

          - arch: amd64
            os: windows

          - arch: arm64
            os: linux

          - arch: arm64
            os: darwin
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          ref: ${{ inputs.ref || github.head_ref }}

      - name: Setup bazel
        uses: ./.github/actions/setup_bazel
        with:
          useCache: "false"

      - name: Build CLI
        uses: ./.github/actions/build_cli
        with:
          targetOS: ${{ matrix.os }}
          targetArch: ${{ matrix.arch }}
          enterpriseCLI: true
          cosignPublicKey: ${{ inputs.key == 'release' && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }}
          cosignPrivateKey: ${{ inputs.key == 'release' && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }}
          cosignPassword: ${{ inputs.key == 'release' && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }}

      - name: Upload CLI as artifact (unix)
        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        if : ${{ matrix.os != 'windows' }}
        with:
          name: constellation-${{ matrix.os }}-${{ matrix.arch }}
          path: |
            build/constellation-${{ matrix.os }}-${{ matrix.arch }}
            build/constellation-${{ matrix.os }}-${{ matrix.arch }}.sig

      - name: Upload CLI as artifact (windows)
        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        if : ${{ matrix.os == 'windows' }}
        with:
          name: constellation-${{ matrix.os }}-${{ matrix.arch }}
          path: |
            build/constellation-${{ matrix.os }}-${{ matrix.arch }}.exe
            build/constellation-${{ matrix.os }}-${{ matrix.arch }}.exe.sig

  push-containers:
    runs-on: ubuntu-22.04
    if: inputs.pushContainers
    permissions:
      actions: read
      contents: write
      id-token: write
      packages: write
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          ref: ${{ inputs.ref || github.head_ref }}

      - name: Setup bazel
        uses: ./.github/actions/setup_bazel
        with:
          useCache: "false"

      - name: Log in to the Container registry
        uses: ./.github/actions/container_registry_login
        with:
          registry: ${{ inputs.registry }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload referenced container images
        shell: bash
        run: bazel run //bazel/release:push

  provenance-subjects:
    runs-on: ubuntu-22.04
    needs:
      - build-cli
      - signed-sbom
    outputs:
      provenance-subjects: ${{ steps.provenance-subjects.outputs.provenance-subjects }}
    steps:
      - name: Download CLI binaries darwin-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-amd64

      - name: Download CLI binaries darwin-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-arm64

      - name: Download CLI binaries linux-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-amd64

      - name: Download CLI binaries linux-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-arm64

      - name: Download CLI binaries windows-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-windows-amd64

      - name: Download CLI SBOM
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation.spdx.sbom

      - name: Generate provenance subjects
        id: provenance-subjects
        run: |
          HASHES=$(sha256sum \
            constellation-darwin-amd64 \
            constellation-darwin-arm64 \
            constellation-linux-amd64 \
            constellation-linux-arm64 \
            constellation-windows-amd64.exe \
            constellation.spdx.sbom)
          HASHESB64=$(echo "${HASHES}" | base64 -w0)
          echo "${HASHES}"
          echo "${HASHESB64}"
          echo provenance-subjects="${HASHESB64}" >> "$GITHUB_OUTPUT"

  signed-sbom:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          ref: ${{ inputs.ref || github.head_ref }}

      - name: Install Cosign
        uses: sigstore/cosign-installer@c85d0e205a72a294fe064f618a87dbac13084086 # v2.8.1

      - name: Download Syft & Grype
        uses: ./.github/actions/install_syft_grype

      - name: Setup bazel
        uses: ./.github/actions/setup_bazel
        with:
          useCache: "false"

      # Build one CLI since Syft's go-module catalog will default to binary parsing.
      # Binary parsing has the advantage that it will not include other dependencies from our repo not included in the CLI.
      # This seems to work fine for one OS & one arch as long as we don't have OS specific imports.
      # Luckily, so far this does not seem to be the case.
      # As of v2.4.0, all SBOMs seem to have the same packages for [linux|darwin] & [amd64|arm64].
      # If this changes, this should be split up into multiple builds & multiple SBOMs.
      - name: Build CLI (amd64, linux)
        uses: ./.github/actions/build_cli
        with:
          targetOS: "linux"
          targetArch: "amd64"
          enterpriseCLI: true

      - name: Build signed SBOM
        run: |
          syft build/constellation-linux-amd64 --catalogers go-module --file constellation.spdx.sbom -o spdx-json
          cosign sign-blob --key env://COSIGN_PRIVATE_KEY constellation.spdx.sbom > constellation.spdx.sbom.sig
          grype constellation.spdx.sbom --fail-on high --only-fixed --add-cpes-if-none
        env:
          COSIGN_EXPERIMENTAL: 1
          COSIGN_PUBLIC_KEY: ${{ startsWith(github.ref, 'refs/tags/v') && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }}
          COSIGN_PRIVATE_KEY: ${{ startsWith(github.ref, 'refs/tags/v') && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }}
          COSIGN_PASSWORD: ${{ startsWith(github.ref, 'refs/tags/v') && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }}

      - name: Upload Constellation CLI SBOM
        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        with:
          name: constellation.spdx.sbom
          path: constellation.spdx.sbom

      - name: Upload Constellation CLI SBOM's signature
        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        with:
          name: constellation.spdx.sbom.sig
          path: constellation.spdx.sbom.sig

  provenance:
    permissions:
      actions: read
      contents: write
      id-token: write
    needs:
      - provenance-subjects
    # This must not be pinned to digest. See:
    # https://github.com/slsa-framework/slsa-github-generator#referencing-slsa-builders-and-generators
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.7.0
    with:
      base64-subjects: "${{ needs.provenance-subjects.outputs.provenance-subjects }}"

  provenance-verify:
    runs-on: ubuntu-22.04
    env:
      SLSA_VERIFIER_VERSION: "2.0.1"
    needs:
      - build-cli
      - provenance
    steps:
      - name: Download CLI binaries darwin-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-amd64

      - name: Download CLI binaries darwin-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-arm64

      - name: Download CLI binaries linux-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-amd64

      - name: Download CLI binaries linux-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-arm64

      - name: Download CLI binaries windows-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-windows-amd64

      - name: Download CLI SBOM
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation.spdx.sbom

      - name: Download provenance
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: ${{ needs.provenance.outputs.provenance-name }}

      - name: Install slsa-verifier
        run: |
          curl -fsSLO https://github.com/slsa-framework/slsa-verifier/releases/download/v${{ env.SLSA_VERIFIER_VERSION }}/slsa-verifier-linux-amd64
          install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier

      - name: Verify provenance
        run: |
          slsa-verifier verify-artifact constellation-darwin-amd64 \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation
          slsa-verifier verify-artifact constellation-darwin-arm64 \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation
          slsa-verifier verify-artifact constellation-linux-amd64 \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation
          slsa-verifier verify-artifact constellation-linux-arm64 \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation
          slsa-verifier verify-artifact constellation-windows-amd64.exe \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation
          slsa-verifier verify-artifact constellation.spdx.sbom \
            --provenance-path ${{ needs.provenance.outputs.provenance-name }} \
            --source-uri github.com/edgelesssys/constellation

  release:
    permissions:
      contents: write
    runs-on: ubuntu-22.04
    needs:
      - build-cli
      - provenance
      - signed-sbom
    steps:
      - name: Write cosign public key
        run: echo "$COSIGN_PUBLIC_KEY" > cosign.pub
        env:
          COSIGN_PUBLIC_KEY: ${{ startsWith(github.ref, 'refs/tags/v') && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }}

      - name: Download CLI binaries darwin-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-amd64

      - name: Download CLI binaries darwin-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-darwin-arm64

      - name: Download CLI binaries linux-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-amd64

      - name: Download CLI binaries linux-arm64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-linux-arm64

      - name: Download CLI binaries windows-amd64
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation-windows-amd64

      - name: Download Constellation CLI SBOM
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation.spdx.sbom

      - name: Download Constellation CLI SBOM's signature
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: constellation.spdx.sbom.sig

      - name: Download Constellation provenance
        uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
        with:
          name: ${{ needs.provenance.outputs.provenance-name }}

      - name: Rename provenance file
        run: |
          mv ${{ needs.provenance.outputs.provenance-name }} constellation.intoto.jsonl

      - name: Create release with artifacts
        # GitHub endorsed release project. See: https://github.com/actions/create-release
        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
        with:
          draft: true
          generate_release_notes: true
          tag_name: ${{ inputs.ref }}
          files: |
            constellation-*
            cosign.pub
            constellation.spdx.sbom
            constellation.spdx.sbom.sig
            constellation.intoto.jsonl