Conversation
Three fields were declared and never reached a pod. ImageSpec.PullSecrets was read nowhere. The only imagePullSecrets on any pod came from code image entries, so a private registry for the server, database or CA setup image could not work at all. All three pod specs now carry them, deduplicated against the code image secrets. Server.image.pullPolicy was ignored: both container specs read cfg.Spec.Image.PullPolicy unconditionally. Fixing that required removing the nested kubebuilder default, for the same reason #549 removed it from repository and tag: a nested default is materialised into every Server, so the field was never empty and could not express inherit. The fallback now lives in code - Server, then Config, then IfNotPresent. ConditionSSLBootstrapped existed as a constant and as a promise in docs/reference/server.md, but nothing ever set it. It now reports whether the referenced Certificate is usable, which also gives the Server a visible status while it waits: a missing or unsigned Certificate previously left no trace at all, so nothing happens looked the same as nothing is wrong. Documented the resolution rules, including that pullSecrets on a Server replaces the Config's list rather than extending it.
…condition fix(api): make pullSecrets and the Server pull policy take effect
A certname identifies exactly one entry on the CA, so two Certificates claiming the same one against the same CertificateAuthority are indistinguishable to it. Nothing prevented that: the webhook validated the certname format but not its uniqueness, there was no index on it, and the CRD defaults it to puppet - so two Certificates created without one collide by default rather than by mistake. The consequences were both silent. Signing and fetching both address the CA by certname, so a Certificate could adopt a certificate issued for another resource's key; the mismatch would only surface later as a failed TLS handshake. And handleCertificateCleanup revokes by certname, so deleting either Certificate revokes the entry the other one depends on. Three layers, because webhooks are disabled by default: - the admission webhook rejects a duplicate at creation, naming the holder - the controller refuses to sign and reports CertnameConflict, permanently: retrying cannot free a name, only a spec change can - a certificate returned by the CA is verified against the private key it was requested for, so a foreign certificate under the same name is never written to a Secret A terminating Certificate releases its claim, since its finalizer cleans the CA entry, and the rule is per CA rather than per namespace. The full-flow test now signs the submitted CSR instead of returning a canned certificate. It passed before only because nothing verified the pairing.
The kubebuilder default was the reason the collision was easy to hit: two Certificates created without a certname both landed on puppet, so they shared one CA entry by default rather than by mistake. It was also wrong on its own terms. A certname is an identity, and puppet is only the right identity for the main server - PuppetDB and any further certificate need their own. The names agents connect through, a load balancer or a service address, belong in dnsAltNames, which the chart already derives from the Pool Services a server joins. certname is now required with MinLength=1. Nothing in the repository relied on the default: the chart writes the value unconditionally and already fails the render when the Database has none, all sixteen CI value files set it explicitly, and so does the sample. The same guard now covers server entries, which were the one path that could still fall through to it. Also folds five copies of the puppet fallback in certificate_signing.go into certnameOf. The two remaining checks stay as they are: they return an error rather than substituting a name, which is correct for renewal and cleanup. Existing resources are unaffected - they carry certname: puppet materialised from the default, and the field is immutable anyway. New manifests that omit it are rejected, which is the point.
The setup Job writes both ca_crl.pem and infra_crl.pem into the {ca}-ca-crl
Secret. The periodic refresh writes only the first, and
createOrUpdateSecret replaces the data map wholesale, so infra_crl.pem
survived exactly until the first refresh and then disappeared for the
lifetime of the CA.
Deployments running with enable-infra-crl lose infrastructure-node
revocation that way, and nothing reports it: the refresh succeeds, the
Secret still exists, only one of its keys is gone.
createOrUpdateSecret now takes an optional list of keys to carry across.
The carry-over reads from the object CreateOrUpdate just fetched, so it
cannot race with a concurrent write.
Closes #574
The setting lived on ConfigSpec but was applied to Server pods. One Config backs several Servers with different roles, typically the CA and the compilers, so a single Server that needs a writable root forced the hardening off for every Server under that Config, the CA included. ServerSpec now carries an optional override that falls back to the Config, the same shape image uses since #549. It is a pointer for the same reason the other booleans are: with a true default on the Config, a plain bool cannot express false. Closes #575
…g them PoolReconciler.injectDNSAltNames wrote the route hostname into Certificate.spec.dnsAltNames of every Server in the Pool - a resource the Pool does not own. Under Argo CD or Flux that turned into a loop: the Pool added the name, the source of truth reverted it, the Pool added it again. Since #549 each round changes a signing-relevant field, so the churn also re-signs the certificate and rolls the pods. The relationship is now the other way round. The Certificate controller derives its effective alt names from its own spec plus the route hostname of every Pool that asks for injection and is joined by a Server using this Certificate. Nothing foreign is written, the result is idempotent, and status.effectiveDNSAltNames makes it visible. The signing hash and the CSR both use the derived names, so a Pool joined later still triggers a re-sign - the mechanism stays, only its trigger moves from a foreign write to observed state. The Certificate controller watches Pools and Servers so a hostname added later reaches it at all. injectDNSAltName stays as an API field; its meaning changes from mutates to is taken into account. The pool-gateway e2e assertion moves with it: the spec now holds what the chart wrote, the hostname appears in status. Closes #552
fix(certificate): refuse to share a certname, and require an explicit one
chore(deps): update dependency conforma/cli to v0.10.2
fix(deps): update module sigs.k8s.io/controller-runtime to v0.25.0
The CRDs are v1alpha1 and the project is deliberately pre-1.0, so a breaking change is expected rather than exceptional. semantic-release did not know that: three BREAKING CHANGE footers in the API hardening work turned the release of 2026-09-02 into 1.0.0, which signals a stability promise that is not intended yet. Map breaking changes to a minor bump so the intent lives in the repository instead of in everyone's head. Remove this rule when 1.0.0 is a deliberate decision; from then on a breaking change should mean what it says. Verified with semantic-release --dry-run against a clone whose v1.0.0 tag was removed: with the rule the same 74 commits produce 0.12.0, without it 1.0.0.
ci: keep breaking changes at a minor bump while below 1.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Features
Fixes
Refactoring
Chores
Files changed
Release prediction
Predicted release:
v1.0.0->v1.1.0(minor)1 feature(s) 5 fix(es)
Source:
develop| Target:main| Trigger: Successful CI on develop