diff --git a/.github/actions/docker-build-and-push/action.yaml b/.github/actions/docker-build-and-push/action.yaml deleted file mode 100644 index 0bdc8d6..0000000 --- a/.github/actions/docker-build-and-push/action.yaml +++ /dev/null @@ -1,69 +0,0 @@ -name: 'Build Docker Image' -description: '' - -inputs: - registry_username: - description: 'Username for Artifactory' - required: true - registry_password: - description: 'Password for Artifactory' - required: true - image_reportory: - description: 'Repository name' - required: true - image_name: - description: 'Name of the image' - required: true - image_tag: - description: 'Tag of the image' - required: true - platforms: - description: 'Comma-separated list of platforms (e.g., linux/amd64,linux/arm64)' - required: true - cache_from: - description: 'List of external cache sources (e.g., type=local,src=path/to/dir)' - default: type=gha - required: false - cache_to: - description: 'List of cache export destinations (e.g., type=local,dest=path/to/dir)' - default: type=gha,mode=max - required: false - add_tag_latest: - description: 'Additionally push with latest tag' - required: false - default: 'false' - -runs: - using: "composite" - steps: - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - registry: ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }} - username: ${{ secrets.ARTIFACTORY_ANGKOR_USERNAME }} - password: ${{ secrets.ARTIFACTORY_ANGKOR_TOKEN_DEVELOPER }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Generate image tags - shell: bash - run: | - BUILD_TAGS="${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ inputs.image_tag }}" - if [[ "${{ inputs.add_tag_latest }}" == "true" ]]; then - BUILD_TAGS="${BUILD_TAGS}\n${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:latest" - fi - echo "BUILD_TAGS=${BUILD_TAGS}" >> $GITHUB_ENV - - - name: Build and push - id: build - uses: docker/build-push-action@v6 - with: - push: true - platforms: ${{ inputs.platforms }} - tags: ${{ env.BUILD_TAGS }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/actions/get-group-topic/action.yaml b/.github/actions/get-group-topic/action.yaml deleted file mode 100644 index f40328c..0000000 --- a/.github/actions/get-group-topic/action.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: 'Get Group Topic' -description: 'Gets the group name from repository topics (angkor, modular, nubia, research, core)' - -inputs: - allowed_topics: - description: 'Space-separated list of allowed topics' - default: 'angkor modular nubia research core' - required: true - -outputs: - group_name: - description: 'The matched group name from repository topics' - value: ${{ steps.topics.outputs.result }} - -runs: - using: "composite" - steps: - - name: Get Repository Topics - id: topics - shell: bash - run: | - # Convert space-separated topics to grep pattern - pattern="^($(echo "${{ inputs.allowed_topics }}" | tr ' ' '|'))\$" - echo "Allowed topics pattern: $pattern" - - echo "Fetching repository topics..." - all_topics=$(gh api repos/${{ github.repository }}/topics --jq '.names[]') - echo "Repository topics: $all_topics" - - group_name=$(gh api repos/${{ github.repository }}/topics --jq '.names[]' | grep -E "$pattern" || echo "") - - if [ -z "$group_name" ]; then - echo "Error: Repository must have one of these topics:" - echo "${{ inputs.allowed_topics }}" | tr ' ' '\n' - exit 1 - fi - echo "Found matching topic: $group_name" - echo "result=$group_name" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ github.token }} \ No newline at end of file diff --git a/.github/actions/jfrog-build-publish/action.yaml b/.github/actions/jfrog-build-publish/action.yaml deleted file mode 100644 index cd083ae..0000000 --- a/.github/actions/jfrog-build-publish/action.yaml +++ /dev/null @@ -1,69 +0,0 @@ -name: 'Publish build-info to JFrog' -description: 'Collects information about the build and publishes it to JFrog' - -inputs: - jfrog_project: - description: 'Key of the JFrog project' - required: true - image_reportory: - description: 'Repository name' - required: true - image_name: - description: 'Name of the image' - required: true - image_tag: - description: 'Tag of the image' - required: true - platforms: - description: 'Comma-separated list of platforms (e.g., linux/amd64,linux/arm64)' - required: true - -runs: - using: composite - steps: - - name: Install JFrog CLI - uses: jfrog/setup-jfrog-cli@v4 - env: - JF_URL: ${{ vars.JFROG_URL }} - JF_PROJECT: ${{ inputs.jfrog_project }} - with: - oidc-provider-name: github-nethermindeth - - - name: JFrog build add context - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ inputs.image_tag }}-${{ github.run_number }} - shell: bash - run: | - jf rt build-collect-env - jf rt build-add-git - - - name: JFrog build add images - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ inputs.image_tag }}-${{ github.run_number }} - shell: bash - run: | - # Pull image manifest - docker manifest inspect ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ inputs.image_tag }} > manifest.json - - # Iterate over platforms - platforms=$(echo ${{ inputs.platforms }} | tr ',' ' ') - for platform in $platforms; do - os=$(echo $platform | cut -d'/' -f1) - arch=$(echo $platform | cut -d'/' -f2) - digest=$(jq -r \ - --arg os "${os}" \ - --arg arch "${arch}" \ - '.manifests[] | select(.platform.os==$os and .platform.architecture==$arch) | .digest' manifest.json) - echo "${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ inputs.image_tag }}@${digest}" > image-file - jf rt build-docker-create --image-file=image-file ${{ inputs.image_reportory }} - done - - - name: JFrog build publish - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ inputs.image_tag }}-${{ github.run_number }} - shell: bash - run: | - jf rt build-publish diff --git a/.github/workflows/docker-build-push-dockerhub.yaml b/.github/workflows/docker-build-push-dockerhub.yaml new file mode 100644 index 0000000..89616b4 --- /dev/null +++ b/.github/workflows/docker-build-push-dockerhub.yaml @@ -0,0 +1,106 @@ +on: + workflow_call: + inputs: + repo_name: + description: "Name of the repository to publish to" + type: string + required: false + default: "nethermindeth" + image_name: + description: "Name of the image to publish. Defaults to the repository name." + type: string + required: false + default: "${{ github.event.repository.name }}" + push: + description: "Whether or not to push to Artifactory" + type: boolean + default: true + required: false + context: + description: "Build's context is the set of files located in the specified PATH or URL" + type: string + default: "." + required: false + platforms: + description: "Platforms to build for (comma-separated)" + type: string + default: "linux/amd64,linux/arm64" + required: false + setup-qemu: + description: "Set up QEMU" + type: boolean + default: false + required: false + dockerfile_path: + description: "Path to Dockerfile" + type: string + default: "Dockerfile" + required: false + additional_tags: + description: "Additional tags to apply (comma-separated)" + type: string + default: "" + required: false + docker_secrets: + description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" + type: string + required: false + docker_secret_envs: + description: "List of secret env vars to expose to the build (e.g., key=envname, MY_SECRET=MY_ENV_VAR)" + required: false + type: string + docker_secret_files: + description: "List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt)" + required: false + type: string + docker_ulimit: + description: "Ulimit options (e.g., nofile=1024:1024)" + required: false + type: string + docker_build_args: + description: "List of build-time variables" + required: false + type: string + secrets: + dockerhub_username: + description: "Docker Hub username" + required: true + dockerhub_password: + description: "Docker Hub password" + required: true + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + publish: + name: Build and publish Docker image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Login to Docker Hub + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + username: ${{ secrets.dockerhub_username }} + password: ${{ secrets.dockerhub_password }} + + - name: Build and push + uses: NethermindEth/github-action-image-build-and-push@9d4a91878e15e6014e3d1f463999e169cadca825 + with: + registry: "dockerhub" + image_name: ${{ inputs.repo_name }}/${{ inputs.image_name }} + image_tags: ${{ inputs.additional_tags }} + push-to-registry: ${{ inputs.push }} + platforms: ${{ inputs.platforms }} + context: ${{ inputs.context }} + dockerfile_path: ${{ inputs.dockerfile_path }} + setup-qemu: ${{ inputs.setup-qemu }} + secrets: ${{ inputs.docker_secrets }} + secret-envs: ${{ inputs.docker_secret_envs }} + secret-files: ${{ inputs.docker_secret_files }} + ulimit: ${{ inputs.docker_ulimit }} + build-args: ${{ inputs.docker_build_args }} diff --git a/.github/workflows/docker-build-push-jfrog.yaml b/.github/workflows/docker-build-push-jfrog.yaml new file mode 100644 index 0000000..2c05f1e --- /dev/null +++ b/.github/workflows/docker-build-push-jfrog.yaml @@ -0,0 +1,133 @@ +on: + workflow_call: + inputs: + repo_name: + description: "Name of the repository to publish to" + type: string + required: false + default: "" + jfrog_url: + description: "URL of Artifactory server" + type: string + default: "nethermind.jfrog.io" + required: false + image_name: + description: "Name of the image to publish. Defaults to the repository name." + type: string + required: false + default: "${{ github.event.repository.name }}" + group_name: + description: "Name of the group in Nethermind. Example: nubia, kyoto, etc" + type: string + required: false + default: "" + push: + description: "Whether or not to push to Artifactory" + type: boolean + default: true + required: false + context: + description: "Build's context is the set of files located in the specified PATH or URL" + type: string + default: "." + required: false + platforms: + description: "Platforms to build for (comma-separated)" + type: string + default: "linux/amd64,linux/arm64" + required: false + setup-qemu: + description: "Set up QEMU" + type: boolean + default: false + required: false + dockerfile_path: + description: "Path to Dockerfile" + type: string + default: "Dockerfile" + required: false + additional_tags: + description: "Additional tags to apply (comma-separated)" + type: string + default: "" + required: false + docker_secrets: + description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" + type: string + required: false + docker_secret_envs: + description: "List of secret env vars to expose to the build (e.g., key=envname, MY_SECRET=MY_ENV_VAR)" + required: false + type: string + docker_secret_files: + description: "List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt)" + required: false + type: string + docker_ulimit: + description: "Ulimit options (e.g., nofile=1024:1024)" + required: false + type: string + docker_build_args: + description: "List of build-time variables" + required: false + type: string + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + publish: + name: Build and publish Docker image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Set env vars + run: | + # Set Repo name + if [[ -n "${{ inputs.repo_name }}" ]]; then + echo "REPO_NAME=${{ inputs.repo_name }}" >> $GITHUB_ENV + elif [[ -n "${{ inputs.group_name }}" ]]; then + echo "REPO_NAME=${{ inputs.group_name }}-oci-local-dev" >> $GITHUB_ENV + else + echo "Unable to determine the repo name. Please set either group_name or the repo_name. + exit 1 + fi + + # Set image name + IMAGE_NAME="${{ inputs.jfrog_url }}/${{ env.REPO_NAME }}/${{ inputs.image_name }}" >> $GITHUB_ENV + + - name: Install JFrog CLI + id: jfrog + uses: jfrog/setup-jfrog-cli@v4 + env: + JF_URL: https://${{ inputs.jfrog_url }} + with: + oidc-provider-name: github-nethermindeth + + - name: Login to Registry with OIDC + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + registry: ${{ inputs.jfrog_url }} + username: ${{ steps.jfrog.outputs.oidc-user }} + password: ${{ steps.jfrog.outputs.oidc-token }} + + - name: Build and push + uses: NethermindEth/github-action-image-build-and-push@9d4a91878e15e6014e3d1f463999e169cadca825 + with: + registry: "artifactory" + image_name: ${{ env.IMAGE_NAME }} + image_tags: ${{ inputs.additional_tags }} + push-to-registry: ${{ inputs.push }} + platforms: ${{ inputs.platforms }} + context: ${{ inputs.context }} + dockerfile_path: ${{ inputs.dockerfile_path }} + setup-qemu: ${{ inputs.setup-qemu }} + secrets: ${{ inputs.docker_secrets }} + secret-envs: ${{ inputs.docker_secret_envs }} + secret-files: ${{ inputs.docker_secret_files }} + ulimit: ${{ inputs.docker_ulimit }} + build-args: ${{ inputs.docker_build_args }} diff --git a/.github/workflows/docker-build-push.yaml b/.github/workflows/docker-build-push.yaml index 24d7a6d..ec0cbfe 100644 --- a/.github/workflows/docker-build-push.yaml +++ b/.github/workflows/docker-build-push.yaml @@ -1,3 +1,5 @@ +# DEPRECATED: Use docker-build-push-jfrog.yaml or docker-build-push-dockerhub.yaml instead + on: workflow_call: inputs: diff --git a/.github/workflows/pipeline-cd-promote-image.yaml b/.github/workflows/docker-promote-dockerhub.yaml similarity index 58% rename from .github/workflows/pipeline-cd-promote-image.yaml rename to .github/workflows/docker-promote-dockerhub.yaml index aa136cd..f26a911 100644 --- a/.github/workflows/pipeline-cd-promote-image.yaml +++ b/.github/workflows/docker-promote-dockerhub.yaml @@ -1,48 +1,42 @@ -name: CD promote image - on: workflow_call: inputs: + source_repo_name: + description: "Name of the repository to get the image from" + type: string + required: false + default: "nethermindeth" + target_repo_name: + description: "Name of the repository to push the image to" + type: string + required: false + default: "nethermind" image_name: description: 'Name of the image to publish. Defaults to the repository name.' type: string required: false default: "${{ github.event.repository.name }}" - target_env: - description: 'Target environment to promote to (either staging or prod)' - type: string - required: true tags: description: 'Tags to promote (comma-separated)' type: string required: true secrets: - artifactory_access_token: - description: 'A token used to communicate with Artifactory' + dockerhub_username: + description: "Docker Hub username" required: true - artifactory_username: - description: 'Username for Artifactory authentication' + dockerhub_password: + description: "Docker Hub password" required: true jobs: promote: - name: Promote image + name: Promote Docker image runs-on: ubuntu-latest steps: - - name: Validate input - run: | - if [[ ! "${{ inputs.target_env }}" =~ ^(staging|prod)$ ]]; then - echo "Invalid environment. Choose 'staging' or 'prod'" - exit 1 - fi - - name: Set environment variables run: | - SOURCE_ENV=$([[ "${{ inputs.target_env }}" == "staging" ]] && echo "dev" || echo "staging") - echo "SOURCE_ENV=${SOURCE_ENV}" >> $GITHUB_ENV - - SOURCE_IMAGE="${{ inputs.jfrog_url }}/${{ secrets.artifactory_username }}-oci-local-${SOURCE_ENV}/${{ inputs.image_name }}" - TARGET_IMAGE="${{ inputs.jfrog_url }}/${{ secrets.artifactory_username }}-oci-local-${{ inputs.target_env }}/${{ inputs.image_name }}" + SOURCE_IMAGE="${{ inputs.source_repo_name }}/${{ inputs.image_name }}" + TARGET_IMAGE="${{ inputs.target_repo_name }}/${{ inputs.image_name }}" echo "SOURCE_IMAGE=${SOURCE_IMAGE}" >> $GITHUB_ENV echo "TARGET_IMAGE=${TARGET_IMAGE}" >> $GITHUB_ENV @@ -50,19 +44,15 @@ jobs: - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + - name: Login to Docker Hub + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + username: ${{ secrets.dockerhub_username }} + password: ${{ secrets.dockerhub_password }} - name: Setup oras cli uses: oras-project/setup-oras@8d34698a59f5ffe24821f0b48ab62a3de8b64b20 # v1.2.3 - - name: Login to Registry - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - registry: https://${{ inputs.jfrog_url }} - username: ${{ secrets.artifactory_username }} - password: ${{ secrets.artifactory_access_token }} - - name: Promote Images id: promote run: | @@ -81,10 +71,10 @@ jobs: done - name: Attest - uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 + uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 id: attest with: - subject-name: ${{ inputs.jfrog_url }}/${{ secrets.artifactory_username }}-oci-local-${{ inputs.target_env }}/${{ github.event.repository.name }} + subject-name: ${{ env.TARGET_IMAGE }} subject-checksums: subject.checksums.txt push-to-registry: true diff --git a/.github/workflows/docker-promote-jfrog.yaml b/.github/workflows/docker-promote-jfrog.yaml new file mode 100644 index 0000000..d780cd4 --- /dev/null +++ b/.github/workflows/docker-promote-jfrog.yaml @@ -0,0 +1,118 @@ +on: + workflow_call: + inputs: + jfrog_url: + description: 'URL of Artifactory server' + type: string + default: 'nethermind.jfrog.io' + required: false + image_name: + description: 'Name of the image to publish. Defaults to the repository name.' + type: string + required: false + default: "${{ github.event.repository.name }}" + group_name: + description: "Name of the group in Nethermind. Example: nubia, kyoto, etc" + type: string + required: false + default: "" + target_env: + description: 'Target environment to promote to (either staging or prod)' + type: string + required: true + source_env: + description: 'Source environment to promote from (either dev or staging)' + type: string + required: false + default: "none" + tags: + description: 'Tags to promote (comma-separated)' + type: string + required: true + +jobs: + promote: + name: Promote Docker image + runs-on: ubuntu-latest + steps: + - name: Validade input + run: | + if [[ ! "${{ inputs.target_env }}" =~ ^(staging|prod)$ ]]; then + echo "Invalid environment. Choose 'staging' or 'prod'" + exit 1 + fi + + if [[ ! "${{ inputs.source_env }}" =~ ^(dev|staging|none)$ ]]; then + echo "Invalid environment. Choose 'dev', 'staging' or don't set it" + exit 1 + fi + + - name: Set environment variables + run: | + if [[ "${{ inputs.source_env }}" == "none" ]]; then + SOURCE_ENV=$([[ "${{ inputs.target_env }}" == "staging" ]] && echo "dev" || echo "staging") + echo "SOURCE_ENV=${SOURCE_ENV}" >> $GITHUB_ENV + else + SOURCE_ENV="${{ inputs.source_env }}" + echo "SOURCE_ENV=${SOURCE_ENV}" >> $GITHUB_ENV + fi + + SOURCE_IMAGE="${{ inputs.jfrog_url }}/${{ inputs.group_name }}-oci-local-${SOURCE_ENV}/${{ inputs.image_name }}" + TARGET_IMAGE="${{ inputs.jfrog_url }}/${{ inputs.group_name }}-oci-local-${{ inputs.target_env }}/${{ inputs.image_name }}" + echo "SOURCE_IMAGE=${SOURCE_IMAGE}" >> $GITHUB_ENV + echo "TARGET_IMAGE=${TARGET_IMAGE}" >> $GITHUB_ENV + + + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Install JFrog CLI + id: jfrog + uses: jfrog/setup-jfrog-cli@v4 + env: + JF_URL: ${{ inputs.jfrog_url }} + with: + oidc-provider-name: github-nethermindeth + + - name: Login to Registry with OIDC + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + registry: ${{ inputs.jfrog_url }} + username: ${{ steps.jfrog.outputs.oidc-user }} + password: ${{ steps.jfrog.outputs.oidc-token }} + + - name: Setup oras cli + uses: oras-project/setup-oras@8d34698a59f5ffe24821f0b48ab62a3de8b64b20 # v1.2.3 + + - name: Promote Images + id: promote + run: | + # Promote all specified tags + IFS=',' read -ra TAGS <<< "${{ inputs.tags }}" + for TAG in "${TAGS[@]}"; do + source_image="${SOURCE_IMAGE}:${TAG}" + target_image="${TARGET_IMAGE}:${TAG}" + echo "Promoting ${source_image} to ${target_image}" + + oras cp -r ${source_image} ${target_image} + + # Get image digest and add it to the subject.checksums.txt file + DIGEST=$(docker buildx imagetools inspect "${target_image}" --raw | sha256sum | cut -d' ' -f1) + echo "${DIGEST} ${TAG}" >> subject.checksums.txt + done + + - name: Attest + uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 + id: attest + with: + subject-name: ${{ env.TARGET_IMAGE }} + subject-checksums: subject.checksums.txt + push-to-registry: true + + - name: Record Promotion + run: | + echo "## Image Promotion :rocket:" >> $GITHUB_STEP_SUMMARY + echo "- From: $SOURCE_IMAGE" >> $GITHUB_STEP_SUMMARY + echo "- To: $TARGET_IMAGE" >> $GITHUB_STEP_SUMMARY + echo "- Tags: ${{ inputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo "- Timestamp: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/pipeline-ci-build-and-push-image.yaml b/.github/workflows/pipeline-ci-build-and-push-image.yaml deleted file mode 100644 index c0d44c8..0000000 --- a/.github/workflows/pipeline-ci-build-and-push-image.yaml +++ /dev/null @@ -1,156 +0,0 @@ -# This workflow is used to build and push Docker images to JFrog Artifactory. -# Structure of the workflow: -# - It is triggered by a workflow call. -# - It checks out the code from the repository. -# - It runs pre-commit hooks to ensure code quality. -# - If workflow triggered by a push to main, it creates a changelog and version bump using commitizen. -# - It defines the image tag. -# - It installs JFrog CLI and logs in to Artifactory using the OIDC token. -# - It sets up QEMU and Docker Buildx for multi-platform builds. -# - It builds and pushes the Docker image to Artifactory. -# - It collects environment variables and Git information for the build. -# - It adds the built images to the JFrog build context. -# - It publishes the build information to JFrog Artifactory. - -name: CI pull request - -on: - workflow_call: - inputs: - is_pull_request: - description: 'Is this a pull request?' - type: boolean - default: false - artifactory_project: - description: 'Key of the Artifactory project' - type: string - required: true - image_reportory: - description: 'Repository name' - type: string - required: true - image_name: - description: 'Name of the image to publish. Defaults to the repository name.' - type: string - required: false - default: "${{ github.event.repository.name }}" - platforms: - description: 'Comma-separated list of platforms (e.g., linux/amd64,linux/arm64)' - type: string - required: true - -permissions: - id-token: write - contents: write - attestations: write - -jobs: - pipeline: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.head_ref }} - - - name: Run pre-commit - uses: pre-commit/action@v3.0.1 - - - id: cz - if: inputs.is_pull_request == false - name: Create bump and changelog - uses: commitizen-tools/commitizen-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Define image tag - id: set_tag - run: | - HEAD_REF=${{ github.head_ref }} - HEAD_SLUG=${HEAD_REF//\//-} - if [[ "${{ steps.cz.conclusion }}" == "success" ]]; then - IMAGE_TAG=${{ steps.cz.outputs.version }} - else - IMAGE_TAG=${HEAD_SLUG}-${{ github.sha }} - fi - echo "HEAD_SLUG=${HEAD_SLUG}" >> $GITHUB_ENV - echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV - - - name: Install JFrog CLI - id: jfrog - uses: jfrog/setup-jfrog-cli@v4 - env: - JF_URL: ${{ vars.JFROG_URL }} - JF_PROJECT: ${{ inputs.artifactory_project }} - with: - oidc-provider-name: github-nethermindeth - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - registry: ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }} - username: ${{ steps.jfrog.outputs.oidc-user }} - password: ${{ steps.jfrog.outputs.oidc-token }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and push - id: build - uses: docker/build-push-action@v6 - with: - push: true - platforms: ${{ inputs.platforms }} - tags: | - ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:latest - ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ env.IMAGE_TAG }} - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Attest - uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 - id: attest - with: - subject-name: ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }} - subject-digest: ${{ steps.build.outputs.digest }} - push-to-registry: true - - - name: JFrog build add context - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ env.HEAD_SLUG }}-${{ github.run_number }} - run: | - jf rt build-collect-env - jf rt build-add-git - - - name: JFrog build add images - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ env.HEAD_SLUG }}-${{ github.run_number }} - run: | - # Pull image manifest - docker manifest inspect ${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ env.IMAGE_TAG }} > manifest.json - - # Iterate over platforms - platforms=$(echo ${{ inputs.platforms }} | tr ',' ' ') - for platform in $platforms; do - os=$(echo $platform | cut -d'/' -f1) - arch=$(echo $platform | cut -d'/' -f2) - digest=$(jq -r \ - --arg os "${os}" \ - --arg arch "${arch}" \ - '.manifests[] | select(.platform.os==$os and .platform.architecture==$arch) | .digest' manifest.json) - echo "${{ vars.JFROG_HOST }}/${{ inputs.image_reportory }}/${{ inputs.image_name }}:${{ env.IMAGE_TAG }}@${digest}" > image-file - jf rt build-docker-create --image-file=image-file ${{ inputs.image_reportory }} - done - - - name: JFrog build publish - env: - JFROG_CLI_BUILD_NAME: ${{ inputs.image_name }} - JFROG_CLI_BUILD_NUMBER: ${{ env.HEAD_SLUG }}-${{ github.run_number }} - run: | - jf rt build-publish diff --git a/.github/workflows/promote-docker.yaml b/.github/workflows/promote-docker.yaml index e255108..f771b49 100644 --- a/.github/workflows/promote-docker.yaml +++ b/.github/workflows/promote-docker.yaml @@ -1,3 +1,5 @@ +# DEPRECATED: Use docker-promote-jfrog.yaml or docker-promote-dockerhub.yaml instead + on: workflow_call: inputs: diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml index 738b240..7199b25 100644 --- a/.github/workflows/publish-docker.yaml +++ b/.github/workflows/publish-docker.yaml @@ -1,3 +1,5 @@ +# DEPRECATED: Use docker-promote-jfrog.yaml or docker-promote-dockerhub.yaml instead + on: workflow_call: inputs: diff --git a/LICENSE b/LICENSE index 87ab2ba..9a6b707 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ -Copyright (c) 2024 Nethermind +Copyright (c) 2025 Nethermind All rights reserved. This repository contains proprietary code owned by Nethermind. No license is granted to use, copy, modify, or distribute this code -without explicit written permission from Nethermind. \ No newline at end of file +without explicit written permission from Nethermind. diff --git a/README.md b/README.md index 94f8f43..baa81c8 100644 --- a/README.md +++ b/README.md @@ -2,60 +2,16 @@ This repository contains reusable GitHub Actions workflows for Nethermind projects. -## Docker Image Workflows - -### Build and Publish - -The workflow for building and publishing Docker images to Artifactory. - -**Implementation:** [`.github/workflows/publish-docker.yaml`](.github/workflows/publish-docker.yaml) -**Example:** [`examples/publish-docker.yml`](examples/publish-docker.yml) - -Features: -- Multi-platform builds (linux/amd64, linux/arm64) -- Automatic tagging based on git refs -- Security scanning with Trivy -- Build provenance attestation -- Caching support -- Publishes to dev environment - -Build Process: -1. Build image without pushing -2. Run Trivy vulnerability scan (CRITICAL,HIGH) -3. Push to registry if scan passes -4. Create and upload attestation - -### Promote +The workflows follow a simple name convention: +- technology-action-flavor.yaml -The workflow for promoting Docker images between environments (dev → staging → prod). +For example: +- docker-build-push-dockerhub.yaml. Docker is the technology, build-push is the action, dockerhub is the flavor. -**Implementation:** [`.github/workflows/promote-docker.yaml`](.github/workflows/promote-docker.yaml) -**Example:** [`examples/promote-docker.yml`](examples/promote-docker.yml) -Features: -- Promotes images between environments -- Maintains build provenance attestation -- Supports multiple tags promotion -- Detailed promotion summary - -## Actions - -### Get Group Topic - -Located in [`.github/actions/get-group-topic/action.yaml`](.github/actions/get-group-topic/action.yaml) - -A utility action that determines the appropriate group name for Artifactory repositories based on repository topics. - -## Environment Flow - -Docker images follow this promotion path: - -dev (build) → staging (promotion) → prod (promotion) +## Docker Image Workflows -Each environment has its own Artifactory repository: -- `{group}-oci-local-dev` -- `{group}-oci-local-staging` -- `{group}-oci-local-prod` +Read about it in the [examples/docker/README.md](examples/docker/README.md) file. ## Security @@ -66,7 +22,7 @@ All workflows include: ## License -Copyright (c) 2024 Nethermind - All rights reserved +Copyright (c) 2025 Nethermind - All rights reserved This is an internal repository containing proprietary workflows and examples. See [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/examples/docker-build-push.yml b/examples/docker-build-push.yml deleted file mode 100644 index 4504457..0000000 --- a/examples/docker-build-push.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Docker Build and Push - -on: - push: - branches: [main] - tags: ['v*'] - paths-ignore: - - '**.md' - - '.github/**' - - '!.github/workflows/**' - -permissions: - id-token: write - attestations: write - contents: read - -jobs: - build: - uses: NethermindEth/github-workflows/.github/workflows/docker-build-push.yaml@main - with: - # Optional inputs (with their defaults shown) - artifactory_url: 'nethermind.jfrog.io' - image_name: '' - platforms: 'linux/amd64,linux/arm64' - context: '.' - setup-qemu: false - dockerfile_path: 'Dockerfile' - additional_tags: '' # Example: 'latest,1.0.0' - # Required Inputs - artifactory_repo: 'angkor-oci-local' - - # Required secrets - secrets: - artifactory_access_token: ${{ secrets.ARTIFACTORY_TOKEN }} # JFrog access token - artifactory_username: ${{ secrets.ARTIFACTORY_USERNAME }} # Repository prefix, e.g. 'angkor' diff --git a/examples/docker/README.md b/examples/docker/README.md new file mode 100644 index 0000000..0d9452a --- /dev/null +++ b/examples/docker/README.md @@ -0,0 +1,75 @@ +# Docker Image Workflows + +## Build and Publish + +Features: +- Multi-platform builds (linux/amd64, linux/arm64 by default) +- Automatic repository naming based on group name +- OIDC authentication with JFrog +- Flexible build configuration (context, dockerfile path, build args, secrets) +- Build attestation support +- Custom additional tags + +### JFrog Artifactory + +The workflow for building and publishing Docker images to JFrog Artifactory. + +**Implementation:** [`.github/workflows/docker-build-push-jfrog.yaml`](../../.github/workflows/docker-build-push-jfrog.yaml) + +**Simple Example:** [`examples/docker/build-push-jfrog-simple.yml`](./build-push-jfrog-simple.yml) +**Complete Example:** [`examples/docker/build-push-jfrog-complete.yml`](./build-push-jfrog-complete.yml) + + +### Docker Hub + +The workflow for building and publishing Docker images to Docker Hub. + +**Implementation:** [`.github/workflows/docker-build-push-dockerhub.yaml`](../../.github/workflows/docker-build-push-dockerhub.yaml) + +**Simple Example:** [`examples/docker/build-push-dockerhub-simple.yml`](./build-push-dockerhub-simple.yml) +**Complete Example:** [`examples/docker/build-push-dockerhub-complete.yml`](./build-push-dockerhub-complete.yml) + + +## Promote + +The workflow for promoting Docker images between environments (dev → staging → prod). + +Features: +- Promotes images between environments +- Maintains build provenance attestation +- Supports multiple tags promotion +- Detailed promotion summary + +### JFrog Artifactory + +**Implementation:** [`.github/workflows/docker-promote-jfrog.yaml`](../../.github/workflows/docker-promote-jfrog.yaml) + +**Example:** [`examples/docker/promote-jfrog.yml`](./promote-jfrog.yml) + + +### Docker Hub + +**Implementation:** [`.github/workflows/docker-promote-dockerhub.yaml`](../../.github/workflows/docker-promote-dockerhub.yaml) +**Example:** [`examples/docker/promote-dockerhub.yml`](./promote-dockerhub.yml) + + +## Environment Flow - JFrog Artifactory + +Docker images follow this promotion path: + +dev (build) → staging (promotion) → prod (promotion) + +Each environment has its own Artifactory repository: +- `{group}-oci-local-dev` +- `{group}-oci-local-staging` +- `{group}-oci-local-prod` + +## Environment Flow - Docker Hub + +Docker images follow this promotion path: + +dev (build) → prod (promotion) + +Each environment has its own Docker Hub repository: +- dev -> `nethermindeth` +- prod -> `nethermind` \ No newline at end of file diff --git a/examples/docker/build-push-dockehub-complete.yml b/examples/docker/build-push-dockehub-complete.yml new file mode 100644 index 0000000..ff48da5 --- /dev/null +++ b/examples/docker/build-push-dockehub-complete.yml @@ -0,0 +1,40 @@ +name: Docker Build and Push + +on: + push: + branches: [main] + tags: ['v*'] + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + build_complete: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-dockerhub.yaml@main + with: + # By default it pushes it to nethermindeth, which is a test repo + # in dockerhub. If you want to push to a different repo, you can + # set this value. + repo_name: 'nethermindeth' + + # By default it uses the repository name as the image name + image_name: '' + + # By default latest and the git sha are added + # Use this if you want something custom, for example a semver. + additional_tags: '' + + platforms: 'linux/amd64,linux/arm64' + context: '.' + setup-qemu: false + dockerfile_path: 'Dockerfile' + docker_secrets: '' + docker_secret_envs: '' + docker_secret_files: '' + docker_ulimit: '' + docker_build_args: '' + secrets: + dockerhub_username: ${{ secrets.DOCKER_USERNAME }} + dockerhub_password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/examples/docker/build-push-dockerhub-simple.yml b/examples/docker/build-push-dockerhub-simple.yml new file mode 100644 index 0000000..cabbc60 --- /dev/null +++ b/examples/docker/build-push-dockerhub-simple.yml @@ -0,0 +1,21 @@ +name: Docker Build and Push + +on: + push: + branches: [main] + tags: ['v*'] + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + build_public_image_simple: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-dockerhub.yaml@main + with: + repo_name: 'nubia' + image_name: 'juno' + secrets: + dockerhub_username: ${{ secrets.DOCKER_USERNAME }} + dockerhub_password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/examples/docker/build-push-jfrog-complete.yml b/examples/docker/build-push-jfrog-complete.yml new file mode 100644 index 0000000..ff0073a --- /dev/null +++ b/examples/docker/build-push-jfrog-complete.yml @@ -0,0 +1,41 @@ +name: Docker Build and Push + +on: + push: + branches: [main] + tags: ['v*'] + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + # This workflow is an example with all of the possible inputs + build_complete: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-jfrog.yaml@main + with: + # To decide the name of the repo, you can use the repo_name + # input or the group_name input + # The easiest and recommended one is to use the group_name + group_name: '' # Example kyoto, nubia, angkor, etc + + # If you need to push into a repo which is not dev + # (anti-pattern btw), you can use the repo_name input + repo_name: '' # example kyoto-oci-local-staging + + image_name: '' # Example: 'my_awesome_backend' + + # By default latest and the git sha are added + # Use this if you want something custom, for example a semver. + additional_tags: '' + + platforms: 'linux/amd64,linux/arm64' + context: '.' + setup-qemu: false + dockerfile_path: 'Dockerfile' + docker_secrets: '' + docker_secret_envs: '' + docker_secret_files: '' + docker_ulimit: '' + docker_build_args: '' diff --git a/examples/docker/build-push-jfrog-simple.yml b/examples/docker/build-push-jfrog-simple.yml new file mode 100644 index 0000000..067a3ac --- /dev/null +++ b/examples/docker/build-push-jfrog-simple.yml @@ -0,0 +1,18 @@ +name: Docker Build and Push + +on: + push: + branches: [main] + tags: ['v*'] + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + build_simple: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-jfrog.yaml@main + with: + group_name: 'nubia' + image_name: 'juno' diff --git a/examples/docker/docker-push-multiple-jfrog.yaml b/examples/docker/docker-push-multiple-jfrog.yaml new file mode 100644 index 0000000..e928646 --- /dev/null +++ b/examples/docker/docker-push-multiple-jfrog.yaml @@ -0,0 +1,28 @@ +name: Docker Build and Push + +on: + push: + branches: [main] + tags: ['v*'] + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + build_service_a: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-jfrog.yaml@main + with: + group_name: 'nubia' + image_name: 'juno' + context: 'service_a/' + dockerfile_path: 'service_a/Dockerfile' + + build_service_b: + uses: NethermindEth/github-workflows/.github/workflows/docker-build-push-jfrog.yaml@main + with: + group_name: 'nubia' + image_name: 'juno' + context: 'service_b/' + dockerfile_path: 'service_b/Dockerfile' diff --git a/examples/docker/promote-dockerhub.yml b/examples/docker/promote-dockerhub.yml new file mode 100644 index 0000000..800d839 --- /dev/null +++ b/examples/docker/promote-dockerhub.yml @@ -0,0 +1,30 @@ +name: Docker Image Promotion + +on: + workflow_dispatch: + inputs: + tags: + description: 'Tags to promote (comma-separated)' + type: string + required: true + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + promote: + uses: NethermindEth/github-workflows/.github/workflows/docker-promote-dockerhub.yaml@main + with: + source_repo_name: 'nethermindeth' # This is the default value + target_repo_name: 'nethermind' # This is the default value + image_name: 'juno' + tags: ${{ inputs.tags }} + secrets: + dockerhub_username: ${{ secrets.DOCKER_USERNAME }} + dockerhub_password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/examples/docker/promote-jfrog.yml b/examples/docker/promote-jfrog.yml new file mode 100644 index 0000000..9fbff95 --- /dev/null +++ b/examples/docker/promote-jfrog.yml @@ -0,0 +1,32 @@ +name: Docker Image Promotion + +on: + workflow_dispatch: + inputs: + target_env: + description: 'Target environment to promote to' + type: choice + options: ['staging', 'prod'] + required: true + tags: + description: 'Tags to promote (comma-separated)' + type: string + required: true + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + id-token: write + attestations: write + contents: read + +jobs: + promote: + uses: NethermindEth/github-workflows/.github/workflows/docker-promote-jfrog.yaml@main + with: + image_name: aztec-p2p-explorer + group_name: modular + target_env: ${{ inputs.target_env }} + tags: ${{ inputs.tags }} diff --git a/examples/promote-docker.yml b/examples/promote-docker.yml deleted file mode 100644 index d7467ed..0000000 --- a/examples/promote-docker.yml +++ /dev/null @@ -1,43 +0,0 @@ -# Promotes Docker images between environments in JFrog Artifactory -# Features: -# - Promotes from dev to staging, or staging to prod -# - Maintains build provenance attestation -# - Supports multiple tag promotion -name: Docker Image Promotion - -on: - workflow_dispatch: - inputs: - target_env: - description: 'Target environment to promote to' - type: choice - options: ['staging', 'prod'] - required: true - tags: - description: 'Tags to promote (comma-separated)' - type: string - required: true - -permissions: - id-token: write - attestations: write - contents: read - -jobs: - promote: - uses: NethermindEth/github-workflows/.github/workflows/promote-docker.yaml@main - with: - # Required inputs - target_env: ${{ inputs.target_env }} # Target: 'staging' or 'prod' - tags: ${{ inputs.tags }} # Example: 'v1.0.0,latest' - - # Optional inputs (with defaults shown) - jfrog_url: 'nethermind.jfrog.io' - image_name: '' - login_with_oidc: false - - # Optional secrets - Deprecated - # Use those secrets if you don't have the OIDC enabled yet - secrets: - artifactory_access_token: ${{ secrets.ARTIFACTORY_TOKEN }} # JFrog access token - artifactory_username: ${{ secrets.ARTIFACTORY_USERNAME }} # Repository prefix, e.g. 'angkor' diff --git a/examples/publish-docker.yml b/examples/publish-docker.yml deleted file mode 100644 index 0a85b65..0000000 --- a/examples/publish-docker.yml +++ /dev/null @@ -1,42 +0,0 @@ -# Builds and publishes Docker images to JFrog Artifactory -# Features: -# - Multi-platform build support (amd64/arm64) -# - Vulnerability scanning with Trivy -# - Build provenance attestation -# - Configurable build context and Dockerfile path -# - Automated builds on main branch and tags -name: Docker Image Build & Publish - -on: - push: - branches: [main] - tags: ['v*'] - paths-ignore: - - '**.md' - - '.github/**' - - '!.github/workflows/**' - -permissions: - id-token: write - attestations: write - contents: read - -jobs: - build: - uses: NethermindEth/github-workflows/.github/workflows/publish-docker.yaml@main - with: - # Optional inputs (with their defaults shown) - jfrog_url: 'nethermind.jfrog.io' - image_name: '' - platforms: 'linux/amd64,linux/arm64' - context: '.' - setup-qemu: false - dockerfile_path: 'Dockerfile' - additional_tags: '' # Example: 'latest,1.0.0' - login_with_oidc: false - - # Optional secrets - Deprecated - secrets: - # Use those secrets if you don't have the OIDC enabled yet - artifactory_access_token: ${{ secrets.ARTIFACTORY_TOKEN }} # JFrog access token - artifactory_username: ${{ secrets.ARTIFACTORY_USERNAME }} # Repository prefix, e.g. 'angkor' diff --git a/examples/publish-multiple-docker.yaml b/examples/publish-multiple-docker.yaml deleted file mode 100644 index 9f71a87..0000000 --- a/examples/publish-multiple-docker.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Builds and publishes Docker images to JFrog Artifactory -name: Docker Image Build & Publish - -on: - push: - branches: [main] - tags: ['v*'] - paths-ignore: - - '**.md' - - '.github/**' - - '!.github/workflows/**' - -permissions: - id-token: write - attestations: write - contents: read - -jobs: - build_service_a: - uses: NethermindEth/github-workflows/.github/workflows/publish-docker.yaml@main - with: - image_name: 'service-a' - context: 'service_a/' - dockerfile_path: 'service_a/Dockerfile' - login_with_oidc: true - - build_service_b: - uses: NethermindEth/github-workflows/.github/workflows/publish-docker.yaml@main - with: - image_name: 'service-b' - context: 'service_b/' - dockerfile_path: 'service_b/Dockerfile' - login_with_oidc: true