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 8d4f6592b34 Align key/id path validation for variables and connections
(#63897)
8d4f6592b34 is described below
commit 8d4f6592b34e6c7e9057be8983e19ea3e58dcff9
Author: Henry Chen <[email protected]>
AuthorDate: Fri Mar 20 19:46:19 2026 +0800
Align key/id path validation for variables and connections (#63897)
---
.../execution_api/routes/connections.py | 5 +++--
.../api_fastapi/execution_api/routes/variables.py | 23 ++++++++++------------
.../execution_api/versions/head/test_variables.py | 16 ++++++++-------
3 files changed, 22 insertions(+), 22 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
index a7bb9959c6d..9182570a01e 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
@@ -29,7 +29,7 @@ from airflow.models.connection import Connection
async def has_connection_access(
- connection_id: str = Path(),
+ connection_id: Annotated[str, Path(min_length=1)],
token=CurrentTIToken,
) -> bool:
"""Check if the task has access to the connection."""
@@ -59,7 +59,8 @@ log = logging.getLogger(__name__)
},
)
def get_connection(
- connection_id: str, team_name: Annotated[str | None,
Depends(get_team_name_dep)]
+ connection_id: Annotated[str, Path(min_length=1)],
+ team_name: Annotated[str | None, Depends(get_team_name_dep)],
) -> ConnectionResponse:
"""Get an Airflow connection."""
try:
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/variables.py
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/variables.py
index 1e2e2058932..a139ce0c011 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/routes/variables.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/routes/variables.py
@@ -32,7 +32,7 @@ from airflow.models.variable import Variable
async def has_variable_access(
request: Request,
- variable_key: str = Path(),
+ variable_key: Annotated[str, Path(min_length=1)],
token=CurrentTIToken,
):
"""Check if the task has access to the variable."""
@@ -63,12 +63,10 @@ log = logging.getLogger(__name__)
},
)
def get_variable(
- variable_key: str, team_name: Annotated[str | None,
Depends(get_team_name_dep)]
+ variable_key: Annotated[str, Path(min_length=1)],
+ team_name: Annotated[str | None, Depends(get_team_name_dep)],
) -> VariableResponse:
"""Get an Airflow Variable."""
- if not variable_key:
- raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Not Found")
-
try:
variable_value = Variable.get(variable_key, team_name=team_name)
except KeyError:
@@ -92,12 +90,11 @@ def get_variable(
},
)
def put_variable(
- variable_key: str, body: VariablePostBody, team_name: Annotated[str |
None, Depends(get_team_name_dep)]
+ variable_key: Annotated[str, Path(min_length=1)],
+ body: VariablePostBody,
+ team_name: Annotated[str | None, Depends(get_team_name_dep)],
):
"""Set an Airflow Variable."""
- if not variable_key:
- raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Not Found")
-
Variable.set(key=variable_key, value=body.value,
description=body.description, team_name=team_name)
return {"message": "Variable successfully set"}
@@ -110,9 +107,9 @@ def put_variable(
status.HTTP_403_FORBIDDEN: {"description": "Task does not have access
to the variable"},
},
)
-def delete_variable(variable_key: str, team_name: Annotated[str | None,
Depends(get_team_name_dep)]):
+def delete_variable(
+ variable_key: Annotated[str, Path(min_length=1)],
+ team_name: Annotated[str | None, Depends(get_team_name_dep)],
+):
"""Delete an Airflow Variable."""
- if not variable_key:
- raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Not Found")
-
Variable.delete(key=variable_key, team_name=team_name)
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_variables.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_variables.py
index 93cd8ca672e..fe761163635 100644
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_variables.py
+++
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_variables.py
@@ -159,20 +159,22 @@ class TestPutVariable:
assert var_from_db.description == payload["description"]
@pytest.mark.parametrize(
- ("key", "status_code", "payload"),
+ ("key", "payload", "error_type"),
[
- pytest.param("", 404, {"value": "{}", "description":
"description"}, id="missing-key"),
- pytest.param("var_create", 422, {"description": "description"},
id="missing-value"),
+ pytest.param(
+ "", {"value": "{}", "description": "description"},
"string_too_short", id="missing-key"
+ ),
+ pytest.param("var_create", {"description": "description"},
"missing", id="missing-value"),
],
)
- def test_variable_missing_mandatory_fields(self, client, key, status_code,
payload, session):
+ def test_variable_missing_mandatory_fields(self, client, key, payload,
error_type, session):
response = client.put(
f"/execution/variables/{key}",
json=payload,
)
- assert response.status_code == status_code
- if response.status_code == 422:
- assert response.json()["detail"][0]["type"] == "missing"
+ assert response.status_code == 422
+ assert response.json()["detail"][0]["type"] == error_type
+ if error_type == "missing":
assert response.json()["detail"][0]["msg"] == "Field required"
@pytest.mark.parametrize(