feat: 发布固件底层开发 Skill 套件
This commit is contained in:
commit
c7ae3b4ce1
72 files changed
+10212
No files matched your search
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Behavioral tests for psp_project_guard.py."""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import psp_project_guard
|
||||
|
||||
|
||||
def git(path: Path, *args: str) -> str:
|
||||
result = subprocess.run(
|
||||
["git", "-C", str(path), *args],
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
)
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def create_empty_project(psp_root: Path, name: str) -> Path:
|
||||
project = psp_root / name
|
||||
project.mkdir()
|
||||
git(project, "init", "-q")
|
||||
git(project, "remote", "add", "origin", f"ssh://git.example/Psp/{name}.git")
|
||||
return project
|
||||
|
||||
|
||||
def expect_guard_error(action, message: str) -> None:
|
||||
try:
|
||||
action()
|
||||
except psp_project_guard.GuardError:
|
||||
return
|
||||
raise AssertionError(message)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
psp_root = root / "Psp"
|
||||
psp_root.mkdir()
|
||||
reference = psp_root / "REF"
|
||||
reference.mkdir()
|
||||
(reference / "configs").mkdir()
|
||||
(reference / "configs" / "board.json").write_text(
|
||||
json.dumps({"project": "REF"}), encoding="utf-8"
|
||||
)
|
||||
(reference / "psp.json").write_text(
|
||||
json.dumps({"project": "REF"}), encoding="utf-8"
|
||||
)
|
||||
(reference / "build").mkdir()
|
||||
(reference / "build" / "generated.bin").write_bytes(b"generated")
|
||||
git(reference, "init", "-q")
|
||||
git(reference, "add", "configs/board.json", "psp.json")
|
||||
git(
|
||||
reference,
|
||||
"-c",
|
||||
"user.name=PSP Test",
|
||||
"-c",
|
||||
"user.email=psp-test@example.invalid",
|
||||
"commit",
|
||||
"-qm",
|
||||
"reference",
|
||||
)
|
||||
|
||||
target = create_empty_project(psp_root, "LY-SM-YT42-AI")
|
||||
original_branch = git(target, "symbolic-ref", "--short", "HEAD")
|
||||
original_remote = git(target, "remote", "get-url", "origin")
|
||||
inspected = psp_project_guard.inspect_project(target, psp_root)
|
||||
assert inspected["mode"] == "precreated-empty-repository"
|
||||
assert inspected["project"] == "LY-SM-YT42-AI"
|
||||
manifest = root / "evidence" / "clone-manifest.json"
|
||||
prepared = psp_project_guard.prepare(
|
||||
reference, target, manifest, ["REF"], include_dirty=False, psp_root=psp_root
|
||||
)
|
||||
staging = Path(prepared["staging"])
|
||||
assert prepared["target_mode"] == "precreated-empty-repository"
|
||||
assert prepared["psp_root"] == str(psp_root)
|
||||
assert not (staging / ".git").exists()
|
||||
assert not (staging / "build").exists()
|
||||
|
||||
(staging / "psp.json").write_text(
|
||||
json.dumps({"project": "NEW"}), encoding="utf-8"
|
||||
)
|
||||
failing = psp_project_guard.verify(manifest, ["psp.json"], [], None)
|
||||
assert failing["passed"] is False
|
||||
assert failing["residues"]
|
||||
|
||||
(staging / "configs" / "board.json").write_text(
|
||||
json.dumps({"project": "NEW"}), encoding="utf-8"
|
||||
)
|
||||
report_path = root / "evidence" / "verify.json"
|
||||
verified = psp_project_guard.verify(
|
||||
manifest, ["psp.json", "configs/board.json"], [], report_path
|
||||
)
|
||||
assert verified["passed"] is True, verified
|
||||
finalized = psp_project_guard.finalize(manifest, report_path)
|
||||
assert finalized["target"] == str(target)
|
||||
assert finalized["repository_preserved"] is True
|
||||
assert not staging.exists()
|
||||
assert (target / ".git").is_dir()
|
||||
assert git(target, "symbolic-ref", "--short", "HEAD") == original_branch
|
||||
assert git(target, "remote", "get-url", "origin") == original_remote
|
||||
assert not (target / ".git" / "refs" / "heads" / original_branch).exists()
|
||||
audit_path = root / "evidence" / "final-audit.json"
|
||||
audited = psp_project_guard.audit_final(
|
||||
manifest, ["psp.json", "configs/board.json"], [], audit_path
|
||||
)
|
||||
assert audited["passed"] is True, audited
|
||||
assert audited["repository_unchanged"] is True
|
||||
|
||||
missing = psp_root / "MISSING"
|
||||
expect_guard_error(
|
||||
lambda: psp_project_guard.prepare(
|
||||
reference, missing, root / "missing-manifest.json", [], False, psp_root
|
||||
),
|
||||
"missing target must be rejected",
|
||||
)
|
||||
|
||||
outside = create_empty_project(root, "OUTSIDE")
|
||||
expect_guard_error(
|
||||
lambda: psp_project_guard.prepare(
|
||||
reference, outside, root / "outside-manifest.json", [], False, psp_root
|
||||
),
|
||||
"target outside the fixed PSP root must be rejected",
|
||||
)
|
||||
|
||||
populated = create_empty_project(psp_root, "POPULATED")
|
||||
(populated / "README.md").write_text("existing\n", encoding="utf-8")
|
||||
assert psp_project_guard.inspect_project(populated, psp_root)["mode"] == "existing-project"
|
||||
expect_guard_error(
|
||||
lambda: psp_project_guard.prepare(
|
||||
reference, populated, root / "populated-manifest.json", [], False, psp_root
|
||||
),
|
||||
"populated target must use the existing-project update flow",
|
||||
)
|
||||
|
||||
changed = create_empty_project(psp_root, "CHANGED")
|
||||
changed_manifest = root / "evidence" / "changed-manifest.json"
|
||||
changed_prepared = psp_project_guard.prepare(
|
||||
reference, changed, changed_manifest, [], False, psp_root
|
||||
)
|
||||
changed_report = root / "evidence" / "changed-verify.json"
|
||||
changed_verified = psp_project_guard.verify(changed_manifest, [], [], changed_report)
|
||||
assert changed_verified["passed"] is True
|
||||
git(changed, "remote", "set-url", "origin", "ssh://git.example/changed.git")
|
||||
expect_guard_error(
|
||||
lambda: psp_project_guard.finalize(changed_manifest, changed_report),
|
||||
"Git metadata drift after prepare must block finalization",
|
||||
)
|
||||
assert Path(changed_prepared["staging"]).is_dir()
|
||||
assert not (changed / "psp.json").exists()
|
||||
|
||||
(reference / "psp.json").write_text(
|
||||
json.dumps({"project": "UNCOMMITTED"}), encoding="utf-8"
|
||||
)
|
||||
head_target = create_empty_project(psp_root, "FROM-HEAD")
|
||||
head_manifest = root / "evidence" / "head-manifest.json"
|
||||
from_head = psp_project_guard.prepare(
|
||||
reference, head_target, head_manifest, ["REF"], False, psp_root
|
||||
)
|
||||
assert from_head["warnings"]
|
||||
assert json.loads((Path(from_head["staging"]) / "psp.json").read_text())["project"] == "REF"
|
||||
|
||||
unsafe = root / "unsafe"
|
||||
unsafe.mkdir()
|
||||
(unsafe / "psp.json").write_text("{}", encoding="utf-8")
|
||||
(unsafe / ".env").write_text("TOKEN=secret", encoding="utf-8")
|
||||
unsafe_target = create_empty_project(psp_root, "UNSAFE")
|
||||
expect_guard_error(
|
||||
lambda: psp_project_guard.prepare(
|
||||
unsafe, unsafe_target, root / "unsafe-manifest.json", [], False, psp_root
|
||||
),
|
||||
"credential-like files must be rejected",
|
||||
)
|
||||
|
||||
print("PSP project guard tests passed")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user