114 lines
4.7 KiB
Python
114 lines
4.7 KiB
Python
import importlib.util
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
|
|
spec = importlib.util.spec_from_file_location(
|
|
"debian_acceptance", Path(__file__).resolve().parents[1] / "deploy" / "debian_acceptance.py")
|
|
acceptance = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(acceptance)
|
|
|
|
COMMIT = "a" * 40
|
|
RELEASE_SHA = "b" * 64
|
|
|
|
|
|
def common(system):
|
|
return {
|
|
"schemaVersion": 1,
|
|
"system": system,
|
|
"evidenceId": acceptance.SYSTEMS[system]["evidenceId"],
|
|
"releaseVersion": "0.2.0",
|
|
"releaseCommit": COMMIT,
|
|
"releaseRecordSha256": RELEASE_SHA,
|
|
"archiveSha256": "c" * 64,
|
|
"environment": "https://sandbox-guestops.futuresens.co.uk",
|
|
"hostIdentifier": "guestops-sandbox-01",
|
|
"images": {
|
|
"api": {"reference": f"guestops-api:{COMMIT}", "id": "sha256:" + "d" * 64},
|
|
"worker": {"reference": f"guestops-worker:{COMMIT}", "id": "sha256:" + "e" * 64},
|
|
},
|
|
"operator": "Deployment operator",
|
|
"reviewedBy": "Independent reviewer",
|
|
"startedAt": "2026-09-30T09:00:00Z",
|
|
"endedAt": "2026-09-30T10:00:00Z",
|
|
"reviewedAt": "2026-09-30T11:00:00Z",
|
|
"unresolvedCriticalFindings": 0,
|
|
"scenarios": [
|
|
{"id": scenario, "status": "pass", "evidence": [f"restricted-{index}"]}
|
|
for index, scenario in enumerate(sorted(acceptance.SYSTEMS[system]["scenarios"]), 1)
|
|
],
|
|
}
|
|
|
|
|
|
def valid_records():
|
|
host = common("guestops-debian-host")
|
|
host["hostFacts"] = {
|
|
"debianMajor": 12,
|
|
"cpuCores": 4,
|
|
"memoryBytes": 8_140_382_208,
|
|
"freeDiskBytes": 14_275_686_400,
|
|
"publicTcpPorts": [80, 443],
|
|
}
|
|
host["featureControls"] = {
|
|
"googleSending": "disabled",
|
|
"faqLiveMode": "disabled",
|
|
"pmsWrites": "disabled",
|
|
"paymentCreation": "disabled",
|
|
}
|
|
persistence = common("guestops-persistence")
|
|
persistence["drillCommand"] = "python3 deploy/ops.py persistence-drill --confirm-restart"
|
|
return host, persistence
|
|
|
|
|
|
class DebianAcceptanceTests(unittest.TestCase):
|
|
def test_complete_matching_records_pass(self):
|
|
acceptance.validate_pair(*valid_records(), COMMIT, RELEASE_SHA)
|
|
|
|
def test_expected_release_identity_is_required(self):
|
|
host, persistence = valid_records()
|
|
host["releaseCommit"] = "f" * 40
|
|
with self.assertRaisesRegex(ValueError, "approved candidate"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
host, persistence = valid_records()
|
|
persistence["releaseRecordSha256"] = "f" * 64
|
|
with self.assertRaisesRegex(ValueError, "retained release record"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
|
|
def test_exact_images_and_cross_record_identity_are_required(self):
|
|
host, persistence = valid_records()
|
|
host["images"]["api"]["reference"] = "guestops-api:latest"
|
|
with self.assertRaisesRegex(ValueError, "full approved commit"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
host, persistence = valid_records()
|
|
persistence["archiveSha256"] = "f" * 64
|
|
with self.assertRaisesRegex(ValueError, "same archiveSha256"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
|
|
def test_host_capacity_ports_and_disabled_controls_are_required(self):
|
|
host, persistence = valid_records()
|
|
host["hostFacts"]["publicTcpPorts"] = [80, 443, 8080]
|
|
with self.assertRaisesRegex(ValueError, "Only TCP ports"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
host, persistence = valid_records()
|
|
host["featureControls"]["googleSending"] = "enabled"
|
|
with self.assertRaisesRegex(ValueError, "must remain disabled"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
|
|
def test_independent_review_scenarios_and_findings_are_required(self):
|
|
host, persistence = valid_records()
|
|
host["reviewedBy"] = host["operator"]
|
|
with self.assertRaisesRegex(ValueError, "different people"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
host, persistence = valid_records()
|
|
persistence["scenarios"][0]["status"] = "not-run"
|
|
with self.assertRaisesRegex(ValueError, "has not passed"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
host, persistence = valid_records()
|
|
host["unresolvedCriticalFindings"] = 1
|
|
with self.assertRaisesRegex(ValueError, "critical findings"):
|
|
acceptance.validate_pair(host, persistence, COMMIT, RELEASE_SHA)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|