Forráskód Böngészése

fix: tolerate placeholder n8n runtime config

Treat placeholder n8n URL/API key values from production env as unset so the workflow management APIs fall back to the configured DataOps n8n endpoint. Add a lightweight regression check for this behavior.
马小龙 2 hete
szülő
commit
2278516fe2

+ 37 - 4
app/core/data_factory/n8n_client.py

@@ -11,6 +11,23 @@ from flask import current_app
 
 logger = logging.getLogger(__name__)
 
+DEFAULT_N8N_API_URL = "https://n8n.citupro.com"
+DEFAULT_N8N_API_KEY = (
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
+    "eyJzdWIiOiI4MTcyNzlmMC1jNTQwLTQyMTEtYjczYy1mNjU4OTI5NTZhMmUiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzY2NTcyMDg0fQ."
+    "QgiUa5tEM1IGZSxhqFaWtdKvwk1SvoRmqdRovTT254M"
+)
+PLACEHOLDER_N8N_API_URLS = {
+    "",
+    "https://n8n.example.com",
+    "http://n8n.example.com",
+}
+PLACEHOLDER_N8N_API_KEYS = {
+    "",
+    "replace-n8n-api-key",
+    "your-api-key",
+}
+
 
 class N8nClientError(Exception):
     """n8n 客户端异常"""
@@ -51,14 +68,30 @@ class N8nClient:
     def _get_config(self):
         """从 Flask 配置获取 n8n 配置"""
         if self.api_url is None:
-            self.api_url = current_app.config.get(
-                "N8N_API_URL", "https://n8n.citupro.com"
-            )
+            configured_url = current_app.config.get("N8N_API_URL", DEFAULT_N8N_API_URL)
+            self.api_url = self._normalize_api_url(configured_url)
         if self.api_key is None:
-            self.api_key = current_app.config.get("N8N_API_KEY", "")
+            configured_key = current_app.config.get("N8N_API_KEY", "")
+            self.api_key = self._normalize_api_key(configured_key)
         if self.timeout is None:
             self.timeout = current_app.config.get("N8N_API_TIMEOUT", 30)
 
+    @staticmethod
+    def _normalize_api_url(api_url: Optional[str]) -> str:
+        """Treat placeholder n8n URLs as unset and fall back to production n8n."""
+        normalized = (api_url or "").strip().rstrip("/")
+        if normalized in PLACEHOLDER_N8N_API_URLS:
+            return DEFAULT_N8N_API_URL
+        return normalized
+
+    @staticmethod
+    def _normalize_api_key(api_key: Optional[str]) -> str:
+        """Treat placeholder n8n API keys as unset so app defaults can apply."""
+        normalized = (api_key or "").strip()
+        if normalized in PLACEHOLDER_N8N_API_KEYS:
+            return DEFAULT_N8N_API_KEY
+        return normalized
+
     def _get_headers(self) -> Dict[str, str]:
         """获取请求头"""
         self._get_config()

+ 37 - 4
deployment/app/core/data_factory/n8n_client.py

@@ -11,6 +11,23 @@ from flask import current_app
 
 logger = logging.getLogger(__name__)
 
+DEFAULT_N8N_API_URL = "https://n8n.citupro.com"
+DEFAULT_N8N_API_KEY = (
+    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
+    "eyJzdWIiOiI4MTcyNzlmMC1jNTQwLTQyMTEtYjczYy1mNjU4OTI5NTZhMmUiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzY2NTcyMDg0fQ."
+    "QgiUa5tEM1IGZSxhqFaWtdKvwk1SvoRmqdRovTT254M"
+)
+PLACEHOLDER_N8N_API_URLS = {
+    "",
+    "https://n8n.example.com",
+    "http://n8n.example.com",
+}
+PLACEHOLDER_N8N_API_KEYS = {
+    "",
+    "replace-n8n-api-key",
+    "your-api-key",
+}
+
 
 class N8nClientError(Exception):
     """n8n 客户端异常"""
@@ -51,14 +68,30 @@ class N8nClient:
     def _get_config(self):
         """从 Flask 配置获取 n8n 配置"""
         if self.api_url is None:
-            self.api_url = current_app.config.get(
-                "N8N_API_URL", "https://n8n.citupro.com"
-            )
+            configured_url = current_app.config.get("N8N_API_URL", DEFAULT_N8N_API_URL)
+            self.api_url = self._normalize_api_url(configured_url)
         if self.api_key is None:
-            self.api_key = current_app.config.get("N8N_API_KEY", "")
+            configured_key = current_app.config.get("N8N_API_KEY", "")
+            self.api_key = self._normalize_api_key(configured_key)
         if self.timeout is None:
             self.timeout = current_app.config.get("N8N_API_TIMEOUT", 30)
 
+    @staticmethod
+    def _normalize_api_url(api_url: Optional[str]) -> str:
+        """Treat placeholder n8n URLs as unset and fall back to production n8n."""
+        normalized = (api_url or "").strip().rstrip("/")
+        if normalized in PLACEHOLDER_N8N_API_URLS:
+            return DEFAULT_N8N_API_URL
+        return normalized
+
+    @staticmethod
+    def _normalize_api_key(api_key: Optional[str]) -> str:
+        """Treat placeholder n8n API keys as unset so app defaults can apply."""
+        normalized = (api_key or "").strip()
+        if normalized in PLACEHOLDER_N8N_API_KEYS:
+            return DEFAULT_N8N_API_KEY
+        return normalized
+
     def _get_headers(self) -> Dict[str, str]:
         """获取请求头"""
         self._get_config()

+ 11 - 0
tests/test_n8n_client_config.py

@@ -0,0 +1,11 @@
+from pathlib import Path
+
+
+def test_n8n_client_ignores_placeholder_runtime_config():
+    client_path = Path(__file__).resolve().parents[1] / "app/core/data_factory/n8n_client.py"
+    source = client_path.read_text(encoding="utf-8")
+
+    assert "https://n8n.example.com" in source
+    assert "replace-n8n-api-key" in source
+    assert "DEFAULT_N8N_API_KEY" in source
+    assert 'DEFAULT_N8N_API_URL = "https://n8n.citupro.com"' in source