Skip to content

Build and Deploy with Evidence and Policy Check #35

Build and Deploy with Evidence and Policy Check

Build and Deploy with Evidence and Policy Check #35

name: Build and Deploy with Evidence and Policy Check
on:
[workflow_dispatch]
permissions:
id-token: write
contents: read
# Global variables
env:
# Name for the Docker image
IMAGE_NAME: example-project-image
# Name of the Docker Registry; i.e., the JFrog Cloud server base URL
DOKCER_REGISTRY: tomjfrog.jfrog.io
# Virtual repository for the Docker image build and deploy operations
DOCKER_VIRTUAL: evdemo-docker-virtual
# Local Docker repository member of the virtual repository. Required for Evidence attachment
DOCKER_LOCAL: evdemo-docker-local
# Name of the generic repo for the README file
GENERIC_LOCAL: evdemo-generic-local
# GENERIC_QA_LOCAL: evdemo-generic-local
# Name of the signing key residing in the JFrog Artifactory
PRIVATE_KEY_NAME: ${{ secrets.PRIVATE_KEY_NAME }}
# Name of the Docker Metadata file
DOCKER_METADATA: build-metadata
# Name of the Build
BUILD_NAME: evdemo-build
# name of the Release bundle
BUNDLE_NAME: evdemo-bundle-two
# Public Key Alias Name of the "Public Key" uploaded to the JFrog Platform under "Keys Management"
# Used to verify the signature on attached evidence
KEY_ALIAS: evidence-key
# Project Name
JF_PROJECT: ${{ vars.JF_PROJECT }}
# Sonar Cloud Token
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# Sonar Cloud Organization
SONAR_ORGANIZATION: tomjfrog
# Sonar Cloud Project Key
SONAR_PROJECT_KEY: tomjfrog_Evidence-Examples
# SonarQube Scan Result File Name
SONAR_RESULT_FILE: sonar-results.json
jobs:
Docker-Build-With-Evidence:
runs-on: ubuntu-latest
steps:
- name: Install JFrog CLI
uses: jfrog/setup-jfrog-cli@v4
id: cli
env:
JF_URL: ${{ vars.JF_URL }}
# JF_PROJECT: ${{ vars.JF_URL }}
with:
oidc-provider-name: github-oidc-integration
oidc-audience: jfrog-github
disable-auto-build-publish: true
- uses: actions/checkout@v4
- name: Log in to Artifactory Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ vars.ARTIFACTORY_URL }}
username: ${{ steps.cli.outputs.oidc-user }}
password: ${{ steps.cli.outputs.oidc-token }}
- name: Set up QEMU
id: setup-qemu
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
install: true
- name: Setup Signing Key
id: setup-signing-key
run: |
echo "${{ secrets.PRIVATE_KEY_EXPORT }}" > "${{ secrets.PRIVATE_KEY_NAME }}"
chmod 600 ${{ secrets.PRIVATE_KEY_NAME }}
openssl rsa -in ${{ secrets.PRIVATE_KEY_NAME }} -check
- name: Install SonarQube Scanner
run: |
curl -sL -sSLo sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.1.4610.zip
unzip sonar-scanner.zip
export PATH=$PATH:$PWD/sonar-scanner-6.2.1.4610/bin
pwd
ls -l $PWD/sonar-scanner-6.2.1.4610/bin/
echo "$PWD/sonar-scanner-6.2.1.4610/bin"
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '21' # Specify the desired Java version here
distribution: 'temurin' # You can also use 'temurin', 'zulu', etc.
- name: Build Docker image
run: |
URL=$(echo ${{ vars.ARTIFACTORY_URL }} | sed 's|^https://||')
REPO_URL=${URL}'/${{ env.DOCKER_VIRTUAL}}'
docker build \
--build-arg REPO_URL=${REPO_URL} \
-f Dockerfile . \
--tag ${REPO_URL}/${{ env.IMAGE_NAME }}:${{ github.run_number }} \
--output=type=image \
--platform linux/amd64 \
--metadata-file=${{ env.DOCKER_METADATA }} \
--push
- name: Create Docker Build Info
run: |
jf rt build-docker-create ${{ vars.DOCKER_VIRTUAL}} \
--image-file ${{ env.DOCKER_METADATA }} \
--build-name ${{ vars.BUILD_NAME }} \
--build-number ${{ github.run_number }}
- name: Run SonarScanner
id: run-sonar-scanner
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
$PWD/sonar-scanner-6.2.1.4610/bin/sonar-scanner \
-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }} \
-Dsonar.organization=${{ env.SONAR_ORGANIZATION }} \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.java.jdkHome=$JAVA_HOME \
-Dsonar.verbose=true \
-Dsonar.token=${{ env.SONAR_TOKEN }}
# create evidence from sonar-scan analysis
set +e
# --FailOnAnalysisFailure causes a failure on gateway-failed sonar analysis
cat $PWD/.scannerwork/report-task.txt
EXIT_CODE=$?
set -e
# write the exit code to the github output so that it can be used in the evidence creation step
# echo "------${{ env.SONAR_RESULT_FILE }}------"
# cat ${{ env.SONAR_RESULT_FILE }}
echo "------EXIT------"
echo "create-sonar-evidence=$EXIT_CODE"
echo "create-sonar-evidence=$EXIT_CODE" >> $GITHUB_OUTPUT
- name: Fetch Sonar CE Task Result
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
set -euo pipefail
INPUT_FILE=$PWD/.scannerwork/report-task.txt
OUTPUT_FILE=${{ env.SONAR_RESULT_FILE }}
# Extract the ceTaskUrl from the report file
CE_TASK_URL=$(grep '^ceTaskUrl=' "$INPUT_FILE" | cut -d= -f2-)
if [[ -z "$CE_TASK_URL" ]]; then
echo "Error: ceTaskUrl not found in $INPUT_FILE" >&2
exit 1
fi
# Fetch the CE task details and save as JSON
curl -sS \
-u "${SONAR_TOKEN}:" \
-H "Accept: application/json" \
"$CE_TASK_URL" \
-o "$OUTPUT_FILE"
echo "✅ Fetched Sonar task details into $OUTPUT_FILE"
- name: Create and Attach Evidence on Docker Image
run: |
echo '{ "actor": "${{ github.actor }}", "date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'" }' > sign.json
jf evd create \
--package-name ${{ env.IMAGE_NAME }} \
--package-version ${{ github.run_number }} \
--package-repo-name ${{ env.DOCKER_LOCAL }} \
--key "${{ env.PRIVATE_KEY_NAME }}" \
--key-alias ${{ env.KEY_ALIAS }} \
--predicate ./sign.json \
--predicate-type https://jfrog.com/evidence/foo/v1
echo '🔎 Evidence attached: `signature` 🔏 '
- name: Upload README file
run: |
jf rt upload ./README.md ${{ env.GENERIC_LOCAL }}/readme/${{ github.run_number }}/ \
--build-name ${{ vars.BUILD_NAME }} \
--build-number ${{ github.run_number }}
- name: Attach Evidence on README file
run: |
jf evd create \
--subject-repo-path ${{ env.GENERIC_LOCAL }}/readme/${{ github.run_number }}/README.md \
--key "${{ env.PRIVATE_KEY_NAME }}" \
--key-alias ${{ env.KEY_ALIAS }} \
--predicate ./sign.json \
--predicate-type https://jfrog.com/evidence/signature/v1 \
--project ${{ env.JF_PROJECT }} \
- name: Decorate Build Info with Git Context
run: jf rt build-add-git ${{ vars.BUILD_NAME }} ${{ github.run_number }}
- name: Decorate Build Info with 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: Create and Attach Build Actor & Timestamp 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_NAME }}" \
--key-alias ${{ env.KEY_ALIAS }} \
--project ${{ env.JF_PROJECT }}
echo '🔎 Evidence attached: `build-signature` 🔏 ' >> $GITHUB_STEP_SUMMARY
- name: Attach SonarQube Scan Result Evidence To Build Info
if: ${{ steps.run-sonar-scanner.outputs.create-sonar-evidence == 0 }}
run: |
# Attach evidence onto build using JFrog CLI
jf evd create \
--build-name ${{ vars.BUILD_NAME }} \
--build-number "${{ github.run_number }}" \
--predicate ${{ env.SONAR_RESULT_FILE }} \
--predicate-type https://jfrog.com/evidence/sonar-scan/v1 \
--key "${{ secrets.PRIVATE_KEY_NAME }}" \
--key-alias ${{ env.KEY_ALIAS }} \
--project ${{ env.JF_PROJECT }}
- name: Create Release Bundle
run: |
echo '{ "files": [ {"build": "'"${{ vars.BUILD_NAME }}/${{ github.run_number }}"'", "project": "'"${{ env.JF_PROJECT }}"'" } ] }' > bundle-spec.json
jf release-bundle-create ${{ env.BUNDLE_NAME }} ${{ github.run_number }} \
--signing-key ${{ secrets.GPG_KEY_NAME }} \
--spec bundle-spec.json \
--sync=true \
--project ${{ env.JF_PROJECT }}
NAME_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ env.BUNDLE_NAME }}'&bundleToFlash='${{ env.BUNDLE_NAME }}'&repositoryKey=release-bundles-v2&activeKanbanTab=promotion'
VER_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ env.BUNDLE_NAME }}'&bundleToFlash='${{ env.BUNDLE_NAME }}'&releaseBundleVersion='${{ github.run_number }}'&repositoryKey=release-bundles-v2&activeVersionTab=Version%20Timeline&activeKanbanTab=promotion'
echo '📦 Release bundle ['${{ env.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
id: cli
env:
JF_URL: ${{ vars.JF_URL }}
JF_PROJECT: ${{ vars.PROJECT_NAME }}
with:
oidc-provider-name: github-oidc-integration
oidc-audience: jfrog-github
disable-auto-build-publish: true
- name: Promote to QA
run: |
jf release-bundle-promote ${{ env.BUNDLE_NAME }} ${{ github.run_number }} QA \
--signing-key ${{ secrets.GPG_KEY_NAME }} \
--sync=true \
--project ${{ env.JF_PROJECT }}
echo "🚀 Succesfully promote to \`QA\` environemnt" >> $GITHUB_STEP_SUMMARY
- name: Setup Signing Key
id: setup-signing-key
run: |
echo "${{ secrets.PRIVATE_KEY_EXPORT }}" > "${{ secrets.PRIVATE_KEY_NAME }}"
chmod 600 ${{ secrets.PRIVATE_KEY_NAME }}
openssl rsa -in ${{ secrets.PRIVATE_KEY_NAME }} -check
- name: Attach Evidence on Release Bundle
run: |
echo '{ "actor": "${{ github.actor }}", "date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'", "test": "CI test", "result": "success" }' > test_evidence.json
JF_LINK=${{ vars.ARTIFACTORY_URL }}'/ui/artifactory/lifecycle/?bundleName='${{ env.BUNDLE_NAME }}'&bundleToFlash='${{ env.BUNDLE_NAME }}'&releaseBundleVersion='${{ github.run_number }}'&repositoryKey=release-bundles-v2&activeVersionTab=Version%20Timeline&activeKanbanTab=promotion'
echo 'Test on Release bundle ['${{ env.BUNDLE_NAME }}':'${{ github.run_number }}']('${JF_LINK}') success' >> $GITHUB_STEP_SUMMARY
jf evd create \
--release-bundle ${{ env.BUNDLE_NAME }} \
--release-bundle-version ${{ github.run_number }} \
--predicate ./test_evidence.json \
--predicate-type https://jfrog.com/evidence/testing-results/v1 \
--key ${{ env.PRIVATE_KEY_NAME }} \
--key-alias ${{ env.KEY_ALIAS }} \
--project ${{ env.JF_PROJECT }}
echo '🔎 Evidence attached: integration-test 🧪 ' >> $GITHUB_STEP_SUMMARY
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
id: cli
env:
JF_URL: ${{ vars.JF_URL }}
JF_PROJECT: ${{ vars.PROJECT_NAME }}
with:
oidc-provider-name: github-oidc-integration
oidc-audience: jfrog-github
disable-auto-build-publish: true
- name: Setup Signing Key
id: setup-signing-key
run: |
echo "${{ secrets.PRIVATE_KEY_EXPORT }}" > "${{ secrets.PRIVATE_KEY_NAME }}"
chmod 600 ${{ secrets.PRIVATE_KEY_NAME }}
openssl rsa -in ${{ secrets.PRIVATE_KEY_NAME }} -check
- 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 To Fetch Entire Evidence Graph
run: |
./scripts/graphql.sh ${{ vars.JF_URL }} ${{ steps.cli.outputs.oidc-token }} evdemo-release-bundles-v2 ${{ env.BUNDLE_NAME }} ${{ github.run_number }} ./evidence-graph.json
cat ./evidence-graph.json
- name: Run policy
id: run_policy
run: |
opa eval --input ./evidence-graph.json --data ./policy/policy.rego "data.policy.output" | jq '.result[0].expressions[0].value' > policy.json
result=$(jq .approved ./policy.json)
echo "RESULT=$result" >> $GITHUB_ENV
- name: Promote to Production (expected to fail due to missing policy requirement))
run: |
if [ "${{ env.RESULT }}" == "true" ]; then
jf evd create \
--key "${{ env.PRIVATE_KEY_NAME }}" \ \
--key-alias ${{ env.KEY_ALIAS }} \
--release-bundle ${{ env.BUNDLE_NAME }} \
--release-bundle-version ${{ github.run_number }} \
--predicate ./policy.json \
--predicate-type https://jfrog.com/evidence/approval/v1 \
--project ${{ env.JF_PROJECT }}
jf release-bundle-promote ${{ env.BUNDLE_NAME }} ${{ github.run_number }} PROD \
--signing-key ${{ secrets.GPG_KEY_NAME }} \
--sync=true \
--project ${{ env.JF_PROJECT }}
echo "🚀 Succesfully promote to \`PROD\` environemnt" >> $GITHUB_STEP_SUMMARY
else
echo "Fail promotion policy check" >> $GITHUB_STEP_SUMMARY
exit 1
fi