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.
276 lines
11 KiB
YAML
276 lines
11 KiB
YAML
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
|