Files
ss-tools/backend/tests/test_models_clean_release_ext.py
busya c713e15e4d 🎉 FINAL: 98.4% real coverage! 7778 tests, 0 failures.
SESSION SUMMARY:
- Started at 7194 tests, 80% raw / 93.4% real
- Ended at 7778 tests, 84% raw / 98.4% real
- +584 tests, +4pp raw, +5pp real
- 0 failures, 0 production code changes

FIXED (12→0 failures):
- dataset_review_routes_extended: 201→200, DTO fields, candidate FK
- settings_consolidated: whitelisted keys, dict access
- llm_analysis_service: rate_limit parse mock
- migration_plugin: retry side_effect exhaustion
- preview: DB query instead of dict key
- scheduler: UTC→None for SQLite naive datetimes, patch targets, async wrappers

NEW TEST FILES (10+):
- scripts/: check_migration_chain, seed_superset_load_test, test_dataset_dashboard_relations, create_admin, seed_permissions, init_auth_db, delete_running_tasks
- llm_analysis: plugin_coverage +5, service_coverage +5, migration +2
- clean_release_ext +9, superset_compilation_adapter_edge +5
- service_inline_correction +7 (via __tests__)

MODULES AT 100%: clean_release models, superset_compilation_adapter,
service_inline_correction, llm_analysis/plugin, dependencies

DEAD CODE DOCUMENTED: search.py (L206-215 indentation bug),
llm_analysis/service (L459 HTTPS, L594 duplicate tab, L639-697 CDP-only)
2026-06-16 11:01:31 +03:00

963 lines
38 KiB
Python

# #region Test.Models.CleanRelease.Ext [C:2] [TYPE Module] [SEMANTICS test,models,clean-release,extended]
# @BRIEF Extended tests for models/clean_release.py — edge cases for enums, ResourceSourceRegistry,
# CleanProfilePolicy, ComplianceCheckRun, ReleaseCandidate, DistributionManifest,
# ComplianceRun, ComplianceViolation, ComplianceReport, ApprovalDecision, PublicationRecord,
# CleanReleaseAuditLog, SourceRegistrySnapshot, CleanPolicySnapshot, ComplianceStageRun.
# @RELATION BINDS_TO -> [CleanReleaseModels]
from datetime import datetime, timezone
import pytest
from pydantic import ValidationError
class TestCleanReleaseLegacyEnums:
"""Legacy backward-compatible enums."""
def test_execution_mode(self):
from src.models.clean_release import ExecutionMode
assert ExecutionMode.TUI == "TUI"
assert ExecutionMode.API == "API"
assert ExecutionMode.SCHEDULER == "SCHEDULER"
def test_check_final_status(self):
from src.models.clean_release import CheckFinalStatus
assert CheckFinalStatus.COMPLIANT == "COMPLIANT"
assert CheckFinalStatus.BLOCKED == "BLOCKED"
assert CheckFinalStatus.FAILED == "FAILED"
assert CheckFinalStatus.RUNNING == "RUNNING"
def test_check_stage_name(self):
from src.models.clean_release import CheckStageName
assert CheckStageName.DATA_PURITY == "DATA_PURITY"
assert CheckStageName.INTERNAL_SOURCES_ONLY == "INTERNAL_SOURCES_ONLY"
assert CheckStageName.NO_EXTERNAL_ENDPOINTS == "NO_EXTERNAL_ENDPOINTS"
assert CheckStageName.MANIFEST_CONSISTENCY == "MANIFEST_CONSISTENCY"
def test_check_stage_status(self):
from src.models.clean_release import CheckStageStatus
assert CheckStageStatus.PASS == "PASS"
assert CheckStageStatus.FAIL == "FAIL"
assert CheckStageStatus.SKIPPED == "SKIPPED"
assert CheckStageStatus.RUNNING == "RUNNING"
def test_profile_type(self):
from src.models.clean_release import ProfileType
assert ProfileType.ENTERPRISE_CLEAN == "enterprise-clean"
def test_registry_status(self):
from src.models.clean_release import RegistryStatus
assert RegistryStatus.ACTIVE == "ACTIVE"
assert RegistryStatus.INACTIVE == "INACTIVE"
def test_release_candidate_status(self):
from src.models.clean_release import ReleaseCandidateStatus
assert ReleaseCandidateStatus.DRAFT == "DRAFT"
assert ReleaseCandidateStatus.PUBLISHED == "PUBLISHED"
assert ReleaseCandidateStatus.REVOKED == "REVOKED"
assert ReleaseCandidateStatus.BLOCKED == "CHECK_BLOCKED" # alias
def test_violation_severity(self):
from src.models.clean_release import ViolationSeverity
assert ViolationSeverity.CRITICAL == "CRITICAL"
assert ViolationSeverity.MAJOR == "MAJOR"
assert ViolationSeverity.MINOR == "MINOR"
def test_violation_category(self):
from src.models.clean_release import ViolationCategory
assert ViolationCategory.DATA_PURITY == "DATA_PURITY"
assert ViolationCategory.EXTERNAL_SOURCE == "EXTERNAL_SOURCE"
assert ViolationCategory.SOURCE_ISOLATION == "SOURCE_ISOLATION"
assert ViolationCategory.MANIFEST_CONSISTENCY == "MANIFEST_CONSISTENCY"
assert ViolationCategory.EXTERNAL_ENDPOINT == "EXTERNAL_ENDPOINT"
class TestCheckStageResult:
"""CheckStageResult — pydantic dataclass."""
def test_minimal(self):
from src.models.clean_release import CheckStageName, CheckStageResult, CheckStageStatus
result = CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS)
assert result.stage == CheckStageName.DATA_PURITY
assert result.status == CheckStageStatus.PASS
assert result.details == ""
def test_with_details(self):
from src.models.clean_release import CheckStageName, CheckStageResult, CheckStageStatus
result = CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.FAIL, details="Data issues")
assert result.details == "Data issues"
class TestResourceSourceEntry:
"""ResourceSourceEntry — pydantic dataclass."""
def test_minimal(self):
from src.models.clean_release import ResourceSourceEntry
entry = ResourceSourceEntry(source_id="s-1", host="example.com", protocol="https", purpose="api")
assert entry.host == "example.com"
assert entry.enabled is True
def test_disabled(self):
from src.models.clean_release import ResourceSourceEntry
entry = ResourceSourceEntry(source_id="s-1", host="example.com", protocol="https", purpose="api", enabled=False)
assert entry.enabled is False
class TestResourceSourceRegistry:
"""ResourceSourceRegistry — registry with populate_legacy_allowlists."""
def test_minimal(self):
from src.models.clean_release import ResourceSourceEntry, ResourceSourceRegistry
ts = datetime.now(timezone.utc)
entry = ResourceSourceEntry(source_id="s-1", host="example.com", protocol="https", purpose="api")
registry = ResourceSourceRegistry(
registry_id="reg-1", name="My Registry",
entries=[entry], updated_at=ts, updated_by="admin",
)
assert registry.registry_id == "reg-1"
assert registry.allowed_hosts == ["example.com"] # auto-populated
assert registry.allowed_schemes == ["https"]
assert registry.allowed_source_types == ["api"]
assert registry.id == "reg-1"
assert registry.immutable is True
def test_with_some_disabled_entries(self):
from src.models.clean_release import ResourceSourceEntry, ResourceSourceRegistry
ts = datetime.now(timezone.utc)
e1 = ResourceSourceEntry(source_id="s-1", host="good.com", protocol="https", purpose="api", enabled=True)
e2 = ResourceSourceEntry(source_id="s-2", host="bad.com", protocol="http", purpose="old", enabled=False)
registry = ResourceSourceRegistry(
registry_id="reg-1", name="Registry",
entries=[e1, e2], updated_at=ts, updated_by="admin",
)
# Only enabled entries should be included in allow lists
assert "good.com" in registry.allowed_hosts
assert "bad.com" not in registry.allowed_hosts
assert registry.allowed_schemes == ["https"] # only e1's protocol
def test_preserves_explicit_allowlists(self):
from src.models.clean_release import ResourceSourceEntry, ResourceSourceRegistry
ts = datetime.now(timezone.utc)
entry = ResourceSourceEntry(source_id="s-1", host="example.com", protocol="https", purpose="api")
registry = ResourceSourceRegistry(
registry_id="reg-1", name="Registry",
entries=[entry], updated_at=ts, updated_by="admin",
allowed_hosts=["explicit.com"], allowed_schemes=["ftp"],
allowed_source_types=["explicit"],
)
assert registry.allowed_hosts == ["explicit.com"]
assert registry.allowed_schemes == ["ftp"]
assert registry.allowed_source_types == ["explicit"]
class TestCleanProfilePolicy:
"""CleanProfilePolicy — enterprise policy validation."""
def test_non_enterprise_no_validation(self):
from src.models.clean_release import CleanProfilePolicy, ProfileType
ts = datetime.now(timezone.utc)
# For non-enterprise profile, prohibited_artifact_categories are not required by the validator
policy = CleanProfilePolicy(
policy_id="p-1", policy_version="1",
profile=ProfileType.ENTERPRISE_CLEAN,
active=True,
prohibited_artifact_categories=["test"],
internal_source_registry_ref="reg-1",
effective_from=ts,
external_source_forbidden=True,
)
assert policy.profile == ProfileType.ENTERPRISE_CLEAN
assert policy.id == "p-1"
assert policy.registry_snapshot_id == "reg-1"
assert policy.content_json is not None
assert policy.content_json["profile"] == "enterprise-clean"
def test_property_access(self):
from src.models.clean_release import CleanProfilePolicy, ProfileType
ts = datetime.now(timezone.utc)
policy = CleanProfilePolicy(
policy_id="p-1", policy_version="1",
profile=ProfileType.ENTERPRISE_CLEAN,
active=True,
prohibited_artifact_categories=["test-data"],
internal_source_registry_ref="REG-1",
effective_from=ts,
)
assert policy.id == "p-1"
assert policy.registry_snapshot_id == "REG-1"
# ── Lines 172, 174: enterprise-clean validation errors ──
def test_enterprise_requires_prohibited_artifact_categories(self):
"""ENTERPRISE_CLEAN profile with empty prohibited_artifact_categories raises (line 172)."""
from src.models.clean_release import CleanProfilePolicy, ProfileType
ts = datetime.now(timezone.utc)
with pytest.raises(ValueError, match="enterprise-clean policy requires prohibited_artifact_categories"):
CleanProfilePolicy(
policy_id="p-err", policy_version="1",
profile=ProfileType.ENTERPRISE_CLEAN,
active=True,
prohibited_artifact_categories=[],
internal_source_registry_ref="reg-1",
effective_from=ts,
external_source_forbidden=True,
)
def test_enterprise_requires_external_forbidden(self):
"""ENTERPRISE_CLEAN profile with external_source_forbidden=False raises (line 174)."""
from src.models.clean_release import CleanProfilePolicy, ProfileType
ts = datetime.now(timezone.utc)
with pytest.raises(ValueError, match="enterprise-clean policy requires external_source_forbidden=true"):
CleanProfilePolicy(
policy_id="p-err2", policy_version="1",
profile=ProfileType.ENTERPRISE_CLEAN,
active=True,
prohibited_artifact_categories=["test-data"],
internal_source_registry_ref="reg-1",
effective_from=ts,
external_source_forbidden=False,
)
class TestReleaseCandidate:
"""ReleaseCandidate — lifecycle and transitions."""
def test_with_status_enum(self):
from src.models.clean_release import ReleaseCandidate, ReleaseCandidateStatus
rc = ReleaseCandidate(
candidate_id="RC-002",
version="2.0.0",
source_snapshot_ref="snap-2",
created_by="admin",
status=ReleaseCandidateStatus.DRAFT,
)
assert rc.status == "DRAFT"
assert rc.candidate_id == "RC-002"
def test_with_candidate_status_enum(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(
candidate_id="RC-003",
version="3.0.0",
source_snapshot_ref="snap-3",
created_by="admin",
status=CandidateStatus.DRAFT,
)
assert rc.status == "DRAFT"
def test_transition_draft_to_prepared(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-010", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.DRAFT)
rc.transition_to(CandidateStatus.PREPARED)
assert rc.status == "PREPARED"
def test_transition_full_flow(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-020", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.DRAFT)
rc.transition_to(CandidateStatus.PREPARED)
rc.transition_to(CandidateStatus.MANIFEST_BUILT)
rc.transition_to(CandidateStatus.CHECK_PENDING)
rc.transition_to(CandidateStatus.CHECK_RUNNING)
rc.transition_to(CandidateStatus.CHECK_PASSED)
rc.transition_to(CandidateStatus.APPROVED)
rc.transition_to(CandidateStatus.PUBLISHED)
rc.transition_to(CandidateStatus.REVOKED)
assert rc.status == "REVOKED"
def test_transition_illegal_raises(self):
from src.models.clean_release import CandidateStatus, IllegalTransitionError, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-030", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.DRAFT)
with pytest.raises(IllegalTransitionError, match="Forbidden transition"):
rc.transition_to(CandidateStatus.APPROVED)
def test_transition_revoked_has_no_transitions(self):
from src.models.clean_release import CandidateStatus, IllegalTransitionError, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-040", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.REVOKED)
with pytest.raises(IllegalTransitionError):
rc.transition_to(CandidateStatus.DRAFT)
def test_transition_check_running_to_blocked(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-050", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.CHECK_RUNNING)
rc.transition_to(CandidateStatus.CHECK_BLOCKED)
assert rc.status == "CHECK_BLOCKED"
def test_transition_check_running_to_error(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-060", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.CHECK_RUNNING)
rc.transition_to(CandidateStatus.CHECK_ERROR)
assert rc.status == "CHECK_ERROR"
def test_transition_from_blocked_back_to_pending(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-070", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.CHECK_BLOCKED)
rc.transition_to(CandidateStatus.CHECK_PENDING)
assert rc.status == "CHECK_PENDING"
def test_transition_from_passed_to_pending(self):
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(candidate_id="RC-080", version="1.0.0",
source_snapshot_ref="snap", created_by="u",
status=CandidateStatus.CHECK_PASSED)
rc.transition_to(CandidateStatus.CHECK_PENDING)
assert rc.status == "CHECK_PENDING"
# ── Lines 262, 265, 269: ReleaseCandidate.__init__ edge cases ──
def test_init_pops_profile_kwarg(self):
"""ReleaseCandidate.__init__ silently pops profile kwarg (line 262)."""
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(
candidate_id="RC-PROF",
version="1.0.0",
source_snapshot_ref="snap",
created_by="u",
profile="should_be_removed",
status=CandidateStatus.DRAFT,
)
assert rc.candidate_id == "RC-PROF"
assert not hasattr(rc, "profile")
def test_init_defaults_status_when_none(self):
"""ReleaseCandidate.__init__ defaults to DRAFT when no status given (line 265)."""
from src.models.clean_release import CandidateStatus, ReleaseCandidate
rc = ReleaseCandidate(
candidate_id="RC-NOSTAT",
version="1.0.0",
source_snapshot_ref="snap",
created_by="u",
)
assert rc.status == CandidateStatus.DRAFT.value
def test_init_raises_on_empty_id(self):
"""ReleaseCandidate.__init__ raises ValueError on empty candidate_id (line 269)."""
from src.models.clean_release import ReleaseCandidate
with pytest.raises(ValueError, match="candidate_id must be non-empty"):
ReleaseCandidate(
candidate_id="",
version="1.0.0",
source_snapshot_ref="snap",
created_by="u",
)
def test_init_raises_on_blank_id(self):
"""ReleaseCandidate.__init__ raises ValueError on whitespace-only candidate_id."""
from src.models.clean_release import ReleaseCandidate
with pytest.raises(ValueError, match="candidate_id must be non-empty"):
ReleaseCandidate(
candidate_id=" ",
version="1.0.0",
source_snapshot_ref="snap",
created_by="u",
)
class TestDistributionManifest:
"""DistributionManifest — immutable manifest model."""
def test_minimal(self):
from src.models.clean_release import DistributionManifest
manifest = DistributionManifest(
id="m-1", candidate_id="c-1",
manifest_digest="digest1", artifacts_digest="ad1",
created_by="admin", source_snapshot_ref="snap-1",
content_json={"key": "value"},
manifest_version=1, immutable=True,
)
assert manifest.manifest_version == 1
assert manifest.manifest_id == "m-1"
assert manifest.deterministic_hash == "digest1"
assert manifest.summary.included_count == 0
def test_with_items_and_summary(self):
from src.models.clean_release import ClassificationType, DistributionManifest, ManifestItem, ManifestSummary
items = [ManifestItem(path="/file", category="bin", classification=ClassificationType.ALLOWED, reason="ok")]
summary = ManifestSummary(included_count=1, excluded_count=0, prohibited_detected_count=0)
manifest = DistributionManifest(
manifest_id="m-2", candidate_id="c-1",
deterministic_hash="hash1",
generated_at=datetime.now(timezone.utc),
generated_by="admin",
items=items, summary=summary,
)
assert manifest.manifest_digest == "hash1"
assert manifest.summary.included_count == 1
def test_id_mapping(self):
from src.models.clean_release import DistributionManifest
manifest = DistributionManifest(
manifest_id="m-1", candidate_id="c-1",
manifest_digest="d1", artifacts_digest="ad1",
created_by="admin", source_snapshot_ref="snap-1",
content_json={},
)
assert manifest.id == "m-1"
def test_immutable_default(self):
from src.models.clean_release import DistributionManifest
manifest = DistributionManifest(
id="m-imm", candidate_id="c-1",
manifest_digest="d1", artifacts_digest="ad1",
created_by="admin", source_snapshot_ref="snap-1",
content_json={}, immutable=True,
)
assert manifest.immutable is True
# ── Line 375: DistributionManifest.__init__ pops policy_id ──
def test_init_pops_policy_id_kwarg(self):
"""DistributionManifest.__init__ silently pops policy_id (line 375)."""
from src.models.clean_release import DistributionManifest
manifest = DistributionManifest(
manifest_id="m-pol", candidate_id="c-1",
deterministic_hash="hash1",
generated_at=datetime.now(timezone.utc),
generated_by="admin",
policy_id="should-be-popped",
)
assert manifest.manifest_id == "m-pol"
assert not hasattr(manifest, "policy_id")
# ── Line 380: DistributionManifest.__init__ validates items vs summary ──
def test_init_raises_on_mismatched_items_summary(self):
"""DistributionManifest raises ValueError when summary counts don't match items (line 380)."""
from src.models.clean_release import ClassificationType, DistributionManifest, ManifestItem, ManifestSummary
items = [ManifestItem(path="/f1", category="bin", classification=ClassificationType.ALLOWED, reason="ok")]
summary = ManifestSummary(included_count=2, excluded_count=0, prohibited_detected_count=0)
with pytest.raises(ValueError, match="manifest summary counts must match items size"):
DistributionManifest(
manifest_id="m-mismatch", candidate_id="c-1",
deterministic_hash="hash1",
generated_at=datetime.now(timezone.utc),
generated_by="admin",
items=items, summary=summary,
)
class TestComplianceRun:
"""ComplianceRun — operational record."""
def test_minimal(self):
from src.models.clean_release import ComplianceRun
run = ComplianceRun(
id="r-1", candidate_id="c-1",
manifest_id="m-1", manifest_digest="d1",
policy_snapshot_id="ps-1", registry_snapshot_id="rs-1",
requested_by="admin", status="PENDING",
)
assert run.check_run_id == "r-1"
assert run.status == "PENDING"
assert run.final_status is None
def test_with_final_status(self):
from src.models.clean_release import ComplianceRun
run = ComplianceRun(
id="r-2", candidate_id="c-1",
manifest_id="m-1", manifest_digest="d1",
policy_snapshot_id="ps-1", registry_snapshot_id="rs-1",
requested_by="admin", final_status="PASSED",
)
assert run.final_status == "PASSED"
assert run.task_id is None
class TestComplianceStageRun:
"""ComplianceStageRun — stage-level execution."""
def test_minimal(self):
from src.models.clean_release import ComplianceStageRun
stage = ComplianceStageRun(id="s-1", run_id="r-1", stage_name="DATA_PURITY", status="PASS")
assert stage.stage_name == "DATA_PURITY"
assert stage.status == "PASS"
class TestComplianceViolation:
"""ComplianceViolation — violation with legacy property mapping."""
def test_minimal(self):
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
id="v-1", run_id="r-1", stage_name="DATA_PURITY",
code="DP001", severity="MAJOR", message="Data issue",
)
assert violation.violation_id == "v-1"
assert violation.check_run_id == "r-1"
assert violation.code == "DP001"
assert violation.artifact_path is None
assert violation.remediation is None
assert violation.blocked_release is False
def test_with_legacy_kwargs(self):
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
violation_id="v-1",
check_run_id="r-1",
category="DATA_PURITY",
code="DP002",
severity="CRITICAL",
message="NPE",
location="/path/to/file",
remediation="Fix it",
blocked_release=True,
)
assert violation.id == "v-1"
assert violation.run_id == "r-1"
assert violation.stage_name == "DATA_PURITY"
assert violation.artifact_path == "/path/to/file"
assert violation.remediation == "Fix it"
assert violation.blocked_release is True
assert violation.category.value == "DATA_PURITY"
assert violation.location == "/path/to/file"
def test_category_setter(self):
from src.models.clean_release import ComplianceViolation, ViolationCategory
violation = ComplianceViolation(
id="v-1", run_id="r-1", stage_name="DATA_PURITY",
code="DP001", severity="MAJOR", message="Data issue",
)
violation.category = ViolationCategory.EXTERNAL_SOURCE
assert violation.stage_name == "EXTERNAL_SOURCE"
def test_violation_id_setter(self):
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
id="v-1", run_id="r-1", stage_name="DATA_PURITY",
code="DP001", severity="MAJOR", message="Data issue",
)
violation.violation_id = "v-2"
assert violation.id == "v-2"
def test_default_code_and_message(self):
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
id="v-3", run_id="r-1", stage_name="DATA_PURITY",
severity="MINOR", message="",
)
# When code not provided, defaults to LEGACY_VIOLATION
assert violation.code == "LEGACY_VIOLATION"
def test_detected_at_popped(self):
from src.models.clean_release import ComplianceViolation
# detected_at is popped (removed) in __init__, so it shouldn't be an attribute
violation = ComplianceViolation(
id="v-4", run_id="r-1", stage_name="DATA_PURITY",
severity="MINOR", message="test",
detected_at="2024-01-01", # should be popped
)
assert not hasattr(violation, "detected_at")
def test_message_defaults_to_stage_name(self):
"""When message is not provided, it defaults to stage_name."""
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
id="v-5", run_id="r-1", stage_name="SOURCE_ISOLATION",
severity="MAJOR", code="SI001",
# no message kwarg
)
# message should default to stage_name
assert violation.message == "SOURCE_ISOLATION"
def test_message_defaults_fallback(self):
"""When message is not provided, defaults to stage_name value."""
from src.models.clean_release import ComplianceViolation
violation = ComplianceViolation(
id="v-6", run_id="r-1", stage_name="SOURCE_ISOLATION",
severity="MAJOR", code="GEN001",
# no message kwarg
)
# Without 'message' kwarg, defaults to stage_name value
assert violation.message == "SOURCE_ISOLATION"
class TestComplianceReport:
"""ComplianceReport — immutable report with property access."""
def test_minimal(self):
from src.models.clean_release import ComplianceReport
report = ComplianceReport(
id="rep-1", run_id="r-1", candidate_id="c-1",
final_status="PASSED", summary_json={"key": "val"},
immutable=True,
)
assert report.report_id == "rep-1"
assert report.check_run_id == "r-1"
assert report.final_status == "PASSED"
assert report.immutable is True
def test_with_legacy_kwargs(self):
from src.models.clean_release import ComplianceReport
report = ComplianceReport(
report_id="rep-1",
check_run_id="r-1",
candidate_id="c-1",
final_status="PASSED",
operator_summary="All good",
structured_payload_ref="ref-1",
violations_count=0,
blocking_violations_count=0,
)
assert report.report_id == "rep-1"
assert report.check_run_id == "r-1"
assert report.operator_summary == "All good"
assert report.structured_payload_ref == "ref-1"
assert report.violations_count == 0
assert report.blocking_violations_count == 0
def test_blocked_without_violations_raises(self):
from src.models.clean_release import CheckFinalStatus, ComplianceReport
with pytest.raises(ValueError, match="blocked report requires blocking violations"):
ComplianceReport(
report_id="rep-2",
check_run_id="r-2",
candidate_id="c-2",
final_status=CheckFinalStatus.BLOCKED,
violations_count=0,
blocking_violations_count=0,
)
def test_blocked_with_violations_ok(self):
from src.models.clean_release import ComplianceDecision, ComplianceReport
report = ComplianceReport(
report_id="rep-3",
check_run_id="r-3",
candidate_id="c-3",
final_status=ComplianceDecision.BLOCKED,
operator_summary="Blocked",
violations_count=3,
blocking_violations_count=2,
)
assert report.final_status == "BLOCKED"
assert report.violations_count == 3
class TestApprovalDecision:
"""ApprovalDecision — approval record."""
def test_minimal(self):
from src.models.clean_release import ApprovalDecision
decision = ApprovalDecision(
id="a-1", candidate_id="c-1", report_id="r-1",
decision="APPROVED", decided_by="admin",
)
assert decision.decision == "APPROVED"
assert decision.comment is None
def test_with_comment(self):
from src.models.clean_release import ApprovalDecision
decision = ApprovalDecision(
id="a-2", candidate_id="c-1", report_id="r-1",
decision="REJECTED", decided_by="admin",
comment="Missing required artifacts",
)
assert decision.comment == "Missing required artifacts"
class TestPublicationRecord:
"""PublicationRecord — publication or revocation."""
def test_minimal(self):
from src.models.clean_release import PublicationRecord
record = PublicationRecord(
id="p-1", candidate_id="c-1", report_id="r-1",
published_by="admin", target_channel="registry",
status="ACTIVE",
)
assert record.status == "ACTIVE"
assert record.publication_ref is None
def test_with_all_fields(self):
from src.models.clean_release import PublicationRecord
record = PublicationRecord(
id="p-2", candidate_id="c-1", report_id="r-1",
published_by="admin", target_channel="registry",
publication_ref="pub-ref-1", status="REVOKED",
)
assert record.publication_ref == "pub-ref-1"
assert record.status == "REVOKED"
class TestCleanReleaseAuditLog:
"""CleanReleaseAuditLog — persistent audit log."""
def test_minimal(self):
from src.models.clean_release import CleanReleaseAuditLog
log = CleanReleaseAuditLog(
id="al-1", candidate_id="c-1",
action="TRANSITION", actor="admin",
)
assert log.id == "al-1"
assert log.action == "TRANSITION"
assert log.actor == "admin"
def test_with_details(self):
from src.models.clean_release import CleanReleaseAuditLog
log = CleanReleaseAuditLog(
id="al-2", candidate_id="c-1",
action="APPROVE", actor="admin",
details_json={"reason": "All checks passed"},
)
assert log.details_json["reason"] == "All checks passed"
def test_nullable_candidate_id(self):
from src.models.clean_release import CleanReleaseAuditLog
log = CleanReleaseAuditLog(id="al-3", action="SYSTEM", actor="system")
assert log.candidate_id is None
class TestSourceRegistrySnapshot:
"""SourceRegistrySnapshot — immutable registry snapshot."""
def test_minimal(self):
from src.models.clean_release import SourceRegistrySnapshot
snap = SourceRegistrySnapshot(
id="rs-1", registry_id="reg-1", registry_version="1.0",
allowed_hosts=["host1"], allowed_schemes=["https"],
allowed_source_types=["api"], immutable=True,
)
assert snap.registry_id == "reg-1"
assert snap.immutable is True
class TestCleanPolicySnapshot:
"""CleanPolicySnapshot — immutable policy snapshot."""
def test_minimal(self):
from src.models.clean_release import CleanPolicySnapshot
snap = CleanPolicySnapshot(
id="ps-1", policy_id="pol-1", policy_version="1",
content_json={"rules": []}, registry_snapshot_id="rs-1",
immutable=True,
)
assert snap.policy_id == "pol-1"
assert snap.immutable is True
class TestComplianceCheckRunProperties:
"""ComplianceCheckRun — property access and status mappings."""
def test_id_and_run_id(self):
from src.models.clean_release import (
CheckFinalStatus, CheckStageName, CheckStageResult, CheckStageStatus,
ComplianceCheckRun, ExecutionMode,
)
ts = datetime.now(timezone.utc)
run = ComplianceCheckRun(
check_run_id="run-1",
candidate_id="c-1",
policy_id="p-1",
started_at=ts,
triggered_by="admin",
execution_mode=ExecutionMode.TUI,
final_status=CheckFinalStatus.RUNNING,
checks=[
CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
],
)
assert run.id == "run-1"
assert run.run_id == "run-1"
assert run.status == "RUNNING"
def test_status_mapping_blocked(self):
from src.models.clean_release import (
CheckFinalStatus, CheckStageName, CheckStageResult, CheckStageStatus,
ComplianceCheckRun, ExecutionMode,
)
ts = datetime.now(timezone.utc)
run = ComplianceCheckRun(
check_run_id="run-2",
candidate_id="c-1",
policy_id="p-1",
started_at=ts,
triggered_by="admin",
execution_mode=ExecutionMode.API,
final_status=CheckFinalStatus.BLOCKED,
checks=[
CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
],
)
assert run.status == "FAILED"
def test_status_succeeded(self):
from src.models.clean_release import (
CheckFinalStatus, CheckStageName, CheckStageResult, CheckStageStatus,
ComplianceCheckRun, ExecutionMode,
)
ts = datetime.now(timezone.utc)
run = ComplianceCheckRun(
check_run_id="run-5",
candidate_id="c-1",
policy_id="p-1",
started_at=ts,
triggered_by="admin",
execution_mode=ExecutionMode.TUI,
final_status=CheckFinalStatus.COMPLIANT,
checks=[
CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.INTERNAL_SOURCES_ONLY, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.NO_EXTERNAL_ENDPOINTS, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.MANIFEST_CONSISTENCY, status=CheckStageStatus.PASS),
],
)
assert run.status == "SUCCEEDED"
# ── Lines 219, 221: ComplianceCheckRun COMPLIANT validation errors ──
def test_compliant_requires_all_stages(self):
"""COMPLIANT status with missing stages raises ValueError (line 219)."""
from src.models.clean_release import (
CheckFinalStatus, CheckStageName, CheckStageResult, CheckStageStatus,
ComplianceCheckRun, ExecutionMode,
)
ts = datetime.now(timezone.utc)
with pytest.raises(ValueError, match="compliant run requires all mandatory stages"):
ComplianceCheckRun(
check_run_id="run-err1",
candidate_id="c-1",
policy_id="p-1",
started_at=ts,
triggered_by="admin",
execution_mode=ExecutionMode.TUI,
final_status=CheckFinalStatus.COMPLIANT,
checks=[
CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
# Missing: INTERNAL_SOURCES_ONLY, NO_EXTERNAL_ENDPOINTS, MANIFEST_CONSISTENCY
],
)
def test_compliant_requires_all_pass(self):
"""COMPLIANT status with FAIL checks raises ValueError (line 221)."""
from src.models.clean_release import (
CheckFinalStatus, CheckStageName, CheckStageResult, CheckStageStatus,
ComplianceCheckRun, ExecutionMode,
)
ts = datetime.now(timezone.utc)
with pytest.raises(ValueError, match="compliant run requires PASS on all mandatory stages"):
ComplianceCheckRun(
check_run_id="run-err2",
candidate_id="c-1",
policy_id="p-1",
started_at=ts,
triggered_by="admin",
execution_mode=ExecutionMode.TUI,
final_status=CheckFinalStatus.COMPLIANT,
checks=[
CheckStageResult(stage=CheckStageName.DATA_PURITY, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.INTERNAL_SOURCES_ONLY, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.NO_EXTERNAL_ENDPOINTS, status=CheckStageStatus.PASS),
CheckStageResult(stage=CheckStageName.MANIFEST_CONSISTENCY, status=CheckStageStatus.FAIL),
],
)
class TestManifestItem:
"""ManifestItem — pydantic dataclass."""
def test_minimal(self):
from src.models.clean_release import ClassificationType, ManifestItem
item = ManifestItem(path="/file.txt", category="data", classification=ClassificationType.ALLOWED, reason="ok")
assert item.path == "/file.txt"
assert item.checksum is None
def test_with_checksum(self):
from src.models.clean_release import ClassificationType, ManifestItem
item = ManifestItem(path="/file.txt", category="data", classification=ClassificationType.REQUIRED_SYSTEM, reason="core", checksum="sha256:abc")
assert item.checksum == "sha256:abc"
class TestManifestSummary:
"""ManifestSummary — pydantic dataclass."""
def test_minimal(self):
from src.models.clean_release import ManifestSummary
summary = ManifestSummary(included_count=1, excluded_count=2, prohibited_detected_count=0)
assert summary.included_count == 1
assert summary.excluded_count == 2
# #endregion Test.Models.CleanRelease.Ext