Skip to content

feat(make): add OCI image labels for operator, bundle, catalog#223

Draft
aslakknutsen wants to merge 18 commits intonetworking-incubator:mainfrom
aslakknutsen:kube-agents-215
Draft

feat(make): add OCI image labels for operator, bundle, catalog#223
aslakknutsen wants to merge 18 commits intonetworking-incubator:mainfrom
aslakknutsen:kube-agents-215

Conversation

@aslakknutsen
Copy link
Copy Markdown
Contributor

Describe the pull request

Define org.opencontainers.image.* annotations (version, revision, created,
source, documentation, licenses, vendor) and pass them via docker build
--label on build.image, bundle.build, and catalog.build.

Operator image includes distroless base name/digest matching the root
Dockerfile. Bundle has no base labels (FROM scratch). Catalog includes
opm base name and pinned manifest-list digest for OPM_VERSION.

Which issue this resolves

Resolves #215

Additional context

Must be rebased/merged after #199

aslakknutsen and others added 18 commits March 27, 2026 14:30
Add a script and GitHub Actions workflow that automatically submits the
OLM bundle to k8s-operatorhub/community-operators when a non-prerelease
is published. The workflow triggers on release:published events, generates
the bundle, then uses hack/publish_operatorhub.sh to clone the
community-operators repo, copy the bundle, and open a PR via gh.

Includes:
- hack/publish_operatorhub.sh with --dry-run support
- .github/workflows/operatorhub.yml (release:published trigger)
- bundle/ci.yaml (semver-mode update graph)
- hack/operatorhub-pr-template.md (PR body for community-operators)
- make release.operatorhub target
- RELEASE.md updated with OperatorHub step

Closes #22

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Run operator-test-playbooks (kiwi) against the staged bundle before
OperatorHub publish and on PRs that touch bundle-related paths, using a
pinned public controller image so PRs do not depend on unreleased
digests.

Add hack/operatorhub_opp_test.sh and make bundle.opp for local runs;
align release workflow Python deps with the PR path, set
CONTROLLER_MANAGER_CONTAINER_IMAGE to the release tag when generating
the bundle, and print OPP logs on failure.

Set maintainer email in the CSV template for OperatorHub metadata
checks.
Unquoted semver (e.g. 0.0.0) can round-trip through YAML to JSON as a
number. OLM OperatorVersion unmarshals only from JSON strings, so tools
reported csv.Spec.Version unset. Emit spec.version as a quoted scalar.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
The chart lives under charts/coraza-kubernetes-operator/, not
helm/chart/. Align the workflow path filter so chart changes trigger
the OPP kiwi job.

Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Introduce KUBE_VERSION (default 1.33.0) for Helm --kube-version, CSV
minKubeVersion via generate_bundle --min-kube-version, and OPP kind
(KIND_KUBE_VERSION=v$(KUBE_VERSION) on bundle.opp). Remove minKubeVersion
from the CSV template so the generator is the single writer; keep
DEFAULT_MIN_KUBE_VERSION in sync with the Makefile default for CLI-only
runs.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Aslak Knutsen <aslak.tux@gmail.com>
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Use HTTP Basic (x-access-token) for git-over-HTTPS push; GitHub rejects the REST-style Authorization token header used via http.extraHeader.

Redact http.extraHeader in dry-run logs so credentials are not echoed.

Fail if the version directory already exists in the cloned community-operators tree unless --force is passed, avoiding silent overwrites of submissions.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Aslak Knutsen <aslak.tux@gmail.com>
Co-authored-by: Shane Utt <shane@shaneutt.com>
Signed-off-by: Aslak Knutsen <aslak.tux@gmail.com>
Replace http.extraHeader Basic-auth push in publish_operatorhub.sh with
plain git push after the workflow runs gh auth setup-git using
OPERATORHUB_TOKEN. Simplify skip_in_dry_run now that the push line
carries no secret. Document local gh auth setup in RELEASE.md.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Hand-maintained community-operators metadata lived under bundle/, which
.gitignore treats as generated output. Move the source to bundle/base/
and copy it to bundle/ci.yaml during make bundle so regeneration cannot
drop or confuse it. Document the layout in RELEASE.md and DEVELOPMENT.md.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
The community-operators checkout can already contain operators/<name>/ci.yaml.
Overwrite it from bundle/ci.yaml on every publish so bundle/base/ci.yaml
remains the source of truth for reviewers and updateGraph. Match behavior
in operatorhub_opp_test.sh and document in RELEASE.md.

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Define org.opencontainers.image.* annotations (version, revision, created,
source, documentation, licenses, vendor) and pass them via docker build
--label on build.image, bundle.build, and catalog.build.

Operator image includes distroless base name/digest matching the root
Dockerfile. Bundle has no base labels (FROM scratch). Catalog includes
opm base name and pinned manifest-list digest for OPM_VERSION.

Resolves: networking-incubator#215

Made-with: Cursor
Signed-off-by: Aslak Knutsen <aslak@4fs.no>
Copilot AI review requested due to automatic review settings March 28, 2026 00:27
@shaneutt shaneutt added area/documentation Improvements or additions to documentation area/helm area/infrastructure CI, packaging, etc size/XL Work that should take roughly 2 weeks labels Mar 28, 2026
@shaneutt shaneutt added this to the v0.4.0 milestone Mar 28, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OCI-standard org.opencontainers.image.* metadata to the container images produced by the repo’s build targets, and extends the OperatorHub/OLM release tooling to generate and validate bundles consistently (including min Kubernetes version and OperatorHub ci.yaml handling).

Changes:

  • Add OCI image labels via docker/podman build --label for operator, bundle, and catalog images.
  • Extend OLM/OperatorHub tooling: generate bundle/ci.yaml, add scripts/workflows to run OPP tests and submit to community-operators.
  • Align Kubernetes minimum version settings across bundle generation/Helm chart/docs.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Makefile Adds OCI label sets and applies them to build targets; adds OperatorHub and OPP-related targets; introduces KUBE_VERSION.
hack/lib.py Adds SemverYAML representer to ensure CSV spec.version is emitted as a quoted string.
hack/generate_bundle.py Uses SemverYAML, sets CSV minKubeVersion from a flag/default, and copies bundle/base/ci.yaml to bundle/ci.yaml.
hack/publish_operatorhub.sh New script to stage a bundle into a community-operators checkout and open a PR.
hack/operatorhub_opp_test.sh New script to stage a community-operators tree and run OPP tier tests.
hack/operatorhub-pr-template.md New PR body template used by the publish script.
.github/workflows/operatorhub.yml New release-triggered workflow to generate bundle, run OPP, and submit to OperatorHub.
.github/workflows/operatorhub-opp-pr.yml New PR workflow to run OPP kiwi tests on bundle-related changes.
bundle/base/ci.yaml Adds OperatorHub ci.yaml source-of-truth for reviewers/update graph.
bundle/base/csv-template.yaml Adjusts CSV template metadata (maintainer email; removes template minKubeVersion).
charts/coraza-kubernetes-operator/Chart.yaml Lowers Helm chart kubeVersion constraint to >=1.32.0-0.
README.md Updates stated supported Kubernetes version to v1.32+.
RELEASE.md Documents OperatorHub workflow and new ci.yaml source-of-truth.
DEVELOPMENT.md Documents bundle/base/ci.yaml and generated bundle/ci.yaml.
.gitignore Unignores the new OperatorHub PR template; clarifies bundle generation comments.

Comment on lines +163 to +166
.PHONY: release.operatorhub
release.operatorhub: ## Submit OLM bundle to OperatorHub community-operators
hack/publish_operatorhub.sh --version $(VERSION:v%=%)

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description focuses on adding OCI image labels, but this changeset also introduces OperatorHub submission/testing scripts + workflows and adjusts Kubernetes minimum version defaults (Makefile KUBE_VERSION, Chart kubeVersion, README). Please either update the PR description to cover these additional behavioral/process changes or split them into separate PRs so the scope matches the stated intent.

Copilot uses AI. Check for mistakes.
BRANCH="${OPERATOR_NAME}-${VERSION}"

TMP_DIR="$(mktemp -d -t "${OPERATOR_NAME}.XXXXXXXXXX")"
skip_in_dry_run trap 'rm -rf -- "${TMP_DIR}"' EXIT
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--dry-run currently wraps the trap setup in skip_in_dry_run, so the EXIT trap is never installed during dry runs. That leaves the mktemp directory behind whenever --dry-run is used. Set the cleanup trap unconditionally (and only gate the network/PR actions behind dry-run).

Suggested change
skip_in_dry_run trap 'rm -rf -- "${TMP_DIR}"' EXIT
trap 'rm -rf -- "${TMP_DIR}"' EXIT

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +138
if [[ -d "${OPERATORS_DIR}" && "${FORCE}" != true ]]; then
echo "Error: ${OPERATORS_DIR} already exists in ${OWNER}/${OPERATOR_HUB} (this version may already be submitted)." >&2
echo "Refusing to overwrite. Use --force only if you intend to replace that tree." >&2
exit 1
fi

mkdir -p "${OPERATORS_DIR}/manifests"
mkdir -p "${OPERATORS_DIR}/metadata"
cp -a "${BUNDLE_MANIFESTS}/." "${OPERATORS_DIR}/manifests/"
cp -a "${BUNDLE_METADATA}/." "${OPERATORS_DIR}/metadata/"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When --force is used and operators/<name>/<version> already exists, the script overwrites/merges files with cp -a but never removes files that were deleted from the new bundle. This can leave stale manifests/metadata in the submission. In --force mode, delete the existing ${OPERATORS_DIR} tree (or otherwise sync with deletion) before copying the new bundle content.

Copilot uses AI. Check for mistakes.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

OPP_SCRIPT_URL="https://raw.githubusercontent.com/redhat-openshift-ecosystem/community-operators-pipeline/ci/latest/ci/scripts/opp.sh"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script comment says the OPP pipeline is pinned to a specific commit, but OPP_SCRIPT_URL is pointing at .../ci/latest/.../opp.sh, which can change over time and make CI results non-reproducible. Point this URL at the intended pinned commit (or remove the pinning claim).

Suggested change
OPP_SCRIPT_URL="https://raw.githubusercontent.com/redhat-openshift-ecosystem/community-operators-pipeline/ci/latest/ci/scripts/opp.sh"
OPP_SCRIPT_URL="https://raw.githubusercontent.com/redhat-openshift-ecosystem/community-operators-pipeline/fbac22ff0c713188bdcea36791b70fb3999e6e03/ci/scripts/opp.sh"

Copilot uses AI. Check for mistakes.

# Align with community OperatorHub k8s pipeline (see maistra istio-workspace test.sh).
export OPP_CONTAINER_OPT="${OPP_CONTAINER_OPT:--t}"
export OPP_IMAGE="${OPP_IMAGE:-quay.io/operator_testing/operator-test-playbooks:latest}"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPP_IMAGE defaults to quay.io/operator_testing/operator-test-playbooks:latest. Since this script is used in GitHub Actions, using :latest can introduce flaky/irreproducible CI when the upstream tag moves. Prefer pinning to a specific version tag or digest and bump it intentionally.

Suggested change
export OPP_IMAGE="${OPP_IMAGE:-quay.io/operator_testing/operator-test-playbooks:latest}"
export OPP_IMAGE="${OPP_IMAGE:-quay.io/operator_testing/operator-test-playbooks:v1.0.0}"

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +59
# Base image for the catalog final stage (see catalog/Dockerfile). When bumping OPM_VERSION, refresh
# OPM_BASE_DIGEST to the manifest list digest for that tag (e.g. quay.io API or skopeo inspect).
OPM_BASE_NAME ?= quay.io/operator-framework/opm:$(OPM_VERSION)
OPM_BASE_DIGEST ?= sha256:a070b901663d00312ccabe06a3c04b961d7326868499fe6c4c6b97025c79f014
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPM_BASE_DIGEST is used to set org.opencontainers.image.base.digest for the catalog image, but catalog/Dockerfile currently uses FROM quay.io/operator-framework/opm:${OPM_VERSION} (tag-only) and will pull a platform-specific manifest that may not match this hardcoded manifest-list digest (and could drift if the tag ever changes). To keep the label accurate, either pin the base image by digest in catalog/Dockerfile (and label that digest) or drop the base.digest label for the catalog build.

Suggested change
# Base image for the catalog final stage (see catalog/Dockerfile). When bumping OPM_VERSION, refresh
# OPM_BASE_DIGEST to the manifest list digest for that tag (e.g. quay.io API or skopeo inspect).
OPM_BASE_NAME ?= quay.io/operator-framework/opm:$(OPM_VERSION)
OPM_BASE_DIGEST ?= sha256:a070b901663d00312ccabe06a3c04b961d7326868499fe6c4c6b97025c79f014
# Base image for the catalog final stage (see catalog/Dockerfile). This is intentionally
# referenced by tag only; we do not publish a fixed base digest for the catalog image
# because the actual platform-specific image pulled by the tag may vary.
OPM_BASE_NAME ?= quay.io/operator-framework/opm:$(OPM_VERSION)

Copilot uses AI. Check for mistakes.
@aslakknutsen aslakknutsen self-assigned this Mar 28, 2026
@aslakknutsen aslakknutsen added size/S and removed size/XL Work that should take roughly 2 weeks labels Mar 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/documentation Improvements or additions to documentation area/helm area/infrastructure CI, packaging, etc size/S

Development

Successfully merging this pull request may close these issues.

OCI image labels (org.opencontainers.image.*) for operator, bundle, and catalog images

3 participants