feat(cloud): add edge host enrollment
This commit is contained in:
@@ -14,7 +14,14 @@ from cloud.database import CloudDatabase
|
||||
from cloud.db_models import TaskAttemptRow
|
||||
from cloud.plugins import PluginManifest
|
||||
from cloud.pool import PooledDevice
|
||||
from cloud.repository import CloudRepository, LeasedAssignment, TaskAttemptRecord
|
||||
from cloud.repository import (
|
||||
CloudRepository,
|
||||
DeviceEnrollmentConflictError,
|
||||
EnrollmentTokenConflictError,
|
||||
HostEnrollmentConflictError,
|
||||
LeasedAssignment,
|
||||
TaskAttemptRecord,
|
||||
)
|
||||
from cloud.scheduler import ScheduledTask, TaskConstraints
|
||||
|
||||
|
||||
@@ -53,6 +60,13 @@ def test_cloud_repository_exposes_crud_and_atomic_lease_operations() -> None:
|
||||
members = get_protocol_members(CloudRepository)
|
||||
|
||||
assert {
|
||||
"enroll_host",
|
||||
"authenticate_enrolled_host",
|
||||
"revoke_enrolled_host",
|
||||
"is_enrollment_managed_host",
|
||||
"enroll_device",
|
||||
"get_device_enrollment",
|
||||
"list_device_enrollments",
|
||||
"upsert_host",
|
||||
"replace_host_devices",
|
||||
"list_hosts",
|
||||
@@ -76,6 +90,134 @@ def test_repository_transfer_records_are_immutable() -> None:
|
||||
assert LeasedAssignment.__dataclass_params__.frozen is True
|
||||
|
||||
|
||||
def test_host_enrollment_is_idempotent_and_token_is_one_time(
|
||||
database_url: str,
|
||||
) -> None:
|
||||
database = CloudDatabase(database_url)
|
||||
repository = database.repository
|
||||
enrolled_at = datetime(2026, 7, 13, 4, 0, tzinfo=UTC)
|
||||
host_id = _unique_id("managed-host")
|
||||
agent_instance_id = _unique_id("agent-instance")
|
||||
credential_digest = _unique_id("credential-digest")
|
||||
enrollment_digest = _unique_id("enrollment-digest")
|
||||
|
||||
try:
|
||||
created = repository.enroll_host(
|
||||
host_id=host_id,
|
||||
agent_instance_id=agent_instance_id,
|
||||
credential_digest=credential_digest,
|
||||
enrollment_token_digest=enrollment_digest,
|
||||
display_name="Edge Mac",
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
assert created.host_id == host_id
|
||||
assert created.agent_instance_id == agent_instance_id
|
||||
assert created.display_name == "Edge Mac"
|
||||
assert created.enrolled_at == enrolled_at
|
||||
assert repository.is_enrollment_managed_host(host_id) is True
|
||||
assert repository.authenticate_enrolled_host(credential_digest) == host_id
|
||||
|
||||
retried = repository.enroll_host(
|
||||
host_id=_unique_id("ignored-host"),
|
||||
agent_instance_id=agent_instance_id,
|
||||
credential_digest=credential_digest,
|
||||
enrollment_token_digest=enrollment_digest,
|
||||
display_name="Renamed Edge Mac",
|
||||
enrolled_at=enrolled_at + timedelta(minutes=1),
|
||||
)
|
||||
assert retried == created
|
||||
|
||||
with pytest.raises(HostEnrollmentConflictError):
|
||||
repository.enroll_host(
|
||||
host_id=_unique_id("host"),
|
||||
agent_instance_id=agent_instance_id,
|
||||
credential_digest=_unique_id("different-credential"),
|
||||
enrollment_token_digest=enrollment_digest,
|
||||
display_name=None,
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
|
||||
with pytest.raises(EnrollmentTokenConflictError):
|
||||
repository.enroll_host(
|
||||
host_id=_unique_id("host"),
|
||||
agent_instance_id=_unique_id("different-instance"),
|
||||
credential_digest=_unique_id("credential"),
|
||||
enrollment_token_digest=enrollment_digest,
|
||||
display_name=None,
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
|
||||
assert repository.revoke_enrolled_host(
|
||||
host_id,
|
||||
revoked_at=enrolled_at + timedelta(hours=1),
|
||||
)
|
||||
assert repository.authenticate_enrolled_host(credential_digest) is None
|
||||
assert repository.get_host(host_id) is not None
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def test_device_enrollment_is_host_scoped_and_idempotent(
|
||||
database_url: str,
|
||||
) -> None:
|
||||
database = CloudDatabase(database_url)
|
||||
repository = database.repository
|
||||
enrolled_at = datetime(2026, 7, 13, 5, 0, tzinfo=UTC)
|
||||
host_a = _unique_id("host-a")
|
||||
host_b = _unique_id("host-b")
|
||||
local_device_id = _unique_id("local-device")
|
||||
|
||||
try:
|
||||
device_a = repository.enroll_device(
|
||||
device_id=_unique_id("cloud-device"),
|
||||
host_id=host_a,
|
||||
local_device_id=local_device_id,
|
||||
driver_type="wda",
|
||||
name="iPhone",
|
||||
capability_tags=["ios"],
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
retried = repository.enroll_device(
|
||||
device_id=_unique_id("ignored-device"),
|
||||
host_id=host_a,
|
||||
local_device_id=local_device_id,
|
||||
driver_type="wda",
|
||||
name="Renamed iPhone",
|
||||
capability_tags=["ios", "physical"],
|
||||
enrolled_at=enrolled_at + timedelta(minutes=1),
|
||||
)
|
||||
assert retried.device_id == device_a.device_id
|
||||
assert retried.name == "Renamed iPhone"
|
||||
assert retried.capability_tags == ["ios", "physical"]
|
||||
assert repository.get_device_enrollment(device_a.device_id) == retried
|
||||
assert repository.list_device_enrollments(host_a) == [retried]
|
||||
|
||||
device_b = repository.enroll_device(
|
||||
device_id=_unique_id("cloud-device"),
|
||||
host_id=host_b,
|
||||
local_device_id=local_device_id,
|
||||
driver_type="wda",
|
||||
name="Moved iPhone",
|
||||
capability_tags=[],
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
assert device_b.device_id != device_a.device_id
|
||||
assert device_b.host_id == host_b
|
||||
|
||||
with pytest.raises(DeviceEnrollmentConflictError):
|
||||
repository.enroll_device(
|
||||
device_id=_unique_id("device"),
|
||||
host_id=host_a,
|
||||
local_device_id=local_device_id,
|
||||
driver_type="android",
|
||||
name=None,
|
||||
capability_tags=[],
|
||||
enrolled_at=enrolled_at,
|
||||
)
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def test_repository_crud_contract(database_url: str) -> None:
|
||||
database = CloudDatabase(database_url)
|
||||
repository = database.repository
|
||||
|
||||
Reference in New Issue
Block a user