Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/NEW_RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: New release
about: Checklist for releasing a new version of cluster-inventory-api
title: "Release vX.Y.Z"
labels: kind/release
---

## Release checklist

### Prepare

- [ ] Changelog added below
- [ ] 2-week lazy consensus period elapsed (no OWNER objections)

### Tag

- [ ] Release tag pushed: `git tag -s v<version> && git push origin v<version>`
- [ ] Draft GitHub release created: `gh release create v<version> --draft --generate-notes --verify-tag`

### Staging

- [ ] `test-infra` postsubmit pushed staging images
- [ ] Staging images verified at `us-central1-docker.pkg.dev/k8s-staging-images/cluster-inventory-api/<plugin>:<tag>`

### Promote

- [ ] Promotion PR created: `kpromo pr --fork <yourname> --project cluster-inventory-api --tag v<version>`
- [ ] Promotion PR reviewed and merged

### Publish

- [ ] Production images verified at `registry.k8s.io/cluster-inventory-api/<plugin>:<tag>`
- [ ] Draft GitHub release published
- [ ] This issue closed
- [ ] Announcement sent

## Changelog

14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: false

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.9.0
args: --timeout 5m0s
Expand All @@ -32,10 +32,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: false
Expand All @@ -49,10 +49,10 @@ jobs:
needs: verify
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: false
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/e2e-plugins.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true

- name: Setup kind
uses: helm/kind-action@v1.13.0
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0
with:
install_only: true
version: v0.31.0
Expand All @@ -54,7 +54,7 @@ jobs:
bash ${{ matrix.setup_script }}

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

- name: Run controller example in-cluster (image volume plugin)
run: |
Expand Down
92 changes: 0 additions & 92 deletions .github/workflows/release.yml

This file was deleted.

17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ docker-buildx: ## Build and push docker image for cross-platform support (PLUGIN
--attest type=sbom \
.

PLUGIN_NAMES := $(sort $(patsubst plugins/%/cmd/plugin,%,$(wildcard plugins/*/cmd/plugin)))
STAGING_REGISTRY ?= us-central1-docker.pkg.dev/k8s-staging-images/cluster-inventory-api
RELEASE_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(STAGING_REGISTRY))

.PHONY: release-staging
release-staging: ## Build and push all plugin images to the staging registry (VERSION required)
@[ "$(origin VERSION)" = "command line" ] || [ "$(origin VERSION)" = "environment" ] \
|| { echo "VERSION must be set explicitly (e.g. VERSION=v0.1.0)"; exit 1; }
@set -e; \
for plugin in $(PLUGIN_NAMES); do \
$(MAKE) docker-buildx \
PLUGIN_NAME=$$plugin \
REGISTRY=$(RELEASE_REGISTRY) \
VERSION=$(VERSION) \
PLATFORMS=$(PLATFORMS); \
done

.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
Expand Down
56 changes: 22 additions & 34 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,45 @@ Plugin binaries are released as OCI images built with [Docker Buildx](https://do

### Versioning

Plugin OCI images are tagged with the same version as the repository release tag. For example, pushing `v0.2.0` publishes all plugin images with tag `0.2.0`.
Plugin OCI images are tagged with the same version as the repository release tag. For example, pushing `v0.2.0` publishes all plugin images with tag `v0.2.0`.

### How to release

1. Push a repository tag `v*` (e.g. `v1.0.0`). This triggers the `Release` workflow.
2. The workflow scans `plugins/*/` and checks whether the image already exists in the container registry for that version. Only plugins that haven't been published yet are built and pushed.
3. Container images are published to:
- `ghcr.io/kubernetes-sigs/cluster-inventory-api/<plugin_name>:<version>`
- Example: `ghcr.io/kubernetes-sigs/cluster-inventory-api/secretreader:1.0.0`

### Image signing
### Prerequisites

Each released image is signed using [Cosign](https://docs.sigstore.dev/cosign/signing/overview/) keyless signing with GitHub Actions OIDC. No long-lived signing keys are used; an ephemeral key pair is generated for each signing event and the public key is recorded in the [Sigstore transparency log](https://docs.sigstore.dev/logging/overview/).
Promoting images requires [`kpromo`](https://github.com/kubernetes-sigs/promo-tools) and a fork of [kubernetes/k8s.io](https://github.com/kubernetes/k8s.io).

#### Verifying image signatures
Before the first release, the following must exist in `kubernetes/k8s.io`:

Install [Cosign](https://docs.sigstore.dev/cosign/system_config/installation/) and run:
- `registry.k8s.io/images/k8s-staging-cluster-inventory-api/OWNERS`
- `registry.k8s.io/images/k8s-staging-cluster-inventory-api/images.yaml`
- `registry.k8s.io/manifests/k8s-staging-cluster-inventory-api/promoter-manifest.yaml` (maps `k8s-staging-cluster-inventory-api` to `cluster-inventory-api` under `registry.k8s.io`)

```bash
cosign verify \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity-regexp="^https://github\.com/kubernetes-sigs/cluster-inventory-api/\.github/workflows/release\.yml@refs/tags/v.*$" \
ghcr.io/kubernetes-sigs/cluster-inventory-api/<plugin>:<version>
```
See the [registry.k8s.io README](https://github.com/kubernetes/k8s.io/tree/main/registry.k8s.io) for setup details.

Example:

```bash
cosign verify \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity-regexp="^https://github\.com/kubernetes-sigs/cluster-inventory-api/\.github/workflows/release\.yml@refs/tags/v.*$" \
ghcr.io/kubernetes-sigs/cluster-inventory-api/secretreader:0.1.0
```

### SBOM and provenance
### How to release

Each released image includes attestations as OCI referrers:
1. Push a signed release tag (e.g. `git tag -s v1.0.0 && git push origin v1.0.0`).
2. Create a draft GitHub release for the tag (e.g. `gh release create v1.0.0 --draft --generate-notes --verify-tag`).
3. The test-infra postsubmit job builds all plugin images and pushes them to the staging registry (`us-central1-docker.pkg.dev/k8s-staging-images/cluster-inventory-api`).
4. Create a promotion PR in `kubernetes/k8s.io` using [`kpromo`](https://github.com/kubernetes-sigs/promo-tools):
```bash
kpromo pr --fork <yourname> --project cluster-inventory-api --tag v1.0.0
```
5. After the promotion PR is reviewed and merged, the images become available at `registry.k8s.io/cluster-inventory-api/<plugin>:<tag>`.
6. Publish the draft GitHub release and close the release issue.

- **SBOM** (SPDX): `cosign download sbom ghcr.io/kubernetes-sigs/cluster-inventory-api/<plugin>:<version>`
- **Provenance** (SLSA-style): attached by Buildx; verify with [cosign verify attestation](https://docs.sigstore.dev/cosign/verify-attestation/) or your preferred policy engine.
A release checklist is available as an [issue template](.github/ISSUE_TEMPLATE/NEW_RELEASE.md).

### Local build (no push)
### Local build

- Run `make docker-build PLUGIN_NAME=<name>` to build a single plugin image locally (e.g. `make docker-build PLUGIN_NAME=secretreader`). The image is tagged as `<plugin_name>:latest` by default.
- Run `make release-staging VERSION=<tag> REGISTRY=<registry>` to build and push all plugin images to a staging registry.

## Project release (optional)

For a high-level project release (e.g. announcing a set of plugin versions):

1. Open an issue proposing a release with a changelog since the last release.
2. The release proposal follows a **lazy consensus** model: the proposal is approved unless an [OWNER](OWNERS) objects within **two weeks** of the issue being opened. Silence is treated as approval.
3. An OWNER pushes a release tag (e.g. `v1.0.0`) to trigger the Release workflow.
3. An OWNER pushes a release tag (e.g. `v1.0.0`) to trigger the release process described above.
4. Close the release issue.
5. Optionally send an announcement (e.g. to the project mailing list or Slack).
15 changes: 15 additions & 0 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# See https://cloud.google.com/cloud-build/docs/build-config
timeout: 7200s
options:
substitution_option: ALLOW_LOOSE
machineType: "E2_HIGHCPU_8"
steps:
- name: "gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20251215-d7853fe2a6"
args:
- make
- release-staging
- VERSION=$_PULL_BASE_REF
- REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/cluster-inventory-api
- PLATFORMS=linux/amd64,linux/arm64
substitutions:
_PULL_BASE_REF: "main"
Loading