Skip to content
Back to skills

Loom Kustomize

DSecurity

Kubernetes-native configuration management with Kustomize.

  • 56 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
ai-agentsrustgoshellbashnodekubernetesgitapici/cdsecurity

Works with

  • cli
  • api

Security analysis

D50/100
  • criticalAccesses sensitive system or user directories
  • criticalSends environment variables or credentials to an external URL

Pro shows the line behind each finding and how to fix it

Scanned September 5, 2026

npx -y skills add cosmix/loom --skill loom-kustomize --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Loom Kustomize?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Loom Kustomize
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/cosmix-loom-kustomize/badge)](https://www.skillsdirectory.com/skills/cosmix-loom-kustomize)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: loom-kustomize
description: Kubernetes-native configuration management with Kustomize.
allowed-tools:
  - Read
  - Grep
  - Glob
  - Edit
  - Write
  - Bash
triggers:
  - kustomize
  - kustomization
  - overlay
  - base
  - patch
  - strategic merge
  - json patch
  - json6902
  - configmap generator
  - secret generator
  - namespace
  - namePrefix
  - nameSuffix
  - commonLabels
  - commonAnnotations
  - component
  - transformer
  - replacement
  - multi-environment
  - dev/staging/prod configs
  - k8s manifest management
---

# Kustomize Skill

## Overview

Template-free, declarative Kubernetes config management via merging. `kubectl apply -k <dir>` and `kustomize build <dir>` render an overlay. Failure modes here are overwhelmingly **silent** (wrong output, exit 0) — always `diff` the `kustomize build` output before/after any structural change.

## Core Concepts

| Term            | Meaning                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------ |
| **Base**        | Dir with `kustomization.yaml` + shared resources; never modified in place.                       |
| **Overlay**     | Dir referencing a base under `resources:`, applying env-specific patches/generators.             |
| **Patch**       | Partial resource that modifies existing ones — strategic merge (default) or JSON 6902.           |
| **Component**   | Reusable opt-in feature bundle (`kind: Component`); runs against the parent's accumulated set.    |
| **Generator**   | Builds ConfigMaps/Secrets from literals/files/envs, appending a content-hash name suffix.        |
| **Transformer** | Cross-cutting mutation: `namespace`, `namePrefix`/`nameSuffix`, `labels`, `images`, `replicas`.  |
| **Replacement** | Copies a field value from a source resource into target field paths (successor to `vars`).       |

## Directory Layout

```text
k8s/
├── base/                    # shared, env-agnostic (kustomization.yaml + resources)
├── overlays/
│   ├── dev/                 # low resources, debug
│   ├── staging/             # + monitoring component
│   └── prod/                # HA, security, digest-pinned images
└── components/              # opt-in features: monitoring, ingress, debug-tools
```

Keep the hierarchy **shallow** (base → overlay, not base → overlay1 → overlay2). Paths in `resources:` are relative to the kustomization.yaml's own directory.

## Quick Reference

| Task             | Command                                                                    |
| ---------------- | -------------------------------------------------------------------------- |
| Build            | `kustomize build k8s/overlays/prod`                                        |
| Preview diff     | `kubectl diff -k k8s/overlays/prod`                                        |
| Apply            | `kubectl apply -k k8s/overlays/prod`                                       |
| Validate         | `kustomize build k8s/overlays/prod \| kubectl apply --dry-run=client -f -` |
| Migrate deprecated fields | `kustomize edit fix` (idempotent; run per dir; see Idioms)        |
| Set image tag    | `kustomize edit set image myapp=registry/myapp:v1.2.3`                     |
| Add ConfigMap    | `kustomize edit add configmap app-config --from-literal=KEY=value`         |

**Generators** (`configMapGenerator` / `secretGenerator` items): `literals:` (`K=v`), `files:` (`app.properties`, or `alias=path`), `envs:` (`config.env`). Secrets add `type:` (e.g. `kubernetes.io/tls`). `behavior:` = `create` (default) | `merge` | `replace`.

**Transformers** (top-level keys): `namespace`, `namePrefix`, `nameSuffix`, `labels` (use over deprecated `commonLabels`), `commonAnnotations`, `images` (`newName`/`newTag`/`digest`), `replicas` (`- name: x count: n`), `replacements`.

## Patch Strategies

| Aspect        | Strategic Merge (default)                                    | JSON 6902 (RFC 6902)                                    |
| ------------- | ----------------------------------------------------------- | ------------------------------------------------------ |
| Merge model   | K8s-schema-aware; maps by key, lists merge on known key     | `op` (`add`/`remove`/`replace`/`move`/`copy`/`test`) on JSON Pointer paths |
| Best for      | Field/env/resource-limit tweaks, adding containers          | Precise array-index ops, conditional `test`, CRDs      |
| Whole-list replace | **Unreliable** — `$patch: replace` regressed (issue #2980, ignored/merged instead) | Reliable: `op: replace` on the list path          |

Both go under the unified `patches:` field, which auto-detects type from content and whose `target` supports `group/version/kind/name/namespace` + `labelSelector`/`annotationSelector` (one patch → many resources). `patchesStrategicMerge`/`patchesJson6902` are deprecated (v5.0.0) and gone from the v1 API.

## Components

Reusable opt-in bundles for features only some environments need (monitoring, ingress, debug tools, security hardening). Use a **patch** instead for required, always-applied, or env-specific value tweaks.

```yaml
# k8s/components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1   # alpha — API may change without deprecation window
kind: Component
resources:
  - servicemonitor.yaml
patches:
  - path: patch-metrics.yaml
    target: {kind: Deployment}
labels:
  - pairs: {prometheus.io/scrape: "true"}
    includeSelectors: false
```

> **Reference Components under `components:`, never `resources:`.** A Component placed under `resources:` is silently misapplied as a plain manifest; kustomize enforces the split (Components rejected from `resources:`, Kustomizations from `components:`). Components run against the parent's accumulated resource set and **can be nested**.

## Examples

### Base kustomization + Deployment

```yaml
# k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: myapp

# Use the labels transformer, NOT deprecated commonLabels (which mutates the
# IMMUTABLE spec.selector.matchLabels → delete/recreate on any later change).
# includeSelectors defaults false (safe on live resources); includeTemplates
# reaches pod templates. Define real selector labels directly in deployment.yaml.
labels:
  - pairs: {app: myapp, managed-by: kustomize}
    includeSelectors: false
    includeTemplates: true

commonAnnotations: {contact: team@example.com}

resources:
  - deployment.yaml
  - service.yaml
  - serviceaccount.yaml

configMapGenerator:
  - name: app-config
    literals: [LOG_LEVEL=info, MAX_CONNECTIONS=100]

images:
  - name: myapp
    newName: registry.example.com/myapp
    newTag: latest
```

```yaml
# k8s/base/deployment.yaml (selector label defined explicitly — not injected)
apiVersion: apps/v1
kind: Deployment
metadata: {name: myapp}
spec:
  replicas: 1
  selector:
    matchLabels: {app: myapp}
  template:
    metadata:
      labels: {app: myapp}
    spec:
      serviceAccountName: myapp
      containers:
        - name: app
          image: myapp
          ports: [{containerPort: 8080, name: http}]
          envFrom: [{configMapRef: {name: app-config}}]
          resources:
            requests: {memory: 128Mi, cpu: 100m}
            limits: {memory: 256Mi, cpu: 200m}
          readinessProbe:
            httpGet: {path: /ready, port: http}
            initialDelaySeconds: 5
```

### Production overlay (annotated)

```yaml
# k8s/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: myapp-prod

labels:
  - pairs: {environment: prod, criticality: high}
    includeSelectors: false
    includeTemplates: true

commonAnnotations:
  oncall: sre-team@example.com

# SINGLE resources: block. A second resources: key later in the same document
# silently wins (duplicate YAML map keys), dropping ../../base entirely.
resources:
  - ../../base
  - poddisruptionbudget.yaml
  - horizontalpodautoscaler.yaml
  - networkpolicy.yaml

patches:
  - path: patch-resources.yaml     # bump requests/limits
  - path: patch-affinity.yaml      # required podAntiAffinity + nodeAffinity
  - path: patch-security.yaml      # runAsNonRoot, drop ALL, RO rootfs, seccomp

configMapGenerator:
  - name: app-config
    behavior: merge
    envs: [config-values.env]

secretGenerator:
  - name: app-secrets
    envs: [secrets.env]            # gitignored / external-managed

images:
  - name: myapp
    newTag: v1.2.3
    digest: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  # pin by digest in prod

replicas:
  - {name: myapp, count: 5}

components:
  - ../../components/monitoring
  - ../../components/ingress
```

Overlay patch files are minimal partial docs matched by `kind`/`name`, e.g. a security patch:

```yaml
# patch-security.yaml
apiVersion: apps/v1
kind: Deployment
metadata: {name: myapp}
spec:
  template:
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        seccompProfile: {type: RuntimeDefault}
      containers:
        - name: app
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: {drop: [ALL]}
```

### JSON 6902 patch (precise array ops)

```yaml
# kustomization.yaml
patches:
  - path: json-patch.yaml
    target: {group: apps, version: v1, kind: Deployment, name: myapp}
```

```yaml
# json-patch.yaml — list of {op, path, value}; auto-detected as JSON 6902
- op: add                                                 # append sidecar
  path: /spec/template/spec/containers/-
  value: {name: log-shipper, image: fluent/fluent-bit:2.0}
- op: replace                                             # container 0 image
  path: /spec/template/spec/containers/0/image
  value: registry.example.com/myapp:v1.2.3
- op: remove                                              # env var by index
  path: /spec/template/spec/containers/0/env/3
- op: test                                                # conditional guard
  path: /spec/replicas
  value: 1
- op: replace
  path: /spec/replicas
  value: 5
```

### Generators

```yaml
configMapGenerator:
  - name: app-config
    behavior: merge                 # create (default) | replace | merge
    literals: [LOG_LEVEL=debug]     # overrides base key
    files: [app.properties, tls.crt=certs/server.crt]
    envs: [config.env]
    options:
      disableNameSuffixHash: true   # ⚠ defeats config-driven rollouts (see Gotchas)

secretGenerator:
  - name: tls-secrets
    files: [tls.crt, tls.key]
    type: kubernetes.io/tls
  - name: app-secrets
    envs: [secrets.env]             # gitignored — never commit secrets
```

### Replacements (propagate a field value)

```yaml
replacements:
  # Propagate hashed ConfigMap name into the Deployment volume ref
  - source: {kind: ConfigMap, name: app-config, fieldPath: metadata.name}
    targets:
      - select: {kind: Deployment}
        fieldPaths:
          - spec.template.spec.volumes.[name=config].configMap.name
```

### Remote bases

```yaml
resources:
  - https://github.com/org/repo//k8s/base?ref=v1.0.0   # pin to tag or full SHA (see Security)
```

## Common Tasks

```bash
# Validate / preview
kustomize build k8s/overlays/prod | kubectl apply --dry-run=server -f -
kubectl diff -k k8s/overlays/prod

# Inspect name/hash transformations
kustomize build k8s/overlays/prod | rg '^  name:'
kustomize build k8s/overlays/prod | rg -A2 'kind: ConfigMap'

# Migrate deprecated fields in place (idempotent; wrap in a build-diff)
kustomize edit fix

# Bootstrap kustomization.yaml from existing manifests
kustomize create --autodetect        # or --resources deployment.yaml,service.yaml
```

## GitOps & CI/CD Integration

**ArgoCD**: `Application.spec.source.path: k8s/overlays/prod`, `syncPolicy.automated {prune, selfHeal}`.
**Flux**: `kustomize.toolkit.fluxcd.io/v1 Kustomization` with `spec.path`, `prune: true`, `sourceRef` (GitRepository), `healthChecks`.

Both bundle their **own** kustomize version — pin/match it (see Currency gotcha). Prefer the controller's authenticated Git source over remote bases in `resources:`.

```bash
# CI: render, then validate. kubeval is unmaintained — use kubeconform.
kustomize build "k8s/overlays/${OVERLAY}" > all.yaml
kubeconform -strict -summary -kubernetes-version 1.29.0 all.yaml
conftest test all.yaml    # OPA policy gate
```

### Helm inflation gotcha

> **`helmCharts` requires `kustomize build --enable-helm`.** Without the flag the whole `helmCharts` section is **silently skipped** (no error), so CI can emit manifests missing entire components yet still "pass". `kubectl apply -k` CANNOT pass `--enable-helm` (`unknown flag`), making `helmCharts` effectively dead there — use `kustomize build --enable-helm | kubectl apply -f -`. It's a deliberately limited subset (no private-registry auth, no post-renderers). For anything nontrivial, `helm template` then kustomize-patch on top.

## Troubleshooting

| Error (excerpt)                              | Cause / Fix                                                                 |
| -------------------------------------------- | -------------------------------------------------------------------------- |
| `evalsymlink failure ... no such file`       | Wrong base path; paths are relative to the kustomization.yaml's own dir.   |
| `no matches for OriginalId ... ConfigMap`    | Patched resource missing in base, or name/kind mismatch.                   |
| `conflict: multiple matches`                 | Patch too broad — add metadata or use JSON 6902 for precise targeting.     |
| `base ... refers back to overlay` (cyclic)   | Bases must never reference overlays.                                        |
| `unknown flag: --enable-helm`                | Using `kubectl apply -k`; switch to `kustomize build --enable-helm`.       |

## Expert Practices: Idioms, Anti-Patterns & Gotchas

High-signal guidance for production Kustomize. Most of these failure modes are **silent** — wrong output with exit code 0 — so always diff `kustomize build` output before and after any structural change.

### Anti-Patterns (deprecated fields removed from the v1 API)

**`commonLabels` → `labels` transformer.** `commonLabels` (deprecated v5.0.0) injects every label into `spec.selector.matchLabels` in addition to `metadata.labels` and pod templates. Because a Deployment/StatefulSet/Service selector is **immutable after first apply**, adding or changing any `commonLabel` later forces a delete-and-recreate. The `labels` transformer defaults `includeSelectors: false` (safe on live resources); add `includeTemplates: true` so pod labels still propagate (Prometheus scraping, log aggregation). Reserve `includeSelectors: true` for stable identity labels set only at creation time — and prefer defining those directly in base manifests so the selector contract is explicit. The docs warn that changing selectors on live resources "could result in failures."

```yaml
labels:
  - pairs:
      app.kubernetes.io/part-of: myplatform
      environment: prod
    includeSelectors: false   # safe on live resources — does NOT touch matchLabels
    includeTemplates: true    # still reaches pod template labels
```

**`patchesStrategicMerge` / `patchesJson6902` → unified `patches`.** Both deprecated in v5.0.0. The `patches` field auto-detects the type from content (resource-shaped doc = strategic merge; list of `{op, path, value}` = JSON 6902), and its `target` supports `group/version/kind/name/namespace` plus `labelSelector` and `annotationSelector`, so one patch can hit many resources. **Migration is not behavior-neutral:** `patches` runs *after* the label transformers while `patchesJson6902` ran *before* them, so a patch that touched `/metadata/labels` can produce different output post-migration. Always diff.

**`vars` → `replacements`.** `vars` (`$(VAR)` substitution, deprecated v5.0.0) is replaced by `replacements`, a structured source/target model that propagates any field value (including hashed ConfigMap/Secret names). **Migration is NOT 1:1:** `replacements` works on field pointers and cannot do free-form mid-string concatenation like `path: $(ROOT)/cluster/$(REVISION)`. It *can* do single-segment replacement within a string via the `delimiter` + `index` options, but for true composite strings, restructure (compose in an init container/env var) before migrating.

```yaml
replacements:
  - source: {kind: ConfigMap, name: app-config, fieldPath: metadata.name}
    targets:
      - select: {kind: Deployment}
        fieldPaths:
          - spec.template.spec.volumes.[name=config].configMap.name
```

### Idioms

**`kustomize edit fix` is the canonical, idempotent migration tool.** It migrates deprecated fields in place — `bases`→`resources`, `commonLabels`→`labels`, `patchesStrategicMerge`/`patchesJson6902`→`patches`, and (experimentally, `--vars`) `vars`→`replacements`. Run it per kustomization directory; use it as a CI lint to surface remaining deprecated fields. Two things it can't guarantee semantically: the patch apply-order shift and `vars` mid-string interpolation — so wrap it in a build diff:

```bash
kustomize build . > before.yaml
kustomize edit fix
kustomize build . > after.yaml
diff before.yaml after.yaml   # confirm semantic equivalence
```

**Components apply against the accumulated resource set.** Components use `apiVersion: kustomize.config.k8s.io/v1alpha1`, `kind: Component` (alpha — the API may change without a deprecation window). Unlike a base, a Component runs its patches/generators against the resource set the *parent* has accumulated so far, enabling additive opt-in feature bundles. They must be referenced under `components:`, never `resources:`, and **can be nested** (a Component may itself reference other Components via `components:`).

**Design with Kustomize's deliberate constraints.** The maintainers commit to NOT supporting: (1) removal directives (you cannot delete a label/patch/resource from a base — restructure/fork the base, or use a JSON 6902 `op: remove` for a specific path); (2) `${VAR}` templating; (3) build-time side effects from CLI args or shell env vars (output must be fully determined by version-controlled files); (4) globs. The sanctioned pattern for env-driven output is to mutate the kustomization, commit, then build:

```bash
kustomize edit set image myapp=registry.example.com/myapp:${GIT_SHA}
kustomize build overlays/prod
```

**Namespace transformer only re-homes `default`-named RBAC subjects.** Setting top-level `namespace:` runs the namespace transformer in `DefaultSubjectsOnly` mode: it only namespaces `RoleBinding`/`ClusterRoleBinding` subjects whose `name` is literally `default`. A ServiceAccount subject with any other name gets **no namespace** — silently breaking RBAC — unless you configure a custom `NamespaceTransformer` with `setRoleBindingSubjects: allServiceAccounts`. Verify RBAC subjects explicitly after setting a namespace.

### Gotchas (silent failures)

**Strategic merge patches silently REPLACE entire list fields on CRDs.** For built-in types, strategic merge knows array merge keys from the embedded OpenAPI schema (e.g. `containers` merges on `name`). Custom Resources have no such schema, so kustomize falls back to JSON merge semantics: a patched list field **replaces the whole array** with no error — dropping every element not in the patch. Fix with either an `openapi` field carrying `x-kubernetes-patch-merge-key`/`x-kubernetes-patch-strategy`, or a JSON 6902 patch (which behaves identically for built-in and custom resources):

```yaml
patches:
  - target: {group: argoproj.io, version: v1alpha1, kind: Application, name: my-app}
    patch: |-
      - op: add
        path: /spec/sources/-
        value:
          repoURL: https://github.com/org/repo
```

**`disableNameSuffixHash: true` defeats config-driven rolling updates — and a global `true` cannot be overridden.** The content-hash suffix (`app-config-k8bgk8h4t6`) is what triggers a rollout on config change: the new name changes the pod spec, so pods are replaced. Disabling it gives a stable name but silently breaks this — config changes apply to the ConfigMap, but Deployments do not roll. Worse, the boolean follows "global true wins": setting it in top-level `generatorOptions` strips the hash from **every** generator, and a per-generator `disableNameSuffixHash: false` is **ignored**. Only ever disable per-generator, and only for resources referenced by a fixed external name; if you need a stable name *and* rolling updates, keep the hash and propagate the hashed name via `replacements`.

**`replacements` list filters like `[name=nginx]` are unanchored regex.** Since v4.5.3, `spec.template.spec.containers.[name=nginx].image` matches *any* element whose name *contains* `nginx` — `my-nginx`, `nginx-sidecar` — and all matches are targeted, silently overwriting several containers. Anchor explicitly with `[name=^nginx$]`, or use index-based paths. (This differs from a `patches` `target`'s `name`/`namespace`, which ARE auto-anchored.)

**`configMapGenerator` `behavior: merge` matches by logical name AND namespace.** An overlay generator with `behavior: merge` matches the base by pre-hash name — but if one side specifies `namespace` and the other omits it, kustomize treats them as different generators and creates a **second** ConfigMap instead of merging (no error). `merge` also only merges discrete keys; if both reference the same filename, the overlay file replaces the base file entirely. Keep `namespace` consistent (or absent) on both sides, and verify the build emits one ConfigMap, not two.

**`sortOptions` only applies to the top-level (build-target) kustomization.** `sortOptions` (`order: legacy | fifo`; v5.0.0+, replaces `--reorder`) controls output ordering — `legacy` (default) places Namespaces/ServiceAccounts/RBAC first, which is why `kubectl apply -k` usually works without explicit ordering. Instances in bases/components reached via `resources` are **ignored**, so set it in the overlay that is the actual build target (what ArgoCD/Flux points to), never in a shared base.

**Pin a standalone kustomize version.** kubectl embeds an older kustomize that does not track standalone releases (the lag has spanned major versions). Features added after the embedded version — unified `patches`, `sortOptions`, Components, newer `replacements` behaviors — may error or be silently ignored under `kubectl apply -k` while a dev's standalone v5 produces correct output. ArgoCD/Flux also bundle their own versions. Standardize on a pinned `kustomize build | kubectl apply -f -` in CI and match the GitOps controller's version. Check with `kustomize version` and `kubectl version --client -o json` (`kustomizeVersion`).

### Security

**Never use `--load-restrictor=LoadRestrictionsNone` with untrusted input.** The default `LoadRestrictionsRootOnly` (v2.0) prevents file references (`resources`, `configMapGenerator` files) from reading outside the kustomization root — a real security boundary. With it off, a kustomization you don't fully control (e.g. a compromised remote base) can use a `configMapGenerator` file reference to read arbitrary host files (credentials, TLS keys, `/etc/passwd`). It also breaks relocatability. Only use it in fully trusted, audited build environments; the legitimate alternative for cross-directory file needs is a proper base with its own `kustomization.yaml`.

**Pin remote bases to a full commit SHA or tag.** Kustomize fetches remote bases over the network at build time. `?ref=main` (or no ref, which uses default-branch HEAD) means a force-push or compromised upstream flows straight into your cluster on the next reconcile with no change to your repo. Short SHAs are unsupported — use a full fetchable SHA (strongest; tags can be force-pushed) or a versioned tag. Remote fetches also add latency and a rate-limit/availability dependency, so mirror critical bases locally. In GitOps, prefer the controller's own authenticated `GitRepository`/`OCIRepository` source.

```yaml
resources:
  - https://github.com/org/platform-base//k8s/base?ref=a3f8c2d1e4b5f6a7b8c9d0e1f2a3b4c5d6e7f8a9   # full SHA
  - https://github.com/org/platform-base//k8s/base?ref=v2.3.1                                       # or versioned tag
```

**Never commit secrets.** Use sealed-secrets / external-secrets-operator / SOPS, or `secretGenerator` with gitignored env files. Pin production images by `digest`, not mutable tags. Enforce policy at admission (OPA Gatekeeper, Kyverno).

### Currency

**Validate with `kubeconform`, not `kubeval`.** `kubeval` is unmaintained and its schema registry is stale, so it cannot validate recent Kubernetes API versions and silently passes manifests using newer/renamed fields. `kubeconform` is the maintained successor on the same JSON-schema approach, with a current registry and CRD support via `-schema-location`:

```bash
kustomize build k8s/overlays/prod | kubeconform -strict -summary -kubernetes-version 1.29.0
```

## Verification Checklist

- [ ] `kustomize build <overlay>` succeeds and output diffed against the prior render for **unintended** changes.
- [ ] No deprecated fields remain (`commonLabels`/`patchesStrategicMerge`/`patchesJson6902`/`vars`/`bases`) — `kustomize edit fix` clean.
- [ ] Labels use the `labels` transformer with `includeSelectors: false`; selectors defined explicitly in base manifests.
- [ ] Exactly one `resources:` key per file; Components under `components:` (never `resources:`).
- [ ] ConfigMap/Secret hash suffix intact where rolling updates are wanted; `merge` generators emit ONE object (consistent `namespace`).
- [ ] CRD list patches use JSON 6902 (or `openapi` merge keys), not bare strategic merge.
- [ ] Prod images pinned by digest; secrets gitignored/external; remote bases pinned to full SHA/tag.
- [ ] CI validates with `kubeconform` (+ policy gate); GitOps controller kustomize version matches CI.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…