Fix symlink snapshot (#1833)

* Fix symbolic link issue with snapshot

* Add tests

* fix symlink

* add encrypted test

* Modify x
This commit is contained in:
Pascal Vizeli 2020-07-14 15:39:03 +02:00 committed by GitHub
parent 685788bcdf
commit bb64dca6e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 13 deletions

View File

@ -46,6 +46,3 @@ COPY requirements.txt requirements_tests.txt ./
RUN pip3 install -r requirements.txt -r requirements_tests.txt \
&& pip3 install tox \
&& rm -f requirements.txt requirements_tests.txt
# Set the default shell to bash instead of sh
ENV SHELL /bin/bash

View File

@ -12,15 +12,21 @@
"esbenp.prettier-vscode"
],
"settings": {
"python.pythonPath": "/usr/local/bin/python",
"terminal.integrated.shell.linux": "/bin/bash",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"python.pythonPath": "/usr/local/bin/python3",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"python.formatting.blackArgs": ["--target-version", "py38"],
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
"python.formatting.blackPath": "/usr/local/bin/black",
"python.linting.banditPath": "/usr/local/bin/bandit",
"python.linting.flake8Path": "/usr/local/bin/flake8",
"python.linting.mypyPath": "/usr/local/bin/mypy",
"python.linting.pylintPath": "/usr/local/bin/pylint",
"python.linting.pydocstylePath": "/usr/local/bin/pydocstyle"
}
}

View File

@ -659,7 +659,7 @@ class Addon(AddonModel):
# Restore data
def _restore_data():
"""Restore data."""
shutil.copytree(Path(temp, "data"), self.path_data)
shutil.copytree(Path(temp, "data"), self.path_data, symlinks=True)
_LOGGER.info("Restore data for addon %s", self.slug)
if self.path_data.is_dir():

View File

@ -165,7 +165,7 @@ def atomic_contents_add(
continue
arcpath = PurePath(arcname, directory_item.name).as_posix()
if directory_item.is_dir():
if directory_item.is_dir() and not directory_item.is_symlink():
atomic_contents_add(tar_file, directory_item, excludes, arcpath)
continue

3
tests/fixtures/tar_data/README.md vendored Normal file
View File

@ -0,0 +1,3 @@
# Tar Data
This is just a test for backup files

3
tests/fixtures/tar_data/test1/script.sh vendored Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "Test Script"

1
tests/fixtures/tar_data/test_symlink vendored Symbolic link
View File

@ -0,0 +1 @@
test1

View File

@ -1,10 +1,17 @@
"""Test Tarfile functions."""
from pathlib import PurePath
import os
from pathlib import Path, PurePath
import shutil
from tempfile import TemporaryDirectory
import attr
from supervisor.utils.tar import _is_excluded_by_filter, secure_path
from supervisor.utils.tar import (
SecureTarFile,
_is_excluded_by_filter,
atomic_contents_add,
secure_path,
)
@attr.s
@ -61,3 +68,68 @@ def test_is_exclude_by_filter_bad():
for path_object in test_list:
assert _is_excluded_by_filter(path_object, filter_list) is True
def test_create_pure_tar():
"""Test to create a tar file without encryption."""
with TemporaryDirectory() as temp_dir:
temp = Path(temp_dir)
# Prepair test folder
temp_orig = temp.joinpath("orig")
fixture_data = Path(__file__).parents[1].joinpath("fixtures/tar_data")
shutil.copytree(fixture_data, temp_orig, symlinks=True)
# Create Tarfile
temp_tar = temp.joinpath("backup.tar")
with SecureTarFile(temp_tar, "w") as tar_file:
atomic_contents_add(
tar_file, temp_orig, excludes=[], arcname=".",
)
assert temp_tar.exists()
# Restore
temp_new = temp.joinpath("new")
with SecureTarFile(temp_tar, "r") as tar_file:
tar_file.extractall(path=temp_new, members=tar_file)
assert temp_new.is_dir()
assert temp_new.joinpath("test_symlink").is_symlink()
assert temp_new.joinpath("test1").is_dir()
assert temp_new.joinpath("test1/script.sh").is_file()
assert temp_new.joinpath("test1/script.sh").stat().st_mode == 33261
assert temp_new.joinpath("README.md").is_file()
def test_create_ecrypted_tar():
"""Test to create a tar file with encryption."""
with TemporaryDirectory() as temp_dir:
temp = Path(temp_dir)
key = os.urandom(16)
# Prepair test folder
temp_orig = temp.joinpath("orig")
fixture_data = Path(__file__).parents[1].joinpath("fixtures/tar_data")
shutil.copytree(fixture_data, temp_orig, symlinks=True)
# Create Tarfile
temp_tar = temp.joinpath("backup.tar")
with SecureTarFile(temp_tar, "w", key=key) as tar_file:
atomic_contents_add(
tar_file, temp_orig, excludes=[], arcname=".",
)
assert temp_tar.exists()
# Restore
temp_new = temp.joinpath("new")
with SecureTarFile(temp_tar, "r", key=key) as tar_file:
tar_file.extractall(path=temp_new, members=tar_file)
assert temp_new.is_dir()
assert temp_new.joinpath("test_symlink").is_symlink()
assert temp_new.joinpath("test1").is_dir()
assert temp_new.joinpath("test1/script.sh").is_file()
assert temp_new.joinpath("test1/script.sh").stat().st_mode == 33261
assert temp_new.joinpath("README.md").is_file()