The Bootc Operator is a Kubernetes operator for managing bootc nodes. We welcome contributions of all kinds: bug reports, feature requests, documentation improvements, and code changes.
- Prerequisites
- Development Environment
- Building
- Testing
- Investigating CI Failures
- Code Style
- Submitting Changes
- AI Generated Code
- Community
- License
- Other Useful Documentation
Before contributing, make sure you have the following installed:
- Go (see
go.modfor the required version) - Make
- Podman
- kubectl
For end-to-end testing you will also need:
Tool dependencies like controller-gen, kustomize, golangci-lint, and
setup-envtest are downloaded automatically to ./bin/ by the Makefile when
needed.
Most contributors work on a Linux host with Go and Podman available. Make sure the Podman socket is running — bink and the build system communicate with Podman through it:
systemctl --user start podman.socketBefore diving into the code, familiarize yourself with the project from a user perspective by reading the README and the Architecture document. We also recommend getting familiar with bink, which is used to create lightweight Kubernetes clusters backed by bootc nodes for development and testing.
You can create a bink cluster by running:
make deploy-binkTo tear down the cluster when done:
make teardown-binkBy default, deploy-bink and e2e share the same cluster named e2e. To use
a separate development cluster:
make deploy-bink BINK_CLUSTER_NAME=devmake build # Build all binaries (manager + daemon) to ./bin/
make buildimg # Build the container image (default: bootc-operator:dev)The bootc-operator container image contains both the controller and daemon
binaries.
After modifying API types in api/, regenerate CRDs and code:
make manifests # Regenerate CRD and RBAC manifests
make generate # Regenerate DeepCopy implementationsUnit tests live in internal/controller/ and internal/daemon/ alongside the
code they test. They use the controller-runtime
envtest framework, which
provides a local control plane (etcd + API server) without a full cluster. The
required binaries are downloaded automatically.
make unit # Run all unit tests
make unit V=1 # Verbose output
make unit RUN=Foo # Run tests matching "Foo"E2E tests live in test/e2e/ and run against a real
bink cluster. The full workflow is:
Each e2e test creates a dedicated worker node for the duration of the test and tears it down when the test completes. The freshly provisioned node ensures that each test starts from a clean state.
make buildimg # Build the operator container image
make deploy-bink # Start a bink cluster and deploy the operator
make e2e # Run the e2e test suite
make e2e V=1 # Verbose streaming output
make e2e RUN=Foo # Run tests matching "Foo"Note
The container image must be rebuilt and pushed to the bink registry after
every code change. Run make buildimg followed by make deploy-bink to
pick up your latest changes in the cluster.
The bink cluster includes an internal container registry. From the host, push
images to localhost:5000:
podman push --tls-verify=false localhost:5000/my-image:latestFrom inside the cluster, the same image is available at
registry.cluster.local:5000:
image: registry.cluster.local:5000/my-image:latestEach e2e test automatically gathers diagnostic logs when it completes
(regardless of pass or fail). Logs are written to _output/logs/<test-name>/
and include:
- Operator pod logs
- Pod and deployment descriptions
- BootcNodePool and BootcNode descriptions
- Kubernetes events
- Node descriptions and journal logs for each worker node
You can also manually gather logs from a running cluster:
make gather-binkThis collects the same diagnostics into _output/logs/gather-bink/.
CI runs on GitHub Actions
and consists of three jobs: unit, build-bink, and e2e. When a run fails,
you can inspect it using the gh CLI.
View a run summary:
gh run view <run-id> --repo bootc-dev/bootc-operatorThe e2e job uploads diagnostic logs as a GitHub Actions artifact named
e2e-logs. These contain the same logs collected by make gather-bink
(operator pod logs, node journals, event dumps, etc.). Download them with:
gh run download <run-id> --repo bootc-dev/bootc-operatorThis creates a local e2e-logs/ directory with per-test subdirectories
matching the structure described in Finding Test Logs.
-
Run
make fmtandmake vetbefore submitting. -
Run
make lintto check with golangci-lint. Usemake lint-fixto apply automatic fixes. -
All Go files must include the SPDX license header:
// SPDX-License-Identifier: Apache-2.0
If you are planning a large change, please open an issue first to discuss the approach. This avoids wasted effort and helps maintainers give early feedback.
This project uses the Developer Certificate of Origin (DCO). You must sign off each commit to certify that you have the right to submit it under the project's open source license.
Add a sign-off line to your commits:
Signed-off-by: Your Name <your.email@example.com>
Use git commit -s to add this automatically. Your sign-off name must match
your real name.
Follow a commit style similar to the Linux kernel:
- Subject line: a short contextual prefix, imperative mood, under 72 characters, no trailing period.
- Body: separated by a blank line, wrapped at 72 characters. Explain what changed and why.
- Use
Closes: #<number>orFixes: #<number>to link to issues.
-
Fork the repository and create a topic branch from
main. -
Make your changes in small, focused commits.
-
Ensure all checks pass locally:
make fmt manifests generate make vet make lint make unit
-
Push your branch and open a pull request against
main. -
Describe the change clearly in the PR description — what it does and why.
-
Address review feedback. Maintainers may request changes before merging.
All submissions require review before merging. Reviewers look for:
- Correctness and test coverage
- Consistency with existing patterns
- Clear commit messages
- Generated files kept in sync
For AI generated code, please refer the AGENTS.md document.
- Issues: Use GitHub Issues to report bugs or request features.
By contributing, you agree that your contributions will be licensed under the Apache License 2.0.
Please, refer to these guides for further help: