Skip to content

bug(api): apps.cozystack.io apiserver ignores --dry-run=server and persists the write #3971

Description

@scooby87

Summary

The apps.cozystack.io aggregated apiserver does not honour --dry-run=server: a server-side dry-run write to an Application resource is persisted instead of being simulated and discarded. A dry-run request must run admission and return the would-be result without mutating storage.

Reproduce (verified live)

  1. kubectl patch vmdisk <name> -n <tenant> --type=merge -p '{"spec":{"storageClass":"local"}}' --dry-run=server
  2. kubectl reports vmdisk ... patched (no (dry run) marker).
  3. kubectl get vmdisk <name> -n <tenant> -o jsonpath='{.spec.storageClass}' → returns local. The change was written to real storage despite --dry-run=server.

Impact

Any tooling or operator that relies on server-side dry-run against Application kinds — kubectl apply --dry-run=server, kubectl diff, admission previews — mutates the cluster instead of previewing. This is dangerous precisely for the read-only workflows dry-run exists to make safe.

Suggested direction

Thread the dryRun option through the Application registry's create/update paths so a server dry-run runs defaulting/validation and returns the result object without persisting, matching apiserver semantics.

Discovered while investigating #2985 (see also #3969).

Activity

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    area/apiIssues or PRs related to the cozystack-api aggregated API server
    on Aug 26, 2026
  2. dosubot commented on Aug 26, 2026

    @dosubot

    scooby87 This is a duplicate of #2981, which has the same root-cause analysis and suggested fix.

    Root cause: REST.Update() in rest.go receives options *metav1.UpdateOptions but discards it. At line 609 it constructs a brand-new empty UpdateOptions:

    updateErr := r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}})

    This drops DryRun, FieldManager, and FieldValidation. The sibling Create and Delete paths forward the incoming options correctly — Create at line 245 passes &client.CreateOptions{Raw: options}, and Delete at line 691 passes &client.DeleteOptions{Raw: options} [1].

    Fix — two spots, mirroring Create/Delete:

    1. Main update path (line 609):

      // before
      updateErr := r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}})
      // after
      updateErr := r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: options})
    2. Create-on-update (upsert) path (line 502):

      // before
      createdObj, err := r.Create(ctx, obj, createValidation, &metav1.CreateOptions{})
      // after
      createdObj, err := r.Create(ctx, obj, createValidation, &metav1.CreateOptions{DryRun: options.DryRun})

    This affects every apps.cozystack.io kind (Postgres, MariaDB, Kafka, VMDisk, Kubernetes, etc.), not just VMDisk [1].

    To reply, just mention @dosu.


    Share context across your team and agents. Try Dosu.

    Leave Feedback Learn about cozystack with Dosu Add Dosu to your team

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiIssues or PRs related to the cozystack-api aggregated API serverkind/bugCategorizes issue or PR as related to a bugtriage/needs-triageIndicates an issue needs triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions