forgejo-mcp/.tekton/on-tag-push-release.yaml
Christoph Görn b12dd07410
chore: 🔧 prefix all .tekton PipelineRun names with forgejo-mcp-
Namespace every PipelineRun under a single forgejo-mcp- prefix so runs
are unambiguous in shared op1st-pipelines (code-scans, on-pull-request,
on-push-to-main, on-tag-push-release, openspec-validate-{pr,push},
release-tools-on-{pull-request-build,tag-publish}). PaC matches on
annotations, not name, so triggering is unaffected.
2026-06-01 11:19:24 +02:00

276 lines
11 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: forgejo-mcp-on-tag-push-release
annotations:
# PipelinesAsCode: trigger on tag pushes matching v* refs.
# `on-target-branch` is overloaded to match refs/tags/* as well as
# refs/heads/* when on-event is "push" — PaC resolves the ref via
# the underlying provider payload (Codeberg/Forgejo).
pipelinesascode.tekton.dev/on-event: "[push]"
pipelinesascode.tekton.dev/on-target-branch: "[refs/tags/v*]"
# T11 defensive CEL (A1 tag-isolation): PaC's glob [refs/tags/v*] may
# match refs/tags/release-tools/vX.Y.Z on some PaC versions because the
# glob is applied after stripping refs/tags/ and "release-tools/v1.0.0"
# starts with a non-v prefix, but belt-and-suspenders ensures this pipeline
# never fires on a release-tools tag. The expression requires the ref to
# start with refs/tags/v followed by a digit, which excludes
# refs/tags/release-tools/... entirely.
pipelinesascode.tekton.dev/on-cel-expression: |
event == "push" && target_branch.matches("^refs/tags/v[0-9]")
pipelinesascode.tekton.dev/task: "[git-clone, .tekton/tasks/goreleaser-release.yaml, .tekton/tasks/cosign-sign-release.yaml, .tekton/tasks/mcpb-pack.yaml, .tekton/release-tools/tasks/build-image.yaml, .tekton/release-tools/tasks/push-image-by-digest.yaml, .tekton/release-tools/tasks/cosign-sign-image-by-digest.yaml, .tekton/release-tools/tasks/cosign-attach-sbom.yaml, .tekton/release-tools/tasks/promote-image-tag.yaml]"
pipelinesascode.tekton.dev/max-keep-runs: "10"
# Releases are not cancellable — let in-flight runs finish even if
# another tag arrives.
pipelinesascode.tekton.dev/cancel-in-progress: "false"
# Tekton Chains: upload in-toto SLSA v1.0 provenance for the published app
# image to the Rekor transparency log. Chains reads the IMAGE_URL +
# IMAGE_DIGEST pipeline results below and attaches a cosign attestation
# binding the image digest → PipelineRun → git commit → builder identity.
# Verify with: cosign verify-attestation --type slsaprovenance \
# --key cosign-images.pub codeberg.org/goern/forgejo-mcp:<tag>
chains.tekton.dev/transparency-upload: "true"
# dn0 — App OCI image publish (decided 2026-06-01):
# Registry: codeberg.org/goern/forgejo-mcp (mirrors the signed-binary
# release namespace). Tags: vMAJOR.MINOR.PATCH + latest (promote-image-tag).
# Single-arch amd64 (reuses release-tools-build-image, which is not a
# manifest-list build). Image build runs in parallel with goreleaser — it
# compiles its own binary inside the Containerfile and only depends on
# resolve-tag.
# Required Secrets in op1st-pipelines (operator-confirmable preconditions):
# - codeberg-pusher (dockerconfigjson — push auth). Its PAT MUST
# carry `write:package` on goern/forgejo-mcp. The cluster cannot validate
# token scope; confirm once via the Codeberg UI before the first vX.Y.Z
# tag. The release-tools image proved this Secret can push to codeberg.org,
# but that auth targets the operate-first org — package-write on goern is
# a SEPARATE grant that must be present on the same PAT identity.
# - cosign-signing-key-images (cosign.key/.password — optional: false,
# fail-closed). A missing key fails the run; no tag is ever promoted.
spec:
params:
- name: repo_url
value: "{{ repo_url }}"
- name: revision
value: "{{ revision }}"
- name: target_branch
value: "{{ target_branch }}"
pipelineSpec:
params:
- name: repo_url
- name: revision
- name: target_branch
description: |
PaC passes the matched ref here (e.g. refs/tags/v2.24.0). Stripped
to the bare tag name (v2.24.0) for downstream tasks.
results:
# Tekton Chains reads IMAGE_URL + IMAGE_DIGEST at the Pipeline level to
# bind the published app image to the SLSA provenance attestation it
# generates. Without these, Chains produces subject-less provenance that
# cannot be verified against a specific image digest.
- name: IMAGE_URL
value: $(tasks.push-image-by-digest.results.IMAGE_URL)
- name: IMAGE_DIGEST
value: $(tasks.push-image-by-digest.results.IMAGE_DIGEST)
workspaces:
- name: source
- name: registry-credentials
description: |
Kubernetes Secret containing .dockerconfigjson (or config.json) with
push credentials for codeberg.org/goern/forgejo-mcp. Used by the
image push, cosign-sign, SBOM-attach, and tag-promote tasks.
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: source
params:
- name: url
value: $(params.repo_url)
- name: revision
value: $(params.revision)
- name: resolve-tag
runAfter:
- fetch-source
params:
- name: target_branch
value: $(params.target_branch)
taskSpec:
params:
- name: target_branch
results:
- name: tag
description: Bare tag name (e.g. v2.24.0).
steps:
- name: resolve
image: registry.access.redhat.com/ubi9/ubi-minimal:latest
script: |
#!/usr/bin/env sh
set -eu
TAG="$(params.target_branch)"
TAG="${TAG#refs/tags/}"
echo "Resolved tag: $TAG"
printf '%s' "$TAG" > "$(results.tag.path)"
- name: goreleaser
runAfter:
- resolve-tag
taskRef:
name: goreleaser-release
workspaces:
- name: source
workspace: source
params:
- name: TAG
value: $(tasks.resolve-tag.results.tag)
- name: cosign-sign
runAfter:
- goreleaser
taskRef:
name: cosign-sign-release
workspaces:
- name: source
workspace: source
params:
- name: TAG
value: $(tasks.resolve-tag.results.tag)
- name: REPO
value: goern/forgejo-mcp
- name: mcpb-pack
runAfter:
- goreleaser
taskRef:
name: mcpb-pack
workspaces:
- name: source
workspace: source
params:
- name: TAG
value: $(tasks.resolve-tag.results.tag)
- name: REPO
value: goern/forgejo-mcp
# dn0 — App OCI image (codeberg.org/goern/forgejo-mcp). Reuses the
# release-tools image tasks. The Containerfile compiles its own binary, so
# it is logically independent of goreleaser. It MUST NOT run in parallel
# with the goreleaser-family tasks, however: build-image runs buildah
# privileged-as-root and writes its ~1GB store (.buildah) into the SHARED
# `source` PVC, while goreleaser/cosign-sign/mcpb-pack read+write the same
# volume as uid 1000. On the single-node topolvm cluster this concurrency
# corrupted goreleaser's view of the workspace — the first release that
# added this task failed every time goreleaser ran beside buildah
# (compile fork/exec EACCES, then `error reading .git`). Gating on all
# three goreleaser-family tasks gives buildah the PVC to itself.
- name: build-image
runAfter:
- goreleaser
- cosign-sign
- mcpb-pack
taskRef:
name: release-tools-build-image
workspaces:
- name: source
workspace: source
params:
- name: IMAGE
value: "forgejo-mcp:$(tasks.resolve-tag.results.tag)"
- name: CONTEXT
value: "."
- name: CONTAINERFILE
value: Containerfile
# Inject the release version so the in-image binary reports the tag
# instead of the Containerfile's ARG VERSION=dev default.
- name: BUILD_ARGS
value: "VERSION=$(tasks.resolve-tag.results.tag)"
# L1 TOCTOU fix: push by digest first, no human-readable tag yet.
- name: push-image-by-digest
runAfter:
- build-image
taskRef:
name: release-tools-push-image-by-digest
workspaces:
- name: source
workspace: source
- name: registry-credentials
workspace: registry-credentials
params:
- name: IMAGE
value: "forgejo-mcp:$(tasks.resolve-tag.results.tag)"
- name: REGISTRY_IMAGE
value: "codeberg.org/goern/forgejo-mcp"
# Fail-closed: cosign-signing-key-images is optional: false in the task.
# If absent, this fails and no human-readable tag is promoted.
- name: cosign-sign-image
runAfter:
- push-image-by-digest
taskRef:
name: release-tools-cosign-sign-image-by-digest
workspaces:
- name: registry-credentials
workspace: registry-credentials
params:
- name: IMAGE_REPO_DIGEST
value: $(tasks.push-image-by-digest.results.IMAGE_REPO_DIGEST)
- name: attach-image-sbom
runAfter:
- cosign-sign-image
taskRef:
name: release-tools-cosign-attach-sbom
workspaces:
- name: source
workspace: source
- name: registry-credentials
workspace: registry-credentials
params:
- name: IMAGE_REPO_DIGEST
value: $(tasks.push-image-by-digest.results.IMAGE_REPO_DIGEST)
# L1 TOCTOU fix: promote vX.Y.Z + latest ONLY after sign + SBOM succeed.
- name: promote-image-tag
runAfter:
- push-image-by-digest
- cosign-sign-image
- attach-image-sbom
taskRef:
name: release-tools-promote-image-tag
workspaces:
- name: registry-credentials
workspace: registry-credentials
params:
- name: IMAGE_REPO_DIGEST
value: $(tasks.push-image-by-digest.results.IMAGE_REPO_DIGEST)
- name: TAG
value: $(tasks.resolve-tag.results.tag)
- name: REGISTRY_IMAGE
value: "codeberg.org/goern/forgejo-mcp"
workspaces:
- name: source
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
# Release builds need ~6× CI: cross-compiled binaries +
# SBOMs + checksums + .mcpb bundles per platform. dn0 adds a
# container image build (buildah store + layers) and a syft
# image SBOM scan into the same workspace — bumped 8Gi → 12Gi.
storage: 12Gi
- name: registry-credentials
secret:
# dn0 (decided 2026-06-01): push to codeberg.org/goern/forgejo-mcp.
# Reuse the existing codeberg-pusher dockerconfigjson Secret in
# op1st-pipelines. Its auth covers codeberg.org, but for push to the
# goern namespace to succeed the underlying PAT MUST carry
# `write:package` on goern/forgejo-mcp — a separate grant from the
# operate-first package-write the release-tools image relies on.
# Operator confirms out-of-band (cluster cannot validate token scope).
secretName: codeberg-pusher