Repository navigation
Prepare the first release: README rewrite and weft.alethic.solutions/v1 API - #12
Merged
Merged
Conversation
Rewrite the README for people meeting Weft for the first time: what it is, a runnable quick start, a feature summary, install and verification, and a documentation index. The behavioural detail and design rationale the old README carried move into docs/operating.md (status conditions, pruning, teardown, flags, metrics, uninstall) and docs/design.md (comparison with other tools, why Starlark, non-goals), so nothing is lost. Install instructions in the README, chart README and demo no longer assume there is no stable release: plain `helm install` resolves the newest release, with --devel described for prereleases. Move the API group from weft.run to weft.alethic.solutions before anything is released under the old one. This changes the CRD name (weaves.weft.alethic.solutions), the apiVersion, and every annotation, label and finalizer key Weft writes. The group is still defined once in internal/naming; the rest is generated output, markers, docs and examples.
The previous commit renamed the API group outright, which would strand every Weave in clusters that already run weft.run. Instead, serve both: weft.alethic.solutions/v1 is the current API, and weft.run/v1alpha1 keeps working unchanged so existing installations can upgrade without touching anything and move their Weaves across one at a time. Kubernetes cannot convert between groups, so these are two CRDs. The canonical types live in api/v1; api/v1alpha1 embeds v1's spec and status so the schemas cannot drift, and a test asserts the generated CRDs agree. The weft.run CRD is unchanged apart from descriptions. internal/naming now describes each group, and every key a Weave writes follows its own group: finalizers, provenance, the owned and adopt annotations, and the server-side-apply field manager. The weft.run identifiers are pinned by a test, because they are on objects that predate v1. The leader election lease keeps its old name so a rolling upgrade's old and new replicas share one. The controller runs one reconciler per group, working on v1 internally and converting the envelope at the API boundary. The watch registry, metrics and kube client are group-aware, so a weft.run Weave and a v1 Weave of the same name are fully independent. Moving a Weave is a delete with --cascade=orphan and a create. A v1 Weave takes over what its same-named weft.run predecessor made, in place, once that predecessor is gone: it transfers field ownership from the weft.run manager to its own, so its first apply prunes the old provenance and anything else the program no longer sets. While the predecessor exists it refuses with the exact kubectl command to finish the move; while it is deleting it waits. A v1 program still using weft.run/owned is refused rather than silently owning what it meant to keep. The chart installs both CRDs and grants both groups by default; legacyAPI.enabled=false drops the CRD, the grant and the reconciler together. reap covers both groups. docs/migrating.md describes the move. Per-Weave metrics gain a group label, and the weft.run controller is now named weave-weft-run in controller-runtime's metrics.
Deploying tools move a Weave between groups by creating the new object and then deleting the old one. Helm, Flux's helm-controller and kustomize-controller all apply first and prune after, with background propagation, and none can orphan. The weft.run Weave being pruned would then tear down everything it made, only for its v1 successor to recreate it. A weft.run Weave deleted while a live v1 Weave of the same name exists now strips its own owner references, so garbage collection has nothing to collect, releases its holds, and lets go. The successor takes each object over through the existing handover. The existence check reads past the cache, since a stale answer here is the difference between a handover and a teardown, and an error is retried rather than treated as absence. The chart now renders when legacyAPI is missing from the values, as it is under helm upgrade --reuse-values from a release that predates it, and treats missing as enabled.
helm upgrade --reuse-values carries the previous release's values in place of the new chart's defaults. The publish job wrote the image digest into values.yaml, so a reused upgrade kept the previous release's image under the new chart. Verified on kind: the 0.1.0-pre.37 binary exits on the new --serve-legacy-api flag, so the new pod crash-loops while the old one keeps serving. The digest now goes to files/image-digest, read by the image helper after anything the user set: image.digest, then image.tag, then the published digest, then the appVersion tag. A tag set by the user now takes effect on a published chart instead of being silently overridden. Prereleases already carry a digest in their stored values, so their first reused upgrade needs --set image.digest=; docs/migrating.md says so.
--reuse-values keeps the old chart's defaults, which for prereleases include the image digest. --reset-then-reuse-values starts from the new chart's defaults and re-applies only the user's overrides, which is what keeping one's settings across an upgrade should mean. Also restore a line continuation the previous edit lost.
The legacyAPI toggle let a cluster leave weft.run out, but turning it off while weft.run Weaves remained would strand them: nothing would reconcile them or release their finalizers. The saving - one unused CRD and a few RBAC rules - is not worth that. Both groups are now always installed, granted and reconciled, until a future release removes weft.run altogether. The --serve-legacy-api flag goes with it. With the flag gone, the --reuse-values digest problem no longer crash-loops the old binary; it silently keeps the old controller running, which serves no v1. The migration doc says so.
wasabii
force-pushed
the
claude/readme-rewrite-release-311bea
branch
from
October 18, 2026 17:05
8de4fad to
a9c34db
Compare
The line stripped carriage returns from GitVersion's output with a literal CR byte between quotes. An earlier edit of the Makefile normalised line endings and turned that byte into a newline, splitting the line, so make refused to parse the file and every CI job that runs make failed. Write it as the escape '\r', which tr understands and which no editor will reinterpret.
govulncheck now reports nine vulnerabilities reachable from this code, in net/http, crypto/tls, net/textproto and the HTTP/2 implementation in both the standard library and golang.org/x/net. All are fixed in Go 1.27.2 and x/net v0.60.0, and CI's vulncheck fails until they are. main pins the same versions, so it fails this check too. Also brought forward while here: - prometheus/client_golang 1.24.1 -> 1.25.0 - go.starlark.net to the latest commit - golang.org/x/* to current releases (x/net 0.61.0) - controller-gen 0.22.0 -> 0.23.0 (generated CRDs change only in the version annotation) - setup-envtest 0.25.0 -> 0.25.2 - golangci-lint 2.13.2 -> 2.15.0 (no new findings) The Kubernetes libraries and controller-runtime were already current. Their own indirect dependencies (kube-openapi, structured-merge-diff, k8s.io/utils, sigs.k8s.io/json) stay where Kubernetes 0.37.1 pins them: the newer kube-openapi needs structured-merge-diff v7, which apimachinery 0.37.1 does not build against.
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.
What this changes
Gets Weft ready for its first release to external users.
README for external readers. The README is rewritten for people meeting Weft for the first time. It now covers what Weft is, a runnable quick start, features, install and image verification, and an index of the docs. The detail the old README carried is moved, not dropped:
docs/operating.mdcovers status conditions, pruning, teardown, flags, metrics and uninstalling;docs/design.mdcovers the comparison with other tools, why Starlark, and non-goals. Install instructions no longer assume prerelease-only (--devel).New API group,
weft.alethic.solutions/v1, served alongsideweft.run/v1alpha1. Weft is already deployed internally underweft.run, so the old group keeps working unchanged:api/v1;api/v1alpha1embeds v1's spec and status, and a test checks the generated schemas match. Theweaves.weft.runCRD changes only in two description lines.internal/naming): finalizers, provenance label and annotation, the owned and adopt annotations, and the field manager. A test pins theweft.runkeys so they can't change by accident. The leader election lease keeps its old name, so a rolling upgrade's old and new pods share one lease.internal/controller/served.go). The watch registry, metrics and kube client know which group a Weave belongs to, so same-named Weaves in the two groups never interfere.weft.runpredecessor made, without recreating anything. It moves field ownership from the old field manager to its own, so its first apply removes the old provenance. This happens in two ways:kubectl delete … --cascade=orphan, then apply the v1 one.apiVersionin one release. Helm, Flux's helm-controller and kustomize-controller all create new objects before pruning removed ones (checked in their source). Aweft.runWeave deleted while a live v1 successor exists strips its own owner references and lets go, instead of tearing down. That existence check bypasses the cache, because a stale answer would mean a teardown.weft.run/ownedis refused, rather than owning (and later deleting) what it meant to keep.weft.runoff, because turning it off whileweft.runWeaves remain would strand them. It goes away when a future release removes it.reapcovers both groups.docs/migrating.mdis the guide for internal teams.Upgrade fix found by a real Helm upgrade test:
values.yaml, so--reuse-valueskept the previous release's image under the new chart. The upgrade then reports success, but the old controller keeps running and serves no v1. (On kind, with an intermediate version of this branch, the old binary crash-looped on a since-removed flag.) The digest now ships incharts/weft/files/image-digest. Order of precedence:image.digest, thenimage.tag, then the published digest, thenappVersion. The docs recommend--reset-then-reuse-valuesfor the first upgrade from a prerelease.Behaviour changes worth noting:
grouplabel.weft.runcontroller is now namedweave-weft-runin controller-runtime's own metrics;weavenow means v1.kubectl get weaveis ambiguous between the two groups. I expect it resolves to v1, but haven't checked that on a cluster.image.tagnow takes effect on a published chart instead of being silently overridden by the pinned digest.Checks
make generateproduces no diff. Run as the equivalentcontroller-gensteps;makeisn't available on the Windows machine this was written on.make testpasses, and the controller and chart suites actually ran rather than skipping. The full suite ran with-racein agolang:1.27.1container against envtest 1.37.0; the controller suite has 54 tests, 8 of them new for the two groups and handover. The chart suite ran locally with Helm 4.3.make lintis clean (golangci-lintv2.13.2 in a container).End-to-end on kind (Kubernetes 1.37, Helm 4.3):
0.1.0-pre.37chart.weft.runWeaves (ConfigMaps, a Secret, an unowned ConfigMap, a Deployment) from an app Helm chart.--reuse-values(with an earlier revision that still had a toggle, since removed). Both groups were served, the old Weaves stayed Ready, and they were actively reconciled (an input edit propagated within about a second).apiVersionin onehelm upgrade. With a real garbage collector running, every object kept its UID, ownership moved to the v1 Weaves, noweft.runlabels, annotations or field managers were left, and the Deployment's pod never restarted.Nothing here needs a
+semverbump; the next version is still the first0.1.0.Does this touch the impersonation boundary?
Yes:
internal/kubeand the controller's RBAC.weavesinweft.alethic.solutionsthat it already held inweft.run. It gains no access to anything a composition might generate.Factory.Fornow takes the Weave's group. It only selects the field manager; the impersonated identity is still built solely from the Weave's own namespace and ServiceAccount.Client.TransferFieldOwnership. It runs on the impersonated client, so it needspatchon the object as that ServiceAccount, the same verb server-side apply already needs. It only rewritesmetadata.managedFieldsentries for apply operations.RemoveOwnerReference.weaves, which the controller already reads with its own identity. No composition data is read without impersonation.So a Weave still cannot do more than its ServiceAccount can. The handover takes over only objects whose provenance names the same Weave, and anyone able to forge that provenance could already grant consent with the adopt annotation.