diff --git a/.github/actions/docker-build/action.yaml b/.github/actions/docker-build/action.yaml new file mode 100644 index 000000000..961f9567b --- /dev/null +++ b/.github/actions/docker-build/action.yaml @@ -0,0 +1,132 @@ +# Copyright Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Docker Build (Hermetic) +description: Build operator image hermetically using Hermeto (simulates Konflux+Cachi2) +inputs: + imageName: + description: The full image name including registry (e.g., quay.io/rhdh-community/operator) + required: true + imageTags: + description: The tags to apply to the image + required: true + imageLabels: + description: The labels for the Docker image + required: false + platform: + description: "Target given CPU platform architecture (default: linux/amd64)" + required: false + default: linux/amd64 + +runs: + using: composite + steps: + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 + with: + images: ${{ inputs.imageName }} + tags: | + ${{ inputs.imageTags }} + labels: | + ${{ inputs.imageLabels }} + + - name: Set up hermetic build variables + shell: bash + run: | + echo "HERMETO_IMAGE=quay.io/konflux-ci/hermeto:latest" >> $GITHUB_ENV + echo "LOCAL_CACHE_DIR=./hermeto-cache" >> $GITHUB_ENV + + - name: Cache dependencies with Hermeto + shell: bash + run: | + set -ex + + echo "::group::Creating local cache directory" + mkdir -p ${{ env.LOCAL_CACHE_DIR }} + echo "::endgroup::" + + echo "::group::Fetching dependencies with Hermeto (rpm + gomod)" + podman run --rm \ + -v "$PWD:/source:z" \ + -v "${{ env.LOCAL_CACHE_DIR }}:/cachi2:z" \ + -w /source \ + "${{ env.HERMETO_IMAGE }}" \ + --log-level DEBUG \ + fetch-deps --dev-package-managers \ + --source . \ + --output /cachi2/output \ + '[{"type": "rpm"}, {"type": "gomod", "path": "."}]' + echo "::endgroup::" + + echo "::group::Generating environment file" + podman run --rm \ + -v "$PWD:/source:z" \ + -v "${{ env.LOCAL_CACHE_DIR }}:/cachi2:z" \ + -w /source \ + "${{ env.HERMETO_IMAGE }}" \ + --log-level DEBUG \ + generate-env --format env \ + --output /cachi2/cachi2.env /cachi2/output + echo "::endgroup::" + + echo "::group::Injecting files" + podman run --rm \ + -v "$PWD:/source:z" \ + -v "${{ env.LOCAL_CACHE_DIR }}:/cachi2:z" \ + -w /source \ + "${{ env.HERMETO_IMAGE }}" \ + --log-level DEBUG \ + inject-files /cachi2/output + echo "::endgroup::" + + echo LOCAL_CACHE_DIR_REALPATH=$(realpath "${{ env.LOCAL_CACHE_DIR }}") >> $GITHUB_ENV + + - name: Fix cache ownership for non-root buildah + shell: bash + run: | + sudo chown -R runner ${{ env.LOCAL_CACHE_DIR_REALPATH }} + + - name: Transform Dockerfile for hermetic build + shell: bash + id: transform-dockerfile + env: + TRANSFORMED_DOCKERFILE: Dockerfile.hermeto + run: | + set -x + + echo "::group::Transforming Dockerfile for hermetic build" + cp Dockerfile "$TRANSFORMED_DOCKERFILE" + + # Configure dnf/microdnf to use the hermeto repo + sed -i '/RUN *\(dnf\|microdnf\) install/i RUN rm -r /etc/yum.repos.d/* && cp /cachi2/output/deps/rpm/$(uname -m)/repos.d/hermeto.repo /etc/yum.repos.d/' "$TRANSFORMED_DOCKERFILE" + + # Inject cachi2 env variables into every RUN command + sed -i 's/^\s*RUN /RUN . \/cachi2\/cachi2.env \&\& /' "$TRANSFORMED_DOCKERFILE" + echo "::endgroup::" + + echo "transformed_dockerfile=$TRANSFORMED_DOCKERFILE" >> $GITHUB_OUTPUT + + - name: Build Docker image (hermetic) + id: build + uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2.13 + with: + containerfiles: ${{ steps.transform-dockerfile.outputs.transformed_dockerfile }} + context: . + platform: ${{ inputs.platform }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + extra-args: | + --network=none + --volume ${{ env.LOCAL_CACHE_DIR_REALPATH }}:/cachi2:z diff --git a/.github/workflows/pr-hermetic-build.yaml b/.github/workflows/pr-hermetic-build.yaml new file mode 100644 index 000000000..ab1c3df49 --- /dev/null +++ b/.github/workflows/pr-hermetic-build.yaml @@ -0,0 +1,49 @@ +# Copyright Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: PR Hermetic Build + +on: + pull_request: + branches: + - main + - rhdh-1.[0-9]+ + - release-1.[0-9]+ + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + hermetic-build: + name: Hermetic Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Build operator image (hermetic) + uses: ./.github/actions/docker-build + with: + imageName: quay.io/rhdh-community/operator + imageTags: | + hermetic-pr-${{ github.event.number }} + imageLabels: quay.expires-after=14d + platform: linux/amd64 diff --git a/.github/workflows/update-rpm-lockfile.yaml b/.github/workflows/update-rpm-lockfile.yaml index 9b6a8b9df..fb1064e9d 100644 --- a/.github/workflows/update-rpm-lockfile.yaml +++ b/.github/workflows/update-rpm-lockfile.yaml @@ -11,14 +11,14 @@ on: - release-1.** paths: - 'rpms.in.yaml' - - '.rhdh/docker/Dockerfile' + - 'Dockerfile' - '.github/workflows/update-rpm-lockfile.yaml' permissions: contents: write env: - DOCKERFILE_PATH: .rhdh/docker/Dockerfile + DOCKERFILE_PATH: Dockerfile jobs: update-lockfile: diff --git a/.rhdh/docker/Dockerfile b/.rhdh/docker/Dockerfile deleted file mode 100644 index dcdb33565..000000000 --- a/.rhdh/docker/Dockerfile +++ /dev/null @@ -1,72 +0,0 @@ -# THIS IS USED BY Konflux builds >= 1.4 with Cachi2 enabled - -#@follow_tag(registry.redhat.io/rhel9/go-toolset:latest) -# https://registry.access.redhat.com/ubi9/go-toolset -FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1781757851@sha256:b2c0898987b688a95f4d2f38abdfd929f45903948831783153019ab749495c72 AS builder -ARG TARGETOS -ARG TARGETARCH -# hadolint ignore=DL3002 -USER 0 -ENV GOPATH=/go/ - -# '(micro)dnf update -y' not allowed in Konflux+Cachi2: instead use renovate or https://github.com/konflux-ci/rpm-lockfile-prototype to update the rpms.lock.yaml file -# Downstream comment -# RUN dnf -q -y update -#/ Downstream comment - -ENV EXTERNAL_SOURCE=. -ENV CONTAINER_SOURCE=/opt/app-root/src -WORKDIR $CONTAINER_SOURCE - -# cache deps before building and copying source so that we don't need to re-download as much -# and so that source changes don't invalidate our downloaded layer -COPY $EXTERNAL_SOURCE/go.mod $CONTAINER_SOURCE/go.mod -COPY $EXTERNAL_SOURCE/go.sum $CONTAINER_SOURCE/go.sum -RUN go mod download - -COPY $EXTERNAL_SOURCE $CONTAINER_SOURCE - -# Build -# hadolint ignore=SC3010 -# Build -# the GOARCH has not a default value to allow the binary be built according to the host where the command -# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO -# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, -# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go - -# Install openssl for FIPS support -#@follow_tag(registry.redhat.io/ubi9/ubi-minimal:latest) -# https://registry.access.redhat.com/ubi9-minimal -FROM registry.access.redhat.com/ubi9-minimal:9.8-1781496742@sha256:1bc3c5c15720506a0cf48adfdf8b623dfe704377e007d7bbae8d14876392ca6a AS runtime -# Downstream uncomment -RUN cat /cachi2/cachi2.env -#/ Downstream uncomment - -# '(micro)dnf update -y' not allowed in Konflux+Cachi2: instead use renovate or https://github.com/konflux-ci/rpm-lockfile-prototype to update the rpms.lock.yaml file -# Downstream comment -# RUN microdnf update --setopt=install_weak_deps=0 -y -#/ Downstream comment - -RUN microdnf install -y openssl; microdnf clean -y all - -ENV EXTERNAL_SOURCE=. -ENV CONTAINER_SOURCE=/opt/app-root/src - -# RHIDP-4220 - make Konflux preflight and EC checks happy - [check-container] Create a directory named /licenses and include all relevant licensing -COPY $EXTERNAL_SOURCE/LICENSE /licenses/ - -ENV HOME=/ \ - USER_NAME=backstage \ - USER_UID=1001 - -RUN echo "${USER_NAME}:x:${USER_UID}:0:${USER_NAME} user:${HOME}:/sbin/nologin" >> /etc/passwd - -# Copy manager binary -COPY --from=builder $CONTAINER_SOURCE/manager . - -USER ${USER_UID} - -WORKDIR ${HOME} - -ENTRYPOINT ["/manager"] diff --git a/Dockerfile b/Dockerfile index a9f5b8c0e..76eb7e636 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,14 +5,14 @@ FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1781757851@sha256:b2c0898987b688a95f4d2f38abdfd929f45903948831783153019ab749495c72 AS builder ARG TARGETOS ARG TARGETARCH +ARG HERMETIC=false # hadolint ignore=DL3002 USER 0 ENV GOPATH=/go/ -# '(micro)dnf update -y' not allowed in Konflux+Cachi2: instead use renovate or https://github.com/konflux-ci/rpm-lockfile-prototype to update the rpms.lock.yaml file -# Downstream comment -RUN dnf -q -y update -#/ Downstream comment +# In hermetic (Konflux+Cachi2) builds, dnf/microdnf update is not allowed; +# use renovate or rpm-lockfile-prototype to update rpms.lock.yaml instead +RUN if [ "$HERMETIC" = "false" ]; then dnf -q -y update; fi ENV EXTERNAL_SOURCE=. ENV CONTAINER_SOURCE=/opt/app-root/src @@ -39,15 +39,11 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o ma #@follow_tag(registry.redhat.io/ubi9/ubi-minimal:latest) # https://registry.access.redhat.com/ubi9-minimal FROM registry.access.redhat.com/ubi9-minimal:9.8-1781496742@sha256:1bc3c5c15720506a0cf48adfdf8b623dfe704377e007d7bbae8d14876392ca6a AS runtime +ARG HERMETIC=false -# Downstream uncomment -# RUN cat /cachi2/cachi2.env -#/ Downstream uncomment +RUN if [ "$HERMETIC" = "true" ]; then cat /cachi2/cachi2.env; fi -# '(micro)dnf update -y' not allowed in Konflux+Cachi2: instead use renovate or https://github.com/konflux-ci/rpm-lockfile-prototype to update the rpms.lock.yaml file -# Downstream comment -RUN microdnf update --setopt=install_weak_deps=0 -y -#/ Downstream comment +RUN if [ "$HERMETIC" = "false" ]; then microdnf update --setopt=install_weak_deps=0 -y; fi RUN microdnf install -y openssl; microdnf clean -y all diff --git a/Makefile b/Makefile index fae5219f7..c3bc62a97 100644 --- a/Makefile +++ b/Makefile @@ -245,6 +245,10 @@ PLATFORM ?= linux/amd64 image-build: ## Build container image with the manager. $(CONTAINER_TOOL) build --platform $(PLATFORM) -t $(IMG) --label $(LABEL) . +.PHONY: image-build-hermetic +image-build-hermetic: ## Build container image in hermetic mode (simulates Konflux+Cachi2). + $(CONTAINER_TOOL) build --platform $(PLATFORM) -t $(IMG) --label $(LABEL) --build-arg HERMETIC=true . + .PHONY: image-push image-push: ## Push container image with the manager. $(CONTAINER_TOOL) push $(IMG) diff --git a/rpms.in.yaml b/rpms.in.yaml index 37169e9f9..50ffa8865 100644 --- a/rpms.in.yaml +++ b/rpms.in.yaml @@ -1,6 +1,6 @@ # RHDH Operator RPM dependencies # after editing, run (https://github.com/konflux-ci/rpm-lockfile-prototype): -# rpm-lockfile-prototype -f .rhdh/docker/Dockerfile rpms.in.yaml +# rpm-lockfile-prototype -f Dockerfile rpms.in.yaml # to regenerate rpms.lock.yaml # # Note that the repoid values are special, and must be from here: