diff --git a/airflow/api_fastapi/core_api/base.py b/airflow/api_fastapi/core_api/base.py index fc1c68884c881..d88ec1757eb60 100644 --- a/airflow/api_fastapi/core_api/base.py +++ b/airflow/api_fastapi/core_api/base.py @@ -27,3 +27,15 @@ class BaseModel(PydanticBaseModel): """ model_config = ConfigDict(from_attributes=True, populate_by_name=True) + + +class StrictBaseModel(BaseModel): + """ + StrictBaseModel is a base Pydantic model for REST API that does not allow any extra fields. + + Use this class for models that should not have any extra fields in the payload. + + :meta private: + """ + + model_config = ConfigDict(from_attributes=True, populate_by_name=True, extra="forbid") diff --git a/airflow/api_fastapi/core_api/datamodels/assets.py b/airflow/api_fastapi/core_api/datamodels/assets.py index c7b7bec034c06..fd8f7cef2d415 100644 --- a/airflow/api_fastapi/core_api/datamodels/assets.py +++ b/airflow/api_fastapi/core_api/datamodels/assets.py @@ -21,11 +21,11 @@ from pydantic import Field, field_validator -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.utils.log.secrets_masker import redact -class DagScheduleAssetReference(BaseModel): +class DagScheduleAssetReference(StrictBaseModel): """DAG schedule reference serializer for assets.""" dag_id: str @@ -33,7 +33,7 @@ class DagScheduleAssetReference(BaseModel): updated_at: datetime -class TaskOutletAssetReference(BaseModel): +class TaskOutletAssetReference(StrictBaseModel): """Task outlet reference serializer for assets.""" dag_id: str @@ -84,7 +84,7 @@ class AssetAliasCollectionResponse(BaseModel): total_entries: int -class DagRunAssetReference(BaseModel): +class DagRunAssetReference(StrictBaseModel): """DAGRun serializer for asset responses.""" run_id: str @@ -141,7 +141,7 @@ class QueuedEventCollectionResponse(BaseModel): total_entries: int -class CreateAssetEventsBody(BaseModel): +class CreateAssetEventsBody(StrictBaseModel): """Create asset events request.""" asset_id: int diff --git a/airflow/api_fastapi/core_api/datamodels/backfills.py b/airflow/api_fastapi/core_api/datamodels/backfills.py index e36e50ea3b8d7..c74a7e2020313 100644 --- a/airflow/api_fastapi/core_api/datamodels/backfills.py +++ b/airflow/api_fastapi/core_api/datamodels/backfills.py @@ -19,11 +19,11 @@ from datetime import datetime -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.models.backfill import ReprocessBehavior -class BackfillPostBody(BaseModel): +class BackfillPostBody(StrictBaseModel): """Object used for create backfill request.""" dag_id: str diff --git a/airflow/api_fastapi/core_api/datamodels/common.py b/airflow/api_fastapi/core_api/datamodels/common.py index 4af5356f2ed3a..3c7a04255c963 100644 --- a/airflow/api_fastapi/core_api/datamodels/common.py +++ b/airflow/api_fastapi/core_api/datamodels/common.py @@ -27,7 +27,7 @@ from pydantic import Discriminator, Field, Tag -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel # Common Bulk Data Models T = TypeVar("T") @@ -57,7 +57,7 @@ class BulkActionNotOnExistence(enum.Enum): SKIP = "skip" -class BulkBaseAction(BaseModel, Generic[T]): +class BulkBaseAction(StrictBaseModel, Generic[T]): """Base class for bulk actions.""" action: BulkAction = Field(..., description="The action to be performed on the entities.") @@ -88,7 +88,7 @@ def _action_discriminator(action: Any) -> str: return BulkAction(action["action"]).value -class BulkBody(BaseModel, Generic[T]): +class BulkBody(StrictBaseModel, Generic[T]): """Serializer for bulk entity operations.""" actions: list[ diff --git a/airflow/api_fastapi/core_api/datamodels/config.py b/airflow/api_fastapi/core_api/datamodels/config.py index c16aa98093fb1..42a327431ceed 100644 --- a/airflow/api_fastapi/core_api/datamodels/config.py +++ b/airflow/api_fastapi/core_api/datamodels/config.py @@ -16,10 +16,10 @@ # under the License. from __future__ import annotations -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import StrictBaseModel -class ConfigOption(BaseModel): +class ConfigOption(StrictBaseModel): """Config option.""" key: str @@ -32,7 +32,7 @@ def text_format(self): return f"{self.key} = {self.value}" -class ConfigSection(BaseModel): +class ConfigSection(StrictBaseModel): """Config Section Schema.""" name: str @@ -53,7 +53,7 @@ def text_format(self): return f"[{self.name}]\n" + "\n".join(option.text_format for option in self.options) + "\n" -class Config(BaseModel): +class Config(StrictBaseModel): """List of config sections with their options.""" sections: list[ConfigSection] diff --git a/airflow/api_fastapi/core_api/datamodels/connections.py b/airflow/api_fastapi/core_api/datamodels/connections.py index 00d075bc4ace4..4650e1354dc1e 100644 --- a/airflow/api_fastapi/core_api/datamodels/connections.py +++ b/airflow/api_fastapi/core_api/datamodels/connections.py @@ -22,7 +22,7 @@ from pydantic import Field, field_validator from pydantic_core.core_schema import ValidationInfo -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.utils.log.secrets_masker import redact @@ -76,7 +76,7 @@ class ConnectionTestResponse(BaseModel): # Request Models -class ConnectionBody(BaseModel): +class ConnectionBody(StrictBaseModel): """Connection Serializer for requests body.""" connection_id: str = Field(serialization_alias="conn_id", max_length=200, pattern=r"^[\w.-]+$") diff --git a/airflow/api_fastapi/core_api/datamodels/dag_run.py b/airflow/api_fastapi/core_api/datamodels/dag_run.py index 48c92d2a83cb0..78e0254f62240 100644 --- a/airflow/api_fastapi/core_api/datamodels/dag_run.py +++ b/airflow/api_fastapi/core_api/datamodels/dag_run.py @@ -22,7 +22,7 @@ from pydantic import AwareDatetime, Field, NonNegativeInt, computed_field, model_validator -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.models import DagRun from airflow.utils import timezone from airflow.utils.state import DagRunState @@ -37,14 +37,14 @@ class DAGRunPatchStates(str, Enum): FAILED = DagRunState.FAILED -class DAGRunPatchBody(BaseModel): +class DAGRunPatchBody(StrictBaseModel): """DAG Run Serializer for PATCH requests.""" state: DAGRunPatchStates | None = None note: str | None = Field(None, max_length=1000) -class DAGRunClearBody(BaseModel): +class DAGRunClearBody(StrictBaseModel): """DAG Run serializer for clear endpoint body.""" dry_run: bool = True @@ -78,7 +78,7 @@ class DAGRunCollectionResponse(BaseModel): total_entries: int -class TriggerDAGRunPostBody(BaseModel): +class TriggerDAGRunPostBody(StrictBaseModel): """Trigger DAG Run Serializer for POST body.""" dag_run_id: str | None = None @@ -109,7 +109,7 @@ def logical_date(self) -> datetime: return timezone.utcnow() -class DAGRunsBatchBody(BaseModel): +class DAGRunsBatchBody(StrictBaseModel): """List DAG Runs body for batch endpoint.""" order_by: str | None = None diff --git a/airflow/api_fastapi/core_api/datamodels/dags.py b/airflow/api_fastapi/core_api/datamodels/dags.py index 30399b42f8d12..504a41683232c 100644 --- a/airflow/api_fastapi/core_api/datamodels/dags.py +++ b/airflow/api_fastapi/core_api/datamodels/dags.py @@ -31,7 +31,7 @@ field_validator, ) -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.api_fastapi.core_api.datamodels.dag_tags import DagTagResponse from airflow.configuration import conf @@ -92,7 +92,7 @@ def file_token(self) -> str: return serializer.dumps(self.fileloc) -class DAGPatchBody(BaseModel): +class DAGPatchBody(StrictBaseModel): """Dag Serializer for updatable bodies.""" is_paused: bool diff --git a/airflow/api_fastapi/core_api/datamodels/pools.py b/airflow/api_fastapi/core_api/datamodels/pools.py index 0040c49a1efda..096e357dfaf1d 100644 --- a/airflow/api_fastapi/core_api/datamodels/pools.py +++ b/airflow/api_fastapi/core_api/datamodels/pools.py @@ -21,7 +21,7 @@ from pydantic import BeforeValidator, ConfigDict, Field -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel def _call_function(function: Callable[[], int]) -> int: @@ -60,7 +60,7 @@ class PoolCollectionResponse(BaseModel): total_entries: int -class PoolPatchBody(BaseModel): +class PoolPatchBody(StrictBaseModel): """Pool serializer for patch bodies.""" model_config = ConfigDict(populate_by_name=True, from_attributes=True) @@ -71,7 +71,7 @@ class PoolPatchBody(BaseModel): include_deferred: bool | None = None -class PoolBody(BasePool): +class PoolBody(BasePool, StrictBaseModel): """Pool serializer for post bodies.""" pool: str = Field(alias="name", max_length=256) diff --git a/airflow/api_fastapi/core_api/datamodels/task_instances.py b/airflow/api_fastapi/core_api/datamodels/task_instances.py index 7cecb96ca42ce..d9c87b972ba9c 100644 --- a/airflow/api_fastapi/core_api/datamodels/task_instances.py +++ b/airflow/api_fastapi/core_api/datamodels/task_instances.py @@ -32,7 +32,7 @@ model_validator, ) -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.api_fastapi.core_api.datamodels.job import JobResponse from airflow.api_fastapi.core_api.datamodels.trigger import TriggerResponse from airflow.utils.state import TaskInstanceState @@ -97,7 +97,7 @@ class TaskDependencyCollectionResponse(BaseModel): dependencies: list[TaskDependencyResponse] -class TaskInstancesBatchBody(BaseModel): +class TaskInstancesBatchBody(StrictBaseModel): """Task Instance body for get batch.""" dag_ids: list[str] | None = None @@ -159,7 +159,7 @@ class TaskInstanceHistoryCollectionResponse(BaseModel): total_entries: int -class ClearTaskInstancesBody(BaseModel): +class ClearTaskInstancesBody(StrictBaseModel): """Request body for Clear Task Instances endpoint.""" dry_run: bool = True @@ -195,7 +195,7 @@ def validate_model(cls, data: Any) -> Any: return data -class PatchTaskInstanceBody(BaseModel): +class PatchTaskInstanceBody(StrictBaseModel): """Request body for Clear Task Instances endpoint.""" new_state: TaskInstanceState | None = None diff --git a/airflow/api_fastapi/core_api/datamodels/variables.py b/airflow/api_fastapi/core_api/datamodels/variables.py index 8307809bc5f5b..82cfdbb130523 100644 --- a/airflow/api_fastapi/core_api/datamodels/variables.py +++ b/airflow/api_fastapi/core_api/datamodels/variables.py @@ -21,7 +21,7 @@ from pydantic import ConfigDict, Field, model_validator -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.models.base import ID_LEN from airflow.typing_compat import Self from airflow.utils.log.secrets_masker import redact @@ -52,7 +52,7 @@ def redact_val(self) -> Self: return self -class VariableBody(BaseModel): +class VariableBody(StrictBaseModel): """Variable serializer for bodies.""" key: str = Field(max_length=ID_LEN) diff --git a/airflow/api_fastapi/core_api/datamodels/xcom.py b/airflow/api_fastapi/core_api/datamodels/xcom.py index 3a819b317d760..b63db3ff87d15 100644 --- a/airflow/api_fastapi/core_api/datamodels/xcom.py +++ b/airflow/api_fastapi/core_api/datamodels/xcom.py @@ -52,8 +52,8 @@ def value_to_string(cls, v): return str(v) if v is not None else None -class XComCollection(BaseModel): - """List of XCom items.""" +class XComCollectionResponse(BaseModel): + """XCom Collection serializer for responses.""" xcom_entries: list[XComResponse] total_entries: int diff --git a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml index 62df27b568ecd..4ffef0ab838cc 100644 --- a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml +++ b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml @@ -4426,7 +4426,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/XComCollection' + $ref: '#/components/schemas/XComCollectionResponse' '401': content: application/json: @@ -6785,6 +6785,7 @@ components: type: integer title: Max Active Runs default: 10 + additionalProperties: false type: object required: - dag_id @@ -6922,6 +6923,7 @@ components: - $ref: '#/components/schemas/BulkDeleteAction_ConnectionBody_' type: array title: Actions + additionalProperties: false type: object required: - actions @@ -6936,6 +6938,7 @@ components: - $ref: '#/components/schemas/BulkDeleteAction_PoolBody_' type: array title: Actions + additionalProperties: false type: object required: - actions @@ -6950,6 +6953,7 @@ components: - $ref: '#/components/schemas/BulkDeleteAction_VariableBody_' type: array title: Actions + additionalProperties: false type: object required: - actions @@ -6968,6 +6972,7 @@ components: action_on_existence: $ref: '#/components/schemas/BulkActionOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -6987,6 +6992,7 @@ components: action_on_existence: $ref: '#/components/schemas/BulkActionOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7006,6 +7012,7 @@ components: action_on_existence: $ref: '#/components/schemas/BulkActionOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7025,6 +7032,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7044,6 +7052,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7063,6 +7072,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7115,6 +7125,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7134,6 +7145,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7153,6 +7165,7 @@ components: action_on_non_existence: $ref: '#/components/schemas/BulkActionNotOnExistence' default: fail + additionalProperties: false type: object required: - action @@ -7223,6 +7236,7 @@ components: type: boolean title: Include Past default: false + additionalProperties: false type: object title: ClearTaskInstancesBody description: Request body for Clear Task Instances endpoint. @@ -7233,6 +7247,7 @@ components: $ref: '#/components/schemas/ConfigSection' type: array title: Sections + additionalProperties: false type: object required: - sections @@ -7253,6 +7268,7 @@ components: maxItems: 2 minItems: 2 title: Value + additionalProperties: false type: object required: - key @@ -7355,6 +7371,7 @@ components: $ref: '#/components/schemas/ConfigOption' type: array title: Options + additionalProperties: false type: object required: - name @@ -7406,6 +7423,7 @@ components: - type: string - type: 'null' title: Extra + additionalProperties: false type: object required: - connection_id @@ -7745,6 +7763,7 @@ components: is_paused: type: boolean title: Is Paused + additionalProperties: false type: object required: - is_paused @@ -7892,6 +7911,7 @@ components: type: boolean title: Only Failed default: false + additionalProperties: false type: object title: DAGRunClearBody description: DAG Run serializer for clear endpoint body. @@ -7923,6 +7943,7 @@ components: maxLength: 1000 - type: 'null' title: Note + additionalProperties: false type: object title: DAGRunPatchBody description: DAG Run Serializer for PATCH requests. @@ -8133,6 +8154,7 @@ components: format: date-time - type: 'null' title: End Date Lte + additionalProperties: false type: object title: DAGRunsBatchBody description: List DAG Runs body for batch endpoint. @@ -8417,6 +8439,7 @@ components: type: string format: date-time title: Data Interval End + additionalProperties: false type: object required: - run_id @@ -8480,6 +8503,7 @@ components: type: string format: date-time title: Updated At + additionalProperties: false type: object required: - dag_id @@ -9140,6 +9164,7 @@ components: type: boolean title: Include Past default: false + additionalProperties: false type: object title: PatchTaskInstanceBody description: Request body for Clear Task Instances endpoint. @@ -9245,6 +9270,7 @@ components: type: boolean title: Include Deferred default: false + additionalProperties: false type: object required: - name @@ -9289,6 +9315,7 @@ components: - type: boolean - type: 'null' title: Include Deferred + additionalProperties: false type: object title: PoolPatchBody description: Pool serializer for patch bodies. @@ -10006,6 +10033,7 @@ components: - type: string - type: 'null' title: Order By + additionalProperties: false type: object title: TaskInstancesBatchBody description: Task Instance body for get batch. @@ -10041,6 +10069,7 @@ components: type: string format: date-time title: Updated At + additionalProperties: false type: object required: - dag_id @@ -10266,6 +10295,7 @@ components: - type: string - type: 'null' title: Note + additionalProperties: false type: object title: TriggerDAGRunPostBody description: Trigger DAG Run Serializer for POST body. @@ -10351,6 +10381,7 @@ components: - type: string - type: 'null' title: Description + additionalProperties: false type: object required: - key @@ -10413,7 +10444,7 @@ components: - git_version title: VersionInfo description: Version information serializer for responses. - XComCollection: + XComCollectionResponse: properties: xcom_entries: items: @@ -10427,8 +10458,8 @@ components: required: - xcom_entries - total_entries - title: XComCollection - description: List of XCom items. + title: XComCollectionResponse + description: XCom Collection serializer for responses. XComResponse: properties: key: diff --git a/airflow/api_fastapi/core_api/routes/public/xcom.py b/airflow/api_fastapi/core_api/routes/public/xcom.py index 524d0722d1caa..b8fa6456e570d 100644 --- a/airflow/api_fastapi/core_api/routes/public/xcom.py +++ b/airflow/api_fastapi/core_api/routes/public/xcom.py @@ -26,7 +26,7 @@ from airflow.api_fastapi.common.parameters import QueryLimit, QueryOffset from airflow.api_fastapi.common.router import AirflowRouter from airflow.api_fastapi.core_api.datamodels.xcom import ( - XComCollection, + XComCollectionResponse, XComResponseNative, XComResponseString, ) @@ -112,7 +112,7 @@ def get_xcom_entries( session: SessionDep, xcom_key: Annotated[str | None, Query()] = None, map_index: Annotated[int | None, Query(ge=-1)] = None, -) -> XComCollection: +) -> XComCollectionResponse: """ Get all XCom entries. @@ -140,4 +140,4 @@ def get_xcom_entries( ) query = query.order_by(XCom.dag_id, XCom.task_id, XCom.run_id, XCom.map_index, XCom.key) xcoms = session.scalars(query) - return XComCollection(xcom_entries=xcoms, total_entries=total_entries) + return XComCollectionResponse(xcom_entries=xcoms, total_entries=total_entries) diff --git a/airflow/api_fastapi/execution_api/datamodels/taskinstance.py b/airflow/api_fastapi/execution_api/datamodels/taskinstance.py index 6cc82259cf758..abb2f6fa23c0a 100644 --- a/airflow/api_fastapi/execution_api/datamodels/taskinstance.py +++ b/airflow/api_fastapi/execution_api/datamodels/taskinstance.py @@ -32,7 +32,7 @@ ) from airflow.api_fastapi.common.types import UtcDateTime -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel from airflow.api_fastapi.execution_api.datamodels.asset import AssetProfile from airflow.api_fastapi.execution_api.datamodels.connection import ConnectionResponse from airflow.api_fastapi.execution_api.datamodels.variable import VariableResponse @@ -42,7 +42,7 @@ AwareDatetimeAdapter = TypeAdapter(AwareDatetime) -class TIEnterRunningPayload(BaseModel): +class TIEnterRunningPayload(StrictBaseModel): """Schema for updating TaskInstance to 'RUNNING' state with minimal required fields.""" state: Annotated[ @@ -60,7 +60,7 @@ class TIEnterRunningPayload(BaseModel): """When the task started executing""" -class TITerminalStatePayload(BaseModel): +class TITerminalStatePayload(StrictBaseModel): """Schema for updating TaskInstance to a terminal state except SUCCESS state.""" state: Literal[ @@ -74,7 +74,7 @@ class TITerminalStatePayload(BaseModel): """When the task completed executing""" -class TISuccessStatePayload(BaseModel): +class TISuccessStatePayload(StrictBaseModel): """Schema for updating TaskInstance to success state.""" state: Annotated[ @@ -96,13 +96,13 @@ class TISuccessStatePayload(BaseModel): outlet_events: Annotated[list[Any], Field(default_factory=list)] -class TITargetStatePayload(BaseModel): +class TITargetStatePayload(StrictBaseModel): """Schema for updating TaskInstance to a target state, excluding terminal and running states.""" state: IntermediateTIState -class TIDeferredStatePayload(BaseModel): +class TIDeferredStatePayload(StrictBaseModel): """Schema for updating TaskInstance to a deferred state.""" state: Annotated[ @@ -128,7 +128,7 @@ def validate_moment(cls, v): return v -class TIRescheduleStatePayload(BaseModel): +class TIRescheduleStatePayload(StrictBaseModel): """Schema for updating TaskInstance to a up_for_reschedule state.""" state: Annotated[ @@ -146,7 +146,7 @@ class TIRescheduleStatePayload(BaseModel): end_date: UtcDateTime -def ti_state_discriminator(v: dict[str, str] | BaseModel) -> str: +def ti_state_discriminator(v: dict[str, str] | StrictBaseModel) -> str: """ Determine the discriminator key for TaskInstance state transitions. @@ -185,7 +185,7 @@ def ti_state_discriminator(v: dict[str, str] | BaseModel) -> str: ] -class TIHeartbeatInfo(BaseModel): +class TIHeartbeatInfo(StrictBaseModel): """Schema for TaskInstance heartbeat endpoint.""" hostname: str @@ -194,7 +194,7 @@ class TIHeartbeatInfo(BaseModel): # This model is not used in the API, but it is included in generated OpenAPI schema # for use in the client SDKs. -class TaskInstance(BaseModel): +class TaskInstance(StrictBaseModel): """Schema for TaskInstance model with minimal required fields needed for Runtime.""" id: uuid.UUID @@ -207,7 +207,7 @@ class TaskInstance(BaseModel): hostname: str | None = None -class DagRun(BaseModel): +class DagRun(StrictBaseModel): """Schema for DagRun model with minimal required fields needed for Runtime.""" # TODO: `dag_id` and `run_id` are duplicated from TaskInstance diff --git a/airflow/api_fastapi/execution_api/datamodels/variable.py b/airflow/api_fastapi/execution_api/datamodels/variable.py index 6c597524763aa..73361908a810f 100644 --- a/airflow/api_fastapi/execution_api/datamodels/variable.py +++ b/airflow/api_fastapi/execution_api/datamodels/variable.py @@ -19,7 +19,7 @@ from pydantic import Field -from airflow.api_fastapi.core_api.base import BaseModel, ConfigDict +from airflow.api_fastapi.core_api.base import BaseModel, ConfigDict, StrictBaseModel class VariableResponse(BaseModel): @@ -29,7 +29,7 @@ class VariableResponse(BaseModel): val: str | None = Field(alias="value") -class VariablePostBody(BaseModel): +class VariablePostBody(StrictBaseModel): """Request body schema for creating variables.""" model_config = ConfigDict(extra="forbid") diff --git a/airflow/auth/managers/simple/datamodels/login.py b/airflow/auth/managers/simple/datamodels/login.py index 9d8eef55d23ba..ff4883625eccd 100644 --- a/airflow/auth/managers/simple/datamodels/login.py +++ b/airflow/auth/managers/simple/datamodels/login.py @@ -19,7 +19,7 @@ from pydantic import Field -from airflow.api_fastapi.core_api.base import BaseModel +from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel class LoginResponse(BaseModel): @@ -28,7 +28,7 @@ class LoginResponse(BaseModel): jwt_token: str -class LoginBody(BaseModel): +class LoginBody(StrictBaseModel): """Login serializer for post bodies.""" username: str = Field() diff --git a/airflow/auth/managers/simple/openapi/v1-generated.yaml b/airflow/auth/managers/simple/openapi/v1-generated.yaml index 4ae5c70876149..d0efc68864d17 100644 --- a/airflow/auth/managers/simple/openapi/v1-generated.yaml +++ b/airflow/auth/managers/simple/openapi/v1-generated.yaml @@ -75,6 +75,7 @@ components: password: type: string title: Password + additionalProperties: false type: object required: - username diff --git a/airflow/ui/openapi-gen/queries/prefetch.ts b/airflow/ui/openapi-gen/queries/prefetch.ts index 63a949aca94e6..b40c3243b0ded 100644 --- a/airflow/ui/openapi-gen/queries/prefetch.ts +++ b/airflow/ui/openapi-gen/queries/prefetch.ts @@ -2123,7 +2123,7 @@ export const prefetchUseXcomServiceGetXcomEntry = ( * @param data.mapIndex * @param data.limit * @param data.offset - * @returns XComCollection Successful Response + * @returns XComCollectionResponse Successful Response * @throws ApiError */ export const prefetchUseXcomServiceGetXcomEntries = ( diff --git a/airflow/ui/openapi-gen/queries/queries.ts b/airflow/ui/openapi-gen/queries/queries.ts index c4d201767e17d..04905e188e495 100644 --- a/airflow/ui/openapi-gen/queries/queries.ts +++ b/airflow/ui/openapi-gen/queries/queries.ts @@ -2503,7 +2503,7 @@ export const useXcomServiceGetXcomEntry = < * @param data.mapIndex * @param data.limit * @param data.offset - * @returns XComCollection Successful Response + * @returns XComCollectionResponse Successful Response * @throws ApiError */ export const useXcomServiceGetXcomEntries = < diff --git a/airflow/ui/openapi-gen/queries/suspense.ts b/airflow/ui/openapi-gen/queries/suspense.ts index d2f3bfc937c72..63beafe117da2 100644 --- a/airflow/ui/openapi-gen/queries/suspense.ts +++ b/airflow/ui/openapi-gen/queries/suspense.ts @@ -2482,7 +2482,7 @@ export const useXcomServiceGetXcomEntrySuspense = < * @param data.mapIndex * @param data.limit * @param data.offset - * @returns XComCollection Successful Response + * @returns XComCollectionResponse Successful Response * @throws ApiError */ export const useXcomServiceGetXcomEntriesSuspense = < diff --git a/airflow/ui/openapi-gen/requests/schemas.gen.ts b/airflow/ui/openapi-gen/requests/schemas.gen.ts index 170b977beb0ed..8b30ecc9c1ec0 100644 --- a/airflow/ui/openapi-gen/requests/schemas.gen.ts +++ b/airflow/ui/openapi-gen/requests/schemas.gen.ts @@ -413,6 +413,7 @@ export const $BackfillPostBody = { default: 10, }, }, + additionalProperties: false, type: "object", required: ["dag_id", "from_date", "to_date"], title: "BackfillPostBody", @@ -587,6 +588,7 @@ export const $BulkBody_ConnectionBody_ = { title: "Actions", }, }, + additionalProperties: false, type: "object", required: ["actions"], title: "BulkBody[ConnectionBody]", @@ -612,6 +614,7 @@ export const $BulkBody_PoolBody_ = { title: "Actions", }, }, + additionalProperties: false, type: "object", required: ["actions"], title: "BulkBody[PoolBody]", @@ -637,6 +640,7 @@ export const $BulkBody_VariableBody_ = { title: "Actions", }, }, + additionalProperties: false, type: "object", required: ["actions"], title: "BulkBody[VariableBody]", @@ -661,6 +665,7 @@ export const $BulkCreateAction_ConnectionBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkCreateAction[ConnectionBody]", @@ -685,6 +690,7 @@ export const $BulkCreateAction_PoolBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkCreateAction[PoolBody]", @@ -709,6 +715,7 @@ export const $BulkCreateAction_VariableBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkCreateAction[VariableBody]", @@ -733,6 +740,7 @@ export const $BulkDeleteAction_ConnectionBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkDeleteAction[ConnectionBody]", @@ -757,6 +765,7 @@ export const $BulkDeleteAction_PoolBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkDeleteAction[PoolBody]", @@ -781,6 +790,7 @@ export const $BulkDeleteAction_VariableBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkDeleteAction[VariableBody]", @@ -850,6 +860,7 @@ export const $BulkUpdateAction_ConnectionBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkUpdateAction[ConnectionBody]", @@ -874,6 +885,7 @@ export const $BulkUpdateAction_PoolBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkUpdateAction[PoolBody]", @@ -898,6 +910,7 @@ export const $BulkUpdateAction_VariableBody_ = { default: "fail", }, }, + additionalProperties: false, type: "object", required: ["action", "entities"], title: "BulkUpdateAction[VariableBody]", @@ -1012,6 +1025,7 @@ export const $ClearTaskInstancesBody = { default: false, }, }, + additionalProperties: false, type: "object", title: "ClearTaskInstancesBody", description: "Request body for Clear Task Instances endpoint.", @@ -1027,6 +1041,7 @@ export const $Config = { title: "Sections", }, }, + additionalProperties: false, type: "object", required: ["sections"], title: "Config", @@ -1061,6 +1076,7 @@ export const $ConfigOption = { title: "Value", }, }, + additionalProperties: false, type: "object", required: ["key", "value"], title: "ConfigOption", @@ -1191,6 +1207,7 @@ export const $ConfigSection = { title: "Options", }, }, + additionalProperties: false, type: "object", required: ["name", "options"], title: "ConfigSection", @@ -1287,6 +1304,7 @@ export const $ConnectionBody = { title: "Extra", }, }, + additionalProperties: false, type: "object", required: ["connection_id", "conn_type"], title: "ConnectionBody", @@ -1839,6 +1857,7 @@ export const $DAGPatchBody = { title: "Is Paused", }, }, + additionalProperties: false, type: "object", required: ["is_paused"], title: "DAGPatchBody", @@ -2074,6 +2093,7 @@ export const $DAGRunClearBody = { default: false, }, }, + additionalProperties: false, type: "object", title: "DAGRunClearBody", description: "DAG Run serializer for clear endpoint body.", @@ -2124,6 +2144,7 @@ export const $DAGRunPatchBody = { title: "Note", }, }, + additionalProperties: false, type: "object", title: "DAGRunPatchBody", description: "DAG Run Serializer for PATCH requests.", @@ -2464,6 +2485,7 @@ export const $DAGRunsBatchBody = { title: "End Date Lte", }, }, + additionalProperties: false, type: "object", title: "DAGRunsBatchBody", description: "List DAG Runs body for batch endpoint.", @@ -2891,6 +2913,7 @@ export const $DagRunAssetReference = { title: "Data Interval End", }, }, + additionalProperties: false, type: "object", required: [ "run_id", @@ -2948,6 +2971,7 @@ export const $DagScheduleAssetReference = { title: "Updated At", }, }, + additionalProperties: false, type: "object", required: ["dag_id", "created_at", "updated_at"], title: "DagScheduleAssetReference", @@ -3956,6 +3980,7 @@ export const $PatchTaskInstanceBody = { default: false, }, }, + additionalProperties: false, type: "object", title: "PatchTaskInstanceBody", description: "Request body for Clear Task Instances endpoint.", @@ -4101,6 +4126,7 @@ export const $PoolBody = { default: false, }, }, + additionalProperties: false, type: "object", required: ["name", "slots"], title: "PoolBody", @@ -4174,6 +4200,7 @@ export const $PoolPatchBody = { title: "Include Deferred", }, }, + additionalProperties: false, type: "object", title: "PoolPatchBody", description: "Pool serializer for patch bodies.", @@ -5286,6 +5313,7 @@ export const $TaskInstancesBatchBody = { title: "Order By", }, }, + additionalProperties: false, type: "object", title: "TaskInstancesBatchBody", description: "Task Instance body for get batch.", @@ -5336,6 +5364,7 @@ export const $TaskOutletAssetReference = { title: "Updated At", }, }, + additionalProperties: false, type: "object", required: ["dag_id", "task_id", "created_at", "updated_at"], title: "TaskOutletAssetReference", @@ -5738,6 +5767,7 @@ export const $TriggerDAGRunPostBody = { title: "Note", }, }, + additionalProperties: false, type: "object", title: "TriggerDAGRunPostBody", description: "Trigger DAG Run Serializer for POST body.", @@ -5864,6 +5894,7 @@ export const $VariableBody = { title: "Description", }, }, + additionalProperties: false, type: "object", required: ["key", "value"], title: "VariableBody", @@ -5946,7 +5977,7 @@ export const $VersionInfo = { description: "Version information serializer for responses.", } as const; -export const $XComCollection = { +export const $XComCollectionResponse = { properties: { xcom_entries: { items: { @@ -5962,8 +5993,8 @@ export const $XComCollection = { }, type: "object", required: ["xcom_entries", "total_entries"], - title: "XComCollection", - description: "List of XCom items.", + title: "XComCollectionResponse", + description: "XCom Collection serializer for responses.", } as const; export const $XComResponse = { diff --git a/airflow/ui/openapi-gen/requests/services.gen.ts b/airflow/ui/openapi-gen/requests/services.gen.ts index bf6e528da11ed..0e3c33dba9d65 100644 --- a/airflow/ui/openapi-gen/requests/services.gen.ts +++ b/airflow/ui/openapi-gen/requests/services.gen.ts @@ -2978,7 +2978,7 @@ export class XcomService { * @param data.mapIndex * @param data.limit * @param data.offset - * @returns XComCollection Successful Response + * @returns XComCollectionResponse Successful Response * @throws ApiError */ public static getXcomEntries(data: GetXcomEntriesData): CancelablePromise { diff --git a/airflow/ui/openapi-gen/requests/types.gen.ts b/airflow/ui/openapi-gen/requests/types.gen.ts index 6ff1a083ec6e8..3db3e1ea2ecf1 100644 --- a/airflow/ui/openapi-gen/requests/types.gen.ts +++ b/airflow/ui/openapi-gen/requests/types.gen.ts @@ -1469,9 +1469,9 @@ export type VersionInfo = { }; /** - * List of XCom items. + * XCom Collection serializer for responses. */ -export type XComCollection = { +export type XComCollectionResponse = { xcom_entries: Array; total_entries: number; }; @@ -2300,7 +2300,7 @@ export type GetXcomEntriesData = { xcomKey?: string | null; }; -export type GetXcomEntriesResponse = XComCollection; +export type GetXcomEntriesResponse = XComCollectionResponse; export type GetTasksData = { dagId: string; @@ -4698,7 +4698,7 @@ export type $OpenApiTs = { /** * Successful Response */ - 200: XComCollection; + 200: XComCollectionResponse; /** * Bad Request */ diff --git a/tests/api_fastapi/core_api/routes/public/test_backfills.py b/tests/api_fastapi/core_api/routes/public/test_backfills.py index 1836bae3ac7a1..1eeae8b667566 100644 --- a/tests/api_fastapi/core_api/routes/public/test_backfills.py +++ b/tests/api_fastapi/core_api/routes/public/test_backfills.py @@ -425,7 +425,6 @@ def test_create_backfill_dry_run_with_depends_on_past( "max_active_runs": max_active_runs, "run_backwards": run_backwards, "dag_run_conf": {"param1": "val1", "param2": True}, - "dry_run": False, "reprocess_behavior": repro_act, } response = test_client.post(