fix(evidence): close canonical contract gaps
This commit is contained in:
@@ -176,7 +176,7 @@ def test_datetimes_must_be_aware_and_are_normalized_to_utc():
|
||||
|
||||
def test_source_errors_are_typed_retryable_and_safe():
|
||||
transient = EvidenceSourceError(
|
||||
"remote source unavailable",
|
||||
"password=hunter2 at https://user:secret@host",
|
||||
category=EvidenceSourceErrorCategory.TRANSIENT,
|
||||
details={"status": 503},
|
||||
)
|
||||
@@ -188,6 +188,16 @@ def test_source_errors_are_typed_retryable_and_safe():
|
||||
assert transient.retryable is True
|
||||
assert permanent.retryable is False
|
||||
assert transient.details["status"] == 503
|
||||
assert str(transient) == "evidence source operation failed"
|
||||
assert transient.args == ("evidence source operation failed",)
|
||||
assert "hunter2" not in repr(transient)
|
||||
with pytest.raises(AttributeError):
|
||||
transient.category = EvidenceSourceErrorCategory.PERMANENT
|
||||
with pytest.raises(AttributeError):
|
||||
transient.args = ("leak",)
|
||||
with pytest.raises(AttributeError):
|
||||
transient.details = {"unsafe": True}
|
||||
assert "hunter2" not in repr(transient.__dict__)
|
||||
with pytest.raises(TypeError):
|
||||
transient.details["status"] = 200
|
||||
with pytest.raises(ValueError, match="credential-like"):
|
||||
@@ -202,3 +212,28 @@ def test_source_errors_are_typed_retryable_and_safe():
|
||||
category=EvidenceSourceErrorCategory.PERMANENT,
|
||||
details={"not_json": object()},
|
||||
)
|
||||
|
||||
|
||||
def test_source_error_preserves_original_only_through_exception_chaining():
|
||||
cause = RuntimeError("transport diagnostic with password=hunter2")
|
||||
error = EvidenceSourceError(
|
||||
"ignored unsafe diagnostic",
|
||||
category=EvidenceSourceErrorCategory.TRANSIENT,
|
||||
)
|
||||
|
||||
try:
|
||||
raise error from cause
|
||||
except EvidenceSourceError as caught:
|
||||
assert caught.__cause__ is cause
|
||||
assert "hunter2" not in str(caught)
|
||||
assert "hunter2" not in caught.args
|
||||
|
||||
|
||||
def test_model_copy_revalidates_source_and_acquired_records():
|
||||
source = SourceObject(source_id="source:a", uri="file:///a", fingerprint="sha256:a")
|
||||
acquired = AcquiredDocument(source=source, content=b"a")
|
||||
|
||||
with pytest.raises(ValidationError, match="namespaced"):
|
||||
source.model_copy(update={"source_id": "invalid"})
|
||||
with pytest.raises(ValidationError, match="timezone-aware"):
|
||||
acquired.model_copy(update={"acquired_at": datetime(2026, 7, 12)})
|
||||
|
||||
Reference in New Issue
Block a user