fix(oci): honor --insecure-registry when up re-loads the model

`docker compose -f oci://<insecure-registry>/... up` failed against a
plain-HTTP registry unless --yes was passed:

    failed to pull OCI resource "localhost:5000/test:interpolated":
    Head "https://localhost:5000/v2/test/manifests/interpolated":
    http: server gave HTTP response to HTTPS client

`up` loads the project twice. The first load goes through ToProject,
which built its OCI options from --insecure-registry correctly. Without
--yes, checksForRemoteStack then calls promptForInterpolatedVariables,
which re-loads the project through ToModel to list the interpolation
variables. That second load builds its own resource loaders via
remoteLoaders, and those passed an empty api.OCIOptions{}, dropping the
flag. Since the OCI loader always performs a network resolve, the
re-load spoke HTTPS to a plain-HTTP registry and failed before the
prompt could be shown.

The two construction sites had drifted apart, so rather than patching
the second one, both now share ProjectOptions.ociOptions(). `config`
and `viz` use the same ToModel path and are fixed as well.

Covered by an e2e case in TestPublish, which already runs an insecure
registry and an oci:// round-trip: it publishes a fixture carrying an
interpolation variable so the prompt fires, then runs `up` without
--yes and declines, asserting the re-load does not fail with
"server gave HTTP response to HTTPS client".

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Domantas Petrauskas <[email protected]>
This commit is contained in:
Domantas Petrauskas
2026-07-21 16:24:34 +02:00
committed by Guillaume Lours
co-authored by Claude Opus 4.8
parent 358efafdf5
commit 5534be0a28
3 changed files with 39 additions and 4 deletions
+13 -4
View File
@@ -348,9 +348,7 @@ func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, b
Compatibility: o.Compatibility,
ProjectOptionsFns: po,
LoadListeners: []api.LoadListener{metricsListener},
OCI: api.OCIOptions{
InsecureRegistries: o.insecureRegistries,
},
OCI: o.ociOptions(),
}
project, err := backend.LoadProject(ctx, loadOpts)
@@ -369,10 +367,21 @@ func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceL
return nil
}
git := remote.NewGitRemoteLoader(dockerCli, o.Offline)
oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline, api.OCIOptions{})
oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline, o.ociOptions())
return []loader.ResourceLoader{git, oci}
}
// ociOptions builds the OCI loader configuration from the project options.
// Both the primary project load and the loaders returned by remoteLoaders
// must use this so the --insecure-registry flag is honored on every path
// that pulls an OCI compose artifact (e.g. the interpolation-variable
// re-load that `up` runs via ToModel). See docker/compose#13824.
func (o *ProjectOptions) ociOptions() api.OCIOptions {
return api.OCIOptions{
InsecureRegistries: o.insecureRegistries,
}
}
func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
opts := []cli.ProjectOptionsFn{
cli.WithWorkingDirectory(o.ProjectDir),
@@ -0,0 +1,5 @@
services:
app:
image: alpine
environment:
GREETING: ${GREETING:-hello}
+21
View File
@@ -205,4 +205,25 @@ networks:
default:
name: oci_default
`)
// `up` loads the project twice: once through ToProject, then again through
// ToModel (checksForRemoteStack -> promptForInterpolatedVariables) to list
// the interpolation variables when --yes is not passed. That second load
// builds its own OCI loader, which used to drop --insecure-registry and so
// talked HTTPS to a plain-HTTP registry. See docker/compose#13824.
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/publish/oci/compose-interpolated.yaml",
"-p", projectName, "publish", "--with-env", "--yes", "--insecure-registry", registry+"/test:interpolated")
res.Assert(t, icmd.Expected{ExitCode: 0})
// Declining the prompt keeps the test hermetic: nothing is created, but the
// re-load has already happened by then, which is what we want to cover.
cmd = c.NewDockerComposeCmd(t, "--project-name=oci-reload",
"--insecure-registry", registry,
"-f", fmt.Sprintf("oci://%s/test:interpolated", registry), "up")
cmd.Stdin = strings.NewReader("n\n")
res = icmd.RunCmd(cmd, func(cmd *icmd.Cmd) {
cmd.Env = append(cmd.Env, "XDG_CACHE_HOME="+t.TempDir())
})
assert.Assert(t, !strings.Contains(res.Combined(), "server gave HTTP response to HTTPS client"), res.Combined())
res.Assert(t, icmd.Expected{ExitCode: 1, Err: "operation cancelled by user"})
}