Skip to content

test(e2e): reproduce --project-directory ignored on an oci:// project (#14224) - #14234

Draft
ndeloof wants to merge 2 commits into
docker:mainfrom
ndeloof:14224-project-directory-oci
Draft

ndeloof wants to merge 2 commits into
docker:mainfrom
ndeloof:14224-project-directory-oci

Conversation

@ndeloof

@ndeloof ndeloof commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Draft: adds the regression test for #14224, plus a temporary go.mod replace pointing at the compose-go fix (compose-spec/compose-go#930) so the test can actually be seen passing before that PR merges.

What this PR does, in one sentence

docker compose -f oci://... --project-directory DIR must resolve a relative volume path against DIR, not against the local copy compose downloaded the artifact into.

Context

Reported in #14224: an OCI artifact whose service declares a relative bind mount ends up with that mount resolved under ~/.cache/docker-compose/<digest>/... instead of the directory the user explicitly passed via --project-directory. Root cause is in compose-go (see the issue comment) — LoadConfigFiles can't tell an explicit working dir from a defaulted one once it reaches the loader as a plain string, so a remote resource loader (git, oci) overrides it the same way it would a default.

What this PR brings

  • TestOciRemoteProjectDirectory (pkg/e2e/remote_oci_test.go): publishes a project with a relative volume, runs up on the oci:// artifact with an explicit --project-directory elsewhere, and asserts the bind mount resolves there.
  • BindMountSource (pkg/e2e/checks.go): a new, reusable check pinning a service's bind mount source to an exact expected path.
  • A temporary go.mod/go.sum commit replacing compose-go with fix: an explicit working dir must survive a remote resource loader compose-spec/compose-go#930's branch, purely so this test is green in this draft. To be squashed away once that PR merges and this repo's compose-go pin bumps normally — not meant to land as-is.

Depends on compose-spec/compose-go#930.

🤖 Generated with Claude Code

TestOciRemoteProjectDirectory publishes a project whose only service
mounts a relative volume, then runs `up` on the oci:// artifact with an
explicit --project-directory pointing elsewhere. The relative volume
must resolve against that directory.

It currently fails against the pinned compose-go: LoadConfigFiles
defaults the working dir to the downloaded artifact's own cache
directory whenever a remote resource loader is involved, silently
overriding the explicit --project-directory the same way it would a
mere default -- docker#14224. On Docker Desktop this surfaces
as a hard failure (the cache directory isn't a shared mount); on Linux
it silently mounts the wrong directory, matching the original report.

New BindMountSource check (pkg/e2e/checks.go) pins a service's bind
mount source to an exact expected path, for tests that need to verify
which working directory a relative volume path resolved against.

Needs the compose-go fix (github.com/ndeloof/compose-go@a626c70,
branch 14224-working-dir) to pass -- not yet reflected in go.mod here.
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
…o the test

Points compose-go at ndeloof/compose-go@a626c70 (branch
14224-working-dir, PR pending) so TestOciRemoteProjectDirectory has
something to pass against. This commit exists only to let CI/reviewers
see the new test go green with the fix applied -- to drop once the
compose-go PR merges and this repo's go.mod bumps to the released
pseudo-version normally.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

The regression test and BindMountSource check are well-constructed. The go.mod replace directive is correctly flagged in the PR description as a temporary draft measure to be squashed before merging — no action needed there. One low-severity latent issue in the new check function is noted inline.

Comment thread pkg/e2e/checks.go
if len(containers) == 0 {
return errors.New("service has no container")
}
wantAbs, err := filepath.Abs(wantSource)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] filepath.Abs(wantSource) resolves relative paths against the test process CWD, not --project-directory

filepath.Abs calls os.Getwd() internally, so if a caller passes a relative wantSource it gets resolved against wherever the test binary is running — not against any --project-directory. The current call site in TestOciRemoteProjectDirectory passes filepath.Join(projectDir, "data"), which is already absolute (t.TempDir() always returns an absolute path), so that test is fine today.

However, the doc-comment frames this as a general check for "pinning down which working directory a relative volume path was resolved against", which actively invites relative-path usage. A future caller that passes "./data" would silently compare against the wrong base and the check would pass even when Compose resolves the mount under the wrong directory — undermining the exact guarantee this function is meant to provide.

A simple fix is to require callers to always provide an absolute path:

Suggested change
wantAbs, err := filepath.Abs(wantSource)
if !filepath.IsAbs(wantSource) {
return fmt.Errorf("BindMountSource: wantSource must be absolute, got %q", wantSource)
}
wantAbs := wantSource
Confidence Score
🟡 moderate 70/100

@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

2 participants