From 25dd69476edcc4b1dc40744bdcd8e43e57f08ef6 Mon Sep 17 00:00:00 2001 From: Eris Hoxha Date: Fri, 7 Aug 2026 14:42:53 +0200 Subject: [PATCH] OCPCRT-598: Fix CRD/annotation phase desync for release signing The signer reads release phases from istag annotations via GetTagPhase() but syncAudit() never calls populatePayloadPhases(), so PayloadPhases is nil and it always falls back to the annotation. When the ReleasePayload CRD advances to Accepted faster than the sync loop can propagate phase transitions to the annotation, the annotation stays Pending permanently and the signer skips the release. This has been affecting OKD releases since PR #792 migrated phase routing to CRD-derived phases without updating the signer path. Fix: 1. Call populatePayloadPhases() in syncAudit() so the signer reads phases from CRDs instead of annotations. 2. Add annotation reconciliation in syncAccepted() to bring stale annotations forward through the proper phase sequence when the CRD is ahead. 3. Handle Accepted payloads in syncPending() for the within-sync race where the payload advances while a tag is being processed. --- cmd/release-controller/audit.go | 1 + cmd/release-controller/sync.go | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/cmd/release-controller/audit.go b/cmd/release-controller/audit.go index d127393cb..7cb707c4e 100644 --- a/cmd/release-controller/audit.go +++ b/cmd/release-controller/audit.go @@ -41,6 +41,7 @@ func (c *Controller) syncAudit(key queueKey) error { if err != nil || release == nil { return err } + c.populatePayloadPhases(release) klog.V(4).Infof("Audit %s", release.Config.Name) c.auditTracker.Sync(release) diff --git a/cmd/release-controller/sync.go b/cmd/release-controller/sync.go index f1d91c63b..ce7a1fcd3 100644 --- a/cmd/release-controller/sync.go +++ b/cmd/release-controller/sync.go @@ -390,6 +390,13 @@ func (c *Controller) syncPending(release *releasecontroller.Release, pendingTags return err } c.precacheChangelog(release, tag) + case releasecontroller.ReleasePhaseAccepted: + if err := c.markReleaseReady(release, nil, tag.Name); err != nil { + return err + } + if err := c.markReleaseAccepted(release, nil, tag.Name); err != nil { + return err + } case releasecontroller.ReleasePhaseFailed: if err := c.transitionReleasePhaseFailure(release, []string{releasecontroller.ReleasePhasePending}, releasecontroller.ReleasePhaseFailed, reasonAndMessage("CreateReleaseFailed", "Could not create the release image"), tag.Name); err != nil { return err @@ -445,6 +452,13 @@ func (c *Controller) syncPending(release *releasecontroller.Release, pendingTags return err } c.precacheChangelog(release, tag) + case releasecontroller.ReleasePhaseAccepted: + if err := c.markReleaseReady(release, nil, tag.Name); err != nil { + return err + } + if err := c.markReleaseAccepted(release, nil, tag.Name); err != nil { + return err + } case releasecontroller.ReleasePhaseFailed: if err := c.transitionReleasePhaseFailure(release, []string{releasecontroller.ReleasePhasePending}, releasecontroller.ReleasePhaseFailed, reasonAndMessage("CreateReleaseFailed", "Could not create the release image"), tag.Name); err != nil { return err @@ -520,6 +534,31 @@ func (c *Controller) syncAccepted(release *releasecontroller.Release) error { klog.Infof("release=%s accepted=%v", release.Config.Name, releasecontroller.TagNames(acceptedTags)) } + for _, tag := range acceptedTags { + annotationPhase := tag.Annotations[releasecontroller.ReleaseAnnotationPhase] + if annotationPhase == releasecontroller.ReleasePhaseAccepted { + continue + } + klog.V(2).Infof("Reconciling phase for %s: annotation=%q, payload=Accepted", tag.Name, annotationPhase) + switch annotationPhase { + case releasecontroller.ReleasePhasePending, "": + if err := c.markReleaseReady(release, nil, tag.Name); err != nil { + return err + } + if err := c.markReleaseAccepted(release, nil, tag.Name); err != nil { + return err + } + case releasecontroller.ReleasePhaseReady: + if err := c.markReleaseAccepted(release, nil, tag.Name); err != nil { + return err + } + default: + klog.Warningf("Tag %s has payload Accepted but annotation phase %q; skipping reconciliation", tag.Name, annotationPhase) + continue + } + return nil + } + if len(release.Config.Publish) == 0 || len(acceptedTags) == 0 { return nil }