apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: cosign-sign-release annotations: tekton.dev/displayName: "cosign sign-blob checksums + upload to Codeberg release" spec: description: | Signs the GoReleaser-produced `checksums.txt` with cosign (key from the `cosign-signing-key-artifacts` Secret) and uploads the resulting `.sig` as a release asset. Signing the checksum file covers all archives + SBOMs transitively via the checksum chain. Skipped (exit 0) if the cosign secret is empty/missing — mirrors the behavior of .forgejo/workflows/release.yml so releases continue to ship if signing infrastructure is unavailable. The `cosign-signing-key-artifacts` Secret is provisioned in op1st-pipelines upstream of this Task (typically via the op1st-gitops repo + emberstack reflector). Expected keys: cosign.key, cosign.password, cosign.pub. All tools (cosign, jq, curl) are pre-baked into RELEASE_TOOLS_IMAGE. No runtime installs. params: - name: RELEASE_TOOLS_IMAGE description: | Pre-built release-tools image containing go, goreleaser, syft, cosign, govulncheck, node, npm, jq, curl, mcpb, and openspec. type: string default: codeberg.org/operate-first/release-tools:latest - name: TAG description: Tag ref name (e.g. v2.24.0). type: string - name: REPO description: Repo slug owner/name (e.g. goern/forgejo-mcp). type: string - name: CODEBERG_API description: Codeberg API base URL. type: string default: https://codeberg.org/api/v1 workspaces: - name: source mountPath: /workspace/src stepTemplate: workingDir: $(workspaces.source.path) steps: - name: sign-checksums image: $(params.RELEASE_TOOLS_IMAGE) env: - name: COSIGN_PRIVATE_KEY valueFrom: secretKeyRef: name: cosign-signing-key-artifacts key: cosign.key optional: true - name: COSIGN_PASSWORD valueFrom: secretKeyRef: name: cosign-signing-key-artifacts key: cosign.password optional: true script: | #!/usr/bin/env sh set -eu if [ -z "${COSIGN_PRIVATE_KEY:-}" ]; then echo "WARN: COSIGN_PRIVATE_KEY not set; skipping signature step." exit 0 fi TAG="$(params.TAG)" VERSION="${TAG#v}" CHECKSUMS="dist/forgejo-mcp_${VERSION}_checksums.txt" if [ ! -f "$CHECKSUMS" ]; then echo "ERROR: Expected $CHECKSUMS not produced by GoReleaser" >&2 exit 1 fi SIG="${CHECKSUMS}.sig" KEY_FILE="$(mktemp)" trap 'rm -f "$KEY_FILE"' EXIT printf '%s' "$COSIGN_PRIVATE_KEY" > "$KEY_FILE" cosign sign-blob --yes \ --key "$KEY_FILE" \ --bundle "$SIG" \ "$CHECKSUMS" ls -l "$SIG" - name: upload-signature image: $(params.RELEASE_TOOLS_IMAGE) env: - name: GITEA_TOKEN valueFrom: secretKeyRef: name: op1st-release-token key: token script: | #!/usr/bin/env bash set -euo pipefail TAG="$(params.TAG)" VERSION="${TAG#v}" SIG="dist/forgejo-mcp_${VERSION}_checksums.txt.sig" if [ ! -f "$SIG" ]; then echo "INFO: No signature file present; signing step was skipped." exit 0 fi RELEASE_ID=$(curl -fsSL \ -H "Authorization: token ${GITEA_TOKEN}" \ "$(params.CODEBERG_API)/repos/$(params.REPO)/releases/tags/${TAG}" \ | jq -r '.id') if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then echo "ERROR: Could not resolve release ID for tag ${TAG}" >&2 exit 1 fi ASSET_NAME=$(basename "$SIG") curl -fsSL -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@${SIG}" \ "$(params.CODEBERG_API)/repos/$(params.REPO)/releases/${RELEASE_ID}/assets?name=${ASSET_NAME}"