From 7f157158d2937a781b0f14c64c40494e23363a98 Mon Sep 17 00:00:00 2001 From: Atanas Dinov Date: Wed, 13 Mar 2024 09:12:44 +0200 Subject: [PATCH 1/2] Keep custom files' permissions Signed-off-by: Atanas Dinov --- pkg/combustion/custom.go | 26 +++++++----- pkg/combustion/custom_test.go | 78 ++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/pkg/combustion/custom.go b/pkg/combustion/custom.go index 5d27124f..4ce53b64 100644 --- a/pkg/combustion/custom.go +++ b/pkg/combustion/custom.go @@ -41,43 +41,47 @@ func configureCustomFiles(ctx *image.Context) ([]string, error) { func handleCustomFiles(ctx *image.Context) error { fullFilesDir := generateComponentPath(ctx, filepath.Join(customDir, customFilesDir)) - _, err := copyCustomFiles(fullFilesDir, ctx.CombustionDir, fileio.NonExecutablePerms) + _, err := copyCustomFiles(fullFilesDir, ctx.CombustionDir) return err } func handleCustomScripts(ctx *image.Context) ([]string, error) { fullScriptsDir := generateComponentPath(ctx, filepath.Join(customDir, customScriptsDir)) - scripts, err := copyCustomFiles(fullScriptsDir, ctx.CombustionDir, fileio.ExecutablePerms) + scripts, err := copyCustomFiles(fullScriptsDir, ctx.CombustionDir) return scripts, err } -func copyCustomFiles(fromDir, combustionDir string, params os.FileMode) ([]string, error) { +func copyCustomFiles(fromDir, toDir string) ([]string, error) { if _, err := os.Stat(fromDir); os.IsNotExist(err) { return nil, nil } - dirListing, err := os.ReadDir(fromDir) + dirEntries, err := os.ReadDir(fromDir) if err != nil { return nil, fmt.Errorf("reading the custom directory at %s: %w", fromDir, err) } // If the directory exists but there's nothing in it, consider it an error case - if len(dirListing) == 0 { + if len(dirEntries) == 0 { return nil, fmt.Errorf("no files found in directory %s", fromDir) } var copiedFiles []string - for _, scriptEntry := range dirListing { - copyMe := filepath.Join(fromDir, scriptEntry.Name()) - copyTo := filepath.Join(combustionDir, scriptEntry.Name()) + for _, entry := range dirEntries { + copyMe := filepath.Join(fromDir, entry.Name()) + copyTo := filepath.Join(toDir, entry.Name()) - err = fileio.CopyFile(copyMe, copyTo, params) + info, err := entry.Info() if err != nil { - return nil, fmt.Errorf("copying script to %s: %w", copyTo, err) + return nil, fmt.Errorf("reading file info: %w", err) } - copiedFiles = append(copiedFiles, scriptEntry.Name()) + if err = fileio.CopyFile(copyMe, copyTo, info.Mode()); err != nil { + return nil, fmt.Errorf("copying file to %s: %w", copyTo, err) + } + + copiedFiles = append(copiedFiles, entry.Name()) } return copiedFiles, nil diff --git a/pkg/combustion/custom_test.go b/pkg/combustion/custom_test.go index 85346d80..e69b0219 100644 --- a/pkg/combustion/custom_test.go +++ b/pkg/combustion/custom_test.go @@ -1,14 +1,13 @@ package combustion import ( + "io/fs" "os" "path/filepath" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/suse-edge/edge-image-builder/pkg/fileio" ) func TestConfigureCustomFiles(t *testing.T) { @@ -16,23 +15,45 @@ func TestConfigureCustomFiles(t *testing.T) { ctx, teardown := setupContext(t) defer teardown() - // - scripts - fullScriptsDir := filepath.Join(ctx.ImageConfigDir, customDir, customScriptsDir) - err := os.MkdirAll(fullScriptsDir, os.ModePerm) - require.NoError(t, err) + scriptsDir := filepath.Join(ctx.ImageConfigDir, customDir, customScriptsDir) + require.NoError(t, os.MkdirAll(scriptsDir, os.ModePerm)) + + filesDir := filepath.Join(ctx.ImageConfigDir, customDir, customFilesDir) + require.NoError(t, os.MkdirAll(filesDir, os.ModePerm)) + + files := map[string]struct { + isScript bool + perms fs.FileMode + }{ + "foo.sh": { + isScript: true, + perms: 0o744, + }, + "bar.sh": { + isScript: true, + perms: 0o755, + }, + "baz": { + isScript: false, + perms: 0o744, + }, + "qux": { + isScript: false, + perms: 0o644, + }, + } - _, err = os.Create(filepath.Join(fullScriptsDir, "foo.sh")) - require.NoError(t, err) - _, err = os.Create(filepath.Join(fullScriptsDir, "bar.sh")) - require.NoError(t, err) + for filename, info := range files { + var path string - // - files - fullFilesDir := filepath.Join(ctx.ImageConfigDir, customDir, customFilesDir) - err = os.MkdirAll(fullFilesDir, os.ModePerm) - require.NoError(t, err) + if info.isScript { + path = filepath.Join(scriptsDir, filename) + } else { + path = filepath.Join(filesDir, filename) + } - _, err = os.Create(filepath.Join(fullFilesDir, "baz")) - require.NoError(t, err) + require.NoError(t, os.WriteFile(path, nil, info.perms)) + } // Test scripts, err := configureCustomFiles(ctx) @@ -41,25 +62,24 @@ func TestConfigureCustomFiles(t *testing.T) { require.NoError(t, err) // - make sure the files were added to the build directory - foundDirListing, err := os.ReadDir(ctx.CombustionDir) + dirEntries, err := os.ReadDir(ctx.CombustionDir) require.NoError(t, err) - assert.Equal(t, 3, len(foundDirListing)) + require.Len(t, dirEntries, 4) // - make sure the copied files have the right permissions - for _, entry := range foundDirListing { - fullEntryPath := filepath.Join(ctx.CombustionDir, entry.Name()) - stats, err := os.Stat(fullEntryPath) + for _, entry := range dirEntries { + file, ok := files[entry.Name()] + require.Truef(t, ok, "Unexpected file: %s", entry.Name()) + + entryPath := filepath.Join(ctx.CombustionDir, entry.Name()) + stats, err := os.Stat(entryPath) require.NoError(t, err) - if strings.HasSuffix(entry.Name(), ".sh") { - assert.Equal(t, fileio.ExecutablePerms, stats.Mode()) - } else { - assert.Equal(t, fileio.NonExecutablePerms, stats.Mode()) - } + assert.Equal(t, file.perms, stats.Mode()) } // - make sure only script entries were added to the combustion scripts list - require.Equal(t, 2, len(scripts)) + require.Len(t, scripts, 2) assert.Contains(t, scripts, "foo.sh") assert.Contains(t, scripts, "bar.sh") } @@ -83,7 +103,7 @@ func TestCopyCustomFiles_MissingFromDir(t *testing.T) { defer teardown() // Test - files, err := copyCustomFiles("missing", ctx.CombustionDir, fileio.NonExecutablePerms) + files, err := copyCustomFiles("missing", ctx.CombustionDir) // Verify assert.Nil(t, files) @@ -101,7 +121,7 @@ func TestCopyCustomFiles_EmptyFromDir(t *testing.T) { require.NoError(t, err) // Test - scripts, err := copyCustomFiles(fullScriptsDir, ctx.CombustionDir, fileio.NonExecutablePerms) + scripts, err := copyCustomFiles(fullScriptsDir, ctx.CombustionDir) // Verify require.Error(t, err) From 142912be184c337b47a053dc14fc3da399457ce6 Mon Sep 17 00:00:00 2001 From: Atanas Dinov Date: Wed, 13 Mar 2024 15:50:54 +0200 Subject: [PATCH 2/2] Update release notes Signed-off-by: Atanas Dinov --- RELEASE_NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 51320731..b8ee8781 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -30,6 +30,7 @@ * [#242](https://github.com/suse-edge/edge-image-builder/issues/242) - Empty rpms directory triggers resolution * [#283](https://github.com/suse-edge/edge-image-builder/issues/283) - Definition file argument to EIB is incorrect * [#245](https://github.com/suse-edge/edge-image-builder/issues/245) - Pass additional arguments to Helm resolver +* [#272](https://github.com/suse-edge/edge-image-builder/issues/272) - Custom files should keep their permissions ---