Skip to content

chore: Update release_binaries.yml workflow #42

chore: Update release_binaries.yml workflow

chore: Update release_binaries.yml workflow #42

Workflow file for this run

name: Release Docker
# Trigger on all push events, new semantic version tags, and all PRs
on:
push:
branches-ignore:
- '**'
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
pull_request:
workflow_dispatch:
env:
GITHUB_REG: ghcr.io
MAINTAINER: ${{ github.repository_owner }}
DESCRIPTION: "${{ github.repository_owner }} repository ${{ github.repository }}"
jobs:
prepare-env:
runs-on: "ubuntu-latest"
outputs:
repo_owner: ${{ steps.setting_env.outputs.repo_owner }}
output_short_sha: ${{ steps.setting_env.outputs.short_sha }}
output_image_name: ${{ steps.setting_env.outputs.image_name }}
build_for_pr: ${{ steps.setting_logic.outputs.build_for_pr }}
build_for_merge: ${{ steps.setting_logic.outputs.build_for_merge }}
not_a_fork: ${{ steps.setting_logic.outputs.not_a_fork }}
steps:
- name: Checkout
uses: "actions/checkout@v4"
- name: Add vars to ENV
id: setting_env
run: |
# Extract both the repository owner and repository name
# According to docs, github.repository is in the format of owner/repo, not just repo
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
REPO_OWNER=$(echo "${{ github.repository }}" | awk -F'/' '{print $1}' | tr '[:upper:]' '[:lower:]')
REPO_NAME=$(echo "${{ github.repository }}" | awk -F'/' '{print $2}' | tr '[:upper:]' '[:lower:]')
# Check repo name for .github use to test this workflow
if [[ $REPO_NAME == ".github" ]]; then
# Remove the leading . to avoid failing the character check
REPO_NAME="github"
fi
# Log variables for debugging
echo "Repository Owner: $REPO_OWNER"
echo "Repository Name: $REPO_NAME"
echo "INPUT PACKAGE NAME: ${{ inputs.packageName }}"
# Set environment variables and outputs
echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV
echo "repo_owner=$REPO_OWNER" >> "$GITHUB_OUTPUT"
echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
echo "short_sha=`echo ${GITHUB_SHA} | cut -c1-8`" >> "$GITHUB_OUTPUT"
if [[ "${{ inputs.packageName }}" == "${{ github.repository }}" ]]; then
# If a user submitted package name that has the naming containing
# both the repository owner and repository name, we fail
# e.g: inputs.packageName = "utnet-org/unc-node" is not allowed
echo "------------------------------------------------------------"
echo "ERROR: Package name not valid! => [ ${{ inputs.packageName }} ]"
echo "Don't use the repository owner and repository name in the package name."
echo "------------------------------------------------------------"
exit 1
fi
# Set the default package name to the repository name
PACKAGE_NAME=$REPO_NAME
# If there is a user submitted package name, use it
if [[ -n "${{ inputs.packageName }}" ]]; then
PACKAGE_NAME=$(echo "${{ inputs.packageName }}" | tr '[:upper:]' '[:lower:]')
fi
# validate the package name characters
if [[ ! $PACKAGE_NAME =~ ^[A-Za-z0-9\-]+$ ]]; then
echo "------------------------------------------------------------"
echo "ERROR: Package name not valid! => [ $PACKAGE_NAME ]"
echo "ONLY can use: A-Za-z0-9\-"
echo "------------------------------------------------------------"
exit 1
fi
# Log the package name for debugging
echo "PACKAGE_NAME: $PACKAGE_NAME"
# Set environment variables and outputs
echo "IMAGE_NAME=$PACKAGE_NAME" >> $GITHUB_ENV
echo "image_name=$PACKAGE_NAME" >> "$GITHUB_OUTPUT"
# The key logic that we want to determine is whether or not we are working
# on a fork and if this is a pull request or merge to main.
#
# We care about forks because of github's security policies that prevent
# forks from pushing images. So we only want to build images on forks
#
# The distinction between pull requests and merges to main is that on pull
# requests we want a single image available quickly for testing. On merges
# to main we want all the images built and are ok waiting longer to ensure
# there are not bugs.
- name: Add logic to ENV
id: setting_logic
run: |
# yamllint disable
echo "build_for_pr=${{ github.event_name == 'pull_request' }}" >> "$GITHUB_OUTPUT"
echo "build_for_merge=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }}" >> "$GITHUB_OUTPUT"
echo "not_a_fork=${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}" >> "$GITHUB_OUTPUT"
# yamllint enable
# Log the key inputs to the logic as well a the outputs. We check that
# build_for_pr and build_for_merge are never equal when they are true as that
# would indicate a bug. If they are both false, this is ok, as this is the
# case on pushing commits to a PR.
logic-check:
needs: prepare-env
runs-on: "ubuntu-latest"
steps:
- name: Log logic
run: |
echo "github.event_name: ${{ github.event_name }}"
echo "github.ref: ${{ github.ref }}"
echo "head repo: ${{ github.event.pull_request.head.repo.full_name }}"
echo "base repo: ${{ github.event.pull_request.base.repo.full_name }}"
echo "build_for_pr: ${{ needs.prepare-env.outputs.build_for_pr }}"
echo "build_for_merge: ${{ needs.prepare-env.outputs.build_for_merge }}"
echo "not_a_fork: ${{ needs.prepare-env.outputs.not_a_fork }}"
- name: Check logic
if: |
(needs.prepare-env.outputs.build_for_pr == needs.prepare-env.outputs.build_for_merge)
&& needs.prepare-env.outputs.build_for_pr != 'false'
run: |
echo "Failing step due to build_for_pr == build_for_merge"
exit 1
docker-security:
needs: ["prepare-env", "logic-check"]
runs-on: "ubuntu-latest"
steps:
- name: Checkout
uses: "actions/checkout@v4"
- name: Build
uses: docker/build-push-action@v5
env:
OUTPUT_SHORT_SHA: ${{ needs.prepare-env.outputs.output_short_sha }}
OUTPUT_IMAGE_NAME: ${{ needs.prepare-env.outputs.output_image_name }}
with:
context: .
push: false
platforms: linux/amd64
# we're building the container before the scan, use the short sha tag
# for referring to it later
tags: ${{ env.OUTPUT_IMAGE_NAME }}:${{ env.OUTPUT_SHORT_SHA }}
file: ./Dockerfile
- name: Run Trivy vulnerability scanner
# source: https://github.com/aquasecurity/trivy-action
# https://github.com/marketplace/actions/aqua-security-trivy
uses: aquasecurity/trivy-action@master
env:
OUTPUT_SHORT_SHA: ${{ needs.prepare-env.outputs.output_short_sha }}
OUTPUT_IMAGE_NAME: ${{ needs.prepare-env.outputs.output_image_name }}
with:
# here we use the local tag that we've built before
image-ref: "${{ env.OUTPUT_IMAGE_NAME }}:${{ env.OUTPUT_SHORT_SHA }}"
format: "table"
#exit-code: '1' # uncomment to stop the CI if the scanner fails
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
docker-build:
name: docker-build (${{ matrix.registry.name }}; ${{ matrix.registry.registry-url }}/${{ matrix.registry.registry-owner }}/${{ needs.prepare-env.outputs.output_image_name }})
runs-on: "ubuntu-latest"
# wait until the jobs are finished.
needs: ["prepare-env", "logic-check", "docker-security"]
# We only want to run this step if one of the build flags is true. We don't
# run if both logic flags are false. This is the case for push events on PR
# commits. The logic-check job protects us from the case of both build flags
# being equal to true.
if: |
needs.prepare-env.outputs.build_for_pr == 'true'
|| needs.prepare-env.outputs.build_for_merge == 'true'
permissions:
contents: write
packages: write
strategy:
matrix:
# run-on-pr is used to skip running registries that are expected to fail
# due to github permission issues with org wide secrets.
registry:
# - name: DockerHub
# user-secret: DOCKERHUB_USERNAME
# token-secret: DOCKER_PAT_TOKEN
# registry-url: docker.io
# registry-owner: utnet-org
# run-on-pr: "false"
- name: GHCR
user-secret: ${{ github.repository_owner }}
token-secret: GITHUB_TOKEN
registry-url: ghcr.io
registry-owner: ${{ needs.prepare-env.outputs.repo_owner }}
run-on-pr: "true"
fail-fast: false
steps:
- name: Check run conditions
id: run_check
# We only want to run when the registry is able to run on PR or if it is a merge event
run: echo "run=${{ matrix.registry.run-on-pr == needs.prepare-env.outputs.build_for_pr || needs.prepare-env.outputs.build_for_merge == 'true'}}" >> "$GITHUB_OUTPUT"
- name: Checkout
if: ${{ steps.run_check.outputs.run == 'true'}}
uses: "actions/checkout@v4"
- name: Login to ${{ matrix.registry.name }}
if: ${{ steps.run_check.outputs.run == 'true'}}
uses: docker/login-action@v3
with:
registry: ${{ matrix.registry.registry-url }}
username: ${{ matrix.registry.registry-url == env.GITHUB_REG && matrix.registry.user-secret || secrets[matrix.registry.user-secret] }}
password: ${{ secrets[matrix.registry.token-secret] }}
- name: Extract Docker Metadata
if: ${{ steps.run_check.outputs.run == 'true'}}
id: meta
uses: docker/metadata-action@v5
env:
OUTPUT_SHORT_SHA: ${{ needs.prepare-env.outputs.output_short_sha }}
OUTPUT_IMAGE_NAME: ${{ needs.prepare-env.outputs.output_image_name }}
with:
images: ${{ matrix.registry.registry-url }}/${{ matrix.registry.registry-owner }}/${{ env.OUTPUT_IMAGE_NAME }}
# yamllint disable
labels: |
maintainer=${{ env.MAINTAINER }}
commitUrl=https://github.com/${{ github.repository }}/commit/${{ github.sha }}
dockerPull=docker pull ${{ matrix.registry.registry-url }}/${{ matrix.registry.registry-owner }}/${{ env.OUTPUT_IMAGE_NAME }}:${{ env.OUTPUT_SHORT_SHA }}
org.opencontainers.image.description=${{ env.DESCRIPTION }}
tags: |
# output minimal (short sha)
type=raw,value={{sha}}
# output v0.2.1/v*-* (or sha of no tag)
type=semver,pattern={{raw}}
# pull request event
type=ref,enable=true,prefix=pr-,suffix=,event=pr
# yamllint enable
- name: Set up QEMU
if: ${{ steps.run_check.outputs.run == 'true'}}
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: ${{ steps.run_check.outputs.run == 'true'}}
uses: docker/setup-buildx-action@v3
# Build and Publish images on main, master, and versioned branches.
#
# The reason we split out these steps into 2 is for better handling of
# forks when building amd64 images and to enable faster availability of
# the amd64 image since building the arm64 image takes significantly
# longer.
- name: "Merge on Main Trigger: Build and Push All Docker Images"
if: ${{ needs.prepare-env.outputs.build_for_merge == 'true' && steps.run_check.outputs.run == 'true'}}
uses: docker/build-push-action@v5
env:
OUTPUT_SHORT_SHA: ${{ needs.prepare-env.outputs.output_short_sha }}
OUTPUT_IMAGE_NAME: ${{ needs.prepare-env.outputs.output_image_name }}
with:
context: .
platforms: linux/arm64,linux/amd64
provenance: false
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: ./Dockerfile
# Build amd64 images always, and publish when it is not a fork. The Github
# security model prevents forks from pushing to the registry so we can
# only push if the branch/PR is not generated from a fork. Even though
# forks can't push, we still want to try and build the image to catch
# bugs. For testing purposes we only need an amd64 image.
- name: "Pull Request Trigger: Build and Push amd64 Docker Image"
if: ${{ needs.prepare-env.outputs.build_for_pr == 'true' && steps.run_check.outputs.run == 'true'}}
uses: docker/build-push-action@v5
env:
OUTPUT_SHORT_SHA: ${{ needs.prepare-env.outputs.output_short_sha }}
OUTPUT_IMAGE_NAME: ${{ needs.prepare-env.outputs.output_image_name }}
with:
context: .
platforms: linux/amd64
provenance: false
# Only push if the head and base repos match, meaning it is not a fork
push: ${{ needs.prepare-env.outputs.not_a_fork == 'true' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: ./Dockerfile