Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches: [master]
push:
branches: [master]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_INCREMENTAL: 0
CARGO_TERM_COLOR: always

jobs:
fmt:
name: fmt
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Rust toolchain
run: rustup show

- name: Check formatting
run: cargo fmt --all -- --check

clippy:
name: clippy
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Rust toolchain
run: rustup show

- name: Restore Rust cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: clippy

- name: Run Clippy
# The standalone P2P tool is outside the maintained main-node scope.
run: cargo clippy --workspace --all-features --exclude p2p-boot-node --locked -- -D warnings

typos:
name: typos
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Check spelling
uses: crate-ci/typos@v1

test:
name: test
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Rust toolchain
run: rustup show

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Restore Rust cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: tests

- name: Run tests
run: cargo test --workspace --locked --verbose

dependency-audit:
name: dependency-audit
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Rust toolchain
run: rustup show

- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny

- name: Check dependency policy
run: cargo deny check
241 changes: 241 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: Build and Push Docker Image

on:
pull_request:
branches: [master]
paths:
- ".github/workflows/docker-build.yml"
- ".dockerignore"
- "Dockerfile"
- "tools/p2p_boot_node/Dockerfile"
- "Cargo.lock"
- "rust-toolchain.toml"
- "**/Cargo.toml"
- "**/*.rs"
push:
branches: [master]
tags:
- "v*"
# NOTE: GitHub does not evaluate `paths` filters for tag pushes, so v*
# releases always publish regardless of which files changed.
paths:
- ".github/workflows/docker-build.yml"
- ".dockerignore"
- "Dockerfile"
- "tools/p2p_boot_node/Dockerfile"
- "Cargo.lock"
- "rust-toolchain.toml"
- "**/Cargo.toml"
- "**/*.rs"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
REGISTRY_NAMESPACE: us-docker.pkg.dev/evmchain/images
WIF_PROVIDER: projects/790288402401/locations/global/workloadIdentityPools/terraform-pool/providers/github-provider
WIF_SERVICE_ACCOUNT: gar-github-action@evmchain.iam.gserviceaccount.com

jobs:
validate:
name: validate (${{ matrix.image.name }})
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
# Keep this list in sync with the `publish` and `merge` matrices.
image:
- name: catalyst-node
dockerfile: Dockerfile
- name: catalyst-p2p-bootnode
dockerfile: tools/p2p_boot_node/Dockerfile
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Build image without publishing
uses: docker/build-push-action@v7
with:
context: .
file: ${{ matrix.image.dockerfile }}
platforms: linux/amd64
push: false

publish:
name: build ${{ matrix.image.name }} (${{ matrix.platform.id }})
if: github.event_name != 'pull_request'
runs-on: ${{ matrix.platform.runner }}
timeout-minutes: 120
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
image:
- name: catalyst-node
dockerfile: Dockerfile
- name: catalyst-p2p-bootnode
dockerfile: tools/p2p_boot_node/Dockerfile
platform:
- runner: ubuntu-latest
id: linux/amd64
- runner: ubuntu-24.04-arm
id: linux/arm64
steps:
- name: Prepare platform name
run: |
platform="${{ matrix.platform.id }}"
echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV"

- name: Checkout
uses: actions/checkout@v7

- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v3
with:
workload_identity_provider: ${{ env.WIF_PROVIDER }}
service_account: ${{ env.WIF_SERVICE_ACCOUNT }}
token_format: access_token
access_token_lifetime: 3600s
create_credentials_file: false

- name: Log in to Google Artifact Registry
uses: docker/login-action@v4
with:
registry: us-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Extract image metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image.name }}

- name: Build and push by digest
id: build
uses: docker/build-push-action@v7
with:
context: .
file: ${{ matrix.image.dockerfile }}
platforms: ${{ matrix.platform.id }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image.name }},push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
mkdir -p "${RUNNER_TEMP}/digests"
digest="${{ steps.build.outputs.digest }}"
touch "${RUNNER_TEMP}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.image.name }}-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

merge:
name: publish manifest (${{ matrix.image }})
if: github.event_name != 'pull_request'
needs: publish
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
image: [catalyst-node, catalyst-p2p-bootnode]
steps:
- name: Download digests
uses: actions/download-artifact@v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-${{ matrix.image }}-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Extract image metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=tag
type=sha,prefix=sha-

- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v3
with:
workload_identity_provider: ${{ env.WIF_PROVIDER }}
service_account: ${{ env.WIF_SERVICE_ACCOUNT }}
token_format: access_token
access_token_lifetime: 3600s
create_credentials_file: false

- name: Log in to Google Artifact Registry
uses: docker/login-action@v4
with:
registry: us-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}

- name: Create and push manifest list
working-directory: ${{ runner.temp }}/digests
env:
REGISTRY_IMAGE: ${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }}
run: |
set -euo pipefail
shopt -s nullglob
digests=( * )
shopt -u nullglob

if (( ${#digests[@]} == 0 )); then
echo "No digest files found; cannot publish a manifest." >&2
exit 1
fi

mapfile -t image_tags < <(jq -r '.tags[]' <<< "$DOCKER_METADATA_OUTPUT_JSON")
if (( ${#image_tags[@]} == 0 )); then
echo "No image tags resolved; cannot publish a manifest." >&2
exit 1
fi

tag_args=()
for image_tag in "${image_tags[@]}"; do
tag_args+=("-t" "$image_tag")
done

source_args=()
for digest in "${digests[@]}"; do
source_args+=("${REGISTRY_IMAGE}@sha256:${digest}")
done

docker buildx imagetools create "${tag_args[@]}" "${source_args[@]}"

- name: Inspect published image
env:
REGISTRY_IMAGE: ${{ env.REGISTRY_NAMESPACE }}/${{ matrix.image }}
run: docker buildx imagetools inspect "${REGISTRY_IMAGE}:${{ steps.meta.outputs.version }}"
Loading