diff --git a/pkg/cmd/repo_index.go b/pkg/cmd/repo_index.go index ece0ce811..095d9a4d7 100644 --- a/pkg/cmd/repo_index.go +++ b/pkg/cmd/repo_index.go @@ -101,7 +101,9 @@ func index(dir, url, mergeTo string, json bool) error { var i2 *repo.IndexFile if _, err := os.Stat(mergeTo); errors.Is(err, fs.ErrNotExist) { i2 = repo.NewIndexFile() - writeIndexFile(i2, mergeTo, json) + if err := writeIndexFile(i2, mergeTo, json); err != nil { + return fmt.Errorf("merge failed: %w", err) + } } else { i2, err = repo.LoadIndexFile(mergeTo) if err != nil { diff --git a/pkg/cmd/repo_index_test.go b/pkg/cmd/repo_index_test.go index 67984f3b7..3a31cf7a4 100644 --- a/pkg/cmd/repo_index_test.go +++ b/pkg/cmd/repo_index_test.go @@ -22,6 +22,7 @@ import ( "io" "os" "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/assert" @@ -141,3 +142,28 @@ func TestRepoIndexFileCompletion(t *testing.T) { checkFileCompletion(t, "repo index", true) checkFileCompletion(t, "repo index mydir", false) } + +func TestRepoIndexCmdMergeWriteError(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("directory permissions are not enforced on Windows") + } + if os.Geteuid() == 0 { + t.Skip("root bypasses directory permissions") + } + + dir := t.TempDir() + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", filepath.Join(dir, "compressedchart-0.1.0.tgz"))) + + // The merge target does not exist and its directory is read-only, so + // creating it must fail and the error must be reported. + roDir := filepath.Join(t.TempDir(), "ro") + require.NoError(t, os.Mkdir(roDir, 0o500)) + mergeTo := filepath.Join(roDir, "index.yaml") + + buf := bytes.NewBuffer(nil) + c := newRepoIndexCmd(buf) + require.NoError(t, c.ParseFlags([]string{"--merge", mergeTo})) + + err := c.RunE(c, []string{dir}) + require.Error(t, err, "expected an error when the missing merge target cannot be written") +}