name: Build CLI
description: |
  Builds CLI. Optionally, Sigstore tools
  are used to sign CLI when inputs are provided. A draft release is published
  when run on v* tag.
inputs:
  targetOS:
    description: "Build CLI for this OS. [linux, darwin, windows]"
    required: true
    default: "linux"
  targetArch:
    description: "Build CLI for this architecture. [amd64, arm64]"
    required: true
    default: "amd64"
  enterpriseCLI:
    description: "Build CLI with enterprise flag."
    required: false
    default: "false"
  cosignPublicKey:
    description: "Cosign public key"
    required: false
    default: ""
  cosignPrivateKey:
    description: "Cosign private key"
    required: false
    default: ""
  cosignPassword:
    description: "Password for Cosign private key"
    required: false
    default: ""
  outputPath:
    description: "Output path of the binary"
    required: false
  push:
    description: "Push container images"
    required: false
    default: false
runs:
  using: "composite"
  steps:
    # https://github.blog/2022-04-12-git-security-vulnerability-announced/
    - name: Mark repository safe
      shell: bash
      run: |
        git config --global --add safe.directory /__w/constellation/constellation

    - name: Build CLI
      shell: bash
      env:
        TARGET_GOOS: ${{ inputs.targetOS }}
        TARGET_GOARCH: ${{ inputs.targetArch }}
        OUTPUT_PATH: ${{ inputs.outputPath || format('./build/constellation-{0}-{1}', inputs.targetOS, inputs.targetArch) }}${{ inputs.targetOS == 'windows' && '.exe' || '' }}
      run: |
        echo "::group::Build CLI"
        mkdir -p "$(dirname "${OUTPUT_PATH}")"
        if [ ${{ inputs.enterpriseCLI }} == 'true' ]
        then
          cli_variant=enterprise
        else
          cli_variant=oss
        fi
        label="//cli:cli_${cli_variant}_${TARGET_GOOS}_${TARGET_GOARCH}"
        bazel build "${label}"
        repository_root=$(git rev-parse --show-toplevel)
        out_rel=$(bazel cquery --output=files "${label}")
        out_loc="$(realpath "${repository_root}/${out_rel}")"
        cp "${out_loc}" "${OUTPUT_PATH}"
        chmod +w "${OUTPUT_PATH}"
        export PATH="$PATH:$(realpath $(dirname "${OUTPUT_PATH}"))"
        echo "$(realpath $(dirname "${OUTPUT_PATH}"))" >> $GITHUB_PATH
        echo "::endgroup::"

    - name: Upload container images
      if: inputs.push == 'true'
      shell: bash
      run: bazel run //bazel/release:push

    # TODO(3u13r): Replace with https://github.com/sigstore/sigstore-installer/tree/initial
    # once it has the functionality
    - name: Install Cosign
      if: inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != ''
      uses: sigstore/cosign-installer@c85d0e205a72a294fe064f618a87dbac13084086 # v2.8.1

    - name: Install Rekor
      if: inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != ''
      shell: bash
      working-directory: build
      run: |
        HOSTOS="$(go env GOOS)"
        HOSTARCH="$(go env GOARCH)"
        curl -fsSLO https://github.com/sigstore/rekor/releases/download/v0.12.0/rekor-cli-${HOSTOS}-${HOSTARCH}
        sudo install rekor-cli-${HOSTOS}-${HOSTARCH} /usr/local/bin/rekor-cli
        rm rekor-cli-${HOSTOS}-${HOSTARCH}

    - name: Sign CLI
      if: inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != ''
      shell: bash
      working-directory: build
      env:
        COSIGN_PUBLIC_KEY: ${{ inputs.cosignPublicKey }}
        COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }}
        COSIGN_PASSWORD: ${{ inputs.cosignPassword }}
        OUTPUT_PATH: ${{ github.workspace }}/${{ inputs.outputPath || format('./build/constellation-{0}-{1}', inputs.targetOS, inputs.targetArch) }}${{ inputs.targetOS == 'windows' && '.exe' || '' }}
      run: |
        echo "$COSIGN_PUBLIC_KEY" > cosign.pub
        # Enabling experimental mode also publishes signature to Rekor
        COSIGN_EXPERIMENTAL=1 cosign sign-blob --key env://COSIGN_PRIVATE_KEY "${OUTPUT_PATH}" > "${OUTPUT_PATH}.sig"
        # Verify - As documentation & check
        # Local Signature (input: artifact, key, signature)
        cosign verify-blob --key cosign.pub --signature "${OUTPUT_PATH}.sig" "${OUTPUT_PATH}"
        # Transparency Log Signature (input: artifact, key)
        uuid=$(rekor-cli search --artifact "${OUTPUT_PATH}" | tail -n 1)
        sig=$(rekor-cli get --uuid=$uuid --format=json | jq -r .Body.HashedRekordObj.signature.content)
        cosign verify-blob --key cosign.pub --signature <(echo $sig) "${OUTPUT_PATH}"
