mirror of
https://github.com/maxDcb/C2TeamServer
synced 2026-06-06 16:14:27 +00:00
85 lines
3.5 KiB
Python
85 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import stat
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
PACKAGING_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(PACKAGING_ROOT))
|
|
|
|
import validate_release # noqa: E402
|
|
|
|
|
|
def _write_file(path: Path, content: str = "x", *, executable: bool = False) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(content, encoding="utf-8")
|
|
if executable and os.name != "nt":
|
|
path.chmod(path.stat().st_mode | stat.S_IXUSR)
|
|
|
|
|
|
def _seed_base_release(root: Path) -> None:
|
|
for filename in validate_release.EXPECTED_TEAMSERVER_FILES:
|
|
_write_file(root / "TeamServer" / filename, executable=filename == "TeamServer")
|
|
(root / "TeamServer" / "logs").mkdir(parents=True)
|
|
|
|
for filename in validate_release.EXPECTED_TEAMSERVER_MODULES:
|
|
_write_file(root / "TeamServerModules" / filename)
|
|
|
|
for filename in validate_release.EXPECTED_COMMAND_SPECS_COMMON:
|
|
_write_file(root / "CommandSpecs" / "common" / filename, "{}")
|
|
for filename in validate_release.EXPECTED_COMMAND_SPECS_MODULES:
|
|
_write_file(root / "CommandSpecs" / "modules" / filename, "{}")
|
|
|
|
_write_file(root / "Client" / "README.md")
|
|
_write_file(root / "Client" / "pyproject.toml")
|
|
_write_file(root / "Client" / "requirements.txt")
|
|
_write_file(root / "Client" / "run-client.sh", executable=True)
|
|
_write_file(root / "Client" / "run-client.ps1")
|
|
_write_file(root / "Client" / "c2client_protocol" / "__init__.py")
|
|
_write_file(root / "Client" / "c2client_protocol" / "TeamServerApi_pb2.py")
|
|
_write_file(root / "Client" / "c2client_protocol" / "TeamServerApi_pb2_grpc.py")
|
|
|
|
|
|
def test_validate_base_release_requires_command_specs(tmp_path):
|
|
release_root = tmp_path / "Release"
|
|
_seed_base_release(release_root)
|
|
|
|
validate_release.validate_base_release(release_root)
|
|
|
|
(release_root / "CommandSpecs" / "modules" / "taskScheduler.json").unlink()
|
|
with pytest.raises(validate_release.ValidationError, match="taskScheduler.json"):
|
|
validate_release.validate_base_release(release_root)
|
|
|
|
|
|
def test_validate_base_release_rejects_runtime_data_roots(tmp_path):
|
|
release_root = tmp_path / "Release"
|
|
_seed_base_release(release_root)
|
|
(release_root / "data" / "Tools").mkdir(parents=True)
|
|
|
|
with pytest.raises(validate_release.ValidationError, match="runtime/operator data"):
|
|
validate_release.validate_base_release(release_root)
|
|
|
|
|
|
def test_validate_implants_requires_linux_arch_layout(tmp_path):
|
|
release_root = tmp_path / "Release"
|
|
for arch in validate_release.EXPECTED_WINDOWS_ARCHES:
|
|
for filename in validate_release.EXPECTED_WINDOWS_BEACONS:
|
|
_write_file(release_root / "WindowsBeacons" / arch / filename)
|
|
for filename in validate_release.EXPECTED_WINDOWS_MODULES:
|
|
_write_file(release_root / "WindowsModules" / arch / filename)
|
|
for arch in validate_release.EXPECTED_LINUX_ARCHES:
|
|
for filename in validate_release.EXPECTED_LINUX_BEACONS:
|
|
_write_file(release_root / "LinuxBeacons" / arch / filename)
|
|
for filename in validate_release.EXPECTED_LINUX_MODULES:
|
|
_write_file(release_root / "LinuxModules" / arch / filename)
|
|
|
|
validate_release.validate_implants(release_root)
|
|
|
|
flat_beacon = release_root / "LinuxBeacons" / "BeaconHttp"
|
|
_write_file(flat_beacon)
|
|
with pytest.raises(validate_release.ValidationError, match="unexpected file"):
|
|
validate_release.validate_implants(release_root)
|