This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 9316ed6df85 Allow fetching XCom with forward slash from the API and
escape it in the UI (#45134)
9316ed6df85 is described below
commit 9316ed6df85234ba7f36437152329d9b1a27424d
Author: Shahar Epstein <[email protected]>
AuthorDate: Sat Dec 21 19:41:16 2024 +0200
Allow fetching XCom with forward slash from the API and escape it in the UI
(#45134)
---
airflow/api_connexion/openapi/v1.yaml | 1 +
airflow/www/static/js/api/useTaskXcom.ts | 18 +++++++++--------
newsfragments/45134.bugfix.rst | 1 +
.../api_connexion/endpoints/test_xcom_endpoint.py | 23 ++++++++++++++++++----
4 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/airflow/api_connexion/openapi/v1.yaml
b/airflow/api_connexion/openapi/v1.yaml
index fcf41462d23..0ead649f421 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -5528,6 +5528,7 @@ components:
name: xcom_key
schema:
type: string
+ format: path
required: true
description: The XCom key.
diff --git a/airflow/www/static/js/api/useTaskXcom.ts
b/airflow/www/static/js/api/useTaskXcom.ts
index 403233285eb..d8758e60b90 100644
--- a/airflow/www/static/js/api/useTaskXcom.ts
+++ b/airflow/www/static/js/api/useTaskXcom.ts
@@ -57,14 +57,16 @@ export const useTaskXcomEntry = ({
}: TaskXcomProps) =>
useQuery(
["taskXcom", dagId, dagRunId, taskId, mapIndex, xcomKey, tryNumber],
- () =>
- axios.get<AxiosResponse, API.XCom>(
- getMetaValue("task_xcom_entry_api")
- .replace("_DAG_RUN_ID_", dagRunId)
- .replace("_TASK_ID_", taskId)
- .replace("_XCOM_KEY_", xcomKey),
- { params: { map_index: mapIndex, stringify: false } }
- ),
+ () => {
+ const taskXcomEntryApiUrl = getMetaValue("task_xcom_entry_api")
+ .replace("_DAG_RUN_ID_", dagRunId)
+ .replace("_TASK_ID_", taskId)
+ .replace("_XCOM_KEY_", encodeURIComponent(xcomKey));
+
+ return axios.get<AxiosResponse, API.XCom>(taskXcomEntryApiUrl, {
+ params: { map_index: mapIndex, stringify: false },
+ });
+ },
{
enabled: !!xcomKey,
}
diff --git a/newsfragments/45134.bugfix.rst b/newsfragments/45134.bugfix.rst
new file mode 100644
index 00000000000..09aaae23a34
--- /dev/null
+++ b/newsfragments/45134.bugfix.rst
@@ -0,0 +1 @@
+(v2 API & UI) Allow fetching XCom with forward slash from the API and escape
it in the UI
diff --git a/tests/api_connexion/endpoints/test_xcom_endpoint.py
b/tests/api_connexion/endpoints/test_xcom_endpoint.py
index 4f0072860fd..ba90e28f3ac 100644
--- a/tests/api_connexion/endpoints/test_xcom_endpoint.py
+++ b/tests/api_connexion/endpoints/test_xcom_endpoint.py
@@ -226,52 +226,67 @@ class TestGetXComEntry(TestXComEndpoint):
)
@pytest.mark.parametrize(
- "allowed, query, expected_status_or_value",
+ "allowed, query, expected_status_or_value, key",
[
pytest.param(
True,
"?deserialize=true",
"real deserialized TEST_VALUE",
+ "key",
id="true",
),
pytest.param(
False,
"?deserialize=true",
400,
+ "key",
id="disallowed",
),
pytest.param(
True,
"?deserialize=false",
"orm deserialized TEST_VALUE",
+ "key",
id="false-irrelevant",
),
pytest.param(
False,
"?deserialize=false",
"orm deserialized TEST_VALUE",
+ "key",
id="false",
),
pytest.param(
True,
"",
"orm deserialized TEST_VALUE",
+ "key",
id="default-irrelevant",
),
pytest.param(
False,
"",
"orm deserialized TEST_VALUE",
+ "key",
id="default",
),
+ pytest.param(
+ False,
+ "",
+ "orm deserialized TEST_VALUE",
+ "key/with/slashes",
+ id="key-with-slashes",
+ ),
],
)
@conf_vars({("core", "xcom_backend"):
"tests.api_connexion.endpoints.test_xcom_endpoint.CustomXCom"})
- def test_custom_xcom_deserialize(self, allowed: bool, query: str,
expected_status_or_value: int | str):
+ def test_custom_xcom_deserialize(
+ self, allowed: bool, query: str, expected_status_or_value: int | str,
key: str
+ ):
XCom = resolve_xcom_backend()
- self._create_xcom_entry("dag", "run", utcnow(), "task", "key",
backend=XCom)
+ self._create_xcom_entry("dag", "run", utcnow(), "task", key,
backend=XCom)
- url =
f"/api/v1/dags/dag/dagRuns/run/taskInstances/task/xcomEntries/key{query}"
+ url =
f"/api/v1/dags/dag/dagRuns/run/taskInstances/task/xcomEntries/{key}{query}"
with mock.patch("airflow.api_connexion.endpoints.xcom_endpoint.XCom",
XCom):
with conf_vars({("api", "enable_xcom_deserialize_support"):
str(allowed)}):
response = self.client.get(url,
environ_overrides={"REMOTE_USER": "test"})