test_bootstrap.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import pytest
  2. from app.core.mcp.bootstrap import (
  3. build_context_service,
  4. build_scheduling_gateway,
  5. )
  6. from app.core.mcp.context import ContextService
  7. from app.core.mcp.gateway import SchedulingGateway
  8. from app.core.mcp.persistence import PostgresContextRepository
  9. def scheduling_environment(monkeypatch):
  10. values = {
  11. "DATAOPS_MCP_DATABASE_URL": "postgresql://dataops:secret@db/dataops",
  12. "KESTRA_BASE_URL": "http://kestra:8080/api/v1",
  13. "KESTRA_USERNAME": "scheduler",
  14. "KESTRA_PASSWORD": "kestra-secret",
  15. "KESTRA_TENANT_ID": "main",
  16. "KESTRA_HTTP_TIMEOUT_SECONDS": "15",
  17. "RUNNER_TASK_TOKEN_SECRET": "x" * 32,
  18. "RUNNER_TASK_TOKEN_TTL_SECONDS": "60",
  19. }
  20. for key, value in values.items():
  21. monkeypatch.setenv(key, value)
  22. return values
  23. def test_scheduling_bootstrap_is_fail_closed_and_keeps_secrets_out_of_repr(
  24. monkeypatch,
  25. ):
  26. values = scheduling_environment(monkeypatch)
  27. gateway = build_scheduling_gateway()
  28. assert isinstance(gateway, SchedulingGateway)
  29. assert gateway.engine.base_url == values["KESTRA_BASE_URL"]
  30. assert gateway.engine.tenant_id == "main"
  31. rendered = repr(gateway)
  32. assert values["KESTRA_PASSWORD"] not in rendered
  33. assert values["RUNNER_TASK_TOKEN_SECRET"] not in rendered
  34. assert values["DATAOPS_MCP_DATABASE_URL"] not in rendered
  35. def test_scheduling_bootstrap_requires_every_security_dependency(monkeypatch):
  36. scheduling_environment(monkeypatch)
  37. monkeypatch.delenv("RUNNER_TASK_TOKEN_SECRET")
  38. with pytest.raises(ValueError, match="RUNNER_TASK_TOKEN_SECRET"):
  39. build_scheduling_gateway()
  40. def test_context_bootstrap_uses_the_persistent_read_model(monkeypatch):
  41. monkeypatch.setenv(
  42. "DATAOPS_MCP_DATABASE_URL",
  43. "postgresql://dataops:secret@db/dataops",
  44. )
  45. service = build_context_service()
  46. assert isinstance(service, ContextService)
  47. assert isinstance(service.repository, PostgresContextRepository)
  48. assert "postgresql://dataops:secret" not in repr(service)
  49. @pytest.mark.parametrize(
  50. ("name", "value"),
  51. [
  52. ("KESTRA_HTTP_TIMEOUT_SECONDS", "0"),
  53. ("KESTRA_HTTP_TIMEOUT_SECONDS", "301"),
  54. ("RUNNER_TASK_TOKEN_TTL_SECONDS", "0"),
  55. ("RUNNER_TASK_TOKEN_TTL_SECONDS", "301"),
  56. ],
  57. )
  58. def test_scheduling_bootstrap_rejects_unsafe_numeric_limits(monkeypatch, name, value):
  59. scheduling_environment(monkeypatch)
  60. monkeypatch.setenv(name, value)
  61. with pytest.raises(ValueError, match=name):
  62. build_scheduling_gateway()