You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a6ce8a2
Browse filesBrowse the repository at this point in the historyBrowse files
fix(gitops): refuse a binding ID that cannot name a Kubernetes object, and clear the delivery path
Two defects found reviewing this branch, both of which reached the cluster
or the publish rather than failing at the render.
A binding ID becomes a ConfigMap name. bindingID checked only that its
parts were non-empty, free of "./ ", and short enough, so a workspace
named My_Workspace produced solution-host-binding-My_Workspace.prod.crm —
not a legal Kubernetes object name. Nothing downstream refused it: core's
bindingPattern deliberately admits uppercase and underscores so a ULID or
a UUID can be a binding ID, and ValidateRenderedTree accepts the tree. The
first refusal was ArgoCD at sync, which is the late, opaque failure
solutionNamespace exists to prevent for namespaces. The route alias
already had exactly the right guard; the ID, which is the half that names
an object, did not. Both now share one rfc1123Label rule.
RenderOwnedTree wrote SolutionHostBindingPath onto the caller's options
only when a binding had been written, and never cleared it. A render that
declared none left a previous render's value standing, and the inventory
then claimed a delivery path the tree did not have. That is not a
cosmetic inaccuracy: generateArgoBootstrap and snapshotAuthority both
kustomize-build "<path>/overlays/<environment>", so a stale value refuses
the entire publication. The field is now derived unconditionally from
what was written, so no code path can leave a stale one.
Each fix has a test that was verified to fail with only that fix reverted.
Also from the same review:
- The bindings component moves from sync wave 2 to the module-resources
wave. Argo starts a wave only once the previous is healthy, so wave 2
withheld the declaration of desired state from a solution whose
workload was unhealthy — exactly when a host needs it. The digests are
over rendered bytes in the delivery repository and exist whatever the
cluster is doing, so nothing required the workloads to be healthy
first.
- docs: removal is not a passive absence. Rendering no binding emits no
ApplicationSet element, and dropping an element deletes its Application,
whose template carries the Argo resources finalizer with prune enabled —
so the delivered ConfigMaps are cascade-deleted. A reconciler must hold
a binding across its document's disappearance.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"solution %s claims the route alias %q; a host keys its registry on the alias as one URL path segment, so it must be lowercase letters, digits and dashes, starting and ending alphanumeric",
return"", fmt.Errorf("solution host binding ID needs the %s name", part.label)
297
305
}
298
-
ifstrings.ContainsAny(part.value, "./ ") {
299
-
return"", fmt.Errorf("solution host binding ID cannot be built from %s %q: it joins its parts on \".\"", part.label, part.value)
306
+
// Each part must be one lowercase DNS label. core's bindingPattern is
307
+
// wider — it admits uppercase and underscores so a ULID or UUID can be
308
+
// a binding ID — so core's own Validate accepts "My_Workspace.prod.crm"
309
+
// and the render would deliver a ConfigMap named
310
+
// "solution-host-binding-My_Workspace.prod.crm", which is not a legal
311
+
// Kubernetes object name. Nothing downstream refuses that: the tree
312
+
// validates, the publish succeeds, and ArgoCD fails at sync.
313
+
if!rfc1123Label.MatchString(part.value) {
314
+
return"", fmt.Errorf(
315
+
"solution host binding ID cannot be built from %s %q: the ID names a Kubernetes object, so each part must be lowercase letters, digits and dashes, starting and ending alphanumeric",
0 commit comments