@hyperlane-xyz/core
Version:
Core solidity contracts for Hyperlane
313 lines (281 loc) • 12.4 kB
YAML
name: Build and Publish Chainlink
description: A composite action that allows building and publishing signed chainlink images.
inputs:
# Inputs for publishing
publish:
description: When set to the string boolean value of "true", the resulting built image will be published
default: "false"
required: false
dockerfile:
description: Path to the Dockerfile (relative to the repo root)
default: core/chainlink.Dockerfile
required: false
dockerhub_username:
description: Username for Docker Hub to avoid rate limits when pulling public images
required: false
dockerhub_password:
description: Password for Docker Hub to avoid rate limits when pulling public images
required: false
ecr-hostname:
description: The ECR registry scope
default: public.ecr.aws
required: false
ecr-image-name:
description: |
The image name with path, in the format of `[registry]/repository`. For private ECR repos the registry name is optional, where for public repos, it is required.
Eg. Public ECR repo `chainlink` and registry alias `chainlinklabs` should be `chainlinklabs/chainlink`. For a private ECR repo `chainlink` the image name should be `chainlink`
default: chainlink/chainlink
required: false
ecr-tag-suffix:
description: Docker image tag suffix
required: false
git-commit-sha:
description: Git commit SHA used as metadata when building the application (appears in logs)
default: ${{ github.event.pull_request.head.sha || github.sha }}
required: false
aws-role-to-assume:
description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action
required: false
aws-role-duration-seconds:
description: The duration of the role assumed
required: false
aws-region:
description: The AWS region the ECR repository is located in, should only be needed for public ECR repositories, used in configuring docker/login-action
required: false
# Inputs for signing
sign-images:
description: When set to the string boolean value of "true", the resulting build image will be signed
default: "false"
required: false
cosign-private-key:
description: The private key to be used with cosign to sign the image
required: false
cosign-public-key:
description: The public key to be used with cosign for verification
required: false
cosign-password:
description: The password to decrypt the cosign private key needed to sign the image
required: false
sign-method:
description: Build image will be signed using keypair or keyless methods
default: "keypair"
required: true
verify-signature:
description: When set to the string boolean value of "true", the resulting build image signature will be verified
default: "false"
required: false
outputs:
docker-image-tag:
description: The docker image tag that was built and pushed
value: ${{ steps.save-non-root-image-name-env.outputs.image-tag }}
docker-image-digest:
description: The docker image digest that was built and pushed
value: ${{ steps.save-non-root-image-name-env.outputs.image-digest }}
runs:
using: composite
steps:
- name: Set shared variables
shell: bash
# See https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#multiline-strings
run: |
SHARED_IMAGES=${{ inputs.ecr-hostname }}/${{ inputs.ecr-image-name }}
SHARED_TAG_LIST=$(cat << EOF
type=ref,event=branch,suffix=${{ inputs.ecr-tag-suffix }}
type=semver,pattern={{version}},suffix=${{ inputs.ecr-tag-suffix }}
type=sha,format=short,suffix=${{ inputs.ecr-tag-suffix }}
EOF
)
SHARED_BUILD_ARGS=$(cat << EOF
COMMIT_SHA=${{ inputs.git-commit-sha }}
EOF
)
echo "shared-images<<EOF" >> $GITHUB_ENV
echo "$SHARED_IMAGES" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "shared-tag-list<<EOF" >> $GITHUB_ENV
echo "$SHARED_TAG_LIST" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "shared-build-args<<EOF" >> $GITHUB_ENV
echo "$SHARED_BUILD_ARGS" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- if: inputs.publish == 'true'
# Log in to AWS for publish to ECR
name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
with:
role-to-assume: ${{ inputs.aws-role-to-assume }}
role-duration-seconds: ${{ inputs.aws-role-duration-seconds }}
aws-region: ${{ inputs.aws-region }}
mask-aws-account-id: true
role-session-name: build-sign-publish-chainlink
- if: inputs.publish == 'true'
name: Login to ECR
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: ${{ inputs.ecr-hostname }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
- name: Generate docker metadata for root image
id: meta-root
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
env:
DOCKER_METADATA_PR_HEAD_SHA: "true"
with:
# list of Docker images to use as base name for tags
images: ${{ env.shared-images }}
# XXX: DO NOT USE SHARED TAGS HERE
tags: |
type=ref,event=branch,suffix=${{ inputs.ecr-tag-suffix }}-root
type=semver,pattern={{version}},suffix=${{ inputs.ecr-tag-suffix }}-root
type=sha,format=short,suffix=${{ inputs.ecr-tag-suffix }}-root
# To avoid rate limiting from Docker Hub, we login with a paid user account.
- name: Login to Docker Hub
if: inputs.dockerhub_username && inputs.dockerhub_password
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
username: ${{ inputs.dockerhub_username }}
password: ${{ inputs.dockerhub_password }}
- name: Build and push root docker image
id: buildpush-root
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
with:
push: ${{ inputs.publish }}
context: .
load: ${{ contains(inputs.publish, false) }}
tags: ${{ steps.meta-root.outputs.tags }}
labels: ${{ steps.meta-root.outputs.labels }}
file: ${{ inputs.dockerfile }}
build-args: |
CHAINLINK_USER=root
${{ env.shared-build-args }}
- name: Save root image name in GITHUB_ENV
id: save-root-image-name-env
shell: sh
run: |
IMAGES_NAME_RAW=${{ fromJSON(steps.buildpush-root.outputs.metadata)['image.name'] }}
IMAGE_NAME=$(echo "$IMAGES_NAME_RAW" | cut -d"," -f1)
echo "root_image_name=${IMAGE_NAME}" >> $GITHUB_ENV
- name: Generate docker metadata for non-root image
id: meta-nonroot
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
env:
DOCKER_METADATA_PR_HEAD_SHA: "true"
with:
flavor: |
latest=auto
prefix=
suffix=
images: ${{ env.shared-images }}
tags: ${{ env.shared-tag-list }}
# To avoid rate limiting from Docker Hub, we login with a paid user account.
- name: Login to Docker Hub
if: inputs.dockerhub_username && inputs.dockerhub_password
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
username: ${{ inputs.dockerhub_username }}
password: ${{ inputs.dockerhub_password }}
- name: Build and push non-root docker image
id: buildpush-nonroot
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
with:
push: ${{ inputs.publish }}
context: .
load: ${{ contains(inputs.publish, false) }}
tags: ${{ steps.meta-nonroot.outputs.tags }}
labels: ${{ steps.meta-nonroot.outputs.labels }}
file: ${{ inputs.dockerfile }}
build-args: |
CHAINLINK_USER=chainlink
${{ env.shared-build-args }}
- name: Save non-root image name in GITHUB_ENV and GITHUB_STEP_SUMMARY
id: save-non-root-image-name-env
shell: sh
run: |
IMAGES_NAME_RAW=${{ fromJSON(steps.buildpush-nonroot.outputs.metadata)['image.name'] }}
IMAGE_DIGEST=${{ fromJSON(steps.buildpush-nonroot.outputs.metadata)['containerimage.digest'] }}
IMAGE_NAME=$(echo "$IMAGES_NAME_RAW" | cut -d"," -f1)
IMAGE_TAG=$(echo "$IMAGES_NAME_RAW" | cut -d":" -f2)
echo "nonroot_image_name=${IMAGE_NAME}" >> $GITHUB_ENV
echo '### Docker Image' >> $GITHUB_STEP_SUMMARY
echo "Image Name: ${IMAGE_NAME}" >> $GITHUB_STEP_SUMMARY
echo "Image Digest: ${IMAGE_DIGEST}" >> $GITHUB_STEP_SUMMARY
echo "image-tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
echo "image-digest=${IMAGE_DIGEST}" >> $GITHUB_OUTPUT
- name: Check if non-root image runs as root
id: check-nonroot-runs-root
shell: sh
env:
PUBLISH: ${{ inputs.publish }}
run: |
echo "Fail build if non-root image runs as user: root"
# if we're publishing the image, it doesn't get loaded into the local docker daemon
# so we need to pull the image into our daemon
if [ $PUBLISH = "true" ]; then
docker pull "${nonroot_image_name}"
fi
docker inspect "${nonroot_image_name}" | jq -r '.[].Config.User' | ( ! grep "root" )
- if: inputs.sign-images == 'true'
name: Install cosign
uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0
with:
cosign-release: "v1.6.0"
- if: inputs.sign-images == 'true' && inputs.sign-method == 'keypair'
name: Sign the published root Docker image using keypair method
shell: sh
env:
COSIGN_PASSWORD: "${{ inputs.cosign-password }}"
run: |
echo "${{ inputs.cosign-private-key }}" > cosign.key
cosign sign --key cosign.key "${{ env.root_image_name }}"
rm -f cosign.key
- if: inputs.verify-signature == 'true' && inputs.sign-method == 'keypair'
name: Verify the signature of the published root Docker image using keypair
shell: sh
run: |
echo "${{ inputs.cosign-public-key }}" > cosign.key
cosign verify --key cosign.key "${{ env.root_image_name }}"
rm -f cosign.key
- if: inputs.sign-images == 'true' && inputs.sign-method == 'keyless'
name: Sign the published root Docker image using keyless method
shell: sh
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign "${{ env.root_image_name }}"
- if: inputs.verify-signature == 'true' && inputs.sign-method == 'keyless'
name: Verify the signature of the published root Docker image using keyless
shell: sh
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign verify "${{ env.root_image_name }}"
- if: inputs.sign-images == 'true' && inputs.sign-method == 'keypair'
name: Sign the published non-root Docker image using keypair method
shell: sh
env:
COSIGN_PASSWORD: "${{ inputs.cosign-password }}"
run: |
echo "${{ inputs.cosign-private-key }}" > cosign.key
cosign sign --key cosign.key "${{ env.nonroot_image_name }}"
rm -f cosign.key
- if: inputs.verify-signature == 'true' && inputs.sign-method == 'keypair'
name: Verify the signature of the published non-root Docker image using keypair
shell: sh
run: |
echo "${{ inputs.cosign-public-key }}" > cosign.key
cosign verify --key cosign.key "${{ env.nonroot_image_name }}"
rm -f cosign.key
- if: inputs.sign-images == 'true' && inputs.sign-method == 'keyless'
name: Sign the published non-root Docker image using keyless method
shell: sh
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign "${{ env.nonroot_image_name }}"
- if: inputs.verify-signature == 'true' && inputs.sign-method == 'keyless'
name: Verify the signature of the published non-root Docker image using keyless
shell: sh
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign verify "${{ env.nonroot_image_name }}"