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
2 changes: 1 addition & 1 deletion .coverage-baseline
Original file line number Diff line number Diff line change
@@ -1 +1 @@
75.6
75.9
1 change: 1 addition & 0 deletions api/v1alpha3/gittarget_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ type GitTargetStreamsStatus struct {
// +kubebuilder:printcolumn:name="Reason",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
// +kubebuilder:printcolumn:name="Streams",type=string,JSONPath=`.status.streams.summary`
// +kubebuilder:printcolumn:name="GitPathAccepted",type=string,JSONPath=`.status.conditions[?(@.type=="GitPathAccepted")].status`,priority=1
// +kubebuilder:printcolumn:name="RenderMatchesLive",type=string,JSONPath=`.status.conditions[?(@.type=="RenderMatchesLive")].status`,priority=1
// +kubebuilder:printcolumn:name="StreamsRunning",type=string,JSONPath=`.status.conditions[?(@.type=="StreamsRunning")].status`,priority=1
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=1
// +kubebuilder:printcolumn:name="Encryption",type=string,JSONPath=`.spec.encryption.provider`,priority=1
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/configbutler.ai_gittargets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ spec:
name: GitPathAccepted
priority: 1
type: string
- jsonPath: .status.conditions[?(@.type=="RenderMatchesLive")].status
name: RenderMatchesLive
priority: 1
type: string
- jsonPath: .status.conditions[?(@.type=="StreamsRunning")].status
name: StreamsRunning
priority: 1
Expand Down
46 changes: 46 additions & 0 deletions docs/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,52 @@ guidance that the changelog's breaking-change entries link to.
We are pre-1.0, so breaking changes bump the **minor** version (release-please is configured with
`bump-minor-pre-major`) rather than the major. Read the relevant entry before upgrading across it.

## Unreleased — the build's output stops leaking into the build's input (next minor; bug fix + behavior change)

**If your kustomization declares `labels:`, `commonLabels:`, `commonAnnotations:` or `namespace:`,
the operator has been writing those injected values into your source manifests.** Measured, on a
folder we accept today, with nothing changed in the cluster and nothing changed in the render:

```yaml
# kustomization.yaml (yours) # deployment.yaml, after one reconcile (ours)
labels: metadata:
- pairs: labels:
env: prod env: prod # <- the OVERLAY's, absorbed into the BASE
commonAnnotations: annotations:
owner: platform owner: platform
```

The writer mirrors a live object into the file that produced it — but under kustomize that file is
not what the cluster runs, and mirroring the live object straight back writes the build's own
output into the build's input. Every reconcile of an unchanged folder produced a commit, and the
file was left wrong: delete the kustomization later and the injected values are now yours forever.
In a base shared by two overlays, the value baked in is **one environment's**.

The fix needs no model of any transformer, and it is now the rule the writer follows:

> **Where the live object and the render agree, the source keeps its bytes. Where they disagree,
> the user changed something, and that is what we write.**

**Nothing needs migration** — this is a fix, and it makes the operator stop rewriting files it
should have left alone. If a past reconcile has already baked injected metadata into a manifest,
the operator will not remove it for you; remove it by hand and it will not come back.

**Two behavior changes go with it.**

*The re-render now runs for any document a kustomization produces*, not only for one an
`images:`/`replicas:` entry governs. A change to a field the build supplies (relabelling a live
object whose label a `labels:` block sets, say) cannot be expressed in the repository: the source
file cannot hold it, because the build would stamp its own value straight back. That write now
**refuses the flush** — `GitPathAccepted=False` / `WriteBoundaryRefused`, naming the file and the
object — where before it was committed and silently never converged.

*A live change the projection cannot place is refused* (`unplaceable-edit`). It fires when the
build and the live object have **both** rewritten one list whose elements carry no unique `name:`
to pair them by — the source's `args:` rewritten by a patch, for example. There is no honest way
to say which of the source's bytes you meant to keep, and pairing the lists by position is
measurably wrong (kustomize *prepends* a container a patch adds), so the operator refuses rather
than guesses.

## Unreleased — kustomize decides what it renders, and what it touched (next minor; bug fixes + behavior change)

The write path no longer contains a re-implementation of kustomize's image and replica
Expand Down
8 changes: 7 additions & 1 deletion docs/design/support-boundary/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
| Topic | Docs |
|---|---|
| **The boundary** | [support-contract.md](support-contract.md) — the single statement · [kustomize-support-boundary.md](kustomize-support-boundary.md) — field taxonomy + layout allowlist · [gittarget-granularity-and-cross-environment-edits.md](gittarget-granularity-and-cross-environment-edits.md) — **the write boundary; the one home of fan-in = 1** |
| **Renderers & provenance** | [render-attribution.md](render-attribution.md) — attribution and verification · [render-root-scoping.md](render-root-scoping.md) — render roots and the oracle · [render-fidelity.md](render-fidelity.md) — **our render is not the orchestrator's; refuse where they diverge** · [render-fidelity-scenarios.md](render-fidelity-scenarios.md) — red-first fidelity fixtures + the folder-gate state matrix · [kustomize-token-writeback-explained.md](kustomize-token-writeback-explained.md) — teaching explainer: the `${...}` writeback problem, the tried simplifications, and the managedFields question · [renderer-abstraction-idea.md](renderer-abstraction-idea.md) — exploration: a pluggable renderer seam (`Owns` + blind spots), starting with FluxKustomize · [kpt-and-krm-functions.md](kpt-and-krm-functions.md) — how Kpt packages, setters, and KRM functions may fit safely |
| **Orchestrators & expansion** | [orchestrator-knowledge-boundary.md](orchestrator-knowledge-boundary.md) — renderability vs ownership; claims about paths · [expansion-boundary-and-corpus-organisation.md](expansion-boundary-and-corpus-organisation.md) — provenance; ApplicationSet vs ResourceSet; Helm · [`../../facts/expansion-provenance-markers.md`](../../facts/expansion-provenance-markers.md) — **the measured markers** · [argocd-bi-directional.md](argocd-bi-directional.md) — why `selfHeal` is incompatible |
| **Documents & secrets** | [resource-capability-model.md](resource-capability-model.md) — what may I do to this document · [write-only-encrypted-secrets.md](write-only-encrypted-secrets.md) — SOPS · [sealed-secrets-and-external-secrets.md](sealed-secrets-and-external-secrets.md) |
| **Edits with no home** | [unreflectable-edits-and-write-gating.md](unreflectable-edits-and-write-gating.md) |
| **Edits with no home** | [unreflectable-edits-and-write-gating.md](unreflectable-edits-and-write-gating.md) — tier-1/2/3 accounting · [admission-consent.md](admission-consent.md) — say yes to a blast-radius refusal · [orchestrator-reconcile-trigger.md](orchestrator-reconcile-trigger.md) — revert a refusal / order around origin drift |
| **Discovery (read-only)** | [repo-discovery-and-onboarding-scan.md](repo-discovery-and-onboarding-scan.md) |
| **Shipped** | [finished/images-and-replicas-edit-through.md](finished/images-and-replicas-edit-through.md) · [finished/higher-level-krm-documents.md](finished/higher-level-krm-documents.md) |
| **Evidence** | [`test/fixtures/gitops-layouts/`](../../../test/fixtures/gitops-layouts/) — the corpus of real-world repo shapes, and the generated behavioural baseline beside it |
Expand Down Expand Up @@ -120,6 +121,11 @@ rather than guessing.
- **Kustomize `images:` / `replicas:` edit-through** — a live change produced by an
override entry is written back to that entry, never through into the source manifest
([finished/images-and-replicas-edit-through.md](finished/images-and-replicas-edit-through.md)).
- **Render-fidelity token gate** — parsed `${...}` values are compared with live state before a
write. A mismatch refuses the operation and makes the independent
`RenderMatchesLive=False` condition close normal writes until a fresh complete watch epoch is clean
([render-fidelity.md](render-fidelity.md)). Remote-Git revision detection and automatic recovery after
a Git repair remain unbuilt.
- **Higher-level KRM documents** (Flux `HelmRelease`, Argo CD `Application`, KRO
resources) mirror and edit exactly like core resources — the pipeline is kind-agnostic,
and is pinned by a corpus plus a HelmRelease mirror+edit e2e
Expand Down
Loading
Loading