Skip to content

Commit

Permalink
chore: Print error if external paths are empty or in parent
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Dec 10, 2024
1 parent 3739b0b commit fc6fcaa
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
13 changes: 12 additions & 1 deletion internal/chezmoi/sourcestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -1356,9 +1356,20 @@ func (s *SourceState) addExternal(sourceAbsPath, parentAbsPath AbsPath) error {
s.mutex.Lock()
defer s.mutex.Unlock()
for path, external := range externals {
if strings.HasPrefix(path, "/") || filepath.IsAbs(path) {
switch {
case path == "":
return fmt.Errorf("%s: empty path", sourceAbsPath)
case strings.HasPrefix(path, "/") || filepath.IsAbs(path):
return fmt.Errorf("%s: %s: path is not relative", sourceAbsPath, path)
}
switch relPath, err := filepath.Rel(".", path); {
case err != nil:
return fmt.Errorf("%s: %s: %w", sourceAbsPath, path, err)
case relPath == ".":
return fmt.Errorf("%s: %s: empty relative path", sourceAbsPath, path)
case relPath == "..", strings.HasPrefix(relPath, "../"):
return fmt.Errorf("%s: %s: relative path in parent", sourceAbsPath, path)
}
targetRelPath := parentTargetSourceRelPath.JoinString(path)
external.sourceAbsPath = sourceAbsPath
s.externals[targetRelPath] = append(s.externals[targetRelPath], &external)
Expand Down
104 changes: 104 additions & 0 deletions internal/chezmoi/sourcestate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,110 @@ func TestTemplateOptionsParseDirectives(t *testing.T) {
}
}

func TestSourceStateExternalErrors(t *testing.T) {
for _, tc := range []struct {
name string
shareDir map[string]any
expectedErr string
}{
{
name: "missing_type",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`["dir"]`,
` url = "http://example.com/"`,
),
},
expectedErr: "dir: missing external type",
},
{
name: "empty_rel_path",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`[""]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: empty path",
},
{
name: "relative_empty_rel_path",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`["."]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: .: empty relative path",
},
{
name: "parent_root_rel_path",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`[".."]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: ..: relative path in parent",
},
{
name: "relative_parent_root_rel_path",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`["./.."]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: ./..: relative path in parent",
},
{
name: "relative_empty",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`["a/../b/.."]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: a/../b/..: empty relative path",
},
{
name: "relative_parent",
shareDir: map[string]any{
".chezmoiexternal.toml": chezmoitest.JoinLines(
`["a/../b/../.."]`,
` type = "file"`,
` url = "http://example.com/"`,
),
},
expectedErr: "/home/user/.local/share/chezmoi/.chezmoiexternal.toml: a/../b/../..: relative path in parent",
},
} {
t.Run(tc.name, func(t *testing.T) {
chezmoitest.WithTestFS(t, map[string]any{
"/home/user/.local/share/chezmoi": tc.shareDir,
}, func(fileSystem vfs.FS) {
ctx := context.Background()
system := NewRealSystem(fileSystem)
s := NewSourceState(
WithBaseSystem(system),
WithCacheDir(NewAbsPath("/home/user/.cache/chezmoi")),
WithDestDir(NewAbsPath("/home/user")),
WithSourceDir(NewAbsPath("/home/user/.local/share/chezmoi")),
WithSystem(system),
)
err := s.Read(ctx, nil)
assert.Error(t, err)
assert.Equal(t, err.Error(), tc.expectedErr)
})
})
}
}

// applyAll updates targetDirAbsPath in targetSystem to match s.
func (s *SourceState) applyAll(
targetSystem, destSystem System,
Expand Down

0 comments on commit fc6fcaa

Please sign in to comment.