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

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 

18 

19import warnings 

20 

21from fastapi import HTTPException, status 

22from fastapi.responses import Response 

23 

24from airflow.api_fastapi.common.types import Mimetype 

25from airflow.api_fastapi.core_api.datamodels.config import Config 

26from airflow.configuration import conf 

27 

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} 

43 

44 

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) 

49 

50 

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 >" 

64 

65 

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 

80 

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 

87 

88 

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