feat: add MSP workspace operator views
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.alert import AlertHistory
|
||||
from app.models.domain import Domain
|
||||
from app.models.mail_source import MailSource
|
||||
from app.models.mail_source_import import MailSourceImport
|
||||
from app.models.report import DMARCReport
|
||||
from app.models.workspace import Workspace
|
||||
from app.models.workspace_access import WorkspaceAuditLog
|
||||
|
||||
|
||||
def _workspace(db_session: Session, slug: str, name: str) -> Workspace:
|
||||
workspace = Workspace(slug=slug, name=name, active=True)
|
||||
db_session.add(workspace)
|
||||
db_session.flush()
|
||||
return workspace
|
||||
|
||||
|
||||
def test_operator_view_summarizes_each_workspace(
|
||||
authed_client: TestClient,
|
||||
db_session: Session,
|
||||
):
|
||||
"""MSP operators can see health, import, alert, drift, and retention summaries."""
|
||||
now = datetime.utcnow()
|
||||
alpha = _workspace(db_session, "alpha", "Alpha Client")
|
||||
beta = _workspace(db_session, "beta", "Beta Client")
|
||||
alpha_domain = Domain(
|
||||
workspace_id=alpha.id,
|
||||
name="alpha.example",
|
||||
active=True,
|
||||
verified=True,
|
||||
)
|
||||
beta_domain = Domain(
|
||||
workspace_id=beta.id,
|
||||
name="beta.example",
|
||||
active=True,
|
||||
verified=False,
|
||||
)
|
||||
alpha_source = MailSource(
|
||||
workspace_id=alpha.id,
|
||||
name="Alpha inbox",
|
||||
method="IMAP",
|
||||
enabled=True,
|
||||
)
|
||||
beta_source = MailSource(
|
||||
workspace_id=beta.id,
|
||||
name="Beta inbox",
|
||||
method="IMAP",
|
||||
enabled=False,
|
||||
)
|
||||
db_session.add_all([alpha_domain, beta_domain, alpha_source, beta_source])
|
||||
db_session.flush()
|
||||
db_session.add_all(
|
||||
[
|
||||
DMARCReport(
|
||||
domain_id=alpha_domain.id,
|
||||
report_id="alpha-report",
|
||||
org_name="Google",
|
||||
begin_date=1,
|
||||
end_date=2,
|
||||
),
|
||||
MailSourceImport(
|
||||
mail_source_id=alpha_source.id,
|
||||
trigger="manual",
|
||||
status="success",
|
||||
finished_at=now,
|
||||
),
|
||||
MailSourceImport(
|
||||
mail_source_id=beta_source.id,
|
||||
trigger="manual",
|
||||
status="failed",
|
||||
finished_at=now,
|
||||
),
|
||||
AlertHistory(
|
||||
fingerprint="beta-alert",
|
||||
rule="missing_reports",
|
||||
severity="warning",
|
||||
domain="beta.example",
|
||||
title="Missing reports",
|
||||
detail="No reports received",
|
||||
is_active=True,
|
||||
),
|
||||
WorkspaceAuditLog(
|
||||
workspace_id=beta.id,
|
||||
actor_type="api_key",
|
||||
action="mail_source.updated",
|
||||
entity_type="mail_source",
|
||||
entity_name="Beta inbox",
|
||||
created_at=now - timedelta(days=1),
|
||||
),
|
||||
]
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
response = authed_client.get("/api/v1/operator/workspaces")
|
||||
|
||||
assert response.status_code == 200
|
||||
by_slug = {item["workspace"]["slug"]: item for item in response.json()["workspaces"]}
|
||||
assert by_slug["alpha"]["health"]["status"] == "healthy"
|
||||
assert by_slug["alpha"]["reports"]["aggregate_total"] == 1
|
||||
assert by_slug["alpha"]["mail_sources"]["last_import_status"] == "success"
|
||||
assert by_slug["beta"]["health"]["status"] == "critical"
|
||||
assert by_slug["beta"]["health"]["active_alerts"] == 1
|
||||
assert by_slug["beta"]["health"]["failed_imports_7d"] == 1
|
||||
assert by_slug["beta"]["health"]["drift_events_7d"] == 1
|
||||
assert by_slug["beta"]["recent_drift"][0]["action"] == "mail_source.updated"
|
||||
|
||||
|
||||
def test_operator_view_does_not_include_inactive_workspaces(
|
||||
authed_client: TestClient,
|
||||
db_session: Session,
|
||||
):
|
||||
"""Inactive workspaces are not listed in the cross-workspace operator view."""
|
||||
_workspace(db_session, "active", "Active Client")
|
||||
inactive = Workspace(slug="inactive", name="Inactive Client", active=False)
|
||||
db_session.add(inactive)
|
||||
db_session.commit()
|
||||
|
||||
response = authed_client.get("/api/v1/operator/workspaces")
|
||||
|
||||
assert response.status_code == 200
|
||||
slugs = {item["workspace"]["slug"] for item in response.json()["workspaces"]}
|
||||
assert slugs == {"active"}
|
||||
|
||||
|
||||
def test_workspace_retention_update_is_audited(
|
||||
authed_client: TestClient,
|
||||
db_session: Session,
|
||||
):
|
||||
"""Operators can update workspace retention controls with an audit record."""
|
||||
workspace = _workspace(db_session, "client", "Client")
|
||||
db_session.commit()
|
||||
|
||||
response = authed_client.put(
|
||||
f"/api/v1/operator/workspaces/{workspace.id}/retention",
|
||||
json={
|
||||
"aggregate_reports_days": 730,
|
||||
"forensic_reports_days": 120,
|
||||
"tls_reports_days": 365,
|
||||
},
|
||||
headers={"x-forwarded-for": "203.0.113.9"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
db_session.refresh(workspace)
|
||||
assert workspace.report_retention_days == 730
|
||||
assert workspace.forensic_retention_days == 120
|
||||
assert workspace.tls_report_retention_days == 365
|
||||
assert response.json()["retention"]["aggregate_reports_days"] == 730
|
||||
|
||||
audit = (
|
||||
db_session.query(WorkspaceAuditLog)
|
||||
.filter(WorkspaceAuditLog.action == "workspace.retention_updated")
|
||||
.one()
|
||||
)
|
||||
assert audit.workspace_id == workspace.id
|
||||
assert audit.ip_address == "203.0.113.9"
|
||||
assert "730" in (audit.details or "")
|
||||
Reference in New Issue
Block a user