From fd82d93ed26a819886b18e6b3982d7f3beece3f4 Mon Sep 17 00:00:00 2001 From: Tomas Nevrlka Date: Thu, 19 Dec 2024 16:23:04 +0100 Subject: [PATCH] create scaffolding for buildah 0.3 - Buildah 0.3 will be released - Copy buildah 0.2 directory to 0.3 for easier diff comparisons between the versions --- task/buildah/0.3/README.md | 54 +++ task/buildah/0.3/buildah.yaml | 701 ++++++++++++++++++++++++++++ task/buildah/0.3/kustomization.yaml | 5 + 3 files changed, 760 insertions(+) create mode 100644 task/buildah/0.3/README.md create mode 100644 task/buildah/0.3/buildah.yaml create mode 100644 task/buildah/0.3/kustomization.yaml diff --git a/task/buildah/0.3/README.md b/task/buildah/0.3/README.md new file mode 100644 index 0000000000..6be68eb10e --- /dev/null +++ b/task/buildah/0.3/README.md @@ -0,0 +1,54 @@ +# buildah task + +Buildah task builds source code into a container image and pushes the image into container registry using buildah tool. +In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool. +When [Java dependency rebuild](https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/cli/proc_enabled_java_dependencies.html) is enabled it triggers rebuilds of Java artifacts. +When prefetch-dependencies task was activated it is using its artifacts to run build in hermetic environment. + +## Parameters +| name | description | default value | required | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | -------- | +| IMAGE | Reference of the image buildah will produce. | | true | +| DOCKERFILE | Path to the Dockerfile to build. | ./Dockerfile | false | +| CONTEXT | Path to the directory to use as context. | . | false | +| TLSVERIFY | Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry) | true | false | +| HERMETIC | Determines if build will be executed without network access. | false | false | +| PREFETCH_INPUT | In case it is not empty, the prefetched content should be made available to the build. | "" | false | +| IMAGE_EXPIRES_AFTER | Delete image tag after specified time. Empty means to keep the image tag. Time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. | "" | false | +| COMMIT_SHA | The image is built from this commit. | "" | false | +| YUM_REPOS_D_SRC | Path in the git repository in which yum repository files are stored | repos.d | false | +| YUM_REPOS_D_FETCHED | Path in source workspace where dynamically-fetched repos are present | fetched.repos.d | false | +| YUM_REPOS_D_TARGET | Target path on the container in which yum repository files should be made available | /etc/yum.repos.d | false | +| TARGET_STAGE | Target stage in Dockerfile to build. If not specified, the Dockerfile is processed entirely to (and including) its last stage. | "" | false | +| ENTITLEMENT_SECRET | Name of secret which contains the entitlement certificates | etc-pki-entitlement | false | +| ACTIVATION_KEY | Name of secret which contains subscription activation key | activation-key | false | +| ADDITIONAL_SECRET | Name of a secret which will be made available to the build with 'buildah build --secret' at /run/secrets/$ADDITIONAL_SECRET | does-not-exist | false | +| BUILD_ARGS | Array of --build-arg values ("arg=value" strings) | [] | false | +| BUILD_ARGS_FILE | Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file | "" | false | +| caTrustConfigMapName | The name of the ConfigMap to read CA bundle data from. | trusted-ca | false | +| caTrustConfigMapKey | The name of the key in the ConfigMap that contains the CA bundle data. | ca-bundle.crt | false | +| ADD_CAPABILITIES | Comma separated list of extra capabilities to add when running 'buildah build' | "" | false | +| SQUASH | Squash all new and previous layers added as a part of this build, as per --squash | false | false | +| STORAGE_DRIVER | Storage driver to configure for buildah | vfs | false | +| SKIP_UNUSED_STAGES | Whether to skip stages in Containerfile that seem unused by subsequent stages | true | false | + +## Results +| name | description | +| --------------------------- | --------------------------------------------------------------------------------- | +| IMAGE_DIGEST | Digest of the image just built | +| IMAGE_URL | Image repository and tag where the built image was pushed | +| IMAGE_REF | Image reference of the built image | +| SBOM_BLOB_URL | Reference of SBOM blob digest to enable digest-based verification from provenance | +| SBOM_JAVA_COMPONENTS_COUNT | The counting of Java components by publisher in JSON format | +| JAVA_COMMUNITY_DEPENDENCIES | The Java dependencies that came from community sources such as Maven central. | + +## Workspaces +| name | description | optional | +| ------ | ---------------------------------------------- | -------- | +| source | Workspace containing the source code to build. | false | + + +## Changes in 0.2.1 +- Added image reference to the SBOM output file. +- Re-arranged steps to push image first and then generate and push SBOM file. +- Remove SBOM file stored in the image under `/root/buildinfo/content_manifests/` diff --git a/task/buildah/0.3/buildah.yaml b/task/buildah/0.3/buildah.yaml new file mode 100644 index 0000000000..35af0fde84 --- /dev/null +++ b/task/buildah/0.3/buildah.yaml @@ -0,0 +1,701 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + labels: + app.kubernetes.io/version: "0.2.1" + build.appstudio.redhat.com/build_type: "docker" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: "image-build, konflux" + name: buildah +spec: + description: |- + Buildah task builds source code into a container image and pushes the image into container registry using buildah tool. + In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool. + When [Java dependency rebuild](https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/cli/proc_enabled_java_dependencies.html) is enabled it triggers rebuilds of Java artifacts. + When prefetch-dependencies task was activated it is using its artifacts to run build in hermetic environment. + params: + - description: Reference of the image buildah will produce. + name: IMAGE + type: string + - default: ./Dockerfile + description: Path to the Dockerfile to build. + name: DOCKERFILE + type: string + - default: . + description: Path to the directory to use as context. + name: CONTEXT + type: string + - default: "true" + description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry) + name: TLSVERIFY + type: string + - default: "false" + description: Determines if build will be executed without network access. + name: HERMETIC + type: string + - default: "" + description: In case it is not empty, the prefetched content should be made available to the build. + name: PREFETCH_INPUT + type: string + - default: "" + description: Delete image tag after specified time. Empty means to keep the image tag. Time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively. + name: IMAGE_EXPIRES_AFTER + type: string + - name: COMMIT_SHA + description: The image is built from this commit. + type: string + default: "" + - name: YUM_REPOS_D_SRC + description: Path in the git repository in which yum repository files are stored + default: repos.d + - name: YUM_REPOS_D_FETCHED + description: Path in source workspace where dynamically-fetched repos are present + default: fetched.repos.d + - name: YUM_REPOS_D_TARGET + description: Target path on the container in which yum repository files should be made available + default: /etc/yum.repos.d + - name: TARGET_STAGE + description: Target stage in Dockerfile to build. If not specified, the Dockerfile is processed entirely to (and including) its last stage. + type: string + default: "" + - name: ENTITLEMENT_SECRET + description: Name of secret which contains the entitlement certificates + type: string + default: "etc-pki-entitlement" + - name: ACTIVATION_KEY + default: activation-key + description: Name of secret which contains subscription activation key + type: string + - name: ADDITIONAL_SECRET + description: Name of a secret which will be made available to the build with 'buildah build --secret' at /run/secrets/$ADDITIONAL_SECRET + type: string + default: "does-not-exist" + - name: BUILD_ARGS + description: Array of --build-arg values ("arg=value" strings) + type: array + default: [] + - name: BUILD_ARGS_FILE + description: Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file + type: string + default: "" + - name: caTrustConfigMapName + type: string + description: The name of the ConfigMap to read CA bundle data from. + default: trusted-ca + - name: caTrustConfigMapKey + type: string + description: The name of the key in the ConfigMap that contains the CA bundle data. + default: ca-bundle.crt + - name: ADD_CAPABILITIES + description: Comma separated list of extra capabilities to add when running 'buildah build' + type: string + default: "" + - name: SQUASH + description: Squash all new and previous layers added as a part of this build, as per --squash + type: string + default: "false" + - name: STORAGE_DRIVER + description: Storage driver to configure for buildah + type: string + default: vfs + - name: SKIP_UNUSED_STAGES + description: Whether to skip stages in Containerfile that seem unused by subsequent stages + type: string + default: "true" + - name: LABELS + description: Additional key=value labels that should be applied to the image + type: array + default: [] + + results: + - description: Digest of the image just built + name: IMAGE_DIGEST + - description: Image repository and tag where the built image was pushed + name: IMAGE_URL + - description: Image reference of the built image + name: IMAGE_REF + - name: SBOM_BLOB_URL + description: Reference of SBOM blob digest to enable digest-based verification from provenance + type: string + - name: SBOM_JAVA_COMPONENTS_COUNT + description: The counting of Java components by publisher in JSON format + type: string + - name: JAVA_COMMUNITY_DEPENDENCIES + description: The Java dependencies that came from community sources such as Maven central. + stepTemplate: + volumeMounts: + - mountPath: /shared + name: shared + env: + - name: BUILDAH_FORMAT + value: oci + - name: STORAGE_DRIVER + value: $(params.STORAGE_DRIVER) + - name: HERMETIC + value: $(params.HERMETIC) + - name: SOURCE_CODE_DIR + value: source + - name: CONTEXT + value: $(params.CONTEXT) + - name: IMAGE + value: $(params.IMAGE) + - name: TLSVERIFY + value: $(params.TLSVERIFY) + - name: IMAGE_EXPIRES_AFTER + value: $(params.IMAGE_EXPIRES_AFTER) + - name: YUM_REPOS_D_SRC + value: $(params.YUM_REPOS_D_SRC) + - name: YUM_REPOS_D_FETCHED + value: $(params.YUM_REPOS_D_FETCHED) + - name: YUM_REPOS_D_TARGET + value: $(params.YUM_REPOS_D_TARGET) + - name: TARGET_STAGE + value: $(params.TARGET_STAGE) + - name: ENTITLEMENT_SECRET + value: $(params.ENTITLEMENT_SECRET) + - name: ACTIVATION_KEY + value: $(params.ACTIVATION_KEY) + - name: ADDITIONAL_SECRET + value: $(params.ADDITIONAL_SECRET) + - name: BUILD_ARGS_FILE + value: $(params.BUILD_ARGS_FILE) + - name: ADD_CAPABILITIES + value: $(params.ADD_CAPABILITIES) + - name: SQUASH + value: $(params.SQUASH) + - name: SKIP_UNUSED_STAGES + value: $(params.SKIP_UNUSED_STAGES) + + steps: + - image: quay.io/konflux-ci/buildah-task:latest@sha256:b2d6c32d1e05e91920cd4475b2761d58bb7ee11ad5dff3ecb59831c7572b4d0c + name: build + computeResources: + limits: + memory: 8Gi + cpu: '4' + requests: + memory: 2Gi + cpu: '1' + env: + - name: COMMIT_SHA + value: $(params.COMMIT_SHA) + - name: DOCKERFILE + value: $(params.DOCKERFILE) + args: + - --build-args + - $(params.BUILD_ARGS[*]) + - --labels + - $(params.LABELS[*]) + + script: | + #!/bin/bash + set -euo pipefail + ca_bundle=/mnt/trusted-ca/ca-bundle.crt + if [ -f "$ca_bundle" ]; then + echo "INFO: Using mounted CA bundle: $ca_bundle" + cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors + update-ca-trust + fi + + if [ -e "$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" ]; then + dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" + elif [ -e "$SOURCE_CODE_DIR/$DOCKERFILE" ]; then + dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$DOCKERFILE" + elif [ -e "$DOCKERFILE" ]; then + # Custom Dockerfile location is mainly used for instrumented builds for SAST scanning and analyzing. + # Instrumented builds use this step as their base and also need to provide modified Dockerfile. + dockerfile_path="$DOCKERFILE" + elif echo "$DOCKERFILE" | grep -q "^https\?://"; then + echo "Fetch Dockerfile from $DOCKERFILE" + dockerfile_path=$(mktemp --suffix=-Dockerfile) + http_code=$(curl -s -S -L -w "%{http_code}" --output "$dockerfile_path" "$DOCKERFILE") + if [ $http_code != 200 ]; then + echo "No Dockerfile is fetched. Server responds $http_code" + exit 1 + fi + http_code=$(curl -s -S -L -w "%{http_code}" --output "$dockerfile_path.dockerignore.tmp" "$DOCKERFILE.dockerignore") + if [ $http_code = 200 ]; then + echo "Fetched .dockerignore from $DOCKERFILE.dockerignore" + mv "$dockerfile_path.dockerignore.tmp" $SOURCE_CODE_DIR/$CONTEXT/.dockerignore + fi + else + echo "Cannot find Dockerfile $DOCKERFILE" + exit 1 + fi + + dockerfile_copy=$(mktemp --tmpdir "$(basename "$dockerfile_path").XXXXXX") + cp "$dockerfile_path" "$dockerfile_copy" + + if [ -n "${JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR-}" ] && grep -q '^\s*RUN \(./\)\?mvn' "$dockerfile_copy"; then + sed -i -e "s|^\s*RUN \(\(./\)\?mvn\)\(.*\)|RUN echo \"mirror.defaulthttp://$JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR/v1/cache/default/0/*\" > /tmp/settings.yaml; \1 -s /tmp/settings.yaml \3|g" "$dockerfile_copy" + touch /var/lib/containers/java + fi + + # Fixing group permission on /var/lib/containers + chown root:root /var/lib/containers + + sed -i 's/^\s*short-name-mode\s*=\s*.*/short-name-mode = "disabled"/' /etc/containers/registries.conf + + # Setting new namespace to run buildah - 2^32-2 + echo 'root:1:4294967294' | tee -a /etc/subuid >> /etc/subgid + + build_args=() + if [ -n "${BUILD_ARGS_FILE}" ]; then + # Parse BUILD_ARGS_FILE ourselves because dockerfile-json doesn't support it + echo "Parsing ARGs from $BUILD_ARGS_FILE" + mapfile -t build_args < <( + # https://www.mankier.com/1/buildah-build#--build-arg-file + # delete lines that start with # + # delete blank lines + sed -e '/^#/d' -e '/^\s*$/d' "${SOURCE_CODE_DIR}/${BUILD_ARGS_FILE}" + ) + fi + + LABELS=() + # Split `args` into two sets of arguments. + while [[ $# -gt 0 ]]; do + case $1 in + --build-args) + shift + # Note: this may result in multiple --build-arg=KEY=value flags with the same KEY being + # passed to buildah. In that case, the *last* occurrence takes precedence. This is why + # we append BUILD_ARGS after the content of the BUILD_ARGS_FILE - they take precedence. + while [[ $# -gt 0 && $1 != --* ]]; do build_args+=("$1"); shift; done + ;; + --labels) + shift + while [[ $# -gt 0 && $1 != --* ]]; do LABELS+=("--label" "$1"); shift; done + ;; + *) + echo "unexpected argument: $1" >&2 + exit 2 + ;; + esac + done + + BUILD_ARG_FLAGS=() + for build_arg in "${build_args[@]}"; do + BUILD_ARG_FLAGS+=("--build-arg=$build_arg") + done + + + dockerfile-json "${BUILD_ARG_FLAGS[@]}" "$dockerfile_copy" > /shared/parsed_dockerfile.json + BASE_IMAGES=$( + jq -r '.Stages[] | select(.From | .Stage or .Scratch | not) | .BaseName | select(test("^oci-archive:") | not)' /shared/parsed_dockerfile.json + ) + + BUILDAH_ARGS=() + UNSHARE_ARGS=() + + if [ "${HERMETIC}" == "true" ]; then + BUILDAH_ARGS+=("--pull=never") + UNSHARE_ARGS+=("--net") + + for image in $BASE_IMAGES; do + unshare -Ufp --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -- buildah pull $image + done + echo "Build will be executed with network isolation" + fi + + if [ -n "${TARGET_STAGE}" ]; then + BUILDAH_ARGS+=("--target=${TARGET_STAGE}") + fi + + BUILDAH_ARGS+=("${BUILD_ARG_FLAGS[@]}") + + if [ -n "${ADD_CAPABILITIES}" ]; then + BUILDAH_ARGS+=("--cap-add=${ADD_CAPABILITIES}") + fi + + if [ "${SQUASH}" == "true" ]; then + BUILDAH_ARGS+=("--squash") + fi + + if [ "${SKIP_UNUSED_STAGES}" != "true" ] ; then + BUILDAH_ARGS+=("--skip-unused-stages=false") + fi + + VOLUME_MOUNTS=() + + if [ -f "$(workspaces.source.path)/cachi2/cachi2.env" ]; then + cp -r "$(workspaces.source.path)/cachi2" /tmp/ + chmod -R go+rwX /tmp/cachi2 + VOLUME_MOUNTS+=(--volume /tmp/cachi2:/cachi2) + # Read in the whole file (https://unix.stackexchange.com/questions/533277), then + # for each RUN ... line insert the cachi2.env command *after* any options like --mount + sed -E -i \ + -e 'H;1h;$!d;x' \ + -e 's@^\s*(run((\s|\\\n)+-\S+)*(\s|\\\n)+)@\1. /cachi2/cachi2.env \&\& \\\n @igM' \ + "$dockerfile_copy" + echo "Prefetched content will be made available" + + prefetched_repo_for_my_arch="/tmp/cachi2/output/deps/rpm/$(uname -m)/repos.d/cachi2.repo" + if [ -f "$prefetched_repo_for_my_arch" ]; then + echo "Adding $prefetched_repo_for_my_arch to $YUM_REPOS_D_FETCHED" + mkdir -p "$YUM_REPOS_D_FETCHED" + cp --no-clobber "$prefetched_repo_for_my_arch" "$YUM_REPOS_D_FETCHED" + fi + fi + + # if yum repofiles stored in git, copy them to mount point outside the source dir + if [ -d "${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}" ]; then + mkdir -p ${YUM_REPOS_D_FETCHED} + cp -r ${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}/* ${YUM_REPOS_D_FETCHED} + fi + + # if anything in the repofiles mount point (either fetched or from git), mount it + if [ -d "${YUM_REPOS_D_FETCHED}" ]; then + chmod -R go+rwX ${YUM_REPOS_D_FETCHED} + mount_point=$(realpath ${YUM_REPOS_D_FETCHED}) + VOLUME_MOUNTS+=(--volume "${mount_point}:${YUM_REPOS_D_TARGET}") + fi + + DEFAULT_LABELS=( + "--label" "build-date=$(date -u +'%Y-%m-%dT%H:%M:%S')" + "--label" "architecture=$(uname -m)" + "--label" "vcs-type=git" + ) + [ -n "$COMMIT_SHA" ] && DEFAULT_LABELS+=("--label" "vcs-ref=$COMMIT_SHA") + [ -n "$IMAGE_EXPIRES_AFTER" ] && DEFAULT_LABELS+=("--label" "quay.expires-after=$IMAGE_EXPIRES_AFTER") + + # Concatenate defaults and explicit labels. If a label appears twice, the last one wins. + LABELS=("${DEFAULT_LABELS[@]}" "${LABELS[@]}") + + ACTIVATION_KEY_PATH="/activation-key" + ENTITLEMENT_PATH="/entitlement" + + # 0. if hermetic=true, skip all subscription related stuff + # 1. do not enable activation key and entitlement at same time. If both vars are provided, prefer activation key. + # 2. Activation-keys will be used when the key 'org' exists in the activation key secret. + # 3. try to pre-register and mount files to the correct location so that users do no need to modify Dockerfiles. + # 3. If the Dockerfile contains the string "subcription-manager register", add the activation-keys volume + # to buildah but don't pre-register for backwards compatibility. In this case mount an empty directory on + # shared emptydir volume to "/etc/pki/entitlement" to prevent certificates from being included in the produced + # container. + + if [ "${HERMETIC}" != "true" ] && [ -e /activation-key/org ]; then + cp -r --preserve=mode "$ACTIVATION_KEY_PATH" /tmp/activation-key + mkdir -p /shared/rhsm/etc/pki/entitlement + mkdir -p /shared/rhsm/etc/pki/consumer + + VOLUME_MOUNTS+=(-v /tmp/activation-key:/activation-key \ + -v /shared/rhsm/etc/pki/entitlement:/etc/pki/entitlement:Z \ + -v /shared/rhsm/etc/pki/consumer:/etc/pki/consumer:Z) + echo "Adding activation key to the build" + + if ! grep -E "^[^#]*subscription-manager.[^#]*register" "$dockerfile_path"; then + # user is not running registration in the Containerfile: pre-register. + echo "Pre-registering with subscription manager." + subscription-manager register --org "$(cat /tmp/activation-key/org)" --activationkey "$(cat /tmp/activation-key/activationkey)" + trap 'subscription-manager unregister || true' EXIT + + # copy generated certificates to /shared volume + cp /etc/pki/entitlement/*.pem /shared/rhsm/etc/pki/entitlement + cp /etc/pki/consumer/*.pem /shared/rhsm/etc/pki/consumer + + # and then mount get /etc/rhsm/ca/redhat-uep.pem into /run/secrets/rhsm/ca + VOLUME_MOUNTS+=(--volume /etc/rhsm/ca/redhat-uep.pem:/etc/rhsm/ca/redhat-uep.pem:Z) + fi + + elif [ "${HERMETIC}" != "true" ] && find /entitlement -name "*.pem" >> null; then + cp -r --preserve=mode "$ENTITLEMENT_PATH" /tmp/entitlement + VOLUME_MOUNTS+=(--volume /tmp/entitlement:/etc/pki/entitlement) + echo "Adding the entitlement to the build" + fi + + if [ -n "${ADDITIONAL_VOLUME_MOUNTS-}" ]; then + # ADDITIONAL_VOLUME_MOUNTS allows to specify more volumes for the build. + # This is primarily used in instrumented builds for SAST scanning and analyzing. + # Instrumented builds use this step as their base and add some other tools. + while read -r volume_mount; do + VOLUME_MOUNTS+=("--volume=$volume_mount") + done <<< "$ADDITIONAL_VOLUME_MOUNTS" + fi + + ADDITIONAL_SECRET_PATH="/additional-secret" + ADDITIONAL_SECRET_TMP="/tmp/additional-secret" + if [ -d "$ADDITIONAL_SECRET_PATH" ]; then + cp -r --preserve=mode -L "$ADDITIONAL_SECRET_PATH" $ADDITIONAL_SECRET_TMP + while read -r filename; do + echo "Adding the secret ${ADDITIONAL_SECRET}/${filename} to the build, available at /run/secrets/${ADDITIONAL_SECRET}/${filename}" + BUILDAH_ARGS+=("--secret=id=${ADDITIONAL_SECRET}/${filename},src=$ADDITIONAL_SECRET_TMP/${filename}") + done < <(find $ADDITIONAL_SECRET_TMP -maxdepth 1 -type f -exec basename {} \;) + fi + + # Prevent ShellCheck from giving a warning because 'image' is defined and 'IMAGE' is not. + declare IMAGE + + buildah_cmd_array=( + buildah build + "${VOLUME_MOUNTS[@]}" + "${BUILDAH_ARGS[@]}" + "${LABELS[@]}" + --tls-verify="$TLSVERIFY" --no-cache + --ulimit nofile=4096:4096 + -f "$dockerfile_copy" -t "$IMAGE" . + ) + buildah_cmd=$(printf "%q " "${buildah_cmd_array[@]}") + + if [ "${HERMETIC}" == "true" ]; then + # enabling loopback adapter enables Bazel builds to work in hermetic mode. + command="ip link set lo up && $buildah_cmd" + else + command="$buildah_cmd" + fi + + # disable host subcription manager integration + find /usr/share/rhel/secrets -type l -exec unlink {} \; + + unshare -Uf "${UNSHARE_ARGS[@]}" --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -w "${SOURCE_CODE_DIR}/$CONTEXT" -- sh -c "$command" + + container=$(buildah from --pull-never "$IMAGE") + buildah mount $container | tee /shared/container_path + # delete symlinks - they may point outside the container rootfs, messing with SBOM scanners + find $(cat /shared/container_path) -xtype l -delete + echo $container > /shared/container_name + + # Save the SBOM produced by Cachi2 so it can be merged into the final SBOM later + if [ -f "/tmp/cachi2/output/bom.json" ]; then + cp /tmp/cachi2/output/bom.json ./sbom-cachi2.json + fi + + touch /shared/base_images_digests + for image in $BASE_IMAGES; do + base_image_digest=$(buildah images --format '{{ .Name }}:{{ .Tag }}@{{ .Digest }}' --filter reference="$image") + # In some cases, there might be BASE_IMAGES, but not any associated digest. This happens + # if buildah did not use that particular image during build because it was skipped + if [ -n "$base_image_digest" ]; then + echo "$image $base_image_digest" >> /shared/base_images_digests + fi + done + + securityContext: + capabilities: + add: + - SETFCAP + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - mountPath: "/entitlement" + name: etc-pki-entitlement + - mountPath: /activation-key + name: activation-key + - mountPath: "/additional-secret" + name: additional-secret + - name: trusted-ca + mountPath: /mnt/trusted-ca + readOnly: true + workingDir: $(workspaces.source.path) + + - name: push + image: quay.io/konflux-ci/buildah-task:latest@sha256:b2d6c32d1e05e91920cd4475b2761d58bb7ee11ad5dff3ecb59831c7572b4d0c + computeResources: + limits: + memory: 4Gi + cpu: '4' + requests: + memory: 1Gi + cpu: '1' + script: | + #!/bin/bash + set -e + + ca_bundle=/mnt/trusted-ca/ca-bundle.crt + if [ -f "$ca_bundle" ]; then + echo "INFO: Using mounted CA bundle: $ca_bundle" + cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors + update-ca-trust + fi + + retries=5 + # Push to a unique tag based on the TaskRun name to avoid race conditions + echo "Pushing to ${IMAGE%:*}:${TASKRUN_NAME}" + if ! buildah push \ + --retry "$retries" \ + --tls-verify="$TLSVERIFY" \ + "$IMAGE" \ + "docker://${IMAGE%:*}:$(context.taskRun.name)"; + then + echo "Failed to push sbom image to ${IMAGE%:*}:$(context.taskRun.name) after ${retries} tries" + exit 1 + fi + + # Push to a tag based on the git revision + echo "Pushing to ${IMAGE}" + if ! buildah push \ + --retry "$retries" \ + --tls-verify="$TLSVERIFY" \ + --digestfile "$(workspaces.source.path)/image-digest" "$IMAGE" \ + "docker://$IMAGE"; + then + echo "Failed to push sbom image to $IMAGE after ${retries} tries" + exit 1 + fi + + cat "$(workspaces.source.path)"/image-digest | tee $(results.IMAGE_DIGEST.path) + echo -n "$IMAGE" | tee $(results.IMAGE_URL.path) + { + echo -n "${IMAGE}@" + cat "$(workspaces.source.path)/image-digest" + } > "$(results.IMAGE_REF.path)" + + securityContext: + runAsUser: 0 + capabilities: + add: + - SETFCAP + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - name: trusted-ca + mountPath: /mnt/trusted-ca + readOnly: true + workingDir: $(workspaces.source.path) + + - name: sbom-syft-generate + image: registry.access.redhat.com/rh-syft-tech-preview/syft-rhel9:1.4.1@sha256:34d7065427085a31dc4949bd283c001b91794d427e1e4cdf1b21ea4faf9fee3f + # Respect Syft configuration if the user has it in the root of their repository + # (need to set the workdir, see https://github.com/anchore/syft/issues/2465) + workingDir: $(workspaces.source.path)/source + computeResources: + limits: + memory: 4Gi + cpu: '2' + requests: + memory: 1Gi + cpu: 500m + script: | + echo "Running syft on the source directory" + syft dir:"$(workspaces.source.path)/$SOURCE_CODE_DIR/$CONTEXT" --output cyclonedx-json="$(workspaces.source.path)/sbom-source.json" + echo "Running syft on the image filesystem" + syft dir:"$(cat /shared/container_path)" --output cyclonedx-json="$(workspaces.source.path)/sbom-image.json" + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - mountPath: /shared + name: shared + - name: analyse-dependencies-java-sbom + image: quay.io/redhat-appstudio/hacbs-jvm-build-request-processor:127ee0c223a2b56a9bd20a6f2eaeed3bd6015f77 + computeResources: + limits: + memory: 512Mi + cpu: 200m + requests: + memory: 256Mi + cpu: 100m + script: | + if [ -f /var/lib/containers/java ]; then + /opt/jboss/container/java/run/run-java.sh analyse-dependencies path $(cat /shared/container_path) -s $(workspaces.source.path)/sbom-image.json --task-run-name $(context.taskRun.name) --publishers $(results.SBOM_JAVA_COMPONENTS_COUNT.path) + sed -i 's/^/ /' $(results.SBOM_JAVA_COMPONENTS_COUNT.path) # Workaround for SRVKP-2875 + else + touch $(results.JAVA_COMMUNITY_DEPENDENCIES.path) + fi + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - mountPath: /shared + name: shared + securityContext: + runAsUser: 0 + + - name: prepare-sboms + image: quay.io/redhat-appstudio/sbom-utility-scripts-image@sha256:adbe6c723810099c5cf616b1edb8ab6f276385fd2f97dfd201ab3ccc6402b834 + computeResources: + limits: + memory: 512Mi + cpu: 200m + requests: + memory: 256Mi + cpu: 100m + script: | + echo "Merging contents of sbom-source.json and sbom-image.json into sbom-cyclonedx.json" + python3 /scripts/merge_syft_sboms.py + + if [ -f "sbom-cachi2.json" ]; then + echo "Merging contents of sbom-cachi2.json into sbom-cyclonedx.json" + python3 /scripts/merge_cachi2_sboms.py sbom-cachi2.json sbom-cyclonedx.json > sbom-temp.json + mv sbom-temp.json sbom-cyclonedx.json + fi + + echo "Adding base images data to sbom-cyclonedx.json" + python3 /scripts/base_images_sbom_script.py \ + --sbom=sbom-cyclonedx.json \ + --parsed-dockerfile=/shared/parsed_dockerfile.json \ + --base-images-digests=/shared/base_images_digests + + echo "Adding image reference to sbom" + IMAGE_URL="$(cat "$(results.IMAGE_URL.path)")" + IMAGE_DIGEST="$(cat "$(results.IMAGE_DIGEST.path)")" + + python3 /scripts/add_image_reference.py \ + --image-url "$IMAGE_URL" \ + --image-digest "$IMAGE_DIGEST" \ + --input-file sbom-cyclonedx.json \ + --output-file /tmp/sbom-cyclonedx.tmp.json + + mv /tmp/sbom-cyclonedx.tmp.json sbom-cyclonedx.json + workingDir: $(workspaces.source.path) + securityContext: + runAsUser: 0 + + - name: upload-sbom + image: quay.io/konflux-ci/appstudio-utils:48c311af02858e2422d6229600e9959e496ddef1@sha256:91ddd999271f65d8ec8487b10f3dd378f81aa894e11b9af4d10639fd52bba7e8 + script: | + #!/bin/bash + + ca_bundle=/mnt/trusted-ca/ca-bundle.crt + if [ -f "$ca_bundle" ]; then + echo "INFO: Using mounted CA bundle: $ca_bundle" + cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors + update-ca-trust + fi + + cosign attach sbom --sbom sbom-cyclonedx.json --type cyclonedx "$(cat "$(results.IMAGE_REF.path)")" + + # Remove tag from IMAGE while allowing registry to contain a port number. + sbom_repo="${IMAGE%:*}" + sbom_digest="$(sha256sum sbom-cyclonedx.json | cut -d' ' -f1)" + # The SBOM_BLOB_URL is created by `cosign attach sbom`. + echo -n "${sbom_repo}@sha256:${sbom_digest}" | tee "$(results.SBOM_BLOB_URL.path)" + + computeResources: + limits: + memory: 512Mi + cpu: 200m + requests: + memory: 256Mi + cpu: 100m + volumeMounts: + - name: trusted-ca + mountPath: /mnt/trusted-ca + readOnly: true + workingDir: $(workspaces.source.path) + + volumes: + - name: varlibcontainers + emptyDir: {} + - name: shared + emptyDir: {} + - name: etc-pki-entitlement + secret: + secretName: $(params.ENTITLEMENT_SECRET) + optional: true + - name: activation-key + secret: + optional: true + secretName: $(params.ACTIVATION_KEY) + - name: additional-secret + secret: + secretName: $(params.ADDITIONAL_SECRET) + optional: true + - name: trusted-ca + configMap: + name: $(params.caTrustConfigMapName) + items: + - key: $(params.caTrustConfigMapKey) + path: ca-bundle.crt + optional: true + workspaces: + - name: source + description: Workspace containing the source code to build. diff --git a/task/buildah/0.3/kustomization.yaml b/task/buildah/0.3/kustomization.yaml new file mode 100644 index 0000000000..6a3c230a1f --- /dev/null +++ b/task/buildah/0.3/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- buildah.yaml