Skip to content

fix: housekeeping pre-Sprint 3 (Kyverno + ESO + schema)#43

Merged
JackMaarek merged 3 commits into
mainfrom
feat/housekeeping-2-5a
Apr 27, 2026
Merged

fix: housekeeping pre-Sprint 3 (Kyverno + ESO + schema)#43
JackMaarek merged 3 commits into
mainfrom
feat/housekeeping-2-5a

Conversation

@JackMaarek

Copy link
Copy Markdown
Collaborator

Summary

Sprint 2.5A — three CRITICAL non-blocking findings from PR_41_REVIEW.md folded into a housekeeping pass before Sprint 3.

Commits

  • 0a7fbcd fix(kyverno): migrate image-registry policy to foreach
  • f17cf3e fix(eso): migrate ExternalSecret manifests to v1
  • ea06b7e feat(chart-schema): require awsSecretPath when ESO opt-in

Findings addressed

  • F4 (PR_41_REVIEW.md): Kyverno NotEquals + value: "*" was semantically broken (literal-string comparison; every Pod denied, masked by Audit). Migrated to the canonical Kyverno multi-registry allowlist using foreach over containers / initContainers / ephemeralContainers with pattern.image using the | OR operator. REQUIRED before flipping Audit -> Enforce. Preserves Sprint 2C C4 mixed-registry support (ghcr.io/PodYourLife/* main + public.ecr.aws/aws-cli/* initContainer).
  • F6: ESO v1beta1 -> v1 across both ExternalSecret manifests in lockstep (Grafana baseline + ml-batch-job chart template). No spec field changes — v1 is a stable rename per ESO 0.10 release notes.
  • Schema (Topic G): JSON Schema draft-07 if/then at the imagePullSecret level — when enabled: true, awsSecretPath becomes required and must satisfy minLength: 1. Closes the silent-fail path where ESO would receive key: "".

Pattern choice deviation (announced & approved)

The prompt's literal anyPattern shape was reconsidered after Context7 surfaced (a) the Kyverno Operators table documenting | as the logical-OR pattern operator, and (b) the canonical "Enforce trusted registry for Pod images" example using foreach. The anyPattern shape would have denied mixed-registry pods (Sprint 2C C4 regression). The foreach + pipe-OR form is both Kyverno-canonical and preserves C4 behavior.

Out of scope (deferred)

  • F5 (NVIDIA chart polish: failOnInitError: true etc.)
  • F8 (PriorityClass preemptionPolicy explicit)
  • Refactor: config-driven version auto-mapping (platform-bot debt)
  • kubernetes/secrets/local/secret-store.yaml still on external-secrets.io/v1beta1 — out of scope by kind (ClusterSecretStore, not ExternalSecret) and lives in the local-Kind dev dir; flagged for a Sprint 3 tidy

Validation

  • helm lint kubernetes/helm/ml-batch-job/ -f kubernetes/helm/values/quanvnn-dev.yaml → passes (positive).
  • helm template ... | grep -B1 'kind: ExternalSecret' → renders apiVersion: external-secrets.io/v1.
  • helm lint with enabled: true + awsSecretPath: "" → fails with at '/imagePullSecret/awsSecretPath': minLength: got 0, want 1 (negative).
  • YAML safe-load on Kyverno + Grafana ESO manifests; python3 -m json.tool on the schema.

Test plan

  • CI green (validate-pr.yml: no env values, no stray placeholders, no secrets, file size, YAML, sync-wave).
  • Manual review: confirm foreach shape is acceptable vs. literal prompt's anyPattern.
  • Confirm ESO v1 is served on the running ESO 0.10.7 install (no consumer breakage).

Reference

Resolves PR_41_REVIEW.md F4 (MEDIUM, pre-existing).

The previous form was stacked NotEquals conditions with
value: "<registry>/*" — per Kyverno Condition schema, NotEquals is a
fixed-value comparison and the "*" was treated as a literal asterisk
character. Every container image trivially mismatched the literal,
every condition fired, and validate would have denied every Pod —
masked only by validationFailureAction: Audit.

Migrate to the canonical Kyverno multi-registry allowlist pattern:
foreach over each container list (containers, initContainers,
ephemeralContainers) with `pattern.image` using the `|` OR operator.

Evidence (Context7 lookup against /websites/kyverno_io):
- "Operators" table on the validate doc page documents `|` as the
  logical-OR pattern operator.
- "Enforce trusted registry for Pod images" example on the same page
  uses foreach over container lists with `pattern.image: <glob>`.

Note: an earlier draft used anyPattern with one entry per registry.
Reconsidered — that shape forces all containers + initContainers in
a pod to come from a single registry, which would deny mixed-registry
pods (e.g. main from ghcr.io/PodYourLife + initContainer from
public.ecr.aws/aws-cli — Sprint 2C C4 commit 0ec75cf). foreach +
pipe-OR preserves C4's mixed-registry support while flipping the
broken NotEquals semantics into a correct allowlist.

This is REQUIRED before flipping validationFailureAction Audit ->
Enforce in any environment. Audit mode is preserved here.
Resolves PR_41_REVIEW.md F6 (LOW).

ESO 0.10.x ships external-secrets.io/v1 as GA, with v1beta1 still
served for backward compatibility but flagged as legacy in upstream
docs. Migrate both manifests in lockstep to maintain consistency:

- kubernetes/manifests/secrets/grafana-admin-externalsecret.yaml
- kubernetes/helm/ml-batch-job/templates/external-secret.yaml

No spec field changes — v1 is a stable rename of v1beta1 with no
breaking schema changes per ESO 0.10 release notes.

Out-of-scope follow-up flagged: kubernetes/secrets/local/secret-store.yaml
also pins external-secrets.io/v1beta1 but on a ClusterSecretStore (not
an ExternalSecret); local-Kind dev-only file. Worth a Sprint 3 tidy
to keep the API surface consistent.
Resolves PR_41_REVIEW.md schema finding (Topic G, MEDIUM follow-up).

Today the chart schema marks awsSecretPath as optional. With
imagePullSecret.enabled=true and an empty awsSecretPath, helm
template renders an ExternalSecret with key: "" and ESO silently
fails at sync time with an opaque "secret not found" error.

Add a JSON Schema draft-07 conditional (if/then) at the
imagePullSecret level: when enabled=true, awsSecretPath becomes
required and must satisfy minLength: 1.

Existing consumers (quanvnn-dev.yaml) already comply — they set
awsSecretPath: "platform/ghcr-pull-token". No breaking change.

Verified locally:
- helm lint with quanvnn-dev.yaml passes (positive).
- helm lint with enabled=true + awsSecretPath="" fails with
  "at '/imagePullSecret/awsSecretPath': minLength: got 0, want 1"
  (negative).
@JackMaarek
JackMaarek merged commit a6b6430 into main Apr 27, 2026
6 checks passed
@JackMaarek
JackMaarek deleted the feat/housekeeping-2-5a branch April 27, 2026 16:10
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