feat(cloud-api): add correlated lifecycle logging
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from cloud.observability import redact_sensitive_fields
|
||||
|
||||
|
||||
def test_sensitive_payload_fields_are_redacted_recursively() -> None:
|
||||
payload = {
|
||||
"authorization": "Bearer secret",
|
||||
"task_id": "task-a",
|
||||
"result": {
|
||||
"screenshot": "base64-data",
|
||||
"ui_tree": {"typed_text": "private input"},
|
||||
},
|
||||
}
|
||||
|
||||
redacted = redact_sensitive_fields(payload)
|
||||
|
||||
assert redacted == {
|
||||
"authorization": "[REDACTED]",
|
||||
"task_id": "task-a",
|
||||
"result": {
|
||||
"screenshot": "[REDACTED]",
|
||||
"ui_tree": "[REDACTED]",
|
||||
},
|
||||
}
|
||||
@@ -1145,3 +1145,69 @@ def test_unexpired_lease_is_not_reaped(database_url: str) -> None:
|
||||
assert device_id in database.repository.list_reserved_device_ids(now=now)
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
|
||||
def test_task_lifecycle_logs_structured_identifiers(
|
||||
database_url: str, monkeypatch
|
||||
) -> None:
|
||||
import cloud.sql_repository as repository_module
|
||||
|
||||
database = CloudDatabase(database_url)
|
||||
now = datetime(2026, 7, 12, 20, 0, tzinfo=UTC)
|
||||
host_id = _unique_id("log-host")
|
||||
device_id = _unique_id("log-device")
|
||||
task_id = _unique_id("log-task")
|
||||
events: list[dict[str, object]] = []
|
||||
|
||||
def record_info(_message: str, *, extra: dict[str, object]) -> None:
|
||||
events.append(extra)
|
||||
|
||||
monkeypatch.setattr(repository_module.logger, "info", record_info)
|
||||
try:
|
||||
database.repository.upsert_host(host_id, address=None, last_seen_at=now)
|
||||
database.repository.replace_host_devices(
|
||||
host_id,
|
||||
[_device(device_id, host_id)],
|
||||
)
|
||||
database.repository.enqueue_task(
|
||||
ScheduledTask(
|
||||
id=task_id,
|
||||
goal="sensitive typed text",
|
||||
workflow_definition_id=None,
|
||||
constraints=TaskConstraints(),
|
||||
created_at=now,
|
||||
)
|
||||
)
|
||||
database.repository.assign_task(
|
||||
task_id=task_id,
|
||||
host_id=host_id,
|
||||
device_id=device_id,
|
||||
lease_id="log-lease",
|
||||
lease_expires_at=now + timedelta(minutes=1),
|
||||
now=now,
|
||||
)
|
||||
database.repository.claim_assignment(host_id=host_id, now=now)
|
||||
database.repository.record_task_result(
|
||||
task_id=task_id,
|
||||
attempt=1,
|
||||
lease_id="log-lease",
|
||||
host_id=host_id,
|
||||
status="done",
|
||||
failure_reason=None,
|
||||
terminal_result={"screenshot": "secret-image"},
|
||||
completed_at=now + timedelta(seconds=1),
|
||||
)
|
||||
|
||||
assert [event["event"] for event in events] == [
|
||||
"assigned",
|
||||
"claimed",
|
||||
"completed",
|
||||
]
|
||||
assert all(event["task_id"] == task_id for event in events)
|
||||
assert all(event["host_id"] == host_id for event in events)
|
||||
assert all(event["device_id"] == device_id for event in events)
|
||||
assert all(event["correlation_id"] for event in events)
|
||||
assert "sensitive typed text" not in repr(events)
|
||||
assert "secret-image" not in repr(events)
|
||||
finally:
|
||||
database.close()
|
||||
|
||||
Reference in New Issue
Block a user