diff --git a/.github/workflows/images_build.yml b/.github/workflows/images_build.yml index 7b997705e..ff816205a 100644 --- a/.github/workflows/images_build.yml +++ b/.github/workflows/images_build.yml @@ -28,7 +28,7 @@ permissions: env: TRUNK_ONLY_EVENT: ${{ contains(fromJSON('["schedule"]'), github.event_name) }} - AUTO_PUSH_IMAGES: ${{ vars.AUTO_PUSH_IMAGES }} + AUTO_PUSH_IMAGES: ${{ ! contains(fromJSON('["workflow_dispatch"]'), github.event_name) && vars.AUTO_PUSH_IMAGES }} DOCKER_REPOSITORY: ${{ vars.DOCKER_REPOSITORY }} LATEST_BRANCH: ${{ github.event.repository.default_branch }} @@ -36,12 +36,17 @@ env: IMAGES_PREFIX: "zabbix-" BASE_BUILD_NAME: "build-base" + BASE_CACHE_FILE_NAME: "base_image_metadata.json" + BUILD_CACHE_FILE_NAME: "base_build_image_metadata.json" MATRIX_FILE: "build.json" DOCKERFILES_DIRECTORY: "./Dockerfiles" OIDC_ISSUER: "https://token.actions.githubusercontent.com" - IDENITY_REGEX: "https://github.com/zabbix/zabbix-docker/.github/" + IDENTITY_REGEX: "https://github.com/zabbix/zabbix-docker/.github/" + + DOCKER_REGISTRY_TEST: "ghcr.io" + DOCKER_REPOSITORY_TEST: "zabbix" jobs: init_build: @@ -63,7 +68,9 @@ jobs: disable-sudo: true egress-policy: block allowed-endpoints: > + api.github.com:443 github.com:443 + objects.githubusercontent.com:443 - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -163,6 +170,7 @@ jobs: permissions: contents: read id-token: write + packages: write steps: - name: Block egress traffic uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 @@ -193,6 +201,7 @@ jobs: ftpmirror.your.org:80 fulcio.sigstore.dev:443 github.com:443 + ghcr.io:443 iad.mirror.rackspace.com:443 iad.mirror.rackspace.com:80 index.docker.io:443 @@ -251,6 +260,7 @@ jobs: uvermont.mm.fcix.net:443 yum.oracle.com:443 ziply.mm.fcix.net:443 + pkg-containers.githubusercontent.com:443 - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -259,11 +269,13 @@ jobs: fetch-depth: 1 - name: Install cosign + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 with: cosign-release: 'v2.2.3' - name: Check cosign version + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} run: cosign version - name: Set up QEMU @@ -277,12 +289,6 @@ jobs: with: driver-opts: image=moby/buildkit:master - - name: Login to DockerHub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Prepare Platform list id: platform env: @@ -302,37 +308,85 @@ jobs: id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: - images: ${{ env.DOCKER_REPOSITORY }}/${{ env.IMAGES_PREFIX }}${{ env.BASE_BUILD_NAME }} + images: | + ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY_TEST, env.DOCKER_REPOSITORY_TEST, env.IMAGES_PREFIX, env.BASE_BUILD_NAME ) }},enable=${{ env.AUTO_PUSH_IMAGES != 'true' }} + ${{ format('{0}/{1}{2}', env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, env.BASE_BUILD_NAME ) }},enable=${{ env.AUTO_PUSH_IMAGES == 'true' }} context: ${{ env.TRUNK_ONLY_EVENT == 'true' && 'git' || '' }} tags: | type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},prefix=${{ matrix.os }}- type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},suffix=-${{ matrix.os }} - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,suffix=-${{ matrix.os }}-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && !contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && !contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,suffix=-${{ matrix.os }}-latest type=raw,enable=${{ (needs.init_build.outputs.current_branch != 'trunk') && (needs.init_build.outputs.is_default_branch == 'true') }},value=${{matrix.os}}-latest type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,prefix=${{ matrix.os }}- - type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,suffix=-${{ matrix.os }} + type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' || contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,suffix=-${{ matrix.os }} flavor: | - latest=${{ (needs.init_build.outputs.current_branch != 'trunk') && (matrix.os == 'alpine') && ( needs.init_build.outputs.is_default_branch == 'true' ) }} + latest=${{ (matrix.os == 'alpine') && (!contains(fromJSON('["workflow_dispatch"]'), github.event_name)) && ( needs.init_build.outputs.is_default_branch == 'true' ) }} + + - name: Prepare cache data + id: cache_data + env: + IMAGE_TAG: ${{ fromJSON(steps.meta.outputs.json).tags[0] }} + PUBLISH_IMAGES: ${{ env.AUTO_PUSH_IMAGES == 'true' }} + run: | + cache_from=() + cache_to=() + + cache_from+=("type=gha,scope=${IMAGE_TAG}") + #cache_from+=("type=registry,ref=${IMAGE_TAG}") + + cache_to+=("type=gha,mode=max,scope=${IMAGE_TAG}") + + echo "::group::Cache from data" + echo "${cache_from[*]}" + echo "::endgroup::" + + echo "::group::Cache to data" + echo "${cache_to[*]}" + echo "::endgroup::" + + cache_from=$(printf '%s\n' "${cache_from[@]}") + cache_to=$(printf '%s\n' "${cache_to[@]}") + + echo 'cache_from<> "$GITHUB_OUTPUT" + echo "$cache_from" >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + echo 'cache_to<> "$GITHUB_OUTPUT" + echo "$cache_to" >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + + - name: Login to DockerHub + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to ${{ env.DOCKER_REGISTRY_TEST }} + if: ${{ env.AUTO_PUSH_IMAGES != 'true' }} + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ${{ env.DOCKER_REGISTRY_TEST }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and publish image id: docker_build uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ env.BASE_BUILD_NAME }}/${{ matrix.os }} - file: ${{ env.DOCKERFILES_DIRECTORY }}/${{ env.BASE_BUILD_NAME }}/${{ matrix.os }}/Dockerfile + context: ${{ format('{0}/{1}/{2}', env.DOCKERFILES_DIRECTORY, env.BASE_BUILD_NAME, matrix.os) }} + file: ${{ format('{0}/{1}/{2}/Dockerfile', env.DOCKERFILES_DIRECTORY, env.BASE_BUILD_NAME, matrix.os) }} platforms: ${{ steps.platform.outputs.list }} - push: ${{ env.AUTO_PUSH_IMAGES }} + push: true tags: ${{ steps.meta.outputs.tags }} labels: | org.opencontainers.image.revision=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} org.opencontainers.image.created=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - cache-from: | - type=gha,scope=${{ fromJSON(steps.meta.outputs.json).tags[0] }} - type=registry,ref=docker.io/${{ fromJSON(steps.meta.outputs.json).tags[0] }} - cache-to: type=gha,mode=max,scope=${{ fromJSON(steps.meta.outputs.json).tags[0] }} + cache-from: ${{ steps.cache_data.outputs.cache_from }} + cache-to: ${{ steps.cache_data.outputs.cache_to }} - name: Sign the images with GitHub OIDC Token + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} env: DIGEST: ${{ steps.docker_build.outputs.digest }} TAGS: ${{ steps.meta.outputs.tags }} @@ -351,24 +405,24 @@ jobs: cosign sign --yes ${images} echo "::endgroup::" - - name: Image digest + - name: Image metadata env: - DIGEST: ${{ steps.docker_build.outputs.digest }} - CACHE_FILE_NAME: ${{ env.BASE_BUILD_NAME }}_${{ matrix.os }} + CACHE_FILE_NAME: ${{ env.BASE_CACHE_FILE_NAME }} + METADATA: ${{ steps.docker_build.outputs.metadata }} run: | - echo "::group::Image digest" - echo "$DIGEST" + echo "::group::Image metadata" + echo "${METADATA}" echo "::endgroup::" echo "::group::Cache file name" - echo "$CACHE_FILE_NAME" + echo "${CACHE_FILE_NAME}" echo "::endgroup::" - echo "$DIGEST" > "$CACHE_FILE_NAME" + echo "${METADATA}" > "$CACHE_FILE_NAME" - - name: Cache image digest + - name: Cache image metadata uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: - path: ${{ env.BASE_BUILD_NAME }}_${{ matrix.os }} + path: ${{ env.BASE_CACHE_FILE_NAME }} key: ${{ env.BASE_BUILD_NAME }}-${{ matrix.os }}-${{ github.run_id }} build_base_database: @@ -380,11 +434,11 @@ jobs: matrix: build: ${{ fromJson(needs.init_build.outputs.database) }} os: ${{ fromJson(needs.init_build.outputs.os) }} - runs-on: ubuntu-latest permissions: contents: read id-token: write + packages: write steps: - name: Block egress traffic uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 @@ -401,6 +455,7 @@ jobs: golang.org:443 google.golang.org:443 gopkg.in:443 + ghcr.io:443 index.docker.io:443 noto-website.storage.googleapis.com:443 production.cloudflare.docker.com:443 @@ -412,6 +467,7 @@ jobs: objects.githubusercontent.com:443 tuf-repo-cdn.sigstore.dev:443 rekor.sigstore.dev:443 + pkg-containers.githubusercontent.com:443 - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -420,11 +476,13 @@ jobs: fetch-depth: 1 - name: Install cosign + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 with: cosign-release: 'v2.2.3' - name: Check cosign version + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} run: cosign version - name: Set up QEMU @@ -438,12 +496,6 @@ jobs: with: driver-opts: image=moby/buildkit:master - - name: Login to DockerHub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Prepare Platform list id: platform env: @@ -463,82 +515,127 @@ jobs: id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: - images: ${{ env.DOCKER_REPOSITORY }}/${{ env.IMAGES_PREFIX }}${{ matrix.build }} + images: | + ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY_TEST, env.DOCKER_REPOSITORY_TEST, env.IMAGES_PREFIX, matrix.build ) }},enable=${{ env.AUTO_PUSH_IMAGES != 'true' }} + ${{ format('{0}/{1}{2}', env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, matrix.build ) }},enable=${{ env.AUTO_PUSH_IMAGES == 'true' }} context: ${{ env.TRUNK_ONLY_EVENT == 'true' && 'git' || '' }} tags: | type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},prefix=${{ matrix.os }}- type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},suffix=-${{ matrix.os }} - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,suffix=-${{ matrix.os }}-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && (!contains(fromJSON('["workflow_dispatch"]'), github.event_name)) }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && (!contains(fromJSON('["workflow_dispatch"]'), github.event_name)) }},event=branch,suffix=-${{ matrix.os }}-latest type=raw,enable=${{ (needs.init_build.outputs.current_branch != 'trunk') && (needs.init_build.outputs.is_default_branch == 'true') }},value=${{matrix.os}}-latest type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,prefix=${{ matrix.os }}- - type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,suffix=-${{ matrix.os }} + type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' || contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,suffix=-${{ matrix.os }} flavor: | - latest=${{ (needs.init_build.outputs.current_branch != 'trunk') && (matrix.os == 'alpine') && ( needs.init_build.outputs.is_default_branch == 'true' ) }} + latest=${{ (matrix.os == 'alpine') && (!contains(fromJSON('["workflow_dispatch"]'), github.event_name)) && ( needs.init_build.outputs.is_default_branch == 'true' ) }} - - name: Download SHA256 tag of ${{ env.BASE_BUILD_NAME }}:${{ matrix.os }} + - name: Download metadata of ${{ env.BASE_BUILD_NAME }}:${{ matrix.os }} uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: - path: ${{ env.BASE_BUILD_NAME }}_${{ matrix.os }} + path: ${{ env.BASE_CACHE_FILE_NAME }} key: ${{ env.BASE_BUILD_NAME }}-${{ matrix.os }}-${{ github.run_id }} - - name: Retrieve ${{ env.BASE_BUILD_NAME }}:${{ matrix.os }} SHA256 tag + - name: Process ${{ env.BASE_BUILD_NAME }}:${{ matrix.os }} image metadata id: base_build env: - MATRIX_OS: ${{ matrix.os }} - DOCKER_REPOSITORY: ${{ env.DOCKER_REPOSITORY }} - BASE_IMAGE: ${{ env.BASE_BUILD_NAME }} - IMAGES_PREFIX: ${{ env.IMAGES_PREFIX }} + CACHE_FILE_NAME: ${{ env.BASE_CACHE_FILE_NAME }} run: | - BASE_TAG=$(cat "${BASE_IMAGE}_${MATRIX_OS}") - BUILD_BASE_IMAGE="${DOCKER_REPOSITORY}/${IMAGES_PREFIX}${BASE_IMAGE}@${BASE_TAG}" - - echo "::group::Base build image information" - echo "base_tag=${BASE_TAG}" - echo "base_build_image=${BUILD_BASE_IMAGE}" + echo "::group::Base image metadata" + cat "${CACHE_FILE_NAME}" echo "::endgroup::" - echo "base_tag=${BASE_TAG}" >> $GITHUB_OUTPUT - echo "base_build_image=${BUILD_BASE_IMAGE}" >> $GITHUB_OUTPUT + IMAGE_DIGEST=$(jq -r '."containerimage.digest"' "${CACHE_FILE_NAME}") + IMAGE_NAME=$(jq -r '."image.name"' "${CACHE_FILE_NAME}" | cut -d: -f1) + + echo "base_build_image=${IMAGE_NAME}@${IMAGE_DIGEST}" >> $GITHUB_OUTPUT - name: Verify ${{ env.BASE_BUILD_NAME }}:${{ matrix.os }} cosign + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} env: BASE_IMAGE: ${{ steps.base_build.outputs.base_build_image }} OIDC_ISSUER: ${{ env.OIDC_ISSUER }} - IDENITY_REGEX: ${{ env.IDENITY_REGEX }} + IDENTITY_REGEX: ${{ env.IDENTITY_REGEX }} run: | echo "::group::Image sign data" echo "OIDC issuer=$OIDC_ISSUER" - echo "Identity=$IDENITY_REGEX" + echo "Identity=$IDENTITY_REGEX" echo "Image to verify=$BASE_IMAGE" echo "::endgroup::" echo "::group::Verify signature" cosign verify \ --certificate-oidc-issuer-regexp "$OIDC_ISSUER" \ - --certificate-identity-regexp "$IDENITY_REGEX" \ + --certificate-identity-regexp "$IDENTITY_REGEX" \ "$BASE_IMAGE" echo "::endgroup::" + - name: Prepare cache data + id: cache_data + env: + BASE_IMAGE_TAG: ${{ steps.base_build.outputs.base_build_image }} + IMAGE_TAG: ${{ fromJSON(steps.meta.outputs.json).tags[0] }} + PUBLISH_IMAGES: ${{ env.AUTO_PUSH_IMAGES == 'true' }} + run: | + cache_from=() + cache_to=() + + cache_from+=("type=gha,scope=${BASE_IMAGE_TAG}") + cache_from+=("type=registry,ref=${BASE_IMAGE_TAG}") + cache_from+=("type=gha,scope=${IMAGE_TAG}") + cache_from+=("type=registry,ref=${IMAGE_TAG}") + + cache_to+=("type=gha,mode=max,scope=${IMAGE_TAG}") + + echo "::group::Cache from data" + echo "${cache_from[*]}" + echo "::endgroup::" + + echo "::group::Cache to data" + echo "${cache_to[*]}" + echo "::endgroup::" + + cache_from=$(printf '%s\n' "${cache_from[@]}") + cache_to=$(printf '%s\n' "${cache_to[@]}") + + echo 'cache_from<> "$GITHUB_OUTPUT" + echo "$cache_from" >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + echo 'cache_to<> "$GITHUB_OUTPUT" + echo "$cache_to" >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + + - name: Login to DockerHub + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to ${{ env.DOCKER_REGISTRY_TEST }} + if: ${{ env.AUTO_PUSH_IMAGES != 'true' }} + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ${{ env.DOCKER_REGISTRY_TEST }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build ${{ matrix.build }}/${{ matrix.os }} and push id: docker_build uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/${{ matrix.os }} - file: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/${{ matrix.os }}/Dockerfile + context: ${{ format('{0}/{1}/{2}/', env.DOCKERFILES_DIRECTORY, matrix.build, matrix.os) }} + file: ${{ format('{0}/{1}/{2}/Dockerfile', env.DOCKERFILES_DIRECTORY, matrix.build, matrix.os) }} platforms: ${{ steps.platform.outputs.list }} - push: ${{ env.AUTO_PUSH_IMAGES }} + push: true tags: ${{ steps.meta.outputs.tags }} build-args: BUILD_BASE_IMAGE=${{ steps.base_build.outputs.base_build_image }} labels: | org.opencontainers.image.revision=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} org.opencontainers.image.created=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - cache-from: | - type=gha,scope=${{ steps.base_build.outputs.base_build_image }} - type=registry,ref=${{ steps.base_build.outputs.base_build_image }} - cache-to: type=gha,mode=max,scope=${{ fromJSON(steps.meta.outputs.json).tags[0] }} - name: Sign the images with GitHub OIDC Token + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} env: DIGEST: ${{ steps.docker_build.outputs.digest }} TAGS: ${{ steps.meta.outputs.tags }} @@ -557,23 +654,24 @@ jobs: cosign sign --yes ${images} echo "::endgroup::" - - name: Image digest + - name: Image metadata env: - DIGEST: ${{ steps.docker_build.outputs.digest }} - CACHE_FILE_NAME: ${{ matrix.build }}_${{ matrix.os }} + CACHE_FILE_NAME: ${{ env.BUILD_CACHE_FILE_NAME }} + METADATA: ${{ steps.docker_build.outputs.metadata }} run: | - echo "::group::Image digest" - echo "$DIGEST" + echo "::group::Image metadata" + echo "${METADATA}" echo "::endgroup::" echo "::group::Cache file name" - echo "$CACHE_FILE_NAME" + echo "${CACHE_FILE_NAME}" echo "::endgroup::" - echo "$DIGEST" > $CACHE_FILE_NAME - - name: Caching SHA256 tag of the image + echo "${METADATA}" > "$CACHE_FILE_NAME" + + - name: Cache image metadata uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: - path: ${{ matrix.build }}_${{ matrix.os }} + path: ${{ env.BUILD_CACHE_FILE_NAME }} key: ${{ matrix.build }}-${{ matrix.os }}-${{ github.run_id }} build_images: @@ -590,6 +688,7 @@ jobs: permissions: contents: read id-token: write + packages: write steps: - name: Block egress traffic uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 @@ -670,6 +769,7 @@ jobs: pubmirror1.math.uh.edu:443 pubmirror3.math.uh.edu:80 quay.io:443 + ghcr.io:443 registry-1.docker.io:443 repo.ialab.dsu.edu:80 repos.eggycrew.com:80 @@ -708,6 +808,7 @@ jobs: objects.githubusercontent.com:443 tuf-repo-cdn.sigstore.dev:443 rekor.sigstore.dev:443 + pkg-containers.githubusercontent.com:443 - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -716,11 +817,13 @@ jobs: fetch-depth: 1 - name: Install cosign + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 with: cosign-release: 'v2.2.3' - name: Check cosign version + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} run: cosign version - name: Set up QEMU @@ -734,12 +837,6 @@ jobs: with: driver-opts: image=moby/buildkit:master - - name: Login to DockerHub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Prepare Platform list id: platform env: @@ -788,98 +885,107 @@ jobs: id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: - images: ${{ env.DOCKER_REPOSITORY }}/${{ env.IMAGES_PREFIX}}${{ matrix.build }} + images: | + ${{ format('{0}/{1}/{2}{3}', env.DOCKER_REGISTRY_TEST, env.DOCKER_REPOSITORY_TEST, env.IMAGES_PREFIX, matrix.build ) }},enable=${{ env.AUTO_PUSH_IMAGES != 'true' }} + ${{ format('{0}/{1}{2}', env.DOCKER_REPOSITORY, env.IMAGES_PREFIX, matrix.build ) }},enable=${{ env.AUTO_PUSH_IMAGES == 'true' }} context: ${{ env.TRUNK_ONLY_EVENT == 'true' && 'git' || '' }} tags: | type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},prefix=${{ matrix.os }}- type=semver,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},pattern={{version}},suffix=-${{ matrix.os }} - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest - type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' }},event=branch,suffix=-${{ matrix.os }}-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && !contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,prefix=${{ matrix.os }}-,suffix=-latest + type=ref,enable=${{ needs.init_build.outputs.current_branch != 'trunk' && !contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,suffix=-${{ matrix.os }}-latest type=raw,enable=${{ (needs.init_build.outputs.current_branch != 'trunk') && (needs.init_build.outputs.is_default_branch == 'true') }},value=${{matrix.os}}-latest type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,prefix=${{ matrix.os }}- - type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' }},event=branch,suffix=-${{ matrix.os }} + type=ref,enable=${{ needs.init_build.outputs.current_branch == 'trunk' || contains(fromJSON('["workflow_dispatch"]'), github.event_name) }},event=branch,suffix=-${{ matrix.os }} flavor: | - latest=${{ (needs.init_build.outputs.current_branch != 'trunk') && (matrix.os == 'alpine') && ( needs.init_build.outputs.is_default_branch == 'true' ) }} + latest=${{ (matrix.os == 'alpine') && (!contains(fromJSON('["workflow_dispatch"]'), github.event_name)) && ( needs.init_build.outputs.is_default_branch == 'true' ) }} - - name: Download SHA256 tag of ${{ steps.build_base_image.outputs.build_base }}:${{ matrix.os }} + - name: Download metadata of ${{ steps.build_base_image.outputs.build_base }}:${{ matrix.os }} uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 if: ${{ matrix.build != 'snmptraps' }} with: - path: ${{ steps.build_base_image.outputs.build_base }}_${{ matrix.os }} + path: ${{ env.BUILD_CACHE_FILE_NAME }} key: ${{ steps.build_base_image.outputs.build_base }}-${{ matrix.os }}-${{ github.run_id }} - - name: Retrieve ${{ steps.build_base_image.outputs.build_base }}:${{ matrix.os }} SHA256 tag + - name: Process ${{ steps.build_base_image.outputs.build_base }}:${{ matrix.os }} image metadata id: base_build if: ${{ matrix.build != 'snmptraps' }} env: - BUILD_BASE: ${{ steps.build_base_image.outputs.build_base }} - MATRIX_OS: ${{ matrix.os }} - DOCKER_REPOSITORY: ${{ env.DOCKER_REPOSITORY }} - IMAGES_PREFIX: ${{ env.IMAGES_PREFIX }} + CACHE_FILE_NAME: ${{ env.BUILD_CACHE_FILE_NAME }} run: | - BASE_TAG=$(cat "${BUILD_BASE}_${MATRIX_OS}") - BUILD_BASE_IMAGE=${DOCKER_REPOSITORY}/${IMAGES_PREFIX}${BUILD_BASE}@${BASE_TAG} - - echo "::group::Base build image information" - echo "base_tag=${BASE_TAG}" - echo "base_build_image=${BUILD_BASE_IMAGE}" + echo "::group::Base build image metadata" + cat "${CACHE_FILE_NAME}" echo "::endgroup::" - echo "base_tag=${BASE_TAG}" >> $GITHUB_OUTPUT - echo "base_build_image=${BUILD_BASE_IMAGE}" >> $GITHUB_OUTPUT + IMAGE_DIGEST=$(jq -r '."containerimage.digest"' "${CACHE_FILE_NAME}") + IMAGE_NAME=$(jq -r '."image.name"' "${CACHE_FILE_NAME}" | cut -d: -f1) + + echo "base_build_image=${IMAGE_NAME}@${IMAGE_DIGEST}" >> $GITHUB_OUTPUT - name: Verify ${{ steps.build_base_image.outputs.build_base }}:${{ matrix.os }} cosign - if: ${{ matrix.build != 'snmptraps' }} + if: ${{ matrix.build != 'snmptraps' && env.AUTO_PUSH_IMAGES == 'true' }} env: BASE_IMAGE: ${{ steps.base_build.outputs.base_build_image }} OIDC_ISSUER: ${{ env.OIDC_ISSUER }} - IDENITY_REGEX: ${{ env.IDENITY_REGEX }} + IDENTITY_REGEX: ${{ env.IDENTITY_REGEX }} run: | echo "::group::Image sign data" - echo "OIDC issuer=$OIDC_ISSUER" - echo "Identity=$IDENITY_REGEX" - echo "Image to verify=$BASE_IMAGE" + echo "OIDC issuer=${OIDC_ISSUER}" + echo "Identity=${IDENTITY_REGEX}" + echo "Image to verify=${BASE_IMAGE}" echo "::endgroup::" echo "::group::Verify signature" cosign verify \ - --certificate-oidc-issuer-regexp "$OIDC_ISSUER" \ - --certificate-identity-regexp "$IDENITY_REGEX" \ - "$BASE_IMAGE" + --certificate-oidc-issuer-regexp "${OIDC_ISSUER}" \ + --certificate-identity-regexp "${IDENTITY_REGEX}" \ + "${BASE_IMAGE}" echo "::endgroup::" - name: Prepare cache data + if: ${{ matrix.build != 'snmptraps' }} id: cache_data env: BASE_IMAGE_TAG: ${{ steps.base_build.outputs.base_build_image }} run: | - cache_images="" - if [[ ! -z "$BASE_IMAGE_TAG" ]]; then - cache_images="type=gha,scope=$BASE_IMAGE_TAG"$'\n'"type=registry,ref=$BASE_IMAGE_TAG" - fi + cache_from=() + cache_to=() - echo "::group::Base images cache" - echo "$cache_images" + cache_from+=("type=registry,ref=${BASE_IMAGE_TAG}") + + echo "::group::Cache from data" + echo "${cache_from[*]}" echo "::endgroup::" - echo "cache_from=$cache_images" >> $GITHUB_OUTPUT + cache_from=$(printf '%s\n' "${cache_from[@]}") + + echo 'cache_from<> "$GITHUB_OUTPUT" + echo "$cache_from" >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + + - name: Login to DockerHub + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push image id: docker_build uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/${{ matrix.os }} - file: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/${{ matrix.os }}/Dockerfile + context: ${{ format('{0}/{1}/{2}', env.DOCKERFILES_DIRECTORY, matrix.build, matrix.os) }} + file: ${{ format('{0}/{1}/{2}/Dockerfile', env.DOCKERFILES_DIRECTORY, matrix.build, matrix.os) }} platforms: ${{ steps.platform.outputs.list }} - push: ${{ env.AUTO_PUSH_IMAGES }} + push: ${{ env.AUTO_PUSH_IMAGES == 'true' }} tags: ${{ steps.meta.outputs.tags }} build-args: BUILD_BASE_IMAGE=${{ steps.base_build.outputs.base_build_image }} labels: | org.opencontainers.image.revision=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} org.opencontainers.image.created=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - cache-from: ${{ steps.cache_data.outputs.cache_from }} - name: Sign the images with GitHub OIDC Token + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} env: DIGEST: ${{ steps.docker_build.outputs.digest }} TAGS: ${{ steps.meta.outputs.tags }} @@ -898,10 +1004,11 @@ jobs: cosign sign --yes ${images} echo "::endgroup::" - - name: Image digest + - name: Image metadata + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} env: - DIGEST: ${{ steps.docker_build.outputs.digest }} + METADATA: ${{ steps.docker_build.outputs.metadata }} run: | - echo "::group::Image digest" - echo "$DIGEST" + echo "::group::Image metadata" + echo "${METADATA}" echo "::endgroup::" diff --git a/.github/workflows/images_build_rhel.yml b/.github/workflows/images_build_rhel.yml index fa803125f..6f84de1e1 100644 --- a/.github/workflows/images_build_rhel.yml +++ b/.github/workflows/images_build_rhel.yml @@ -29,7 +29,8 @@ permissions: contents: read env: - AUTO_PUSH_IMAGES: ${{ contains(fromJSON('["workflow_dispatch", "push"]'), github.event_name) && 'false' || vars.AUTO_PUSH_IMAGES }} + TRUNK_ONLY_EVENT: ${{ contains(fromJSON('["schedule"]'), github.event_name) }} + AUTO_PUSH_IMAGES: ${{ ! contains(fromJSON('["workflow_dispatch", "push"]'), github.event_name) && vars.AUTO_PUSH_IMAGES }} LATEST_BRANCH: ${{ github.event.repository.default_branch }} TRUNK_GIT_BRANCH: "refs/heads/trunk" @@ -164,7 +165,7 @@ jobs: echo "secret_prefix=RHEL_${github_ref//.}" >> $GITHUB_OUTPUT echo "sha_short=$sha_short" >> $GITHUB_OUTPUT - - name: Cleanup cache + - name: Cleanup existing cache shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -205,11 +206,13 @@ jobs: fetch-depth: 1 - name: Install cosign + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 with: cosign-release: 'v2.2.3' - name: Check cosign version + if: ${{ env.AUTO_PUSH_IMAGES == 'true' }} run: cosign version - name: Fix string case @@ -231,7 +234,7 @@ jobs: id: build_image uses: redhat-actions/buildah-build@b4dc19b4ba891854660ab1f88a097d45aa158f76 # v2.12 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/rhel + context: ${{ format('{0}/{1}/rhel', env.DOCKERFILES_DIRECTORY, matrix.build) }} layers: false tags: ${{ steps.meta.outputs.tags }} containerfiles: | @@ -240,7 +243,7 @@ jobs: --pull --iidfile=${{ github.workspace }}/iidfile - - name: Prepare image metadata + - name: Image metadata id: image_metadata env: IMAGE_TAG: ${{ steps.build_image.outputs.image-with-tag }} @@ -279,7 +282,6 @@ jobs: IMAGE_TAG: ${{ steps.image_metadata.outputs.image_tag }} IMAGE_TAG_ID: ${{ steps.image_metadata.outputs.image_tag_id }} IMAGE_DIR: ${{ env.IMAGE_DIR }} - GITHUB_WORKSPACE: ${{ github.workspace }} run: | echo "::group::Result" echo "Image ${IMAGE_TAG} location: \"${IMAGE_DIR}/${IMAGE_TAG_ID}\"" @@ -310,13 +312,14 @@ jobs: if: ${{ (cancelled() || failure()) && ( steps.push_image.outcome == 'failure' || steps.push_image.outcome == 'cancelled') }} env: IMAGE_TAG_ID: ${{ steps.image_metadata.outputs.image_tag_id }} + IMAGE_DIR: ${{ env.IMAGE_DIR }} run: | echo "::group::Removing orphaned image" rm -rf "${IMAGE_DIR}/${IMAGE_TAG_ID}" echo "::endgroup::" build_base_database: - timeout-minutes: 180 + timeout-minutes: 90 needs: [ "build_base", "init_build"] name: Build ${{ matrix.build }} base (${{ matrix.arch }}) strategy: @@ -348,7 +351,7 @@ jobs: ${{ env.BASE_BUILD_NAME }}_${{ matrix.arch }}_tag key: ${{ env.BASE_BUILD_NAME }}-${{ matrix.arch }}-${{ github.run_id }} - - name: Pull ${{ env.BASE_BUILD_NAME }}:${{ matrix.arch }} image + - name: Pull ${{ env.BASE_BUILD_NAME }}:${{ matrix.arch }} image from local storage id: base_build env: MATRIX_ARCH: ${{ matrix.arch }} @@ -389,7 +392,7 @@ jobs: id: build_image uses: redhat-actions/buildah-build@b4dc19b4ba891854660ab1f88a097d45aa158f76 # v2.12 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/rhel + context: ${{ format('{0}/{1}/rhel', env.DOCKERFILES_DIRECTORY, matrix.build) }} layers: false tags: ${{ steps.meta.outputs.tags }} containerfiles: | @@ -423,7 +426,7 @@ jobs: echo "image_tag_id=${TAG_ID}" >> $GITHUB_OUTPUT echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT - - name: Cache image digest + - name: Cache image metadata uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: | @@ -437,7 +440,6 @@ jobs: IMAGE_TAG: ${{ steps.image_metadata.outputs.image_tag }} IMAGE_TAG_ID: ${{ steps.image_metadata.outputs.image_tag_id }} IMAGE_DIR: ${{ env.IMAGE_DIR }} - GITHUB_WORKSPACE: ${{ github.workspace }} run: | echo "::group::Result" echo "podman push \"${IMAGE_TAG}\" dir:\"${IMAGE_DIR}/${IMAGE_TAG_ID}\"" @@ -468,13 +470,14 @@ jobs: if: ${{ (cancelled() || failure()) && ( steps.push_image.outcome == 'failure' || steps.push_image.outcome == 'cancelled') }} env: IMAGE_TAG_ID: ${{ steps.image_metadata.outputs.image_tag_id }} + IMAGE_DIR: ${{ env.IMAGE_DIR }} run: | echo "::group::Removing orphaned image" rm -rf "${IMAGE_DIR}/${IMAGE_TAG_ID}" echo "::endgroup::" build_images: - timeout-minutes: 90 + timeout-minutes: 30 needs: [ "build_base_database", "init_build"] name: Build ${{ matrix.build }} image (${{ matrix.arch }}) strategy: @@ -580,7 +583,7 @@ jobs: id: build_image uses: redhat-actions/buildah-build@b4dc19b4ba891854660ab1f88a097d45aa158f76 # v2.12 with: - context: ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/rhel + context: ${{ format('{0}/{1}/rhel', env.DOCKERFILES_DIRECTORY, matrix.build) }} layers: false tags: ${{ steps.meta.outputs.tags }} labels: | @@ -588,6 +591,9 @@ jobs: org.opencontainers.image.created=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} containerfiles: | ${{ env.DOCKERFILES_DIRECTORY }}/${{ matrix.build }}/rhel/Dockerfile + extra-args: | + --pull + --iidfile=${{ github.workspace }}/iidfile build-args: BUILD_BASE_IMAGE=${{ steps.base_build.outputs.base_build_image }} - name: Log in to ${{ env.REGISTRY }} @@ -657,11 +663,24 @@ jobs: podman rmi -i -f "$PREFLIGHT_IMAGE" echo "::endgroup::" + - name: Image digest + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + run: | + TAG_ID=$(cat $GITHUB_WORKSPACE/iidfile) + echo "::group::Image digest" + echo "$TAG_ID" + echo "::endgroup::" + - name: Post build image if: ${{ success() || failure() }} + env: + GITHUB_WORKSPACE: ${{ github.workspace }} run: | echo "::group::Result" + rm -rf "$GITHUB_WORKSPACE/iidfile" + echo "Removing working containers" buildah rm -a 2>/dev/null || true echo "Removing container data in storage not controlled by podman" @@ -674,7 +693,7 @@ jobs: echo "::endgroup::" clear_artifacts: - timeout-minutes: 90 + timeout-minutes: 10 needs: [ "build_images", "init_build"] name: Clear ${{ matrix.build }} image cache (${{ matrix.arch }}) strategy: diff --git a/.github/workflows/rhel_registry_description.yml b/.github/workflows/rhel_registry_description.yml new file mode 100644 index 000000000..2fcae397b --- /dev/null +++ b/.github/workflows/rhel_registry_description.yml @@ -0,0 +1,122 @@ +name: Red Hat Catalog Description + +on: + push: + branches: + - 'trunk' + paths: + - 'Dockerfiles/*/*/README.html' + - '.github/workflows/rhel_registry_description.yml' + workflow_dispatch: + +env: + DOCKERFILES_DIRECTORY: "./Dockerfiles" + API_URL: "https://catalog.redhat.com/api/containers/v1/projects/certification/id/" + +defaults: + run: + shell: bash + +permissions: + contents: read + +jobs: + init: + name: Initialize build + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + fail-fast: false + matrix: + component: + - agent + - agent2 + - java-gateway + - proxy-mysql + - proxy-sqlite3 + - server-mysql + - snmptraps + - web-nginx-mysql + - web-service + steps: + - name: Block egress traffic + uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + with: + disable-sudo: true + egress-policy: audit + allowed-endpoints: > + github.com:443 + hub.docker.com:443 + + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 + + - name: Get branch info + id: branch_info + shell: bash + env: + github_ref: ${{ github.ref }} + run: | + result=false + sha_short=$(git rev-parse --short HEAD) + + github_ref=${github_ref##*/} + + echo "::group::Branch metadata" + echo "secret_prefix=RHEL_${github_ref//.}" + echo "::endgroup::" + + echo "secret_prefix=RHEL_${github_ref//.}" >> $GITHUB_OUTPUT + + - name: Prepare Zabbix component list + id: components + env: + MATRIX_FILE: ${{ env.MATRIX_FILE }} + run: | + component_list=$(jq -r '.components | map_values(select(.rhel == true)) | keys | @json' "$MATRIX_FILE") + + echo "::group::Zabbix Component List" + echo "$component_list" + echo "::endgroup::" + + echo "list=$component_list" >> $GITHUB_OUTPUT + + - name: Variables formating + id: var_format + env: + MATRIX_BUILD: ${{ matrix.build }} + run: | + MATRIX_BUILD=${MATRIX_BUILD^^} + MATRIX_BUILD=${MATRIX_BUILD//-/_} + + echo "::group::Result" + echo "matrix_build=${MATRIX_BUILD}" + echo "::endgroup::" + echo "matrix_build=${MATRIX_BUILD}" >> $GITHUB_OUTPUT + + - name: Update Red Hat project description (zabbix-${{ matrix.component }}) + env: + DESCRIPTION_FILE: ${{ format('{0}/{1}/rhel/README.html', env.DOCKERFILES_DIRECTORY, matrix.build) }} + PROJECT_ID: ${{ secrets[format('{0}_{1}_PROJECT', steps.branch_info.outputs.secret_prefix, steps.var_format.outputs.matrix_build)] }} + PYXIS_API_TOKEN: ${{ secrets.REDHAT_API_TOKEN }} + API_URL: ${{ env.API_URL }} + run: | + import requests + import json + import os + + file = open(os.environ["DESCRIPTION_FILE"],mode='r') + repository_description = file.read() + file.close() + + data = dict() + data['container'] = dict() + data['container']['repository_description'] = repository_description[:32768] + + headers = {'accept' : 'application/json', 'X-API-KEY' : os.environ["PYXIS_API_TOKEN"], 'Content-Type' : 'application/json'} + result = requests.patch(os.environ["API_URL"] + os.environ["PROJECT_ID"], headers = headers, data = json.dumps(data)) + print(result) + print(json.loads(r.content)['last_update_date'])