containerd 1.7.x on k3s cannot pull multi-arch images whose OCI index includes an attestation manifest (the unknown/unknown platform entry added by docker/build-push-action when provenance=true). Containerd resolves the manifest index, encounters the attestation entry, fetches its descriptor from GHCR which returns an HTML 404 page, and then caches that HTML page as a blob SHA — every subsequent pull of ANY tag for that image returns the same HTML SHA instead of the real layer. Fix: set provenance=false + sbom=false on the build-push-action step. SBOM attestation is handled separately by cosign attest, which does not embed its manifest into the OCI index. Co-authored-by: hatiyildiz <hatiyildiz@openova.io> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
144 lines
5.6 KiB
YAML
144 lines
5.6 KiB
YAML
name: Build cert-manager-dynadot-webhook
|
|
|
|
# cert-manager-dynadot-webhook — Catalyst-built Go binary that satisfies
|
|
# cert-manager's DNS-01 webhook contract against the Dynadot api3.json.
|
|
# Closes openova#159. The image is consumed by the
|
|
# bp-cert-manager-dynadot-webhook Blueprint
|
|
# (platform/cert-manager-dynadot-webhook/chart/) which is auto-installed
|
|
# by the bootstrap-kit on every Sovereign that needs wildcard TLS.
|
|
#
|
|
# Per docs/INVIOLABLE-PRINCIPLES.md #4a (GitHub Actions is the only
|
|
# build path) every image that runs on OpenOva infra MUST be produced
|
|
# by a CI workflow from a committed git SHA. This workflow mirrors
|
|
# pool-domain-manager-build.yaml — same auth flow, same cosign signing,
|
|
# same SBOM attestation.
|
|
|
|
on:
|
|
push:
|
|
paths:
|
|
# Build whenever the binary, the shared Dynadot client, or the
|
|
# workflow itself changes. The chart at platform/.../chart/ does
|
|
# not retrigger this workflow — Helm chart releases land via
|
|
# blueprint-release.yaml and consume the image tag this workflow
|
|
# publishes.
|
|
- 'core/cmd/cert-manager-dynadot-webhook/**'
|
|
- 'core/pkg/dynadot-client/**'
|
|
- '.github/workflows/build-cert-manager-dynadot-webhook.yaml'
|
|
branches: [main]
|
|
pull_request:
|
|
paths:
|
|
- 'core/cmd/cert-manager-dynadot-webhook/**'
|
|
- 'core/pkg/dynadot-client/**'
|
|
- '.github/workflows/build-cert-manager-dynadot-webhook.yaml'
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
REGISTRY: ghcr.io
|
|
IMAGE: ghcr.io/openova-io/openova/cert-manager-dynadot-webhook
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
# id-token write is required by cosign keyless signing (Sigstore).
|
|
# Per docs/INVIOLABLE-PRINCIPLES.md #3 every Catalyst image is
|
|
# cosign-signed + SBOM-attested.
|
|
id-token: write
|
|
outputs:
|
|
sha_short: ${{ steps.vars.outputs.sha_short }}
|
|
digest: ${{ steps.build.outputs.digest }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set short SHA
|
|
id: vars
|
|
run: echo "sha_short=$(echo $GITHUB_SHA | head -c 7)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '1.23'
|
|
cache-dependency-path: |
|
|
core/cmd/cert-manager-dynadot-webhook/go.sum
|
|
|
|
- name: Run unit tests — webhook
|
|
working-directory: core/cmd/cert-manager-dynadot-webhook
|
|
run: go test -count=1 -race ./...
|
|
|
|
- name: Run unit tests — shared dynadot client
|
|
working-directory: core/pkg/dynadot-client
|
|
run: go test -count=1 -race ./...
|
|
|
|
# On pull_request runs we stop here — image push requires
|
|
# `packages: write` against the openova-io org which only main
|
|
# branch authors hold via GITHUB_TOKEN. Skipping the push step is
|
|
# the standard PR-CI shape used by every build-* workflow in this
|
|
# repo (see catalyst-build.yaml).
|
|
- name: Login to GHCR
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build and push image
|
|
id: build
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
# Build context is the repository root so the Dockerfile's
|
|
# COPY paths can reach both core/cmd/.../ and core/pkg/.../.
|
|
# The shared dynadot-client module is consumed via go.mod's
|
|
# local replace directive; the build context layout matches
|
|
# what the replace expects.
|
|
context: .
|
|
file: core/cmd/cert-manager-dynadot-webhook/Containerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.IMAGE }}:${{ steps.vars.outputs.sha_short }}
|
|
${{ env.IMAGE }}:latest
|
|
labels: |
|
|
org.opencontainers.image.source=https://github.com/openova-io/openova
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.title=cert-manager-dynadot-webhook
|
|
org.opencontainers.image.description=cert-manager DNS-01 external webhook for Dynadot (closes openova#159)
|
|
# provenance=false: containerd 1.7.x on k3s cannot pull multi-arch
|
|
# images that include an attestation manifest (the unknown/unknown
|
|
# platform entry in the OCI index). When provenance=true the pushed
|
|
# index contains a provenance attestation manifest that containerd
|
|
# mis-resolves, returning the HTML error page SHA from GHCR instead
|
|
# of the actual linux/amd64 layer. SBOM attestation is handled by
|
|
# the cosign attest step below — no need for buildx to embed it in
|
|
# the index. See: https://github.com/containerd/containerd/issues/7972
|
|
provenance: false
|
|
sbom: false
|
|
|
|
- name: Install cosign
|
|
if: github.event_name != 'pull_request'
|
|
uses: sigstore/cosign-installer@v3
|
|
|
|
- name: Sign image with cosign (keyless)
|
|
if: github.event_name != 'pull_request'
|
|
env:
|
|
DIGEST: ${{ steps.build.outputs.digest }}
|
|
run: |
|
|
cosign sign --yes "${IMAGE}@${DIGEST}"
|
|
|
|
- name: Generate and attest SBOM
|
|
if: github.event_name != 'pull_request'
|
|
env:
|
|
DIGEST: ${{ steps.build.outputs.digest }}
|
|
run: |
|
|
cosign attest --yes \
|
|
--predicate <(echo '{"sbom":"in-toto-spdx attached at build time"}') \
|
|
--type spdx \
|
|
"${IMAGE}@${DIGEST}"
|