Skip to content

fix(registry): preserve dry-run in tap storage - #4225

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/registry-tap-write-options
Sep 14, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/registry-tap-write-options

Conversation

@IvanHunters

@IvanHunters IvanHunters commented Sep 12, 2026 •

Copy link
Copy Markdown
Collaborator

What this PR does

Tap Create and Delete bound the options parameter to _ and built their own metav1.CreateOptions and DeleteOptions for the dynamic client, so the caller's dry-run directive never reached the backing write. kubectl create --dry-run=server on a tap created the Flux OCIRepository for real, and kubectl delete tap <name> --dry-run=server removed the PackageSource and its source for real. That is the opposite of what a server-side dry-run promises, and it is reachable from the dashboard and from any client that previews a change before applying it.

The directive now reaches all five backing writes: the source create, the update taken on a repeat connect, the PackageSource delete, the delete of an unreferenced OCIRepository, and the orphan-source fallback, which had no access to the options at all and needed them threaded in.

Field manager stays as the storage sets it. Tap synthesizes the backing objects rather than storing what the caller sent, so who owns their fields is a separate question from whether the write happens, and only the second one is a correctness bug.

taps was the last write-capable storage in the aggregated apiserver still discarding its write options. #3937 covers application, tenant-secret and security-group, and excludes this one on the grounds that it uses a different client; the client is not what stood in the way, since dynamic.Interface takes the options by value, dry-run included.

Tests

The fake dynamic client's tracker ignores DryRun and persists regardless, so asserting that an object is absent after a dry-run would pass with or without the fix. The tests assert the options recorded on the backing action instead. Reverting any one of the five forwards, one at a time, turns the suite red.

Screenshots

Not a UI change.

Downstream repositories

Walked the trigger map in docs/agents/contributing.md against the diff. It touches only the write plumbing of the taps aggregated storage: no package added, renamed or removed, no values.schema.json, no version enum, no changed default, no kind or plural, no release.prefix, no renamed output Secret or Service, no hand-typed CRD, and nothing under hack/.

Release note

fix(registry): honor server-side dry-run when connecting or disconnecting a tap, which previously performed the write for real

Summary by CodeRabbit

  • Bug Fixes

    • Server-side dry-run requests for TAP connect and disconnect operations now prevent changes from being written to backing resources.
    • Dry-run settings are consistently applied when creating, updating, or deleting associated sources, including orphaned sources.
  • Tests

    • Added coverage confirming dry-run behavior across create and delete workflows, including requests without write options.

Tap Create and Delete bound the options parameter to _ and built their own
metav1.CreateOptions and DeleteOptions for the dynamic client, so the caller's
dry-run directive never reached the backing write. A --dry-run=server connect
created the Flux OCIRepository and a dry-run disconnect deleted the
PackageSource and its source for real, which is the opposite of what a
server-side dry-run promises.

Forward the directive to all five backing writes, including the orphan-source
fallback that had no access to the options at all. Field manager stays as the
storage sets it: the objects are synthesized here rather than supplied by the
caller, so who owns them is a separate question from whether the write happens.

The fake dynamic client's tracker ignores DryRun and persists regardless, so
the tests assert the options recorded on the backing action instead of the
absence of an object; reverting any one of the five turns the suite red.

Assisted-by: LLM
Signed-off-by: IvanHunters <[email protected]>
@coderabbitai

coderabbitai Bot commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 86284a42-c2c7-4d41-bd07-1cd302d3e4e3

📥 Commits

Reviewing files that changed from the base of the PR and between 37e22dc and 6d42223.

📒 Files selected for processing (2)
  • pkg/registry/core/tap/rest.go
  • pkg/registry/core/tap/rest_write_options_test.go

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The TAP REST storage now forwards caller dry-run options to backing OCIRepository and PackageSource writes. New tests cover create, update, delete, orphan deletion, and nil-option behavior.

Changes

TAP dry-run propagation

Layer / File(s) Summary
Forward dry-run options
pkg/registry/core/tap/rest.go
Create and Delete accept write options and forward their DryRun values to backing create, update, and delete operations, including orphan-source cleanup.
Validate write options
pkg/registry/core/tap/rest_write_options_test.go
Tests inspect backing actions and verify dry-run propagation for create, update, delete, orphan deletion, and nil options.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 6d422

The dry-run propagation change is covered across create, update, delete, orphan cleanup, and nil-option paths, with no remaining actionable merge risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preserving dry-run behavior in TAP registry storage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/registry-tap-write-options

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files labels Sep 12, 2026
@IvanHunters
IvanHunters marked this pull request as ready for review September 12, 2026 18:38

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Reverting any one of the five forwards does turn the suite red, and five is the whole set.

Business context: Create and Delete bound their options to _ and built fresh ones for the dynamic client, so a --dry-run=server connect created the Flux OCIRepository and a dry-run disconnect deleted the PackageSource for real.

I reverted each forward on its own, naming the expected failure before running it:

reverted predicted actual
rest.go:241 source create TestCreateForwardsDryRunToBackingSource that test, nothing else
rest.go:273 repeat-connect update TestCreateForwardsDryRunWhenSourceAlreadyExists as predicted
rest.go:326 PackageSource delete TestDeleteForwardsDryRunToBackingDeletes as predicted, line 118
rest.go:339 unreferenced OCIRepository delete same test as predicted, line 119, separate assertion
rest.go:363 orphan-source delete TestDeleteOrphanTapSourceForwardsDryRun as predicted

Two mutations past the five. deleteDryRun returning DryRunAll unconditionally reddens TestWritesWithoutOptionsDoNotSynthesiseDryRun and nothing else, so that negative control is live rather than vacuous. Dropping the nil guard from createDryRun panics TestCreateRepeatPreservesFinalizerAndRevision, which predates this PR and passes nil options, so both guards are pinned.

On the enumeration: every call in the package that reaches the dynamic client with write intent is one of those five. No patch, no apply, no DeleteCollection, and compute.go makes no client calls at all.

The field manager reasoning holds. None of the five is a server side apply, and dry-run only touches field ownership through an apply's managedFields merge. The two writes that set a field manager set a constant, and the three deletes set none.

One fix for the body rather than the code:

taps was the last write-capable storage in the aggregated apiserver still discarding its write options.

Read as present tense that is wrong. #3937 is open and unmerged, so its storages still discard on main today: pkg/registry/apps/application/rest.go:609 hands the backing HelmRelease update a fresh &metav1.UpdateOptions{} on the ordinary update path, with no Raw subtlety involved. The sentence holds only in the sense of "the last one no open change was already covering". Smaller point in the same sentence: the diff forwards DryRun alone, so "write options" claims more than it does. Propagation policy, grace period and preconditions still stop here. Leaving them is fine, since a Tap is a computed view over a different object and those fields have no honest mapping onto a PackageSource, and the title and the release note both scope to dry-run.

E2E is red on the opensearch suite and I don't attribute it here. The failing job dumps OpenSearch resources only, opensearch-test-nodes-0 and opensearch-test-bootstrap-0, while this diff touches pkg/registry/core/tap/ and cannot reach an OpenSearch StatefulSet. The same single-suite failure sits on unrelated PRs right now, and #4227 and #4230 look like its homes.

go test ./pkg/registry/... green, go vet and gofmt clean.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit bed172b into main Sep 14, 2026
44 of 46 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/registry-tap-write-options branch September 14, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants