Build and deploy with evidence #60
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and deploy with evidence | |
| on: | |
| [workflow_dispatch] | |
| permissions: | |
| id-token: write | |
| contents: read | |
| attestations: write | |
| jobs: | |
| docker-build-with-evidence: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| image_name: ${{ steps.docker-build.outputs.full_image_name }} | |
| env: | |
| REPO_NAME: evidence-demo-docker-dev | |
| # JFROG_CLI_LOG_LEVEL: DEBUG | |
| steps: | |
| - name: Install jfrog cli | |
| uses: jfrog/setup-jfrog-cli@v4 | |
| env: | |
| JF_URL: ${{ vars.ARTIFACTORY_URL }} | |
| JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - uses: actions/checkout@v4 | |
| - name: Log in to Artifactory Docker Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ vars.ARTIFACTORY_URL }} | |
| username: ${{ secrets.JF_USER }} | |
| password: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| install: true | |
| - name: Setup Cosign | |
| uses: sigstore/cosign-installer@main | |
| - name: Build Docker image | |
| id: docker-build | |
| run: | | |
| URL=$(echo ${{ vars.ARTIFACTORY_URL }} | sed 's|^https://||') | |
| REPO_URL=${URL}/${REPO_NAME} | |
| docker build --build-arg REPO_URL=${REPO_URL} -f Dockerfile . \ | |
| --tag ${REPO_URL}/example-project-app:${{ github.run_number }} \ | |
| --output=type=image --platform linux/amd64 --metadata-file=build-metadata --push | |
| jfrog rt build-docker-create ${REPO_NAME} --image-file build-metadata --build-name ${{ vars.BUILD_NAME }} --build-number ${{ github.run_number }} | |
| DIGEST=$(docker buildx imagetools inspect --raw ${REPO_URL}/example-project-app:${{ github.run_number }} | jq -r '.manifests[0].digest') | |
| echo "digest=$DIGEST" >> $GITHUB_OUTPUT | |
| echo "image_name=${REPO_URL}/example-project-app" >> $GITHUB_OUTPUT | |
| echo "full_image_name=example-project-app:${{ github.run_number }}@$DIGEST" >> $GITHUB_OUTPUT | |
| - name: Sign docker image | |
| env: | |
| TAGS: ${{ steps.docker_meta.outputs.tags }} | |
| COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_KEY }} | |
| COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} | |
| DIGEST: ${{ steps.build-and-push.outputs.digest }} | |
| run: | | |
| URL=$(echo ${{ vars.ARTIFACTORY_URL }} | sed 's|^https://||') | |
| REPO_URL=${URL}/${REPO_NAME} | |
| cosign sign --yes --key env://COSIGN_PRIVATE_KEY ${REPO_URL}/example-project-app:${{ github.run_number }} | |
| - name: Evidence on docker | |
| run: | | |
| echo '{ "actor": "${{ github.actor }}", "date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'" }' > sign.json | |
| jf evd create --package-name example-project-app --package-version ${{ github.run_number }} --package-repo-name ${REPO_NAME} \ | |
| --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} \ | |
| --predicate ./sign.json --predicate-type https://jfrog.com/evidence/signature/v1 | |
| echo 'π Evidence attached: `signature` π ' | |
| - name: Build Attestation Generation | |
| uses: actions/attest-build-provenance@v2 | |
| id: attest | |
| with: | |
| subject-name: ${{ steps.docker-build.outputs.image_name }} | |
| subject-digest: ${{ steps.docker-build.outputs.digest }} | |
| push-to-registry: true | |
| - name: Upload Provenance attestation as a Jfrog evidence | |
| id: upload-gh-provenance | |
| run: | | |
| jf evd create --package-name example-project-app --package-version ${{ github.run_number }} --package-repo-name ${REPO_NAME} \ | |
| --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} \ | |
| --predicate ${{ steps.attest.outputs.bundle-path}} --predicate-type https://slsa.dev/provenance/v1 | |
| echo 'π Evidence attached: `provenance` β ' | |
| - name: Upload readme file | |
| run: | | |
| jf rt upload ./README.md evidence-demo-generic-dev-local/readme/${{ github.run_number }}/ --build-name ${{ vars.BUILD_NAME }} --build-number ${{ github.run_number }} | |
| jf evd create --subject-repo-path evidence-demo-generic-dev-local/readme/${{ github.run_number }}/README.md \ | |
| --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} \ | |
| --predicate ./sign.json --predicate-type https://jfrog.com/evidence/signature/v1 | |
| - name: Collecting Information from Git | |
| run: jf rt build-add-git ${{ vars.BUILD_NAME }} ${{ github.run_number }} | |
| - name: Collecting Environment Variables | |
| run: jf rt build-collect-env ${{ vars.BUILD_NAME }} ${{ github.run_number }} | |
| - name: Publish build info | |
| run: jfrog rt build-publish ${{ vars.BUILD_NAME }} ${{ github.run_number }} | |
| - name: Sign build evidence | |
| run: | | |
| echo '{ "actor": "${{ github.actor }}", "date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'" }' > sign.json | |
| jf evd create --build-name ${{ vars.BUILD_NAME }} --build-number ${{ github.run_number }} \ | |
| --predicate ./sign.json --predicate-type https://jfrog.com/evidence/build-signature/v1 \ | |
| --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} | |
| echo 'π Evidence attached: `build-signature` π ' >> $GITHUB_STEP_SUMMARY | |
| - name: Create release bundle | |
| run: | | |
| echo '{ "files": [ {"build": "'"${{ vars.BUILD_NAME }}/${{ github.run_number }}"'" } ] }' > bundle-spec.json | |
| jf release-bundle-create ${{ vars.BUNDLE_NAME }} ${{ github.run_number }} --signing-key ${{ secrets.RB_KEY }} --spec bundle-spec.json --sync=true | |
| NAME_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ vars.BUNDLE_NAME }}'&bundleToFlash='${{ vars.BUNDLE_NAME }}'&repositoryKey=release-bundles-v2&activeKanbanTab=promotion' | |
| VER_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ vars.BUNDLE_NAME }}'&bundleToFlash='${{ vars.BUNDLE_NAME }}'&releaseBundleVersion='${{ github.run_number }}'&repositoryKey=release-bundles-v2&activeVersionTab=Version%20Timeline&activeKanbanTab=promotion' | |
| echo 'π¦ Release bundle ['${{ vars.BUNDLE_NAME }}']('${NAME_LINK}'):['${{ github.run_number }}']('${VER_LINK}') created' >> $GITHUB_STEP_SUMMARY | |
| Promote-to-qa-and-test: | |
| needs: Docker-build-with-evidence | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Install jfrog cli | |
| uses: jfrog/setup-jfrog-cli@v4 | |
| env: | |
| JF_URL: ${{ vars.ARTIFACTORY_URL }} | |
| JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - name: Promote to QA | |
| run: | | |
| jf release-bundle-promote ${{ vars.BUNDLE_NAME }} ${{ github.run_number }} QA --signing-key ${{ secrets.RB_KEY }} --sync=true | |
| echo "π Succesfully promote to \`QA\` environemnt" >> $GITHUB_STEP_SUMMARY | |
| - name: Evidence on release-bundle | |
| run: | | |
| echo '{ "actor": "${{ github.actor }}", "date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'" }' > rbv2_evidence.json | |
| JF_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ vars.BUNDLE_NAME }}'&bundleToFlash='${{ vars.BUNDLE_NAME }}'&releaseBundleVersion='${{ github.run_number }}'&repositoryKey=release-bundles-v2&activeVersionTab=Version%20Timeline&activeKanbanTab=promotion' | |
| echo 'Test on Release bundle ['${{ vars.BUNDLE_NAME }}':'${{ github.run_number }}']('${JF_LINK}') success' >> $GITHUB_STEP_SUMMARY | |
| jf evd create --release-bundle ${{ vars.BUNDLE_NAME }} --release-bundle-version ${{ github.run_number }} \ | |
| --predicate ./rbv2_evidence.json --predicate-type https://jfrog.com/evidence/testing-results/v1 \ | |
| --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} | |
| echo 'π Evidence attached: integration-test π§ͺ ' >> $GITHUB_STEP_SUMMARY | |
| Attestation-check-to-promote: | |
| needs: docker-build-with-evidence | |
| runs-on: ubuntu-latest | |
| env: | |
| REPO_NAME: evidence-demo-docker-dev | |
| steps: | |
| - name: Install jfrog cli | |
| uses: jfrog/setup-jfrog-cli@v4 | |
| env: | |
| JF_URL: ${{ vars.ARTIFACTORY_URL }} | |
| JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - name: Log in to Artifactory Docker Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ vars.ARTIFACTORY_URL }} | |
| username: ${{ secrets.JF_USER }} | |
| password: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - name: prepare data for validation step | |
| id: prepare-input | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| URL=$(echo ${{ vars.ARTIFACTORY_URL }} | sed 's|^https://||') | |
| echo "repo-url=${URL}/${REPO_NAME}" >> $GITHUB_OUTPUT | |
| - name: Validate the attestation and the artifact | |
| id: verify-attestation | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| IMG_NAME: ${{ needs.docker-build-with-evidence.outputs.image_name }} | |
| run: | | |
| gh attestation verify --owner guybar oci://${{ steps.prepare-input.outputs.repo-url }}/$IMG_NAME --bundle-from-oci --format json | |
| Policy-check-and-promote-to-prod: | |
| needs: Promote-to-qa-and-test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Install jfrog cli | |
| uses: jfrog/setup-jfrog-cli@v4 | |
| env: | |
| JF_URL: ${{ vars.ARTIFACTORY_URL }} | |
| JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install OPA | |
| run: | | |
| curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64 | |
| chmod +x opa | |
| sudo mv opa /usr/local/bin/ | |
| - name: Call GraphQL | |
| run: | | |
| ./scripts/graphql.sh ${{ vars.ARTIFACTORY_URL }} ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} release-bundles-v2 ${{ vars.BUNDLE_NAME }} ${{ github.run_number }} | |
| cat evidence_graph.json | |
| - name: Run policy | |
| id: run_policy | |
| run: | | |
| result=$(opa eval --input ./evidence_graph.json --data policy/policy.rego "data.greenpizza.output" | jq '.result[0].expressions[0].value.approved') | |
| echo "RESULT=$result" >> $GITHUB_ENV | |
| echo "RESULT=$result" >> $GITHUB_STEP_SUMMARY | |
| - name: Promote to Production | |
| run: | | |
| if [ "${{ env.RESULT }}" == "true" ]; then | |
| opa eval --input ./evidence_graph.json --data policy/policy.rego "data.greenpizza.output" | jq '.result[0].expressions[0].value' > policy.json | |
| cat policy.json | |
| jf evd create --key "${{ secrets.PRIVATE_KEY }}" --key-alias ${{ secrets.KEY_ALIAS }} \ | |
| --release-bundle ${{ vars.BUNDLE_NAME }} --release-bundle-version ${{ github.run_number }} \ | |
| --predicate ./policy.json --predicate-type https://jfrog.com/evidence/approval/v1 | |
| jf release-bundle-promote ${{ vars.BUNDLE_NAME }} ${{ github.run_number }} PROD --signing-key ${{ secrets.RB_KEY }} --sync=true | |
| echo "π Succesfully promote to \`PROD\` environemnt" >> $GITHUB_STEP_SUMMARY | |
| else | |
| opa eval --input ./evidence_graph.json --data policy/policy.rego "data.greenpizza.output" | jq '.result[0].expressions[0].value' | |
| echo "Fail promotion policy check" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |