Skip to content

SmartJoin incorrectly treats relative paths containing special variable names as special paths #3021

Description

@znnnnnnn-wil

Description

SmartJoin incorrectly treats ordinary relative paths containing special variable names such as .ROOT_DIR as absolute/special paths, causing them to bypass the base-directory join.

What did you do?

I called SmartJoin with a normal relative path whose directory name happens to contain one of the special variable names:

SmartJoin(base, filepath.Join("project.ROOT_DIR", "file.txt"))

A minimal regression test demonstrating the issue is:

func TestSmartJoinRelativePathContainingSpecialVariableName(t *testing.T) {
	base := filepath.Join("base", "dir")
	path := filepath.Join("project.ROOT_DIR", "file.txt")

	got := SmartJoin(base, path)
	want := filepath.Join(base, path)

	if got != want {
		t.Fatalf("SmartJoin() = %q, want %q", got, want)
	}
}

It can be run with:

go test ./internal/filepathext -run TestSmartJoinRelativePathContainingSpecialVariableName -count=1

What did you expect to happen?

The path should be treated as a normal relative path and joined with base.

In other words:

SmartJoin(base, filepath.Join("project.ROOT_DIR", "file.txt"))

should return the same result as:

filepath.Join(base, "project.ROOT_DIR", "file.txt")

What happened instead?

SmartJoin returns the input relative path unchanged instead of joining it with base.

The same behavior also appears to affect relative path components containing:

  • .ROOT_DIR
  • .TASKFILE_DIR
  • .USER_WORKING_DIR

From looking at the implementation, this may be caused by isSpecialDir using strings.Contains to detect special variables. As a result, an ordinary directory name containing one of these strings can be matched even when the variable is not actually part of a {{ ... }} template expression.

This can cause normal relative paths to bypass the base-directory join and potentially be resolved relative to an unintended location, including paths used for task directories, includes, dotenv files, or fingerprint-related logic.

Version

main (385e5ad)

Operating system

Windows amd64, Go 1.26.5

Experiments Enabled

None

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: execChanges related to the execution of commands.

    Type

    Fields

    No fields configured for bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions