100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from server.infrastructure.ssh.remote_archive import (
|
||
|
|
archive_member_list_command,
|
||
|
|
archive_member_type_list_command,
|
||
|
|
decompress_command,
|
||
|
|
tar_compress_commands,
|
||
|
|
validate_archive_member_names,
|
||
|
|
validate_archive_member_types,
|
||
|
|
zip_compress_commands,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_tar_compress_commands_end_options_before_member_names() -> None:
|
||
|
|
commands = tar_compress_commands(["/var/www/-leading"], "/tmp/out.tar.gz")
|
||
|
|
|
||
|
|
assert commands
|
||
|
|
assert all(" -- -leading" in command for command in commands)
|
||
|
|
assert commands[0] == "tar -czf /tmp/out.tar.gz -C /var/www -- -leading"
|
||
|
|
|
||
|
|
|
||
|
|
def test_zip_compress_commands_end_options_before_archive_and_members() -> None:
|
||
|
|
commands = zip_compress_commands(["/var/www/-leading"], "/tmp/out.zip")
|
||
|
|
|
||
|
|
assert commands
|
||
|
|
assert all("zip -qr -- " in command for command in commands)
|
||
|
|
assert commands[0] == "cd /var/www && zip -qr -- /tmp/out.zip -leading"
|
||
|
|
|
||
|
|
|
||
|
|
def test_zip_compress_commands_allow_dash_prefixed_archive_basename() -> None:
|
||
|
|
commands = zip_compress_commands(["/var/www/-leading"], "/var/www/-archive.zip")
|
||
|
|
|
||
|
|
assert commands[0] == "cd /var/www && zip -qr -- -archive.zip -leading"
|
||
|
|
|
||
|
|
def test_archive_member_list_commands() -> None:
|
||
|
|
assert archive_member_list_command("/tmp/a.tgz", "tar.gz") == "tar -tzf /tmp/a.tgz"
|
||
|
|
assert archive_member_type_list_command("/tmp/a.zip", "zip") == "zipinfo -l /tmp/a.zip"
|
||
|
|
|
||
|
|
|
||
|
|
def test_decompress_command_uses_safer_tar_flags() -> None:
|
||
|
|
assert decompress_command("/tmp/a.tgz", "/var/www", "tar.gz") == (
|
||
|
|
"tar --no-same-owner --no-same-permissions -xzf /tmp/a.tgz -C /var/www"
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_names_rejects_parent_traversal() -> None:
|
||
|
|
with pytest.raises(ValueError, match="路径穿越"):
|
||
|
|
validate_archive_member_names("safe.txt\n../evil.txt\n")
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_names_rejects_absolute_path() -> None:
|
||
|
|
with pytest.raises(ValueError, match="绝对路径"):
|
||
|
|
validate_archive_member_names("/etc/passwd\n")
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_names_rejects_windows_separator() -> None:
|
||
|
|
with pytest.raises(ValueError, match="非法路径"):
|
||
|
|
validate_archive_member_names("dir\\evil.txt\n")
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_names_allows_relative_files_and_dirs() -> None:
|
||
|
|
assert validate_archive_member_names("dir/\ndir/file.txt\n./ok.txt\n") == [
|
||
|
|
"dir/",
|
||
|
|
"dir/file.txt",
|
||
|
|
"./ok.txt",
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_types_rejects_symlink() -> None:
|
||
|
|
with pytest.raises(ValueError, match="符号链接"):
|
||
|
|
validate_archive_member_types("lrwxrwxrwx root/root 0 2026-01-01 link -> /etc\n")
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_types_rejects_device_file() -> None:
|
||
|
|
with pytest.raises(ValueError, match="字符设备"):
|
||
|
|
validate_archive_member_types("crw-r--r-- root/root 0 2026-01-01 dev\n")
|
||
|
|
|
||
|
|
|
||
|
|
def test_validate_archive_member_types_allows_files_dirs_and_zipinfo_headers() -> None:
|
||
|
|
validate_archive_member_types(
|
||
|
|
"Archive: a.zip\n"
|
||
|
|
"drwxr-xr-x 3.0 unx 0 bx stor 26-Jan-01 00:00 dir/\n"
|
||
|
|
"-rw-r--r-- 3.0 unx 1 tx stor 26-Jan-01 00:00 dir/a.txt\n"
|
||
|
|
"2 files, 1 bytes uncompressed\n"
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_tar_compress_staged_move_uses_option_terminator() -> None:
|
||
|
|
commands = tar_compress_commands(["/opt/site"], "/var/backups/-out.tar.gz")
|
||
|
|
|
||
|
|
assert "&& mv -f -- " in commands[1]
|
||
|
|
|
||
|
|
|
||
|
|
def test_zip_compress_staged_move_uses_option_terminator() -> None:
|
||
|
|
commands = zip_compress_commands(["/opt/site"], "/var/backups/-out.zip")
|
||
|
|
|
||
|
|
assert "&& mv -f -- " in commands[1]
|