Skip to content

fix: downgrade gate flags rc-to-release finalization as downgrade#160

Merged
joshua-temple merged 1 commit into
mainfrom
fix/downgrade-gate-cascade-scenario
Jun 14, 2026
Merged

fix: downgrade gate flags rc-to-release finalization as downgrade#160
joshua-temple merged 1 commit into
mainfrom
fix/downgrade-gate-cascade-scenario

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

Trunk e2e went red after the downgrade gate (#156) landed. TestMultiStepScenarios/Four_Environment_Cascade_Promotion step 18 ("Cascade promote release to prod with breaking flag", expected to SUCCEED) failed:

preflight failed: downgrade blocked on env "release": current version v1.0.0 is newer than incoming v1.0.0-rc.0; pass --allow-downgrade to permit

Root cause: product false positive (not a scenario artifact)

The scenario uses environments: [dev, qa, uat, prod]. Step 18 is cascade, target: prod; the harness defaults the cascade source to the first env, so it runs dev-to-prod from dev holding v1.0.0-rc.0. Across the publish boundary the cascade materializes a virtual release promotion whose Version is the stripped semver v1.0.0 (stripRCSuffix), and a prod promotion also at v1.0.0. The release env already holds the previously published v1.0.0, so the version that actually LANDS is equal, not older.

checkDowngrade compared every target env against result.SourceVersion (the single source env's raw version, v1.0.0-rc.0) instead of each promotion's Version (what lands on that env). An rc sorts below its release under semver precedence, so the rc-to-release finalization was wrongly flagged as a downgrade. This is the normal cascade flow, so the gate, not the scenario, is wrong.

Fix

internal/promote/preflight.go checkDowngrade: compare each env's current version against promo.Version (the version that lands on that env), falling back to result.SourceVersion only for version-less promotions.

Real downgrades stay blocked: a genuine downgrade carries the older version in promo.Version for every affected env (default-mode and the release-marker/publish paths all populate it).

Verification

  • New unit tests in internal/promote/downgrade_test.go: publish-boundary rc-to-release is not a downgrade; a real downgrade via promo.Version still blocks; rc progressing forward into a prerelease env passes. Existing downgrade tests stay green.
  • go build ./... && go test ./...: 1289 passed. golangci-lint run ./... and e2e go vet/golangci-lint: clean.
  • --- PASS: TestMultiStepScenarios/Four_Environment_Cascade_Promotion (83.23s) locally (Docker).

…sion

The downgrade gate compared every promotion's target env against the
source env's raw version (result.SourceVersion). In a cascade across the
publish boundary the version that lands differs per env: prerelease envs
receive the rc (v1.0.0-rc.0) while release and prod receive the stripped
semver (v1.0.0). An rc sorts below its release under semver precedence, so
finalizing v1.0.0-rc.0 onto a release env already holding v1.0.0 was wrongly
flagged as a downgrade and blocked.

Compare each env against promo.Version (the version that actually lands on
that env), falling back to SourceVersion only for version-less promotions.
Real downgrades stay blocked because a genuine downgrade carries the older
version in promo.Version for every affected env.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple joshua-temple merged commit 2d71c61 into main Jun 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant