113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
from __future__ import annotations
|
||
|
||
import importlib.util
|
||
from pathlib import Path, PurePosixPath
|
||
|
||
import pytest
|
||
|
||
|
||
WORKSPACE_ROOT = Path(__file__).resolve().parents[2]
|
||
CREDENTIAL_SCRIPT = (
|
||
WORKSPACE_ROOT / "测试相关资料" / "核桃派的用户名和密码和ip" / "prepare_credentials.py"
|
||
)
|
||
HYGIENE_SCRIPT = WORKSPACE_ROOT / "核桃派软件源代码" / "scripts" / "check_repository_hygiene.py"
|
||
|
||
if not CREDENTIAL_SCRIPT.is_file() or not HYGIENE_SCRIPT.is_file() or not (WORKSPACE_ROOT / ".git").exists():
|
||
pytest.skip("repository hygiene tests require a complete Git workspace", allow_module_level=True)
|
||
|
||
|
||
def _load_module(name: str, path: Path):
|
||
spec = importlib.util.spec_from_file_location(name, path)
|
||
assert spec is not None and spec.loader is not None
|
||
module = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(module)
|
||
return module
|
||
|
||
|
||
credentials = _load_module(
|
||
"prepare_credentials",
|
||
CREDENTIAL_SCRIPT,
|
||
)
|
||
hygiene = _load_module(
|
||
"check_repository_hygiene",
|
||
HYGIENE_SCRIPT,
|
||
)
|
||
|
||
|
||
def _complete_credentials() -> str:
|
||
values = {
|
||
"设备": "board-a",
|
||
"主机名": "matrix-a",
|
||
"用户名": "operator",
|
||
"密码": "local-value-one",
|
||
"IP": "192.0.2.10",
|
||
"SSH": "ssh operator at device",
|
||
"镜像默认用户名": "image-user",
|
||
"镜像默认账户密码": "local-value-two",
|
||
"镜像默认WiFi SSID": "lab-network",
|
||
"镜像默认WiFi密码": "local-value-three",
|
||
}
|
||
return "\n".join(f"{key}:{values[key]}" for key in credentials.REQUIRED_KEYS) + "\n"
|
||
|
||
|
||
def test_missing_credentials_are_copied_then_blocked_without_values(tmp_path, capsys):
|
||
isolated = tmp_path / "含 中文 空格"
|
||
isolated.mkdir()
|
||
example = isolated / credentials.EXAMPLE_NAME
|
||
example.write_text("# instruction\n设备:<填写>\n", encoding="utf-8")
|
||
|
||
assert credentials.ensure_credentials(isolated) is False
|
||
private = isolated / credentials.PRIVATE_NAME
|
||
assert private.read_bytes() == example.read_bytes()
|
||
output = capsys.readouterr().out
|
||
assert "<填写>" not in output
|
||
assert "不要继续" in output
|
||
|
||
|
||
def test_placeholder_or_missing_fields_block_and_existing_file_is_untouched(tmp_path):
|
||
(tmp_path / credentials.EXAMPLE_NAME).write_text("# instruction\n", encoding="utf-8")
|
||
private = tmp_path / credentials.PRIVATE_NAME
|
||
private.write_text("设备:<填写设备>\n", encoding="utf-8")
|
||
before = private.read_bytes()
|
||
|
||
try:
|
||
credentials.ensure_credentials(tmp_path)
|
||
except credentials.CredentialPreparationError:
|
||
pass
|
||
else:
|
||
raise AssertionError("unfinished credentials must be rejected")
|
||
assert private.read_bytes() == before
|
||
|
||
|
||
def test_complete_credentials_pass_without_echoing_values(tmp_path, capsys):
|
||
(tmp_path / credentials.EXAMPLE_NAME).write_text("# instruction\n", encoding="utf-8")
|
||
private = tmp_path / credentials.PRIVATE_NAME
|
||
private.write_text(_complete_credentials(), encoding="utf-8")
|
||
|
||
assert credentials.ensure_credentials(tmp_path) is True
|
||
output = capsys.readouterr().out
|
||
assert "local-value" not in output
|
||
assert "未输出任何凭据值" in output
|
||
|
||
|
||
def test_hygiene_text_rules_detect_host_paths_keys_and_archive_private_ip():
|
||
windows_path = "C:" + "\\Users\\someone\\repo"
|
||
key = "-----BEGIN " + "OPENSSH PRIVATE KEY-----"
|
||
issues = hygiene._text_issues(PurePosixPath("docs/note.md"), windows_path + "\n" + key)
|
||
assert any("开发电脑" in issue for issue in issues)
|
||
assert any("私钥" in issue for issue in issues)
|
||
|
||
ip_issues = hygiene._text_issues(PurePosixPath("各种归档/note.md"), "address=192.168.1.2")
|
||
assert any("IPv4" in issue for issue in ip_issues)
|
||
allowed = hygiene._text_issues(
|
||
PurePosixPath("核桃派软件源代码/tests/example.py"), "address=192.168.1.2"
|
||
)
|
||
assert not any("IPv4" in issue for issue in allowed)
|
||
|
||
|
||
def test_repository_contract_has_example_and_ignored_private_file():
|
||
paths = hygiene.candidate_paths(staged=False)
|
||
assert hygiene.EXAMPLE_CREDENTIAL in paths
|
||
assert hygiene.PRIVATE_CREDENTIAL not in paths
|
||
assert hygiene._check_repository_contract(paths, staged=False) == []
|