fix(oci): honor --insecure-registry when up re-loads the model - #13894
Conversation
|
@glours Is this PR good to merge? I guess since there is a workaround for the issue then it is not the most urgent, but it seems to me that it would still be good to merge a fix. |
glours
left a comment
There was a problem hiding this comment.
Nice catch, and the fix itself (consolidating both sites into ociOptions()) is exactly right.
One request before merge: I'd prefer covering this with an e2e test rather than the current unit tests, which require exposing ociRemoteLoader.InsecureRegistries() as a public method just for test introspection, I'd rather not widen the production API for that.
TestPublish in pkg/e2e/publish_test.go already spins up an insecure registry:3 and does an oci:// round-trip — perfect base to build on. The gap is that it loads back via config (the ToProject path, which always worked), so it never hits checksForRemoteStack → ToModel where this bug lives.
To guard the real regression, add a case that goes through the re-load:
- publish a fixture with an interpolation variable (e.g. GREETING: ${GREETING:-hello}) so the prompt fires;
- run up without --yes against the oci:// ref with --insecure-registry, feeding n to stay hermetic;
- assert it reaches operation cancelled by user and not server gave HTTP response to HTTPS client.
cmd := c.NewDockerComposeCmd(t, "--project-name=oci-reload",
"--insecure-registry", registry,
"-f", fmt.Sprintf("oci://%s/test:test", 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.Assert(t, icmd.Expected{ExitCode: 1, Err: "operation cancelled by user"})make build-and-e2e-compose runs it locally. With this in place you can drop the getter and compose_remote_loaders_test.go, keeping the PR to the real fix + one focused e2e. Thanks!
`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 <noreply@anthropic.com>
Signed-off-by: Domantas Petrauskas <dom.petrauskas@gmail.com>
f25807e to
ee2c2cf
Compare
|
@glours Thank you for a detailed response, pushed the fixes as requested, PR is ready for review again. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Problem
docker compose -f oci://<insecure-registry>/... upfails against a plain-HTTP /loopback registry unless
--yesis passed, even though the initial projectload succeeds.
Root cause
uploads the project once viaToProject→LoadProject, which correctlyforwards
--insecure-registry.runUpthen callschecksForRemoteStack; without--yesthat path re-loads the model viaToModelto prompt for interpolationvariables.
ToModelbuilds its OCI loader throughProjectOptions.remoteLoaders,which constructed an empty
api.OCIOptions{}— dropping the insecure-registrylist. The resolver then speaks HTTPS to a plain-HTTP registry and fails before the
prompt is even shown.
oci.Getalways performs a network resolve (even with the artifact disk-cached),so the second load genuinely re-contacts the registry with the wrong config.
configandvizshare theToModelpath and hit the same failure.Note this is distinct from the Docker Desktop proxy loopback bypass (#13824): the
shared transport already handles proxy bypass for consuming; this PR fixes the
separate plain-HTTP flag being dropped on the re-load path.
Fix
The two OCI-options construction sites had drifted. Consolidate them into
ProjectOptions.ociOptions()so every path that pulls an OCI artifact uses thesame configuration.
Testing
Covered by an e2e case appended to
TestPublish, which already spins up aninsecure
registry:3and does anoci://round-trip. The existing assertionsload back via
config(theToProjectpath, which always worked), so the newcase drives the re-load instead: publish a fixture carrying an interpolation
variable (
GREETING: ${GREETING:-hello}) so the prompt fires, then runupwithout
--yesand decline, which keeps it hermetic —checksForRemoteStackisthe first statement in
runUp, so nothing is created.Verified in both directions locally with a real registry:
TestPublishpasses;remoteLoadersreverted toapi.OCIOptions{}, it fails on exactly theregression:
The "stack is stored in" line confirms the first load succeeded and only the
ToModelre-load went out over HTTPS.Per review feedback, the earlier unit tests and the
ociRemoteLoader.InsecureRegistries()getter they needed are dropped —
pkg/remote/oci.gois unchanged frommain.🤖 Generated with Claude Code