Skip to content

fix(k8s): support merge/json patch types in k8s_patch_resource (CRDs reject strategic merge)#62

Open
braghettos wants to merge 1 commit into
kagent-dev:mainfrom
braghettos:fix/k8s-patch-resource-crd-merge
Open

fix(k8s): support merge/json patch types in k8s_patch_resource (CRDs reject strategic merge)#62
braghettos wants to merge 1 commit into
kagent-dev:mainfrom
braghettos:fix/k8s-patch-resource-crd-merge

Conversation

@braghettos

@braghettos braghettos commented Jun 17, 2026

Copy link
Copy Markdown

Problem

k8s_patch_resource builds kubectl patch <type> <name> -p <patch> -n <ns> with no --type, so kubectl defaults to a strategic merge patch. Strategic merge is only implemented for built-in Kubernetes types — every CustomResource (CRD) rejects it:

error: application/strategic-merge-patch+json is not supported by
<group>/<version>, Kind=<Kind>: the body of the request was in an unknown
format - accepted media types include: application/json-patch+json,
application/merge-patch+json, application/apply-patch+yaml

So the tool currently cannot patch any custom resource — the agent only sees exit status 1. We hit this driving an install by patching a CRD-backed config resource; the patch failed identically every time with no actionable error surfaced to the model.

Notably, the sibling k8s_patch_status handler (added in #50) already passes --type=merge for exactly this reason — handlePatchResource just never got the same treatment.

Fix

Add an optional patch_type parameter (strategic | merge | json) and pass it through as --type:

  • Default stays strategic — built-in resource patching is unchanged (the emitted --type=strategic is kubectl's existing default).
  • Callers patching a CRD set patch_type: merge (RFC 7386) or json (RFC 6902).
  • Invalid values are rejected before any command runs.

The tool description and patch_type description both call out that CRDs require merge/json, so the model picks correctly.

Tests

go build ./... and go test ./pkg/k8s/ pass. Added cases:

  • merge patch against a CustomResource (asserts --type=merge)
  • invalid patch_type rejected with no command executed
  • updated existing strategic cases to expect the explicit --type=strategic

🤖 Generated with Claude Code

k8s_patch_resource always invoked `kubectl patch -p <patch>` with no
`--type`, so kubectl defaulted to a strategic merge patch. Strategic
merge is only implemented for built-in Kubernetes types — every
CustomResource (CRD) rejects it:

  error: application/strategic-merge-patch+json is not supported by
  <group>/<version>, Kind=<Kind>: the body of the request was in an
  unknown format - accepted media types include:
  application/json-patch+json, application/merge-patch+json,
  application/apply-patch+yaml

This made the tool unable to patch any custom resource. Add an optional
`patch_type` parameter (strategic|merge|json) and pass it through as
`--type`. Default stays "strategic" so built-in patching is unchanged;
callers patching a CRD set "merge" (or "json"). This mirrors the
sibling k8s_patch_status handler, which already uses --type=merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: braghettos <braghettos@users.noreply.github.com>
@braghettos braghettos force-pushed the fix/k8s-patch-resource-crd-merge branch from ea009cb to fe2c45b Compare June 17, 2026 21:22
braghettos added a commit to braghettos/krateo-installer that referenced this pull request Jun 17, 2026
…merge patch

The installer-agent prompt instructed editing the Installer CR with
k8s_patch_resource. kagent's k8s_patch_resource emits a strategic-merge
patch (no --type), which the apiserver rejects for every CustomResource:

  error: application/strategic-merge-patch+json is not supported by
  composition.krateo.io/v0-2-105, Kind=Installer ...

So the documented agent-driven install could never work through the
agent — it only ever worked via helm-apply or operator kubectl. Rewrite
the prompt (eng + ita) to the CRD-safe mechanism: k8s_get_resource_yaml
-> set field(s) -> k8s_apply_manifest of the COMPLETE manifest (apply
performs a merge the CRD accepts; full spec re-applied so no field is
dropped). Soften the conceptual "patch" verbs to "set"/"apply".

Bump krateo-installer-agent chart 0.1.8 -> 0.1.9 and re-pin in the
umbrella. Upstream root-cause fix tracked in kagent-dev/tools#62
(adds patch_type=merge); revert to a merge patch once that ships.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
braghettos added a commit to braghettos/krateo-installer that referenced this pull request Jun 17, 2026
…merge patch (#70)

The installer-agent prompt instructed editing the Installer CR with
k8s_patch_resource. kagent's k8s_patch_resource emits a strategic-merge
patch (no --type), which the apiserver rejects for every CustomResource:

  error: application/strategic-merge-patch+json is not supported by
  composition.krateo.io/v0-2-105, Kind=Installer ...

So the documented agent-driven install could never work through the
agent — it only ever worked via helm-apply or operator kubectl. Rewrite
the prompt (eng + ita) to the CRD-safe mechanism: k8s_get_resource_yaml
-> set field(s) -> k8s_apply_manifest of the COMPLETE manifest (apply
performs a merge the CRD accepts; full spec re-applied so no field is
dropped). Soften the conceptual "patch" verbs to "set"/"apply".

Bump krateo-installer-agent chart 0.1.8 -> 0.1.9 and re-pin in the
umbrella. Upstream root-cause fix tracked in kagent-dev/tools#62
(adds patch_type=merge); revert to a merge patch once that ships.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
braghettos added a commit to braghettos/krateo-installer that referenced this pull request Jun 18, 2026
…strap default (#77)

The installer-agent's CR edit (get→edit→apply) replaced the Installer CR spec
with only {features, installDefinitions, ociRepo}, dropping bootstrap, vertexAI,
exposure, componentValues, components, hitlApproval, namespaces, registryAuth,
secrets. With bootstrap gone the chart fell back to its default (coreProvider.
enabled=true) → composition-mode render + chart-inspector RBAC gen rendered
self-bootstrap.yaml → helm ownership 500s → Installer CR stuck Ready=False,
Pass A never rendered the requested features. Two fixes:

1. installer-agent prompt (eng+ita): CR edit is now read → modify-in-place →
   apply → VERIFY-and-self-heal. Keep the full doc as baseline, change only the
   target field, and after apply re-read and restore from baseline if any spec
   field vanished (apply prunes absent fields; the tool can't merge-patch since
   kagent-dev/tools#62 is unmerged). Bump krateo-installer-agent 0.1.9 → 0.1.10.

2. Defense-in-depth: flip bootstrap.coreProvider.enabled default true → false
   (values.yaml + values.schema.json). It is the sole bootstrap-vs-composition
   mode switch; a composition re-render whose CR lost its bootstrap key now
   stays in composition mode instead of wedging. The real one-shot bootstrap
   install opts in explicitly (--set bootstrap.coreProvider.enabled=true);
   INSTALL-WORKFLOW.md updated.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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