118 lines
4.2 KiB
Python
118 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, timedelta
|
|
import unittest
|
|
|
|
from govoplan_core.core.voting import (
|
|
VOTING_CERTIFICATION_CERTIFIED,
|
|
VOTING_CERTIFICATION_IN_EVALUATION,
|
|
VotingCapabilityError,
|
|
VotingProviderAssuranceDeclaration,
|
|
VotingResult,
|
|
require_voting_provider_assurance,
|
|
)
|
|
|
|
|
|
def result_with_evidence(*evidence):
|
|
return VotingResult(
|
|
ballot_id="ballot-1",
|
|
revision=2,
|
|
counts={"yes": 1},
|
|
weighted_counts={"yes": 1},
|
|
cast_count=1,
|
|
cast_weight=1,
|
|
eligible_count=1,
|
|
eligible_weight=1,
|
|
quorum_met=True,
|
|
threshold_met=True,
|
|
winning_options=("yes",),
|
|
result_sha256="a" * 64,
|
|
evidence=evidence,
|
|
)
|
|
|
|
|
|
class FakeProvider:
|
|
def __init__(self, declaration: VotingProviderAssuranceDeclaration) -> None:
|
|
self.declaration = declaration
|
|
|
|
def assurance_declaration(self) -> VotingProviderAssuranceDeclaration:
|
|
return self.declaration
|
|
|
|
def finalize_ballot(self, session, principal, *, request):
|
|
raise NotImplementedError
|
|
|
|
|
|
class VotingContractTests(unittest.TestCase):
|
|
def test_external_certification_requires_current_evidence_backed_claim(self) -> None:
|
|
now = datetime.now(UTC)
|
|
declaration = VotingProviderAssuranceDeclaration(
|
|
provider_id="certified_provider",
|
|
implementation_ref="certified-provider/adapter@1",
|
|
supported_assurance_profiles=("external_certified",),
|
|
certification_state=VOTING_CERTIFICATION_CERTIFIED,
|
|
protocol_ref="vendor:certified-ballot",
|
|
protocol_version="3.0",
|
|
certification_authority="Independent authority",
|
|
certification_reference="certificate-2026-1",
|
|
certification_evidence_ref="evidence://certificate-2026-1",
|
|
certification_valid_from=now - timedelta(days=1),
|
|
certification_valid_until=now + timedelta(days=1),
|
|
)
|
|
|
|
selected = require_voting_provider_assurance(
|
|
FakeProvider(declaration),
|
|
provider_id="certified_provider",
|
|
assurance_profile="external_certified",
|
|
at=now,
|
|
)
|
|
|
|
self.assertEqual("certificate-2026-1", selected.certification_reference)
|
|
self.assertEqual(
|
|
(now - timedelta(days=1)).isoformat(),
|
|
selected.to_dict()["certification_valid_from"],
|
|
)
|
|
|
|
def test_external_certification_rejects_evaluation_only_provider(self) -> None:
|
|
declaration = VotingProviderAssuranceDeclaration(
|
|
provider_id="candidate_provider",
|
|
implementation_ref="candidate-provider/adapter@1",
|
|
supported_assurance_profiles=("external_certified",),
|
|
certification_state=VOTING_CERTIFICATION_IN_EVALUATION,
|
|
protocol_ref="vendor:candidate-ballot",
|
|
protocol_version="1.0",
|
|
)
|
|
|
|
with self.assertRaisesRegex(VotingCapabilityError, "currently valid"):
|
|
require_voting_provider_assurance(
|
|
FakeProvider(declaration),
|
|
provider_id="candidate_provider",
|
|
assurance_profile="external_certified",
|
|
)
|
|
|
|
def test_accepts_sanitized_provider_evidence(self) -> None:
|
|
value = result_with_evidence(
|
|
{
|
|
"kind": "reference_provider_result",
|
|
"provider_id": "local_confidential",
|
|
"certified": False,
|
|
}
|
|
)
|
|
|
|
self.assertEqual("local_confidential", value.evidence[0]["provider_id"])
|
|
|
|
def test_rejects_secret_or_raw_selection_evidence(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "sensitive field"):
|
|
result_with_evidence({"access_token": "not-for-projection"})
|
|
with self.assertRaisesRegex(ValueError, "sensitive field"):
|
|
result_with_evidence({"nested": {"selections": ["yes"]}})
|
|
|
|
def test_rejects_non_json_or_oversized_evidence(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "bounded JSON"):
|
|
result_with_evidence({"value": b"binary"})
|
|
with self.assertRaisesRegex(ValueError, "size limit"):
|
|
result_with_evidence({"value": "x" * (64 * 1024)})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|