Skip to content

Commit 40dd442

Browse files
committed
fix: resolve relative paths against CWD when parentDir is empty
When agent configs are loaded from OCI/URL/bytes sources, parentDir is empty. Previously, functions like GetAbsolutePaths, makeAbsolute, and ResolveDatabasePath would produce broken relative paths via filepath.Join("", path). Now they fall back to filepath.Abs() which correctly resolves against the current working directory. Added debug logging to help diagnose path resolution issues. Fixes #1655 Assisted-By: docker-agent
1 parent ad4f99b commit 40dd442

4 files changed

Lines changed: 144 additions & 6 deletions

File tree

pkg/rag/manager.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,25 @@ func (m *Manager) readFile(path string) (string, error) {
574574
return string(data), nil
575575
}
576576

577-
// GetAbsolutePaths converts doc paths to absolute paths
577+
// GetAbsolutePaths converts doc paths to absolute paths relative to basePath.
578+
// If basePath is empty (e.g. for OCI/URL sources), relative paths are resolved
579+
// against the current working directory.
578580
func GetAbsolutePaths(basePath string, docPaths []string) []string {
579581
var absPaths []string
580582
for _, p := range docPaths {
581583
if filepath.IsAbs(p) {
582584
absPaths = append(absPaths, p)
585+
continue
586+
}
587+
if basePath == "" {
588+
slog.Debug("Resolving relative path with empty basePath, using working directory", "path", p)
589+
abs, err := filepath.Abs(p)
590+
if err != nil {
591+
slog.Warn("Failed to resolve absolute path, using as-is", "path", p, "error", err)
592+
absPaths = append(absPaths, p)
593+
} else {
594+
absPaths = append(absPaths, abs)
595+
}
583596
} else {
584597
absPaths = append(absPaths, filepath.Join(basePath, p))
585598
}

pkg/rag/manager_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package rag
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestGetAbsolutePaths_WithBasePath(t *testing.T) {
13+
result := GetAbsolutePaths("/base", []string{"relative/file.go", "/absolute/file.go"})
14+
assert.Equal(t, []string{"/base/relative/file.go", "/absolute/file.go"}, result)
15+
}
16+
17+
func TestGetAbsolutePaths_EmptyBasePath(t *testing.T) {
18+
// When basePath is empty (OCI/URL sources), relative paths should be
19+
// resolved against the current working directory instead of producing
20+
// broken paths like "relative/file.go".
21+
cwd, err := os.Getwd()
22+
require.NoError(t, err)
23+
24+
result := GetAbsolutePaths("", []string{"relative/file.go", "/absolute/file.go"})
25+
26+
assert.Equal(t, filepath.Join(cwd, "relative", "file.go"), result[0])
27+
assert.Equal(t, "/absolute/file.go", result[1])
28+
}
29+
30+
func TestGetAbsolutePaths_NilInput(t *testing.T) {
31+
result := GetAbsolutePaths("/base", nil)
32+
assert.Nil(t, result)
33+
}

pkg/rag/strategy/helpers.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ func ResolveDatabasePath(dbCfg latest.RAGDatabaseConfig, parentDir, defaultName
6060

6161
// If it's a relative file path, make it absolute
6262
if !filepath.IsAbs(dbStr) {
63+
if parentDir == "" {
64+
slog.Debug("Resolving relative database path with empty parentDir, using working directory", "path", dbStr)
65+
abs, err := filepath.Abs(dbStr)
66+
if err != nil {
67+
return "", fmt.Errorf("failed to resolve absolute path for %q: %w", dbStr, err)
68+
}
69+
return abs, nil
70+
}
6371
return filepath.Join(parentDir, dbStr), nil
6472
}
6573

@@ -165,12 +173,23 @@ func GetParamPtr[T any](params map[string]any, key string) *T {
165173
}
166174
}
167175

168-
// makeAbsolute makes a path absolute relative to parentDir
169-
func makeAbsolute(path, parentDir string) string {
170-
if filepath.IsAbs(path) {
171-
return path
176+
// makeAbsolute makes a path absolute relative to parentDir.
177+
// If parentDir is empty (e.g. for OCI/URL sources), the path is resolved
178+
// against the current working directory.
179+
func makeAbsolute(p, parentDir string) string {
180+
if filepath.IsAbs(p) {
181+
return p
182+
}
183+
if parentDir == "" {
184+
slog.Debug("Resolving relative path with empty parentDir, using working directory", "path", p)
185+
abs, err := filepath.Abs(p)
186+
if err != nil {
187+
slog.Warn("Failed to resolve absolute path, using as-is", "path", p, "error", err)
188+
return p
189+
}
190+
return abs
172191
}
173-
return filepath.Join(parentDir, path)
192+
return filepath.Join(parentDir, p)
174193
}
175194

176195
// EmitEvent sends an event to the events channel using non-blocking send

pkg/rag/strategy/helpers_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package strategy
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
11+
"github.com/docker/docker-agent/pkg/config/latest"
12+
)
13+
14+
// newDBConfig creates a RAGDatabaseConfig for testing via YAML unmarshaling.
15+
func newDBConfig(t *testing.T, value string) latest.RAGDatabaseConfig {
16+
t.Helper()
17+
var cfg latest.RAGDatabaseConfig
18+
err := cfg.UnmarshalYAML(func(v any) error {
19+
p, ok := v.(*string)
20+
if !ok {
21+
return nil
22+
}
23+
*p = value
24+
return nil
25+
})
26+
require.NoError(t, err)
27+
return cfg
28+
}
29+
30+
func TestMakeAbsolute_WithParentDir(t *testing.T) {
31+
assert.Equal(t, "/parent/relative.go", makeAbsolute("relative.go", "/parent"))
32+
assert.Equal(t, "/absolute/file.go", makeAbsolute("/absolute/file.go", "/parent"))
33+
}
34+
35+
func TestMakeAbsolute_EmptyParentDir(t *testing.T) {
36+
cwd, err := os.Getwd()
37+
require.NoError(t, err)
38+
39+
result := makeAbsolute("relative.go", "")
40+
assert.Equal(t, filepath.Join(cwd, "relative.go"), result)
41+
}
42+
43+
func TestResolveDatabasePath_EmptyParentDir(t *testing.T) {
44+
cwd, err := os.Getwd()
45+
require.NoError(t, err)
46+
47+
result, err := ResolveDatabasePath(newDBConfig(t, "./my.db"), "", "default")
48+
require.NoError(t, err)
49+
assert.Equal(t, filepath.Join(cwd, "my.db"), result)
50+
}
51+
52+
func TestResolveDatabasePath_AbsolutePathIgnoresParentDir(t *testing.T) {
53+
result, err := ResolveDatabasePath(newDBConfig(t, "/absolute/my.db"), "/parent", "default")
54+
require.NoError(t, err)
55+
assert.Equal(t, "/absolute/my.db", result)
56+
}
57+
58+
func TestResolveDatabasePath_RelativeWithParentDir(t *testing.T) {
59+
result, err := ResolveDatabasePath(newDBConfig(t, "./my.db"), "/parent", "default")
60+
require.NoError(t, err)
61+
assert.Equal(t, "/parent/my.db", result)
62+
}
63+
64+
func TestMergeDocPaths_EmptyParentDir(t *testing.T) {
65+
cwd, err := os.Getwd()
66+
require.NoError(t, err)
67+
68+
result := MergeDocPaths([]string{"shared.go"}, []string{"extra.go"}, "")
69+
assert.Equal(t, []string{
70+
filepath.Join(cwd, "shared.go"),
71+
filepath.Join(cwd, "extra.go"),
72+
}, result)
73+
}

0 commit comments

Comments
 (0)