diff --git a/pkg/install/install.go b/pkg/install/install.go index 4a5cacc..495103a 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -77,9 +77,8 @@ func Install(logger logrus.FieldLogger) error { return err } - // Place the new binaries if the directory is writeable. - if err := fileutil.IsDirWriteable(c.CredentialProviderTargetDir); err != nil { - return fmt.Errorf("directory is not writeable: %w", err) + if err := ensureDirExists(c.CredentialProviderTargetDir); err != nil { + return fmt.Errorf("failed to ensure target directory exists and is writable: %w", err) } // Iterate through each binary we might want to install. @@ -112,6 +111,21 @@ func Install(logger logrus.FieldLogger) error { return nil } +func ensureDirExists(dir string) error { + // Create the directory if it does not already exist. + //nolint:revive // 755 is easy to understand file permissions. + if err := os.MkdirAll(dir, 0o755); err != nil { + return fmt.Errorf("failed to create target directory: %w", err) + } + + // Ensure the directory is writeable. + if err := fileutil.IsDirWriteable(dir); err != nil { + return fmt.Errorf("directory is not writeable: %w", err) + } + + return nil +} + // copyFileAndPermissions copies file permission. func copyFileAndPermissions(src, dst string, logger logrus.FieldLogger) error { // If the source and destination are the same, we can simply return. diff --git a/pkg/install/install_test.go b/pkg/install/install_test.go index 6841278..290302b 100644 --- a/pkg/install/install_test.go +++ b/pkg/install/install_test.go @@ -81,6 +81,31 @@ func TestSuccessfulCopy(t *testing.T) { } } +func TestSuccessfulCopyNonExistentTarget(t *testing.T) { + tmpDir := t.TempDir() + targetDir := filepath.Join(tmpDir, "nonexistent") + + t.Setenv(install.CredentialProviderSourceDirEnvVar, "testdata") + t.Setenv(install.CredentialProviderTargetDirEnvVar, targetDir) + + require.NoError(t, install.Install(logrus.New())) + + testFiles, err := os.ReadDir("testdata") + require.NoError(t, err) + + for _, f := range testFiles { + expectedFile := filepath.Join(targetDir, f.Name()) + assert.FileExists(t, expectedFile) + srcFile := filepath.Join("testdata", f.Name()) + srcFileStat, err := os.Stat(srcFile) + assert.NoError(t, err) + expectedFileStat, err := os.Stat(expectedFile) + assert.NoError(t, err) + assert.Equal(t, srcFileStat.Mode(), expectedFileStat.Mode()) + assertFileHashesEqual(t, srcFile, expectedFile) + } +} + func TestSuccessfulCopySkipFile(t *testing.T) { tmpDir := t.TempDir()