Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set permission when pulling image #366

Merged
merged 1 commit into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/vdemeester/k8s-pkg-credentialprovider v1.22.4
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d
k8s.io/apimachinery v0.23.5
k8s.io/client-go v0.23.0 // indirect
k8s.io/klog/v2 v2.60.1
Expand Down Expand Up @@ -65,7 +66,6 @@ require (
golang.org/x/mod v0.5.0 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
Expand Down
25 changes: 6 additions & 19 deletions pkg/imgpkg/image/dir_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,24 @@ func (i *DirImage) extractTarEntry(header *tar.Header, input io.Reader) error {
path := filepath.Join(i.dirPath, header.Name)
mode := header.FileInfo().Mode()

// copy user permissions to group and other
userPermission := int64(mode & 0700)
permMode := os.FileMode(userPermission | userPermission>>3 | userPermission>>6)

err := os.MkdirAll(filepath.Dir(path), 0700)
if err != nil {
return err
}

switch header.Typeflag {
case tar.TypeDir:
err := os.MkdirAll(path, mode)
err := os.MkdirAll(path, permMode)
if err != nil {
return err
}

case tar.TypeReg, tar.TypeRegA:
file, err := os.Create(path)
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, permMode)
if err != nil {
return err
}
Expand Down Expand Up @@ -168,27 +172,10 @@ func (i *DirImage) extractTarEntry(header *tar.Header, input io.Reader) error {
}
}

// must be done after chown
err = lchmod(header, path, mode)
if err != nil {
return err
}

// must be done after everything
return lchtimes(header, path)
}

func lchmod(header *tar.Header, path string, mode os.FileMode) error {
if header.Typeflag == tar.TypeLink {
if fi, err := os.Lstat(header.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
return os.Chmod(path, mode)
}
} else if header.Typeflag != tar.TypeSymlink {
return os.Chmod(path, mode)
}
return nil
}

func lchtimes(header *tar.Header, path string) error {
aTime := header.AccessTime
mTime := header.ModTime
Expand Down
157 changes: 157 additions & 0 deletions test/e2e/pull_test_unix_only_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

//go:build !windows

package e2e

import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/carvel-imgpkg/test/helpers"
"golang.org/x/sys/unix"
)

func TestPull(t *testing.T) {
logger := &helpers.Logger{}

env := helpers.BuildEnv(t)
imgpkg := helpers.Imgpkg{T: t, L: *logger, ImgpkgPath: env.ImgpkgPath}
defer env.Cleanup()

t.Run("Image - copies the User Permission to group and other", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test as this is a known issue: https://github.com/vmware-tanzu/carvel-imgpkg/issues/270")
}

folder := env.Assets.CreateTempFolder("simple-image")
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "all-on-user-only"), "some text", 0755)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "read-on-user-only"), "some text", 0455)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "read-write-on-user-only"), "some text", 0655)

out := imgpkg.Run([]string{"push", "--tty", "-i", env.Image, "-f", folder})
imgDigest := fmt.Sprintf("@%s", helpers.ExtractDigest(t, out))

pullDir := env.Assets.CreateTempFolder("pull-dir-simple-image")
imageRef := fmt.Sprintf("%s%s", env.Image, imgDigest)

oldMask := unix.Umask(0)
defer unix.Umask(oldMask)

imgpkg.Run([]string{"pull", "-i", imageRef, "-o", pullDir})

info, err := os.Stat(filepath.Join(pullDir, "all-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0700).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0070).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0007).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0400).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0040).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0004).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-write-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0600).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0060).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0006).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
})

t.Run("Image - copies the User Permission to group and other but skips execution because umask is set to 0111", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test as this is a known issue: https://github.com/vmware-tanzu/carvel-imgpkg/issues/270")
}

folder := env.Assets.CreateTempFolder("simple-image")
innerFolder := filepath.Join(folder, "some-folder")
env.Assets.AddFolder(innerFolder, 0755)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(innerFolder, "read-on-user-only"), "some text", 0455)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "all-on-user-only"), "some text", 0755)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "read-on-user-only"), "some text", 0455)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(folder, "read-write-on-user-only"), "some text", 0655)

out := imgpkg.Run([]string{"push", "--tty", "-i", env.Image, "-f", folder})
imgDigest := fmt.Sprintf("@%s", helpers.ExtractDigest(t, out))

pullDir := env.Assets.CreateTempFolder("pull-dir-simple-image")
imageRef := fmt.Sprintf("%s%s", env.Image, imgDigest)

oldMask := unix.Umask(0011)
defer unix.Umask(oldMask)

imgpkg.Run([]string{"pull", "-i", imageRef, "-o", pullDir})

logger.Section("check permissions inside a subfolder", func() {
info, err := os.Stat(filepath.Join(pullDir, "some-folder"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0700).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0060).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0006).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "some-folder", "read-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0400).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0040).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0004).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
})

info, err := os.Stat(filepath.Join(pullDir, "all-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0700).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0060).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0006).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0400).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0040).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0004).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-write-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0600).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0060).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0006).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
})

t.Run("Bundle - copies the User Permission to group and other", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test as this is a known issue: https://github.com/vmware-tanzu/carvel-imgpkg/issues/270")
}

bundleDir := env.BundleFactory.CreateBundleDir(helpers.BundleYAML, helpers.ImagesYAML)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(bundleDir, "all-on-user-only"), "some text", 0755)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(bundleDir, "read-on-user-only"), "some text", 0455)
env.Assets.AddFileToFolderWithPermissions(filepath.Join(bundleDir, "read-write-on-user-only"), "some text", 0655)

out := imgpkg.Run([]string{"push", "--tty", "-b", env.Image, "-f", bundleDir})
imgDigest := fmt.Sprintf("@%s", helpers.ExtractDigest(t, out))

pullDir := env.Assets.CreateTempFolder("pull-dir-simple-image")
imageRef := fmt.Sprintf("%s%s", env.Image, imgDigest)

oldMask := unix.Umask(0)
defer unix.Umask(oldMask)

imgpkg.Run([]string{"pull", "-b", imageRef, "-o", pullDir})

info, err := os.Stat(filepath.Join(pullDir, "all-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0700).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0070).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0007).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0400).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0040).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0004).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
info, err = os.Stat(filepath.Join(pullDir, "read-write-on-user-only"))
require.NoError(t, err)
assert.Equal(t, os.FileMode(0600).String(), (info.Mode() & 0700).String(), "user permission doesnt match")
assert.Equal(t, os.FileMode(0060).String(), (info.Mode() & 0070).String(), "group permission doesnt match")
assert.Equal(t, os.FileMode(0006).String(), (info.Mode() & 0007).String(), "other permission doesnt match")
})
}
41 changes: 0 additions & 41 deletions test/e2e/push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ package e2e

import (
"fmt"
"io/fs"
"os"
"path/filepath"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/carvel-imgpkg/test/helpers"
)

Expand Down Expand Up @@ -41,39 +36,3 @@ images:
imgpkg.Run([]string{"push", "-b", env.Image, "-f", bundleDir})
})
}

func TestPushFilesPermissions(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping test as this is a known issue: https://github.com/vmware-tanzu/carvel-imgpkg/issues/270")
}

env := helpers.BuildEnv(t)
logger := helpers.Logger{}
imgpkg := helpers.Imgpkg{T: t, L: helpers.Logger{}, ImgpkgPath: env.ImgpkgPath}
defer env.Cleanup()

// We need this chmod, because in the github action this file permission is converted into
// u+rw even if in the this repository the permission is correct
require.NoError(t, os.Chmod(filepath.Join(".", "assets", "bundle_file_permissions", "read_only_config.yml"), 0400))

logger.Section("Push bundle with different permissions files", func() {
imgpkg.Run([]string{"push", "-f", "./assets/bundle_file_permissions", "-b", env.Image})
})
bundleDir := env.Assets.CreateTempFolder("bundle-location")

logger.Section("Pull bundle", func() {
imgpkg.Run([]string{"pull", "-b", env.Image, "-o", bundleDir})
})

logger.Section("Check files permissions did not change", func() {
info, err := os.Stat(filepath.Join(bundleDir, "exec_file.sh"))
require.NoError(t, err)
assert.Equal(t, fs.FileMode(0700).String(), info.Mode().String(), "have -rwx------ permissions")
info, err = os.Stat(filepath.Join(bundleDir, "read_only_config.yml"))
require.NoError(t, err)
assert.Equal(t, fs.FileMode(0400).String(), info.Mode().String(), "have -r-------- permissions")
info, err = os.Stat(filepath.Join(bundleDir, "read_write_config.yml"))
require.NoError(t, err)
assert.Equal(t, fs.FileMode(0600).String(), info.Mode().String(), "have -rw------- permissions")
})
}
15 changes: 14 additions & 1 deletion test/helpers/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,27 @@ func (a *Assets) CreateAndCopySimpleApp(prefix string) string {
return outDir
}

// AddFolder Adds a file to a folder with 0600 permission
func (a *Assets) AddFolder(path string, perm os.FileMode) {
a.T.Helper()
require.NoError(a.T, os.MkdirAll(path, perm))
}

// AddFileToFolder Adds a file to a folder with 0600 permission
func (a *Assets) AddFileToFolder(path, content string) {
a.T.Helper()
a.AddFileToFolderWithPermissions(path, content, 0600)
}

// AddFileToFolderWithPermissions Adds a file to a folder and sets permissions
func (a *Assets) AddFileToFolderWithPermissions(path, content string, perm os.FileMode) {
a.T.Helper()
subfolders, _ := filepath.Split(path)
if subfolders != "" {
err := os.MkdirAll(subfolders, 0700)
require.NoError(a.T, err)
}

err := ioutil.WriteFile(path, []byte(content), 0600)
err := ioutil.WriteFile(path, []byte(content), perm)
require.NoError(a.T, err)
}