feat(manualapprovalgate): integrate MAG as TektonConfig child component - #3762
feat(manualapprovalgate): integrate MAG as TektonConfig child component#3762pratap0007 wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3762 +/- ##
==========================================
+ Coverage 26.13% 26.39% +0.26%
==========================================
Files 465 467 +2
Lines 24930 25085 +155
==========================================
+ Hits 6516 6622 +106
- Misses 17694 17736 +42
- Partials 720 727 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Integrates the ManualApprovalGate (MAG) component into the TektonConfig reconciliation flow so TektonConfig can create/adopt/delete the MAG CR and propagate platform-data-hash changes, aligning MAG with how other Tekton components are managed.
Changes:
- Add
spec.manualApprovaltoTektonConfigSpecwith defaulting + validation wiring. - Introduce shared
manualapprovalgatehelper package to ensure/create/update/delete the MAG CR (including ownerRef andplatform-data-hashpropagation). - Add unit tests covering MAG create/delete, ownerRef migration, and platform-data-hash propagation.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/reconciler/shared/tektonconfig/tektonconfig.go | Wire MAG lifecycle into TektonConfig reconcile/finalize and propagate platform-data-hash. |
| pkg/reconciler/shared/tektonconfig/manualapprovalgate/manualapprovalgate.go | New shared helper functions to ensure/update/delete MAG CR. |
| pkg/reconciler/shared/tektonconfig/manualapprovalgate/manualapprovalgate_test.go | Unit tests for MAG helper behaviors (create/delete/migration/platform hash). |
| pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go | Generated deepcopy updates for new ManualApproval.Disabled pointer + TektonConfigSpec field. |
| pkg/apis/operator/v1alpha1/tektonconfig_validation.go | Add validation for spec.manualApproval.options. |
| pkg/apis/operator/v1alpha1/tektonconfig_types.go | Add ManualApproval field to TektonConfig spec. |
| pkg/apis/operator/v1alpha1/tektonconfig_defaults.go | Default ManualApproval to disabled on fresh installs. |
| pkg/apis/operator/v1alpha1/manualapprovalgate_types.go | Add ManualApproval.Disabled + helpers (setDefaults, IsDisabled). |
Files not reviewed (1)
- pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0b2d99e to
3f8d01b
Compare
| tektonConfigreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonconfig" | ||
| "github.com/tektoncd/operator/pkg/reconciler/common" | ||
| "github.com/tektoncd/operator/pkg/reconciler/shared/tektonconfig/chain" | ||
| "github.com/tektoncd/operator/pkg/reconciler/shared/tektonconfig/manualapprovalgate" |
There was a problem hiding this comment.
ManualApprovalGate is not registered in webhook.go's types map. This means SetDefaults and Validate are never called when users create or edit MAG CRs directly. Every component that has a standalone reconciler and is in AGENTS.md's "pattern references" table is registered there (TektonPipeline, TektonChain, TektonResult, TektonPruner, etc.). Please add MAG to the types map.
|
@pratap0007 please update docs https://github.com/tektoncd/operator/blob/main/docs/TektonConfig.md to indicate that with this PR MAG configs can now be managed with tektonconfig. Thank you. |
3f8d01b to
a41cb3f
Compare
|
@anithapriyanatarajan Thank you for the review, I've updated the PR and could you please take another look |
| magEnabled := !tc.Spec.ManualApproval.IsDisabled() | ||
| if !magEnabled { | ||
| existingMAG, err := manualapprovalgate.GetManualApprovalGate(ctx, r.operatorClientSet.OperatorV1alpha1().ManualApprovalGates(), v1alpha1.ManualApprovalGates) | ||
| if err == nil && (tc.Spec.ManualApproval.Disabled == nil || len(existingMAG.OwnerReferences) == 0) { |
There was a problem hiding this comment.
Any error other than "not found" (e.g. a transient API error, RBAC issue) is silently treated the same as "no standalone CR found" with no log line. Consider logging non-NotFound errors so real problems (e.g. missing RBAC for manualapprovalgates) aren't invisible.
| magEnabled := !tc.Spec.ManualApproval.IsDisabled() | ||
| if !magEnabled { | ||
| existingMAG, err := manualapprovalgate.GetManualApprovalGate(ctx, r.operatorClientSet.OperatorV1alpha1().ManualApprovalGates(), v1alpha1.ManualApprovalGates) | ||
| if err == nil && (tc.Spec.ManualApproval.Disabled == nil || len(existingMAG.OwnerReferences) == 0) { |
There was a problem hiding this comment.
Step 1 — Fresh upgrade (day 0) A cluster already has a standalone ManualApprovalGate CR (no owner) from before this feature existed. The TektonConfig CR is old too, so its stored spec has no manualApproval field at all → tc.Spec.ManualApproval.Disabled is nil (Go zero value, since the field never existed in that stored object).
Code says:
if tc.Spec.ManualApproval.Disabled == nil || len(existingMAG.OwnerReferences) == 0 {
magEnabled = true // adopt it
}
Disabled == nil is true → it adopts the MAG CR (sets ownerRef on it). Good, this works as intended.
Step 2 — Someone edits TektonConfig later (day 30) Say an admin changes an unrelated field (e.g. targetNamespace, or a GitOps tool just re-applies the same YAML). That triggers a normal Kubernetes Update call, which goes through the mutating webhook. The webhook runs SetDefaults(), and SetDefaults always fills in Disabled: true if it's nil. So now the stored TektonConfig spec permanently has manualApproval.disabled: true written into it — even though nobody touched that field on purpose.
Step 3 — Next reconcile (day 30, same moment) Now check the same condition again:
tc.Spec.ManualApproval.Disabled == nil → false (it's true now, not nil anymore)
len(existingMAG.OwnerReferences) == 0 → false (we already set the ownerRef back in Step 1)
Both are false, so magEnabled stays false. The reconciler thinks "user wants MAG disabled" and calls EnsureManualApprovalGateCRNotExists, which deletes the MAG CR — even though it was already adopted and working fine, and nobody explicitly asked to disable it.
The fix, simply: stop using Disabled == nil as the signal. Once a MAG CR already has the TektonConfig's ownerRef on it, that's proof adoption already happened — the code should just trust the current explicit Disabled value from then on (and never re-trigger deletion just because defaulting ran). Only use "no ownerRef" as the one-time trigger for adopting a legacy CR.
May be a fix would be
magEnabled := !tc.Spec.ManualApproval.IsDisabled()
if !magEnabled {
// If a standalone MAG CR exists with no ownerRef (pre-upgrade legacy CR),
// adopt it now. Once adopted (ownerRef set), the user's explicit Disabled
// value takes over — we never force magEnabled=true again after that.
existingMAG, err := manualapprovalgate.GetManualApprovalGate(ctx, ...)
if err == nil && len(existingMAG.OwnerReferences) == 0 {
logger.Debug("Found standalone ManualApprovalGate CR from previous version, adopting under TektonConfig")
magEnabled = true
}
}
a41cb3f to
62b8a3a
Compare
|
/retest |
1 similar comment
|
/retest |
Add ManualApproval field to TektonConfig spec so that TektonConfig manages the ManualApprovalGate CR lifecycle including ownerRef and platform-data-hash propagation for TLS profile changes. - Disabled by default on fresh installs - On upgrade, standalone MAG CRs (no ownerRef) are adopted under TektonConfig instead of being deleted - Add validation for spec.manualApproval.options - Add unit tests for create, delete, ownerRef migration, and platform-data-hash annotation sync Fixes tektoncd#3656 Signed-off-by: Shiv Verma <shverma@redhat.com> Assisted-by: Claude Opus 4.6 (via Claude Code)
62b8a3a to
4572a2c
Compare
|
/retest |
|
/approve |
|
/approve cancel |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
| // Ensure ManualApprovalGate CR | ||
| // If a standalone MAG CR exists (no ownerRef, from a previous version), | ||
| // adopt its config into TektonConfig and enable it. | ||
| if tc.Spec.ManualApproval.IsDisabled() { |
There was a problem hiding this comment.
Transient GetManualApprovalGate error silently falls through to the MAG deletion branch, potentially destroying a standalone pre-upgrade MAG CR before it has been adopted.
The upgrade scenario to trace:
- Cluster has a standalone MAG CR (no ownerRef) from a pre-integration version.
- Operator is upgraded; preUpgradeManualApprovalGate runs but the MAG API temporarily returns a 503 (or the RBAC permission for get on manualapprovalgates is slow to propagate).
GetManualApprovalGate returns a non-NotFound error → err == nil is false → adoption block does NOT return early. - Code falls through to if !tc.Spec.ManualApproval.IsDisabled() → false → else → - EnsureManualApprovalGateCRNotExists → deletes the standalone MAG CR.
The user's pre-existing MAG installation is destroyed without ever being adopted
Fix
if tc.Spec.ManualApproval.IsDisabled() {
existingMAG, err := manualapprovalgate.GetManualApprovalGate(ctx, ...)
if err != nil {
if !apierrs.IsNotFound(err) {
// Transient error — can't determine whether a standalone MAG
// exists, so don't proceed to the delete branch.
logger.Warnw("Transient error checking for standalone ManualApprovalGate CR, will retry", "error", err)
return v1alpha1.REQUEUE_EVENT_AFTER
}
// NotFound — no standalone MAG, fall through to delete branch (correct)
} else if len(existingMAG.OwnerReferences) == 0 {
// Adopt...
return v1alpha1.REQUEUE_EVENT_AFTER
}
}
There was a problem hiding this comment.
Thank you for reviewing and identifying these edge cases. I will update with the above fix.
|
@pratap0007 There is no E2E test covering the adoption scenario at all. The ideal deliverable from the author is a new sub-test in test/e2e/common/06_manualapprovalgatedeployment_test.go (or a new 06_mag_via_tektonconfig_test.go) that:
|
Changes
Add ManualApproval field to TektonConfig spec so that TektonConfig manages the ManualApprovalGate CR lifecycle including ownerRef and platform-data-hash propagation for TLS profile changes.
Fixes #3656
Assisted-by: Claude Opus 4.6 (via Claude Code)
Testing
Submitter Checklist
These are the criteria that every PR should meet, please check them off as you
review them:
make test lintbefore submitting a PRSee the contribution guide for more details.
Release Notes