Coverage for /home/airflow/.local/lib/python3.12/site-packages/airflow/api_fastapi/core_api/services/public/config.py: 38%
37 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 14:22 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 14:22 +0000
1# Licensed to the Apache Software Foundation (ASF) under one
2# or more contributor license agreements. See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership. The ASF licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License. You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing,
12# software distributed under the License is distributed on an
13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14# KIND, either express or implied. See the License for the
15# specific language governing permissions and limitations
16# under the License.
17from __future__ import annotations
19import warnings
21from fastapi import HTTPException, status
22from fastapi.responses import Response
24from airflow.api_fastapi.common.types import Mimetype
25from airflow.api_fastapi.core_api.datamodels.config import Config
26from airflow.configuration import conf
28# Per-key environment-variable overrides for secrets-backend kwargs are
29# surfaced by ``conf.as_dict`` as synthetic options under the ``secrets``
30# and ``workers`` sections. They carry the same secrets-backend material
31# (e.g. Vault role_id / secret_id) as the registered ``backend_kwargs``
32# option, so they need the same redaction treatment when
33# ``display_sensitive=False``.
34# These match literal section names only, so a team scoped spelling of the same option -- the
35# ``[<team>=secrets]`` section, or ``AIRFLOW__<TEAM>___SECRETS__BACKEND_KWARG__*``, which is
36# reported under a section named after the team -- is not recognised. Nothing leaks today because
37# the secrets backend is not team aware; tracked at
38# https://github.com/apache/airflow/issues/71037
39_PER_KEY_SENSITIVE_PREFIXES: dict[str, str] = {
40 "secrets": "backend_kwarg__",
41 "workers": "secrets_backend_kwarg__",
42}
45def _is_per_key_sensitive_option(section: str, option: str) -> bool:
46 """Return True for synthetic per-key secrets-backend-kwarg options."""
47 prefix = _PER_KEY_SENSITIVE_PREFIXES.get(section)
48 return prefix is not None and option.startswith(prefix)
51def _mask_per_key_sensitive_options(conf_dict: dict) -> None:
52 """Mask synthetic per-key secrets-backend-kwarg options in-place."""
53 for section, prefix in _PER_KEY_SENSITIVE_PREFIXES.items():
54 options = conf_dict.get(section)
55 if not options:
56 continue
57 for option in list(options):
58 if option.startswith(prefix):
59 current = options[option]
60 if isinstance(current, tuple):
61 options[option] = ("< hidden >", current[1])
62 else:
63 options[option] = "< hidden >"
66def _check_expose_config() -> bool:
67 display_sensitive: bool | None = None
68 if conf.get("api", "expose_config").lower() == "non-sensitive-only": 68 ↛ 69line 68 didn't jump to line 69 because the condition on line 68 was never true
69 expose_config = True
70 display_sensitive = False
71 warnings.warn(
72 "The value 'non-sensitive-only' for [api] expose_config is deprecated. "
73 "Use 'true' instead; sensitive configuration values are always masked.",
74 DeprecationWarning,
75 stacklevel=2,
76 )
77 else:
78 expose_config = conf.getboolean("api", "expose_config")
79 display_sensitive = False
81 if not expose_config: 81 ↛ 86line 81 didn't jump to line 86 because the condition on line 81 was always true
82 raise HTTPException(
83 status_code=status.HTTP_403_FORBIDDEN,
84 detail="Your Airflow administrator chose not to expose the configuration, most likely for security reasons.",
85 )
86 return display_sensitive
89def _response_based_on_accept(accept: Mimetype, config: Config):
90 if accept == Mimetype.TEXT:
91 return Response(content=config.text_format, media_type=Mimetype.TEXT)
92 return config