Files
aios/tests/autonomous_release/test_artifact_closure.py
T

42 lines
1.6 KiB
Python

from pathlib import Path
import pytest
from aios_autonomous_release_candidate.artifact import ArtifactBuilder, ArtifactFile, BuiltArtifact
from aios_autonomous_release_candidate.errors import EvidenceIncomplete, ReleaseBlocked
def test_artifact_is_deterministic_and_reverified() -> None:
builder = ArtifactBuilder()
files = (
ArtifactFile("bin/run", b"#!/bin/sh\nexit 0\n", 0o755),
ArtifactFile("config/candidate.json", b'{"production":false}\n'),
)
first = builder.build("a" * 40, "b" * 40, files)
second = builder.build("a" * 40, "b" * 40, tuple(reversed(files)))
assert first.content == second.content
assert first.manifest.manifest_sha256 == second.manifest.manifest_sha256
assert first.manifest.secrets_included is False
builder.verify(first)
with pytest.raises(EvidenceIncomplete, match="ARTIFACT_DIGEST_MISMATCH"):
builder.verify(BuiltArtifact(first.content + b"tampered", first.manifest))
def test_source_tree_rejects_symlink_and_hardlink(tmp_path: Path) -> None:
root = tmp_path / "source"
root.mkdir()
target = root / "file.txt"
target.write_text("safe", encoding="utf-8")
(root / "link.txt").symlink_to(target)
with pytest.raises(ReleaseBlocked, match="ARTIFACT_SOURCE_LINK_REJECTED"):
ArtifactBuilder().build_from_directory("a" * 40, "b" * 40, root)
def test_artifact_rejects_secret_markers() -> None:
with pytest.raises(ReleaseBlocked, match="ARTIFACT_SECRET_MARKER"):
ArtifactBuilder().build(
"a" * 40,
"b" * 40,
(ArtifactFile("unsafe.env", b"password" + b"=" + b"x" * 16),),
)