apiVersion: tekton.dev/v1 kind: Task metadata: name: release-tools-push-image-by-digest annotations: tekton.dev/displayName: "push release-tools image to registry by digest (no tag)" spec: description: | Push the built image to the registry under its version tag (vX.Y.Z) and record the resulting manifest digest for downstream sign/attest. # bd forgejo-mcp-9r4: the earlier design pushed an ephemeral :build-tmp tag # and deleted it after promotion. On Forgejo/Codeberg, deleting ANY tag # deletes the underlying manifest — so removing :build-tmp also removed the # :vX.Y.Z and :latest tags that shared the same digest (only the separate # cosign .sig/.att manifests survived). We now push :vX.Y.Z directly with # no staging tag. cosign-sign + attach-sbom operate on the digest in place; # promote-image-tag adds :latest only after both succeed. The tag is # briefly unsigned (~1 min) until cosign-sign runs; a signing failure # deletes the unsigned :vX.Y.Z via the pipeline's finally cleanup. params: - name: IMAGE description: | Local image tag to push (e.g. release-tools:build-tmp). Must already exist in the buildah store in the workspace. # Path A (decided 2026-05-25): codeberg.org/operate-first/release-tools # Registry path working assumption: codeberg.org/operate-first/release-tools type: string - name: REGISTRY_IMAGE description: | Full registry path without tag (e.g. codeberg.org/operate-first/release-tools). # Path A (decided 2026-05-25): codeberg.org/operate-first/release-tools # Working assumption: codeberg.org/operate-first/release-tools type: string default: "codeberg.org/operate-first/release-tools" - name: TAG description: Human-readable version tag to push (e.g. v1.0.0). type: string - name: STORAGE_DRIVER description: buildah storage driver. type: string default: vfs workspaces: - name: source mountPath: /workspace/source - name: registry-credentials mountPath: /workspace/registry-creds optional: false results: - name: IMAGE_DIGEST description: sha256 digest of the pushed manifest (e.g. sha256:abc123...). - name: IMAGE_URL description: Registry URL without tag or digest (e.g. codeberg.org/operate-first/release-tools). Used by Tekton Chains to bind image to SLSA provenance. - name: IMAGE_REPO_DIGEST description: Full digest reference (e.g. codeberg.org/operate-first/release-tools@sha256:abc123). steps: - name: push-by-digest image: quay.io/buildah/stable:latest securityContext: privileged: true workingDir: $(workspaces.source.path) script: | #!/usr/bin/env bash set -euo pipefail # Configure registry auth REGISTRY_AUTH_FILE="$(workspaces.registry-credentials.path)/.dockerconfigjson" if [ ! -f "${REGISTRY_AUTH_FILE}" ]; then REGISTRY_AUTH_FILE="$(workspaces.registry-credentials.path)/config.json" fi # Use same workspace store as build-image task. BUILDAH_STORE="$(workspaces.source.path)/.buildah" LOCAL_IMAGE="localhost/$(params.IMAGE)" REGISTRY_IMAGE="$(params.REGISTRY_IMAGE)" TAG="$(params.TAG)" DEST="${REGISTRY_IMAGE}:${TAG}" echo "Pushing ${LOCAL_IMAGE} to docker://${DEST} ..." # Push directly to the version tag — NO ephemeral :build-tmp staging # tag (bd forgejo-mcp-9r4: deleting a staging tag on Forgejo/Codeberg # deletes the shared manifest and takes the real tags with it). The # tag is briefly unsigned until cosign-sign runs next; a signing # failure removes it via the pipeline's finally cleanup. --digestfile # still records the manifest digest so sign/attest can pin by digest. buildah --root "${BUILDAH_STORE}" push \ --storage-driver="$(params.STORAGE_DRIVER)" \ --authfile="${REGISTRY_AUTH_FILE}" \ --digestfile=/tmp/pushed-digest \ "${LOCAL_IMAGE}" \ "docker://${DEST}" \ 2>&1 | tee /dev/stderr DIGEST=$(cat /tmp/pushed-digest) REPO_DIGEST="${REGISTRY_IMAGE}@${DIGEST}" printf '%s' "${DIGEST}" > "$(results.IMAGE_DIGEST.path)" printf '%s' "${REGISTRY_IMAGE}" > "$(results.IMAGE_URL.path)" printf '%s' "${REPO_DIGEST}" > "$(results.IMAGE_REPO_DIGEST.path)" echo "Pushed by digest: ${REPO_DIGEST}"