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) == []