Files
gh-christianlouis-dmarq/backend/app/tests/test_ticketing_chatops_templates.py
2026-05-23 18:46:18 +02:00

102 lines
4.0 KiB
Python

import json
from fastapi.testclient import TestClient
from app.services.ticketing_chatops_templates import (
TICKETING_CHATOPS_SCHEMA_VERSION,
WORKFLOW_EVENT_TYPES,
get_ticketing_chatops_templates,
validate_workflow_template_bundle,
)
from app.services.webhook_events import EVENT_ALERT_RESOLVED, EVENT_COMPLIANCE_DROP
def _string_values(value):
if isinstance(value, dict):
for item in value.values():
yield from _string_values(item)
elif isinstance(value, list):
for item in value:
yield from _string_values(item)
elif isinstance(value, str):
yield value
def test_ticketing_chatops_bundle_is_versioned_and_complete():
"""Workflow templates cover every ticketing/chatops event type."""
bundle = get_ticketing_chatops_templates()
assert bundle["schema_version"] == TICKETING_CHATOPS_SCHEMA_VERSION
assert sorted(bundle["event_types"]) == sorted(WORKFLOW_EVENT_TYPES)
assert validate_workflow_template_bundle(bundle) == []
assert bundle["event_workflow_mappings"][EVENT_COMPLIANCE_DROP]["severity"] == "high"
assert (
bundle["event_workflow_mappings"][EVENT_ALERT_RESOLVED]["ticket_action"]
== "resolve_or_comment"
)
def test_ticketing_chatops_templates_have_no_embedded_credentials():
"""Examples must be safe to publish without leaking destination credentials."""
bundle = get_ticketing_chatops_templates()
encoded_values = json.dumps(list(_string_values(bundle))).lower()
for forbidden in ["xoxb-", "ghp_", "jira_pat", "incoming_webhook", "bearer "]:
assert forbidden not in encoded_values
def test_ticketing_chatops_validation_reports_template_drift():
"""Validator explains missing required workflow and destination fields."""
bundle = get_ticketing_chatops_templates()
bundle["schema_version"] = "unexpected"
bundle["event_types"] = [EVENT_COMPLIANCE_DROP]
bundle["event_workflow_mappings"][EVENT_COMPLIANCE_DROP].pop("dedupe_key_template")
bundle["event_workflow_mappings"][EVENT_COMPLIANCE_DROP].pop("owner")
bundle["event_workflow_mappings"][EVENT_COMPLIANCE_DROP].pop("ticket_action")
bundle["payload_templates"].pop("slack")
errors = validate_workflow_template_bundle(bundle)
assert "schema_version must be dmarq.workflow.template.v1" in errors
assert "event_types must match supported workflow events" in errors
assert f"{EVENT_COMPLIANCE_DROP} is missing a dedupe key template" in errors
assert f"{EVENT_COMPLIANCE_DROP} is missing an owner" in errors
assert f"{EVENT_COMPLIANCE_DROP} is missing a ticket action" in errors
assert "missing payload template: slack" in errors
def test_ticketing_chatops_templates_return_independent_copies():
"""Mutating one returned bundle does not alter future callers."""
bundle = get_ticketing_chatops_templates()
bundle["payload_templates"]["jira"]["operation"] = "mutated"
fresh_bundle = get_ticketing_chatops_templates()
assert fresh_bundle["payload_templates"]["jira"]["operation"] == "create_or_update_issue"
def test_ticketing_chatops_endpoint_returns_workflow_templates(
authed_client: TestClient,
):
"""Administrators can fetch issue and chat message templates."""
response = authed_client.get("/api/v1/integrations/ticketing-chatops/templates")
assert response.status_code == 200
body = response.json()
assert body["schema_version"] == TICKETING_CHATOPS_SCHEMA_VERSION
assert set(body["payload_templates"]) == {
"jira",
"github",
"slack",
"microsoft_teams",
}
assert body["payload_templates"]["jira"]["operation"] == "create_or_update_issue"
assert body["payload_templates"]["slack"]["thread_key"] == "{dedupe_key}"
def test_ticketing_chatops_endpoint_requires_admin_auth(client: TestClient):
"""Workflow templates use the same admin boundary as integration settings."""
response = client.get("/api/v1/integrations/ticketing-chatops/templates")
assert response.status_code == 401