From cc4899b19bc78eda362f8c2ec43b0949cdc8634e Mon Sep 17 00:00:00 2001 From: ruizkinio Date: Sun, 19 Jul 2026 00:12:38 +0200 Subject: [PATCH] fix(deploy): preserve resolved image digest --- internal/command/deploy/deploy.go | 4 ++-- internal/command/deploy/deploy_test.go | 25 +++++++++++++++++++++--- internal/command/deploy/machines_test.go | 9 ++++++--- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/internal/command/deploy/deploy.go b/internal/command/deploy/deploy.go index 837a9ebfcc..702b04f009 100644 --- a/internal/command/deploy/deploy.go +++ b/internal/command/deploy/deploy.go @@ -604,7 +604,7 @@ func deployToMachines( status.AppName = app.Name status.OrgSlug = app.Organization.Slug - status.Image = img.Tag + status.Image = img.String() status.Strategy = cfg.DeployStrategy() if flag.GetString(ctx, "strategy") != "" { status.Strategy = flag.GetString(ctx, "strategy") @@ -650,7 +650,7 @@ func deployToMachines( args := MachineDeploymentArgs{ App: app, - DeploymentImage: img.Tag, + DeploymentImage: img.String(), Strategy: flag.GetString(ctx, "strategy"), EnvFromFlags: flag.GetStringArray(ctx, "env"), PrimaryRegionFlag: status.PrimaryRegion, diff --git a/internal/command/deploy/deploy_test.go b/internal/command/deploy/deploy_test.go index 36317a70fd..9fef70d335 100644 --- a/internal/command/deploy/deploy_test.go +++ b/internal/command/deploy/deploy_test.go @@ -28,6 +28,11 @@ var testdata embed.FS func TestCommand_Execute(t *testing.T) { makeTerminalLoggerQuiet(t) + const ( + imageTag = "test-registry.fly.io/my-image:deployment-00000000000000000000000000" + imageDigest = "sha256:f107dbfaa732063b31ee94aa728c4f5648a672259fd62bfaa245f9b7a53b5479" + imageReference = imageTag + "@" + imageDigest + ) // Set FLY_ACCESS_TOKEN to simulate CI/CD environment t.Setenv("FLY_ACCESS_TOKEN", "test-token") @@ -43,7 +48,7 @@ func TestCommand_Execute(t *testing.T) { cmd := New() cmd.SetOut(&buf) cmd.SetErr(&buf) - cmd.SetArgs([]string{"--image", "test-registry.fly.io/my-image:deployment-00000000000000000000000000"}) + cmd.SetArgs([]string{"--image", imageTag}) ctx := context.Background() ctx = iostreams.NewContext(ctx, &iostreams.IOStreams{Out: &buf, ErrOut: &buf}) @@ -62,9 +67,10 @@ func TestCommand_Execute(t *testing.T) { Name: "test-basic", Organization: fly.Organization{Slug: "my-org"}, }) - if err := server.CreateImage(context.Background(), "test-basic", "test-registry.fly.io/my-image:deployment-00000000000000000000000000", &fly.Image{ + if err := server.CreateImage(context.Background(), "test-basic", imageTag, &fly.Image{ ID: "IMAGE1", - Ref: "test-registry.fly.io/my-image:deployment-00000000000000000000000000", + Ref: imageTag, + Digest: imageDigest, CompressedSize: "1000", }); err != nil { t.Fatal(err) @@ -77,6 +83,19 @@ func TestCommand_Execute(t *testing.T) { if err := cmd.ExecuteContext(ctx); err != nil { t.Fatal(err) } + + machines, err := server.FlapsClient("test-basic").ListActive(ctx, "test-basic") + if err != nil { + t.Fatal(err) + } + if len(machines) == 0 { + t.Fatal("expected at least one active app machine") + } + for _, machine := range machines { + if got := machine.Config.Image; got != imageReference { + t.Fatalf("expected immutable deployment image %q, got %q", imageReference, got) + } + } } // copyFS writes the contents of a file system to a destination path on disk. diff --git a/internal/command/deploy/machines_test.go b/internal/command/deploy/machines_test.go index c1874478c0..dc7eb1f33f 100644 --- a/internal/command/deploy/machines_test.go +++ b/internal/command/deploy/machines_test.go @@ -191,6 +191,8 @@ func testMachineDeploymentForSetMachines(t *testing.T, strategy string, flyLaunc // Test any LaunchMachineInput field that must not be set on a machine // used to run release command. func Test_resolveUpdatedMachineConfig_ReleaseCommand(t *testing.T) { + const immutableImage = "super/balloon@sha256:f107dbfaa732063b31ee94aa728c4f5648a672259fd62bfaa245f9b7a53b5479" + md, err := stabMachineDeployment(&appconfig.Config{ AppName: "my-cool-app", Env: map[string]string{ @@ -228,6 +230,7 @@ func Test_resolveUpdatedMachineConfig_ReleaseCommand(t *testing.T) { }}, }) require.NoError(t, err) + md.img = immutableImage md.volumes = map[string][]fly.Volume{ "data": {{ID: "vol_12345"}}, @@ -244,7 +247,7 @@ func Test_resolveUpdatedMachineConfig_ReleaseCommand(t *testing.T) { "OTHER": "value", "FLY_PROCESS_GROUP": "app", }, - Image: "super/balloon", + Image: immutableImage, Metadata: map[string]string{ "fly_platform_version": "v2", "fly_process_group": "app", @@ -294,7 +297,7 @@ func Test_resolveUpdatedMachineConfig_ReleaseCommand(t *testing.T) { "RELEASE_COMMAND": "1", "FLY_PROCESS_GROUP": "fly_app_release_command", }, - Image: "super/balloon", + Image: immutableImage, Metadata: map[string]string{ "fly_platform_version": "v2", "fly_process_group": "fly_app_release_command", @@ -343,7 +346,7 @@ func Test_resolveUpdatedMachineConfig_ReleaseCommand(t *testing.T) { "RELEASE_COMMAND": "1", "FLY_PROCESS_GROUP": "fly_app_release_command", }, - Image: "super/balloon", + Image: immutableImage, Metadata: map[string]string{ "fly_platform_version": "v2", "fly_process_group": "fly_app_release_command",