Skip to content

Commit 7f8814f

Browse files
mikesir87claude
authored andcommitted
Fix invalid path error when using OCI artifacts on Windows
When using OCI artifacts (e.g., `docker compose -f oci://dockersamples/welcome-to-docker up`) on Windows, users encountered the following error: CreateFile C:\Users\username\oci:\dockersamples\.env: The filename, directory name, or volume label syntax is incorrect. This issue was introduced between v5.0.0 and v5.0.1, specifically by commit 6c04392 which fixed error handling in setEnvWithDotEnv. The bug existed in v5.0.0 but was silently ignored due to improper error handling. Root Cause: ----------- The setEnvWithDotEnv function creates ProjectOptions without registering remote loaders. Without remote loaders, the compose-go library doesn't recognize OCI paths as remote resources. It falls through to filepath.Abs() which treats the OCI reference as a relative path. On Windows, filepath.Abs("oci://dockersamples/...") produces an invalid path like: C:\Users\username\oci:\dockersamples Windows rejects this path because colons are only valid after drive letters. Solution: --------- Modified setEnvWithDotEnv to detect remote config paths and skip environment loading for them. Instead of hardcoding string checks, the fix uses the actual remote loaders' Accept() method to determine if a config path is remote. This is more maintainable and consistent with how the compose-go library identifies remote resources. The function now: - Accepts a dockerCli parameter to access remote loaders - Uses opts.remoteLoaders(dockerCli) to get loader instances - Checks if any loader accepts the config path using loader.Accept() - Skips .env loading for remote configs (happens later when loaders are initialized) - Allows normal processing for local compose files Testing: -------- - Added tests for OCI artifacts, Git remotes, and local paths - Verified fix works on Windows ARM64 - All existing tests pass Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Michael Irwin <mikesir87@gmail.com>
1 parent af0029a commit 7f8814f

2 files changed

Lines changed: 92 additions & 2 deletions

File tree

cmd/compose/compose.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ func RootCommand(dockerCli command.Cli, backendOptions *BackendOptions) *cobra.C
477477
logrus.SetLevel(logrus.TraceLevel)
478478
}
479479

480-
err := setEnvWithDotEnv(opts)
480+
err := setEnvWithDotEnv(opts, dockerCli)
481481
if err != nil {
482482
return err
483483
}
@@ -677,7 +677,21 @@ func stdinfo(dockerCli command.Cli) io.Writer {
677677
return dockerCli.Err()
678678
}
679679

680-
func setEnvWithDotEnv(opts ProjectOptions) error {
680+
func setEnvWithDotEnv(opts ProjectOptions, dockerCli command.Cli) error {
681+
// Check if we're using a remote config (OCI or Git)
682+
// If so, skip env loading as remote loaders haven't been initialized yet
683+
// and trying to process the path would fail
684+
remoteLoaders := opts.remoteLoaders(dockerCli)
685+
for _, path := range opts.ConfigPaths {
686+
for _, loader := range remoteLoaders {
687+
if loader.Accept(path) {
688+
// Remote config - skip env loading for now
689+
// It will be loaded later when the project is fully initialized
690+
return nil
691+
}
692+
}
693+
}
694+
681695
options, err := cli.NewProjectOptions(opts.ConfigPaths,
682696
cli.WithWorkingDirectory(opts.ProjectDir),
683697
cli.WithOsEnv,

cmd/compose/compose_oci_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"testing"
21+
22+
"go.uber.org/mock/gomock"
23+
"gotest.tools/v3/assert"
24+
25+
"github.com/docker/compose/v5/pkg/mocks"
26+
)
27+
28+
func TestSetEnvWithDotEnv_WithOCIArtifact(t *testing.T) {
29+
// Test that setEnvWithDotEnv doesn't fail when using OCI artifacts
30+
ctrl := gomock.NewController(t)
31+
defer ctrl.Finish()
32+
cli := mocks.NewMockCli(ctrl)
33+
34+
opts := ProjectOptions{
35+
ConfigPaths: []string{"oci://docker.io/dockersamples/welcome-to-docker"},
36+
ProjectDir: "",
37+
EnvFiles: []string{},
38+
}
39+
40+
err := setEnvWithDotEnv(opts, cli)
41+
assert.NilError(t, err, "setEnvWithDotEnv should not fail with OCI artifact path")
42+
}
43+
44+
func TestSetEnvWithDotEnv_WithGitRemote(t *testing.T) {
45+
// Test that setEnvWithDotEnv doesn't fail when using Git remotes
46+
ctrl := gomock.NewController(t)
47+
defer ctrl.Finish()
48+
cli := mocks.NewMockCli(ctrl)
49+
50+
opts := ProjectOptions{
51+
ConfigPaths: []string{"https://github.com/docker/compose.git"},
52+
ProjectDir: "",
53+
EnvFiles: []string{},
54+
}
55+
56+
err := setEnvWithDotEnv(opts, cli)
57+
assert.NilError(t, err, "setEnvWithDotEnv should not fail with Git remote path")
58+
}
59+
60+
func TestSetEnvWithDotEnv_WithLocalPath(t *testing.T) {
61+
// Test that setEnvWithDotEnv still works with local paths
62+
// This will fail if the file doesn't exist, but it should not panic
63+
// or produce invalid paths
64+
ctrl := gomock.NewController(t)
65+
defer ctrl.Finish()
66+
cli := mocks.NewMockCli(ctrl)
67+
68+
opts := ProjectOptions{
69+
ConfigPaths: []string{"compose.yaml"},
70+
ProjectDir: "",
71+
EnvFiles: []string{},
72+
}
73+
74+
// This may error if files don't exist, but should not panic
75+
_ = setEnvWithDotEnv(opts, cli)
76+
}

0 commit comments

Comments
 (0)