Skip to content

Make CRD dedup winner deterministic#5

Merged
tamalsaha merged 1 commit into
masterfrom
deterministic-crd-dedup-winner
Jul 13, 2026
Merged

Make CRD dedup winner deterministic#5
tamalsaha merged 1 commit into
masterfrom
deterministic-crd-dedup-winner

Conversation

@tamalsaha

Copy link
Copy Markdown
Contributor

Problem

crd-only deduplicates CRDs by GroupKind, keeping the first copy it encounters. But which copy is "first" is decided by the order Helm's CRDObjects() enumerates the chart tree — and that order is not stable. It varies with how subcharts happen to be loaded (a directory vs a vendored .tgz, freshly pulled OCI dependencies, Helm version, diamond dependencies).

#4 made the output file ordering deterministic (sorted crdKeys), but it did not change which duplicate wins. So when the same CRD (GroupKind) is shipped by multiple charts with differing content, the generated *-certified-crds chart still flaps between the conflicting copies from run to run — e.g. cert-manager's Certificate/Issuer CRDs, which several subcharts vendor.

Reproduction (parent chart with subchart sub present as both a directory and a .tgz, each shipping a different version of the same CRD):

OLD (master): distinct outputs across 12 runs = 2   # flaky
NEW (fix):    distinct outputs across 12 runs = 1   # deterministic

Fix

Collect every candidate CRD with its source chart path and a content digest, then choose the winner by a total order:

  1. group, then kind — stable output file order
  2. chart depth — the parent chart wins over its subcharts (preserves the previous "parent takes precedence" intent)
  3. chart path, then filename — stable tiebreak among subcharts
  4. content digest — final tiebreak for the case where one subchart is present as both a directory and a .tgz (or reached via a diamond dependency) with differing content, so the key (group, kind, path, filename) would otherwise tie and sort.Slice (unstable) would pick arbitrarily

Because candidates are sorted by (group, kind) first, the output slice is already in stable order — the separate post-sort of keys is removed. The redundant second pass over ch.Dependencies() is dropped too, since CRDObjects() already recurses into all subcharts.

A duplicate warning is now emitted only when a dropped copy actually differs in content from the winner, so identical duplicates (the common case) stay quiet while genuine version conflicts remain visible.

crd-only deduplicates CRDs by GroupKind, keeping the first copy seen. The
winner was decided by the order Helm's CRDObjects() enumerates charts, which
is not stable — it varies with how subcharts were loaded (directory vs .tgz,
freshly pulled OCI deps, Helm version). #4 only sorted the output file order,
not which duplicate wins, so the generated crds-only chart still flapped
between conflicting copies of the same CRD.

Collect every candidate with its source chart path and a content digest, then
pick the winner by a total order: group, kind, chart depth (the parent chart
wins over its subcharts), chart path, filename, and finally content digest.
The digest tiebreak covers the case where one subchart is present as both a
directory and a .tgz (or reached via a diamond dependency) with differing
content and therefore an otherwise identical (group, kind, path, filename)
key. Warn only when a dropped copy actually differs from the winner.

Signed-off-by: Tamal Saha <tamal@appscode.com>
@tamalsaha
tamalsaha merged commit 26ff9fd into master Jul 13, 2026
4 checks passed
@tamalsaha
tamalsaha deleted the deterministic-crd-dedup-winner branch July 13, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant