Skip to content

Java CI with Maven #128

Java CI with Maven

Java CI with Maven #128

Workflow file for this run

# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
#push:
#branches: [ main ]
#pull_request:
#branches: [ main ]
workflow_dispatch:
jobs:
build:
permissions:
security-events: write
id-token: write
contents: read
attestations: write
packages: write
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '17' ]
# outputs:
# my_output: ${{ steps.generate_sbom.outputs.result }}
steps:
- uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'adopt'
cache: maven
- name: Build with Maven Wrapper
run: |
pwd
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
# echo "$(date +"%d.%m.%Y").$BRANCH_NAME.$GITHUB_RUN_NUMBER"
RESULT=$(date +"%d.%m.%Y").$BRANCH_NAME.$GITHUB_RUN_NUMBER
echo $RESULT
./mvnw -B package > app.jar
# - name: Rego Policy
# run: |
# cat <<EOF > policy.rego
# package signature
# allow[msg] {
# input.Data.author_name != "saurav631"
# msg := sprintf("Invalid Git Author: %v", [input.Data])
# }
# allow[msg] {
# input.Data.branch != "main"
# msg := sprintf("Invalid branch name: %v", [input.Data])
# }
# EOF
# # - uses: actions/checkout@v4
# # with:
# # fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
# - name: Read Rego Policy
# run: |
# cat policy.rego
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
# outputs:
# Attestation:
with:
subject-path: ./app.jar
- name: verify jar attesttion
env:
GH_TOKEN: ${{secrets.GH_TOKEN}}
run: |
# gh attestation download app.jar -o github
# wget https://github.com/saurav631/spring-petclinic/attestations/1598170/download -o sigstore.json
# gh attestation verify github --owner saurav631 --bundle sigstore.json
# gh attestation verify app.jar --owner saurav631 --bundle ./saurav631-spring-petclinic-attestation-1598170.sigstore.json --format=json
gh attestation verify app.jar --owner saurav631 --format=json | jq .
# gh attestation verify app.jar --owner saurv631 --bundle application/vnd.dev.sigstore.bundle.v0.3+json --format=json
# gh attestation verify sigstore.json --owner saurav631 --format=json
# - name: Set up JDK 17
# uses: actions/setup-java@v1
# with:
# java-version: 17
# - name: Cache SonarQube packages
# uses: actions/cache@v1
# with:
# path: ~/.sonar/cache
# key: ${{ runner.os }}-sonar
# restore-keys: ${{ runner.os }}-sonar
# - name: Cache Maven packages
# uses: actions/cache@v1
# with:
# path: ~/.m2
# key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
# restore-keys: ${{ runner.os }}-m2
# - name: Build and analyze
# env:
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# SONAR_HOST_URL: http://20.235.200.36:9000/
# run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=PetClinic -Dsonar.projectName='PetClinic'
# - name: Check SonarQube Quality Gate
# run: |
# sleep 10
# STATUS=$(curl -s -u ${{ secrets.SONAR_TOKEN }} "http://20.235.200.36:9000/api/qualitygates/project_status?projectKey=PetClinic" | jq -r '.projectStatus.status')
# echo "Quality Gate Status: $STATUS"
# if [ "$STATUS" != "OK" ]; then
# echo "SonarQube Quality Gate failed"
# exit 1
# fi
# - name: Install & Running TruffleHog
# run: |
# pip install truffleHog
# trufflehog git_url https://github.com/saurav631/spring-petclinic/ --repo_path .
- name: Install Syft
run: |
curl -sSL https://github.com/anchore/syft/releases/download/v0.66.0/syft_0.66.0_linux_amd64.tar.gz | tar xz -C /usr/local/bin syft
- name: Generate SBOM with Syft
# id: generate_sbom
run: |
# echo "result=`syft dir:. -o cyclonedx-json > sbom.json`" >> $GITHUB_ENV
syft dir:. -o cyclonedx-json > sbom.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
- name: Generate SBOM attestation
uses: actions/attest-sbom@v1
with:
subject-path: ./sbom.json
sbom-path: ./sbom.json
- name: verify SBOM attesttion
env:
GH_TOKEN: ${{secrets.GH_TOKEN}}
run: |
# gh attestation verify sbom.json --owner saurav631 --bundle ./sbom.json
gh attestation verify ./sbom.json --owner saurav631 --format=json | jq .
# gh attestation verify app.jar --owner saurav631 --format=json
# gh attestation verify sbom.json --owner saurav631 --bundle ./saurav631-spring-petclinic-attestation-1599265.sigstore.json
# - name: Dependency Scanning with OWASP Dependency-Check
# run: |
# /opt/dependency-check/bin/dependency-check.sh --project my_project --out dependency-check-report --scan .
# - name: Upload Dependency Check Report
# uses: actions/upload-artifact@v3
# with:
# name: dependency-check-report
# path: dependency-check-report
# - name: Scan Docker Images for Vulnerabilities
# run: |
# sudo apt-get update
# sudo apt-get install -y docker.io
# sudo systemctl start docker
# sudo systemctl enable docker
# curl -sSL https://github.com/aquasecurity/trivy/releases/download/v0.36.0/trivy_0.36.0_Linux-64bit.deb -o trivy.deb
# sudo dpkg -i trivy.deb
# trivy image my_microservice:latest
# - name: Deploy Microservices
# run: |
# kubectl apply -f k8s/deployment.yaml
- name: Build Docker Image
run: ./mvnw spring-boot:build-image
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
# username: ${{ secrets.CR_Username }}
username: ${{ github.actor }}
# password: ${{ secrets.CR_Password }}
password: ${{secrets.GH_TOKEN}}
registry: ghcr.io
- name: Tag Docker Image
run: |
docker tag docker.io/library/spring-petclinic:3.3.0-SNAPSHOT ghcr.io/saurav631/spring-petclinic:latest
- name: Push Docker Image
run: |
docker push ghcr.io/saurav631/spring-petclinic:latest
- name: Run Trivy Vulnerability Scanner
uses: aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe
with:
image-ref: 'ghcr.io/saurav631/spring-petclinic:latest'
format: 'template'
template: '@/contrib/sarif.tpl'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy Scan Results to GitHub Security Tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
sign:
name: Sign Container Image
runs-on: ubuntu-latest
needs: build
steps:
- name: Check Out Source Code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Download file artifact
uses: actions/download-artifact@v4
with:
name: sbom
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
# username: ${{ secrets.CR_Username }}
username: ${{github.actor}}
# password: ${{ secrets.CR_Password }}
password: ${{secrets.GH_TOKEN}}
registry: ghcr.io
# - name: Install Cosign CLI
# run: |
# curl -sSL -o /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.1.1/cosign-linux-amd64
# chmod +x /usr/local/bin/cosign
# cosign version
- name: Install Cosign CLI
run: |
curl -sSL -o /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.2.3/cosign-linux-amd64
chmod +x /usr/local/bin/cosign
cosign version
- name: Cosign Help
run: |
cosign verify-attestation --help
# - name: Create Decrypted Signing Key File
# run: |
# echo "${{ secrets.COSIGN_KEY }}" > cosign.key
# - name: Sign Docker Image with Cosign
# run: |
# cosign sign --key cosign.key ghcr.io/saurav631/spring-petclinic:latest
- name: sign container image
run: |
cosign sign --key env://COSIGN_KEY ghcr.io/saurav631/spring-petclinic:latest --yes
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
# - name: Create Public Key File_
# run: echo "${{ secrets.Cosign_Pub }}" > cosign.pub
- name: Public Key Creation
run: |
cosign public-key --key env://COSIGN_KEY > cosign.pub
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Verify Docker Image Signature
run: |
cosign verify --key cosign.pub ghcr.io/saurav631/spring-petclinic:latest | jq . #--insecure-ignore-tlog #--check-claims=false
- name: Attach SBOM
id: attach-sbom
run: |
set -e # Exit on error
# Run the cosign attach sbom command and capture its output
# echo "sbom: ${{ needs.build.outputs.my_output }}"
# output=$(cosign attach sbom --sbom ${{ needs.build.outputs.my_output }} ghcr.io/saurav631/spring-petclinic:latest) || { echo "Failed to run cosign attach sbom"; exit 1; }
# output=$(cosign attach sbom --sbom sbom.json ghcr.io/saurav631/spring-petclinic:latest) || { echo "Failed to run cosign attach sbom"; exit 1; }
output=$(cosign attach sbom --sbom sbom.json ghcr.io/saurav631/spring-petclinic:latest 2>&1) || { echo "Failed to run cosign attach sbom"; exit 1; }
# output=$(cosign attach sbom --sbom sbom.json ghcr.io/saurav631/spring-petclinic:latest) || { echo "Failed to run cosign attach sbom"; exit 1; }
# cosign attest --predicate <FILE> --type <TYPE> --key cosign.key <IMAGE>
echo "cat output --> showing output below"
echo "output: $output"
# Extract the SHA from the output
sbom_filename=$(echo "$output" | grep -oP 'sha256-[\w\d]+\.sbom') || { echo "Failed to extract SBOM filename"; exit 1; }
echo "sbom_filename: $sbom_filename"
# Check if the extraction was successful
if [ -z "$sbom_filename" ]; then
echo "Error: No SBOM filename found in the output"
exit 1
fi
# Set the extracted SHA as an environment variable
echo "SBOM_FILENAME=$sbom_filename" >> $GITHUB_ENV
- name: Sign the SBOM attached with the Image
run: |
set -e # Exit on error
# Use the environment variable to construct the command
if [ -z "$SBOM_FILENAME" ]; then
echo "Error: SBOM_FILENAME environment variable is not set"
exit 1
fi
echo "Signing SBOM with filename: $SBOM_FILENAME"
cosign sign --key env://COSIGN_KEY ghcr.io/saurav631/spring-petclinic:$SBOM_FILENAME --yes || { echo "Failed to sign with SBOM"; exit 1; }
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Verify Sign of SBOM attached with the Image
run: |
set -e # Exit on error
cosign verify --key cosign.pub ghcr.io/saurav631/spring-petclinic:$SBOM_FILENAME | jq . || { echo "Failed to verify SBOM Sign"; exit 1; }
- name: Directly attest SBOM with the Image
run: |
set -e # Exit on error
# output=$(cosign attest --key env://COSIGN_KEY --type cyclonedx --predicate sbom.json ghcr.io/saurav631/spring-petclinic:latest --yes 2>&1) || { echo "Failed to attest sbom with the image"; exit 1; }
output=$(cosign attest --key env://COSIGN_KEY --predicate sbom.json ghcr.io/saurav631/spring-petclinic:latest --yes 2>&1) || { echo "Failed to attest sbom with the image"; exit 1; }
echo "output: $output"
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Verfiy the attested Image
run: |
set -e # Exit on error
# output1=$(cosign verify-attestation --key cosign.pub ghcr.io/saurav631/spring-petclinic:latest | jq -r .payload | base64 -D | jq . 2>&1) || { echo "Failed to verify the attested image"; exit 1; }
output1=$(cosign verify-attestation --key cosign.pub ghcr.io/saurav631/spring-petclinic:latest | jq . 2>&1) || { echo "Failed to verify the attested image"; exit 1; }
echo "output: $output1"
# - name: Sign SBOM
# run: |
# # set -e # Exit on error
# cosign sign-blob --yes --key env://COSIGN_KEY sbom.json --bundle cosign.bundle 2>&1 #| jq -r .payload | base64 --decode | jq . 2>&1 #|| { echo "Failed to sign the blob"; exit 1; }
# shell: bash
# env:
# COSIGN_KEY: ${{secrets.Cosign_Key}}
# COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
# - name: Push Signed SBOM to Registry
# run: |
# # set -e # Exit on error
# docker push ghcr.io/saurav631/sbom.json
- name: upload Signed SBOM to Github Registry
run: |
# set -e # Exit on error
# output2=$(cosign upload blob -f cosign.bundle ghcr.io/saurav631/spring-petclinic:latest 2>&1) #| jq .) #|| { echo "Failed to upload the blob to the Registry"; exit 1; }
# output2=$(cosign upload blob -f sbom.json ghcr.io/saurav631/spring-petclinic:latest 2>&1) #| jq .) #|| { echo "Failed to upload the blob to the Registry"; exit 1; }
output2=$(cosign upload blob -f sbom.json ghcr.io/saurav631/sbom 2>&1) #| jq .)
echo "output: $output2"
sbom_file=$(echo "$output2" | grep -oP 'sha256:[\w\d]{64}' | head -n 1) || { echo "Failed to extract SBOM filename"; exit 1; }
echo "sbom_file: $sbom_file"
# Set the extracted SHA as an environment variable
# echo "SBOM_FILE=$sbom_file" >> $GITHUB_ENV
- name: Sign the SBOM file using github url
run: |
cosign sign --key env://COSIGN_KEY ghcr.io/saurav631/sbom --yes
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Verify the signature of the SBOM file
run: |
cosign verify --key cosign.pub ghcr.io/saurav631/sbom
# - name: Download SBOM Digest Locally
# run: |
# # set -e # Exit on error
# curl -L ghcr.io/saurav631/demo/sbom.json/blobs/$SBOM_FILE
# - name: Verify SBOM Uploaded to Image Repo
# run: |
# cosign verify-blob sbom.json --bundle cosign.bundle --certificate-github-workflow-name=.github/workflows/maven-build.yml@refs/heads/main --certificate-github-workflow-ref=refs/heads/main --certificate-github-workflow-repository=https://github.com/saurav631/spring-petclinic --certificate-github-workflow-trigger=workflow_dispatch --key cosign.pub 2>&1 #| jq -r .payload | base64 --decode | jq .
# # shell: bash
# # env:
# # COSIGN_KEY: ${{secrets.Cosign_Key}}
# # COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Fetch commit details
run: |
# Get the commit ID
COMMIT_ID=$(git rev-parse HEAD)
# Get the branch name
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
# Get the author name and email
AUTHOR_NAME=$(git log -1 --pretty=format:'%an')
AUTHOR_EMAIL=$(git log -1 --pretty=format:'%ae')
# Get the pull request number from GitHub context if it's a PR
if [ -n "${{ github.event.pull_request.number }}" ]; then
PR_NUMBER="${{ github.event.pull_request.number }}"
else
PR_NUMBER="Not applicable"
fi
# Get the GitHub repository URL
REPO_URL="https://github.com/${{ github.repository }}"
# echo "Commit ID: $COMMIT_ID"
# echo "Branch Name: $BRANCH_NAME"
# echo "Author Name: $AUTHOR_NAME"
# echo "Author Email: $AUTHOR_EMAIL"
# echo "Pull Request Number: $PR_NUMBER"
# echo "GitHub URL: $REPO_URL"
# Create JSON output
OUTPUT=$(jq -n \
--arg commit_id "$COMMIT_ID" \
--arg author_name "$AUTHOR_NAME" \
--arg author_email "$AUTHOR_EMAIL" \
--arg branch "$BRANCH_NAME" \
--arg uri "$REPO_URL" \
'{
commit_id: $commit_id,
author_name: $author_name,
author_email: $author_email,
branch: $branch,
uri: $uri
}')
# Save JSON output to a file
echo "$OUTPUT" > output.json
# Print the contents of the JSON file
cat output.json
- name: Upload JSON file
uses: actions/upload-artifact@v3
with:
name: git-details
path: output.json
last_job:
permissions:
security-events: write
id-token: write
contents: read
attestations: write
packages: write
runs-on: ubuntu-latest
needs: sign
# strategy:
# matrix:
# java: [ '17' ]
steps:
- name: Check Out Source Code
uses: actions/checkout@v3
- name: Download output.json file artifact
uses: actions/download-artifact@v3
with:
name: git-details
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
username: ${{github.actor}}
password: ${{secrets.GH_TOKEN}}
registry: ghcr.io
- name: Install Cosign CLI
run: |
curl -sSL -o /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.2.3/cosign-linux-amd64
chmod +x /usr/local/bin/cosign
cosign version
- name: Public Key Creation
run: |
cosign public-key --key env://COSIGN_KEY > cosign.pub
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Attestation using Predicate
run: |
# cosign attest --key env://COSIGN_KEY --predicate output.json ghcr.io/saurav631/spring-petclinic:latest --yes
cosign attest --key env://COSIGN_KEY --predicate output.json ghcr.io/saurav631/sbom --yes
# $(cosign attest --key env://COSIGN_KEY --predicate output.json ghcr.io/saurav631/spring-petclinic:latest --yes 2>&1) || { echo "Failed to attest predicate with the image"; exit 1; }
# $(cat output.json | cosign attest --predicate - ghcr.io/saurav631/spring-petclinic:latest --yes 2>&1) || { echo "Failed to attest predicate with the image"; exit 1; }
shell: bash
env:
COSIGN_KEY: ${{secrets.Cosign_Key}}
COSIGN_PASSWORD: ${{secrets.Cosign_Key_Password}}
- name: Rego Policy
run: |
cat <<EOF > policy.rego
package signature
allow[msg] {
input.Data.author_name != "saurav631"
msg := sprintf("Invalid Git Author: %v", [input.Data])
}
allow[msg] {
input.Data.branch != "main"
msg := sprintf("Invalid branch name: %v", [input.Data])
}
- name: Read Rego Policy
run: |
cat policy.rego
- name: Verify Predicate Attestation
run: |
cosign verify-attestation --policy policy.rego --certificate-github-workflow-name=.github/workflows/maven-build.yml@refs/heads/main --certificate-github-workflow-ref=refs/heads/main --certificate-github-workflow-repository=https://github.com/saurav631/spring-petclinic --certificate-github-workflow-trigger=workflow_dispatch --key cosign.pub ghcr.io/saurav631/sbom 2>&1 | jq -r .payload | base64 --decode | jq .
# cosign verify-attestation --certificate-github-workflow-name=.github/workflows/maven-build.yml@refs/heads/main --certificate-github-workflow-ref=refs/heads/main --certificate-github-workflow-repository=https://github.com/saurav631/spring-petclinic --certificate-github-workflow-trigger=workflow_dispatch --key cosign.pub ghcr.io/saurav631/sbom | jq -r .payload | base64 --decode | jq .
# cosign verify-attestation --certificate-github-workflow-name=.github/workflows/maven-build.yml@refs/heads/main --certificate-github-workflow-ref=refs/heads/main --certificate-github-workflow-repository=https://github.com/saurav631/spring-petclinic --certificate-github-workflow-trigger=workflow_dispatch --key cosign.pub ghcr.io/saurav631/spring-petclinic:latest | jq -r .payload | base64 --decode | jq .
# $(cosign verify-attestation --key cosign.pub ghcr.io/saurav631/spring-petclinic:latest 2>&1) || { echo "Failed to verify the attested image"; exit 1; }