test_enterprise_connector_metadata_frontend_contract.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. from pathlib import Path
  2. import re
  3. ROOT = Path(__file__).resolve().parents[1]
  4. COMPONENT = ROOT / "frontend/src/components/connectors/ConnectorOperations.vue"
  5. DATABASE_PAGE = ROOT / "frontend/src/views/dataGovernance/development/enterpriseConnectors.vue"
  6. def _method_block(source: str, name: str) -> str:
  7. match = re.search(rf"(?s)\b{name}\s*\([^)]*\)\s*\{{(.*?)(?=\n\s{{4}}\w+\s*\(|\n\s{{2}}\}}\n\}})", source)
  8. assert match, f"{name} method was not found"
  9. return match.group(0)
  10. def test_connector_operations_has_fail_closed_allowlist_for_manifests_and_runs():
  11. assert COMPONENT.is_file(), "ConnectorOperations shared surface is missing"
  12. source = COMPONENT.read_text(encoding="utf-8")
  13. assert re.search(
  14. r"connectorIds:\s*\{\s*type:\s*Array,\s*required:\s*true,.*?validator:",
  15. source,
  16. re.S,
  17. )
  18. assert "/^[a-z][a-z0-9_-]{2,63}$/" in source
  19. assert re.search(
  20. r"mode:\s*\{\s*type:\s*String,\s*required:\s*true,.*?database.*?rest-catalog",
  21. source,
  22. re.S,
  23. )
  24. normalized = _method_block(source, "normalizedConnectorIds")
  25. assert "Array.isArray(this.connectorIds)" in normalized
  26. assert "new Set" in normalized
  27. assert "return []" in normalized
  28. load_all = _method_block(source, "loadAll")
  29. empty_guard = load_all.index("if (!this.normalizedConnectorIds.length)")
  30. first_api_call = load_all.index("getConnectorManifests()")
  31. assert empty_guard < first_api_call
  32. assert "this.clearConnectorState()" in load_all[:first_api_call]
  33. clear_state = _method_block(source, "clearConnectorState")
  34. assert "this.manifests = []" in clear_state
  35. assert "this.runs = []" in clear_state
  36. assert "this.graph = {}" in clear_state
  37. assert "return" in load_all[empty_guard:first_api_call]
  38. assert "const allowedConnectorIds = new Set(this.normalizedConnectorIds)" in load_all
  39. assert "this.manifests = (manifests.data.manifests || []).filter(item => allowedConnectorIds.has(item.connector_id))" in load_all
  40. assert "this.runs = (runs.data.runs || []).filter(item => allowedConnectorIds.has(item.connector_id))" in load_all
  41. def test_database_wrapper_is_database_only_and_keeps_scope_warning():
  42. source = DATABASE_PAGE.read_text(encoding="utf-8")
  43. assert "rest-catalog" not in source
  44. assert "当前开放范围仅限数据库访问。文件目录、对象存储、API 与消息系统等来源将在后续版本扩展开发。" in source
  45. assert re.search(
  46. r"<connector-operations\s+:connector-ids=\"\['oracle', 'postgresql', 'sqlserver'\]\"\s+mode=\"database\"\s*/>",
  47. source,
  48. )