diff --git a/pkg/compiler/types/artifact/artifact.go b/pkg/compiler/types/artifact/artifact.go index 29b64b07..b6ca3f99 100644 --- a/pkg/compiler/types/artifact/artifact.go +++ b/pkg/compiler/types/artifact/artifact.go @@ -19,6 +19,8 @@ import ( "archive/tar" "bufio" "bytes" + "crypto/sha1" + "encoding/base64" "fmt" "io" "io/ioutil" @@ -316,7 +318,6 @@ func (a *PackageArtifact) Compress(src string, concurrency int) error { default: return helpers.Tar(src, a.getCompressedName()) } - return errors.New("Compression type must be supplied") } func (a *PackageArtifact) getCompressedName() string { @@ -339,6 +340,13 @@ func (a *PackageArtifact) GetUncompressedName() string { return a.Path } +func hashContent(bv []byte) string { + hasher := sha1.New() + hasher.Write(bv) + sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil)) + return sha +} + func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { // If the destination path already exists I rename target file name with postfix. var destPath string @@ -350,6 +358,7 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea return nil, nil, err } } + tarHash := hashContent(buffer.Bytes()) // If file is not present on archive but is defined on mods // I receive the callback. Prevent nil exception. @@ -362,8 +371,21 @@ func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Rea return header, buffer.Bytes(), nil } + existingHash := "" + f, err := os.Lstat(destPath) + if err == nil { + dat, err := ioutil.ReadFile(destPath) + Debug("File exists already, computing hash for", destPath) + if err == nil { + existingHash = hashContent(dat) + } + } + + Debug("Existing file hash: ", existingHash, "Tar file hashsum: ", tarHash) + // We want to protect file only if the hash of the files are differing OR the file size are + differs := (existingHash != "" && existingHash != tarHash) || header.Size != f.Size() // Check if exists - if helpers.Exists(destPath) { + if helpers.Exists(destPath) && differs { for i := 1; i < 1000; i++ { name := filepath.Join(filepath.Join(filepath.Dir(path), fmt.Sprintf("._cfg%04d_%s", i, filepath.Base(path)))) diff --git a/pkg/helpers/archive.go b/pkg/helpers/archive.go index d64d174f..a4dfdbcb 100644 --- a/pkg/helpers/archive.go +++ b/pkg/helpers/archive.go @@ -90,8 +90,7 @@ func UntarProtect(src, dst string, sameOwner bool, protectedFiles []string, modi } if sameOwner { - // PRE: i have root privileged. - + // we do have root permissions, so we can extract keeping the same permissions. replacerArchive := archive.ReplaceFileTarWrapper(in, mods) opts := &archive.TarOptions{ diff --git a/tests/integration/12_config_protect_samefile.sh b/tests/integration/12_config_protect_samefile.sh new file mode 100755 index 00000000..1f0d581f --- /dev/null +++ b/tests/integration/12_config_protect_samefile.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +export LUET_NOLOCK=true + +oneTimeSetUp() { +export tmpdir="$(mktemp -d)" +} + +oneTimeTearDown() { + rm -rf "$tmpdir" +} + +testBuild() { + mkdir $tmpdir/testrootfs/testbuild -p + luet build --tree "$ROOT_DIR/tests/fixtures/config_protect" \ + --destination $tmpdir/testrootfs/testbuild --compression gzip test/a + buildst=$? + assertEquals 'builds successfully' "$buildst" "0" + assertTrue 'create package' "[ -e '$tmpdir/testrootfs/testbuild/a-test-1.0.package.tar.gz' ]" +} + +testRepo() { + assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]" + luet create-repo --tree "$ROOT_DIR/tests/fixtures/config_protect" \ + --output $tmpdir/testrootfs/testbuild \ + --packages $tmpdir/testrootfs/testbuild \ + --name "test" \ + --descr "Test Repo" \ + --urls $tmpdir/testrootfs \ + --type disk > /dev/null + + createst=$? + assertEquals 'create repo successfully' "$createst" "0" + assertTrue 'create repository' "[ -e '$tmpdir/testrootfs/testbuild/repository.yaml' ]" +} + +testConfig() { + + mkdir $tmpdir/testrootfs/etc/luet/config.protect.d -p + + cat < $tmpdir/testrootfs/etc/luet/config.protect.d/conf1.yml +name: "protect1" +dirs: +- /etc/ +EOF + + cat < $tmpdir/luet.yaml +general: + debug: true +system: + rootfs: $tmpdir/testrootfs + database_path: "/" + database_engine: "boltdb" +config_protect_confdir: + - /etc/luet/config.protect.d +config_from_host: false +repositories: + - name: "main" + type: "disk" + enable: true + urls: + - "/testbuild" +EOF + luet config --config $tmpdir/luet.yaml + res=$? + assertEquals 'config test successfully' "$res" "0" +} + + + +testInstall() { + + # Simulate previous installation + mkdir $tmpdir/testrootfs/etc/a -p + echo config > $tmpdir/testrootfs/etc/a/conf + + luet install -y --config $tmpdir/luet.yaml test/a + installst=$? + assertEquals 'install test successfully' "$installst" "0" + + + # Simulate config protect + assertTrue 'package A installed' "[ -e '$tmpdir/testrootfs/c' ]" + assertTrue 'config protect not created, file is the same' "[ ! -e '$tmpdir/testrootfs/etc/a/._cfg0001_conf' ]" + assertEquals 'config protect content' "$(cat $tmpdir/testrootfs/etc/a/conf)" "config" +} + + +testUnInstall() { + luet uninstall -y --full --config $tmpdir/luet.yaml test/a + installst=$? + assertEquals 'uninstall test successfully' "$installst" "0" + assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]" + assertTrue 'config protect maintains the protected files' "[ -e '$tmpdir/testrootfs/etc/a/conf' ]" +} + + +testCleanup() { + luet cleanup --config $tmpdir/luet.yaml + installst=$? + assertEquals 'install test successfully' "$installst" "0" + assertTrue 'package installed' "[ ! -e '$tmpdir/testrootfs/packages/a-test-1.0.package.tar.gz' ]" +} + +# Load shUnit2. +. "$ROOT_DIR/tests/integration/shunit2"/shunit2 +