From a26e4f770e4d351589d696efaa9cb85df9130bed Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 4 Aug 2026 16:01:27 +0800 Subject: [PATCH 1/3] Validate provider metadata list entries instead of ignoring them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The items blocks for queues, plugins and task-decorators listed their field names directly under items, where they are not JSON Schema keywords, so the blocks were inert and any shape passed. A provider author following what those blocks appeared to document — a dict for queues, or a path key for a decorator — got no error and was quietly dropped by the consumers instead. Pinning each section to the shape the provider.yaml files and generated payloads actually use turns that into a failure at authoring time. The custom-provider howto named the same nonexistent path field. Raised in review of #70190. --- .../src/airflow/provider.yaml.schema.json | 47 +++++++++++------- .../src/airflow/provider_info.schema.json | 49 ++++++++++++------- .../howto/create-custom-providers.rst | 2 +- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/airflow-core/src/airflow/provider.yaml.schema.json b/airflow-core/src/airflow/provider.yaml.schema.json index 376eacdf93fa8..b5fe0191504c8 100644 --- a/airflow-core/src/airflow/provider.yaml.schema.json +++ b/airflow-core/src/airflow/provider.yaml.schema.json @@ -565,12 +565,21 @@ "type": "array", "description": "Decorators to use with the TaskFlow API. Can be accessed by users via '@task.'", "items": { - "name": { - "type": "string" + "type": "object", + "properties": { + "name": { + "description": "Name the decorator is exposed under, following '@task.'", + "type": "string" + }, + "class-name": { + "description": "Class name that implements the decorator", + "type": "string" + } }, - "path": { - "type": "string" - } + "required": [ + "name", + "class-name" + ] } }, "secrets-backends": { @@ -688,24 +697,28 @@ "type": "array", "description": "Plugins exposed by the provider", "items": { - "name": { - "type": "string" + "type": "object", + "properties": { + "name": { + "description": "Name of the plugin", + "type": "string" + }, + "plugin-class": { + "description": "Class name that implements the plugin", + "type": "string" + } }, - "plugin-class": { - "type": "string" - } + "required": [ + "name", + "plugin-class" + ] } }, "queues": { "type": "array", - "description": "Message Queues exposed by the provider", + "description": "Message queue provider class names", "items": { - "name": { - "type": "string" - }, - "message-queue-class": { - "type": "string" - } + "type": "string" } }, "source-date-epoch": { diff --git a/airflow-core/src/airflow/provider_info.schema.json b/airflow-core/src/airflow/provider_info.schema.json index b3e9bf74b6284..d0e72de436375 100644 --- a/airflow-core/src/airflow/provider_info.schema.json +++ b/airflow-core/src/airflow/provider_info.schema.json @@ -432,38 +432,49 @@ "type": "array", "description": "Apply custom decorators to the TaskFlow API. Can be accessed by users via '@task.'", "items": { - "name": { - "type": "string" + "type": "object", + "properties": { + "name": { + "description": "Name the decorator is exposed under, following '@task.'", + "type": "string" + }, + "class-name": { + "description": "Class name that implements the decorator", + "type": "string" + } }, - "path": { - "type": "string" - } + "required": [ + "name", + "class-name" + ] } }, "plugins": { "type": "array", "description": "Plugins provided by the provider", "items": { - "name": { - "type": "string", - "description": "Name of the plugin" + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the plugin" + }, + "plugin-class": { + "type": "string", + "description": "Class to instantiate the plugin" + } }, - "plugin-class": { - "type": "string", - "description": "Class to instantiate the plugin" - } + "required": [ + "name", + "plugin-class" + ] } }, "queues": { "type": "array", - "description": "Message Queues exposed by the provider", + "description": "Message queue provider class names", "items": { - "name": { - "type": "string" - }, - "message-queue-class": { - "type": "string" - } + "type": "string" } } }, diff --git a/providers-summary-docs/howto/create-custom-providers.rst b/providers-summary-docs/howto/create-custom-providers.rst index 68d2da6acdd05..ed6b00b9a663e 100644 --- a/providers-summary-docs/howto/create-custom-providers.rst +++ b/providers-summary-docs/howto/create-custom-providers.rst @@ -114,7 +114,7 @@ Exposing customized functionality to the Airflow's core: * ``sensors`` - this field should contain the list of all the sensor class names that the provider provides. See :doc:`apache-airflow:core-concepts/sensors` for description of the sensors. -* ``task-decorators`` - this field should contain the list of dictionaries of name/path where the decorators +* ``task-decorators`` - this field should contain the list of dictionaries of name/class-name where the decorators are available. See :doc:`apache-airflow:howto/create-custom-decorator` for description of how to add custom decorators. From 8374f6848aee91ffca8b23d53aad130cd8694671 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 6 Aug 2026 15:17:33 +0800 Subject: [PATCH 2/3] Keep runtime provider metadata validation permissive The runtime schema is documented as deliberately looser than the development one, and its validate() call is unwrapped in provider discovery, so a single installed provider emitting an outdated entry shape would abort discovery for every provider in that process instead of costing just that entry a logged warning. The structural descriptions stay behind so the schema no longer documents a shape it never actually enforced. --- .../src/airflow/provider_info.schema.json | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/airflow-core/src/airflow/provider_info.schema.json b/airflow-core/src/airflow/provider_info.schema.json index d0e72de436375..4e6ddacebd1fb 100644 --- a/airflow-core/src/airflow/provider_info.schema.json +++ b/airflow-core/src/airflow/provider_info.schema.json @@ -442,11 +442,7 @@ "description": "Class name that implements the decorator", "type": "string" } - }, - "required": [ - "name", - "class-name" - ] + } } }, "plugins": { @@ -463,19 +459,12 @@ "type": "string", "description": "Class to instantiate the plugin" } - }, - "required": [ - "name", - "plugin-class" - ] + } } }, "queues": { "type": "array", - "description": "Message queue provider class names", - "items": { - "type": "string" - } + "description": "Message queue provider class names" } }, "definitions": { From da294aa3b1ae6c93555844b93ad727d346800e80 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 6 Aug 2026 16:02:50 +0800 Subject: [PATCH 3/3] Reject unknown keys in provider.yaml decorator and plugin entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Requiring the right keys does not stop a leftover one sitting beside them, so a stale `path:` next to a correct `class-name:` still validated — exactly the confusion this branch set out to remove. Every sibling item block in this authoring schema already closes itself off this way. --- airflow-core/src/airflow/provider.yaml.schema.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/airflow-core/src/airflow/provider.yaml.schema.json b/airflow-core/src/airflow/provider.yaml.schema.json index b5fe0191504c8..d1b0651c670f7 100644 --- a/airflow-core/src/airflow/provider.yaml.schema.json +++ b/airflow-core/src/airflow/provider.yaml.schema.json @@ -576,6 +576,7 @@ "type": "string" } }, + "additionalProperties": false, "required": [ "name", "class-name" @@ -708,6 +709,7 @@ "type": "string" } }, + "additionalProperties": false, "required": [ "name", "plugin-class"