# Copyright 2022 The Sigstore Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Test attest / verify-attestation

on:
  pull_request:
    branches: [ 'main', 'release-*' ]
  workflow_dispatch:

defaults:
  run:
    shell: bash

permissions: {}

jobs:
  cip-test:
    name: attest / verify-attestation test
    runs-on: ubuntu-latest

    strategy:
      matrix:
        k8s-version:
        - v1.30.x
        - v1.31.x
        - v1.32.x
        - v1.33.x
        tuf-root:
        - remote
        - air-gap

    permissions:
      contents: read

    env:
      KO_DOCKER_REPO: "registry.local:5000/policy-controller"
      SCAFFOLDING_RELEASE_VERSION: "v0.7.24"
      GO111MODULE: on
      GOFLAGS: -ldflags=-s -ldflags=-w
      KOCACHE: ~/ko
      COSIGN_YES: "true"

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: Extract version of Go to use
      run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV

    - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
      with:
        go-version: '${{ env.GOVERSION }}'
        check-latest: true
        cache: false

    # will use the latest release available for ko
    - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9

    - name: Install yq
      uses: mikefarah/yq@751d8ad57b84f1794661bc70c0afb92a22ad7b3c # v4.53.2

    - name: build cosign
      run: |
        make cosign

    - name: Install cluster + sigstore
      uses: sigstore/scaffolding/actions/setup@main
      with:
        legacy-variables: "false"
        k8s-version: ${{ matrix.k8s-version }}
        version: ${{ env.SCAFFOLDING_RELEASE_VERSION }}

    - name: Create sample image - demoimage
      run: |
        pushd $(mktemp -d)
        go mod init example.com/demo
        cat <<EOF > main.go
        package main
        import "fmt"
        func main() {
          fmt.Println("hello world")
        }
        EOF
        demoimage=`ko publish -B example.com/demo`
        echo "demoimage=$demoimage" >> $GITHUB_ENV
        echo Created image $demoimage
        popd

    - name: Initialize with our custom TUF root pointing to remote root
      if: ${{ matrix.tuf-root == 'remote' }}
      run: |
        TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}')
        ./cosign initialize --mirror $TUF_MIRROR --root ./root.json

    - name: Get copy of TUF repository
      run: |
        # Grab the compressed repository for airgap testing.
        kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.repository}'  | base64 -d > ./repository.tar.gz
        tar -zxvf ./repository.tar.gz

    - name: Initialize with custom TUF root pointing to local filesystem
      if: ${{ matrix.tuf-root == 'air-gap' }}
      run: |
        # Grab the compressed repository for airgap testing.
        PWD=$(pwd)
        ROOT=${PWD}/repository/1.root.json
        REPOSITORY=${PWD}/repository
        ./cosign initialize --root ${ROOT} --mirror file://${REPOSITORY}

    - name: Set TrustedRoot
      run: |
        trustedroot=$(find ./repository/targets -name "*.trusted_root.json")
        echo "trustedroot=$trustedroot" >> $GITHUB_ENV

    - name: Create SigningConfig
      run: |
        ./cosign signing-config create \
            --fulcio="url=${FULCIO_URL},api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \
            --rekor="url=${REKOR_URL},api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \
            --rekor-config="ANY" \
            --tsa="url=${TSA_URL}/api/v1/timestamp,api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \
            --tsa-config="EXACT:1" \
            --out signingconfig.json
        echo "signingconfig=signingconfig.json" >> $GITHUB_ENV

    - name: Sign demoimage with cosign
      run: |
        ./cosign sign --signing-config=${signingconfig} --trusted-root=${trustedroot} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN}

    - name: Create attestation for it
      run: |
        echo -n 'foobar e2e test' > ./predicate-file
        ./cosign attest --predicate ./predicate-file --signing-config=${signingconfig} --trusted-root=${trustedroot} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN}

    - name: Sign a blob
      run: |
        ./cosign sign-blob README.md --signing-config=${signingconfig} --trusted-root=${trustedroot} --bundle blob.sigstore.json --yes --identity-token ${OIDC_TOKEN}

    - name: Verify with cosign
      run: |
        ./cosign verify --trusted-root=${trustedroot} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local"

    - name: Verify custom attestation with cosign, works
      run: |
        echo '::group:: test custom verify-attestation success'
        if ! ./cosign verify-attestation --trusted-root=${trustedroot} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" --policy ./test/testdata/policies/cue-works.cue --allow-insecure-registry ${demoimage} ; then
          echo Failed to verify attestation with a valid policy
          exit 1
        else
          echo Successfully validated custom attestation with a valid policy
        fi
        echo '::endgroup::'

    - name: Verify custom attestation with cosign, fails
      run: |
        echo '::group:: test custom verify-attestation success'
        if ./cosign verify-attestation --trusted-root=${trustedroot} --policy ./test/testdata/policies/cue-fails.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
          echo custom verify-attestation succeeded with cue policy that should not work
          exit 1
        else
          echo Successfully failed a policy that should not work
        fi
        echo '::endgroup::'

    - name: Verify a blob
      run: |
        ./cosign verify-blob README.md --trusted-root=${trustedroot} --bundle blob.sigstore.json --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local"

    - name: Collect diagnostics
      if: ${{ failure() }}
      uses: chainguard-dev/actions/kind-diag@c69a264ec2a5934c3186c618f368fc1c86f16cff # v1.6.19

    - name: Create vuln attestation for it
      run: |
        ./cosign attest --predicate ./test/testdata/attestations/vuln-predicate.json --type vuln --signing-config=${signingconfig} --trusted-root=${trustedroot} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN}

    - name: Verify vuln attestation with cosign, works
      run: |
        echo '::group:: test vuln verify-attestation success'
        if ! ./cosign verify-attestation --trusted-root=${trustedroot} --type vuln --policy ./test/testdata/policies/cue-vuln-works.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
          echo Failed to verify attestation with a valid policy
          exit 1
        else
          echo Successfully validated vuln attestation with a valid policy
        fi
        echo '::endgroup::'

    - name: Verify vuln attestation with cosign, fails
      run: |
        echo '::group:: test vuln verify-attestation success'
        if ./cosign verify-attestation --trusted-root=${trustedroot} --type vuln --policy ./test/testdata/policies/cue-vuln-fails.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then
          echo verify-attestation succeeded with cue policy that should not work
          exit 1
        else
          echo Successfully failed a policy that should not work
        fi
        echo '::endgroup::'
