Skip to content

[BUG] A declared placement path in a kustomize subdirectory is never rendered, and the identity gate rejects the versionless canonical path #295

Description

@sunib

Two placement defects found while reviewing #291. Both are reachable on main today, both are small,
and neither needs the layout model to land first. Findings and the fix shape:
docs/design/placement-visibility-and-declared-defaults.md
(findings F3, F4, F10).

1. A declared path into a kustomize subdirectory produces a file nothing renders

Symptom. One byType line is enough:

placement:
  byType:
    v1/configmaps: "configmaps/{name}.yaml"

pointed at a folder governed by a kustomization.yaml at its root. The file is committed to
configmaps/foo.yaml, no kustomization lists it, and kubectl apply -k never renders it. The mirror
contains a document that is not part of the folder it claims to be part of.

Cause. governingKustomization uses an own-directory check plus a write-scope special case, so a
declared path is registered with a kustomization only when render-root scoping happens to be in force.
The two cases differ by something the user cannot see.

Fix. Walk up to the nearest kustomization inside the write jail, so a byType or default path
into a subdirectory joins that root's resources: list. After the fix the two cases stop differing.

Note that #293 makes this class of bug unstatable rather than fixed, by registering the file with the
governing kustomization whatever chose the path. This issue is the fix for the model we have now; it
should not wait for the wave.

2. IdentityCompletePlacementTemplate demands {version}, which contradicts the versionless path

IdentityCompletePlacementTemplate(tmpl, false) requires {groupPath}, {version} and
{resource}. The built-in canonical path is deliberately versionless, because two versions of one
group/resource are the same object — which is exactly why the version segment was dropped.

Consequences:

  • a template carrying scope, group, resource and name cannot collide two distinct identities, with or
    without a version, so the requirement is wrong on its own terms;
  • it is what makes any future spec-level default fail our own validation gate: the canonical shape we
    would default to is judged not identity-complete, and every GitTarget that did not also declare an
    identity-complete byType["v1/secrets"] entry would go Validated=False.

Fix. Drop the {version} requirement for a non-narrowed template, with a test asserting the
versionless canonical shape is accepted.

Acceptance

  • A byType path into a subdirectory of a kustomize folder is registered with the root that
    governs it, with a test that fails before the change.
  • placement_kustomization_entries_total no longer counts these as failed (a failed value is
    a file committed outside every render, so this is also the metric's own regression test).
  • IdentityCompletePlacementTemplate accepts the versionless canonical shape; the Secret-safety
    gate still rejects what it should.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions