fix(attribution): resolve the audit route from one ClusterProvider read#264
Conversation
auditRouteFor re-read the GitTarget's ClusterProvider and, when that read failed, returned the provider NAME as the audit route. Its comment claimed this "never a route that silently matches no facts" — true only for a provider that declares no spec.attribution.auditRoute. A provider that declares `shared-route` was declared under its own name instead, filing this target's streams against a partition the audit webhook never writes to: attribution silently resolves nobody, or resolves another cluster's facts if some provider happens to be NAMED like this one's route, writing a wrong author into Git. One reconcile read the same ClusterProvider three times with three different failure policies (error, guess, Unknown), which is what let the wrong one in. It is now read once, after the Validated gate that already proved it exists and admits the namespace, and handed to both consumers: - auditRouteFor is gone; the call site uses AuditRoute() on that object. A read failure returns an error and requeues, the same policy the gate already applies to the identical failure — a route is never guessed. - clusterProviderReadiness takes the provider instead of reading its own, so it is a pure function with no ctx, client, or "cannot observe" branch. That branch was unreachable anyway: a missing provider is the gate's hard denial. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughReconciliation now resolves the source ChangesClusterProvider resolution
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/controller/gittarget_source_cluster.go`:
- Around line 74-77: Update the Godoc comment immediately above
GitTargetConditionClusterProviderReady so its first words begin with the exact
exported identifier, while preserving the existing readiness semantics and
explanatory details.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 190b58c9-93cf-4802-94f9-ebc7b4974a64
📒 Files selected for processing (3)
internal/controller/gittarget_controller.gointernal/controller/gittarget_source_cluster.gointernal/controller/gittarget_source_cluster_test.go
| // EXPLICIT Ready=False downgrades the GitTarget; a provider that has not reported readiness yet | ||
| // is Unknown and does not. A MISSING provider never reaches this projection at all — that is the | ||
| // Validated gate's hard denial (GitTargetReasonClusterProviderNotFound), not a readiness axis. | ||
| GitTargetConditionClusterProviderReady = "ClusterProviderReady" |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Make the exported condition’s Godoc identifier-led.
Line 74 documents GitTargetConditionClusterProviderReady, but its comment does not begin with the identifier.
Proposed fix
- // EXPLICIT Ready=False downgrades the GitTarget; a provider that has not reported readiness yet
- // is Unknown and does not. A MISSING provider never reaches this projection at all — that is the
- // Validated gate's hard denial (GitTargetReasonClusterProviderNotFound), not a readiness axis.
+ // GitTargetConditionClusterProviderReady reports the referenced provider's readiness.
+ // Explicit Ready=False downgrades the GitTarget; missing providers are denied by Validated.
GitTargetConditionClusterProviderReady = "ClusterProviderReady"As per coding guidelines, “add godoc comments for all exported Go identifiers.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // EXPLICIT Ready=False downgrades the GitTarget; a provider that has not reported readiness yet | |
| // is Unknown and does not. A MISSING provider never reaches this projection at all — that is the | |
| // Validated gate's hard denial (GitTargetReasonClusterProviderNotFound), not a readiness axis. | |
| GitTargetConditionClusterProviderReady = "ClusterProviderReady" | |
| // GitTargetConditionClusterProviderReady reports the referenced provider's readiness. | |
| // Explicit Ready=False downgrades the GitTarget; missing providers are denied by Validated. | |
| GitTargetConditionClusterProviderReady = "ClusterProviderReady" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/controller/gittarget_source_cluster.go` around lines 74 - 77, Update
the Godoc comment immediately above GitTargetConditionClusterProviderReady so
its first words begin with the exact exported identifier, while preserving the
existing readiness semantics and explanatory details.
Source: Coding guidelines
…reated The recreate-on-deletion spec waited the shared 10s `timeout` for a recovery that only the periodic requeue can deliver: this controller runs no control-plane Secret watch, so nothing enqueues the GitTarget when its age-key Secret is deleted, and the next reconcile is one RequeueStreamSettleInterval away — also 10s. The wait therefore equalled the interval it was waiting for, and a deletion landing just after a reconcile lost by milliseconds. It failed that way on this branch's CI run and passed on a plain re-run. Wait RequeueStreamSettleInterval + timeout instead, so one full requeue plus reconcile time fits inside the window, and say in the comment what actually drives the recovery — the old one credited a "secret watch" that does not exist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bug
auditRouteForre-read the GitTarget's ClusterProvider and, when that read failed, returned the provider name as the audit route. Its comment claimed this is "never a route that silently matches no facts" — that holds only for a provider that declares nospec.attribution.auditRoute.A provider declaring
auditRoute: shared-routewas instead declared underprod-eu-1, filing that target's streams against a partition the audit webhook never writes to. Attribution then resolves nobody — or, if some other provider happens to be namedshared-route, resolves that cluster's facts and writes a wrong author into Git.It self-heals on the next reconcile, so this is not a release blocker; the safety claim in the comment was simply wrong as written.
The fix
One reconcile read the same ClusterProvider three times, with three different policies for the same failure:
authz.GitTargetAdmitted(Validated gate)auditRouteForclusterProviderReadinessThat inconsistency is what let the wrong policy in. The provider is now read once, after the Validated gate has already proved it exists and admits the namespace, and handed to both consumers:
auditRouteForis deleted. The call site usesAuditRoute()on the object that was read. A read failure returns an error and requeues — the same policy the gate 100 lines earlier already applies to the identical failure. A route is never guessed.clusterProviderReadinesstakes the provider instead of reading its own, so it becomes a pure function: noctx, no client, no "cannot observe" branch. That branch was unreachable in the real flow anyway — a missing provider is the Validated gate's hard denial, not a readiness axis. Its stale comment and the now-impossibleabsent providertest case are removed.Net: one read instead of three, one function gone, one fallback gone, one failure policy.
Deliberately unchanged
authz.GitTargetAdmitted's own read. It is the shared gate for three packages; threading its object out would ripple intowatchrule_compile.goandsource_namespace.gofor no behavioural gain — ClusterProvider is watched by this controller, so it is a cached read.watch.auditRouteForCluster's fallback. Different situation: no client there by design, andDeclareForGitTargetpopulates the map before any watch opens, so a miss means no stream exists yet.Validation
task lint,task test(coverage 77.8%, baseline held), andtask test-e2e(69 passed / 0 failed) all green.🤖 Generated with Claude Code
Summary by CodeRabbit