apache-airflow-providers-fab 2.3.0__py3-none-any.whl → 2.3.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
29
29
 
30
30
  __all__ = ["__version__"]
31
31
 
32
- __version__ = "2.3.0"
32
+ __version__ = "2.3.1"
33
33
 
34
34
  if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
35
35
  "3.0.2"
@@ -34,6 +34,12 @@ from starlette.middleware.wsgi import WSGIMiddleware
34
34
  from airflow import __version__ as airflow_version
35
35
  from airflow.api_fastapi.app import AUTH_MANAGER_FASTAPI_APP_PREFIX
36
36
  from airflow.api_fastapi.auth.managers.base_auth_manager import BaseAuthManager
37
+
38
+ try:
39
+ from airflow.api_fastapi.auth.managers.base_auth_manager import ExtendedResourceMethod
40
+ except ImportError:
41
+ from airflow.api_fastapi.auth.managers.base_auth_manager import ResourceMethod as ExtendedResourceMethod
42
+
37
43
  from airflow.api_fastapi.auth.managers.models.resource_details import (
38
44
  AccessView,
39
45
  BackfillDetails,
@@ -382,7 +388,7 @@ class FabAuthManager(BaseAuthManager[User]):
382
388
 
383
389
  def is_authorized_view(self, *, access_view: AccessView, user: User) -> bool:
384
390
  # "Docs" are only links in the menu, there is no page associated
385
- method: ResourceMethod = "MENU" if access_view == AccessView.DOCS else "GET"
391
+ method: ExtendedResourceMethod = "MENU" if access_view == AccessView.DOCS else "GET"
386
392
  return self._is_authorized(
387
393
  method=method,
388
394
  resource_type=_MAP_ACCESS_VIEW_TO_FAB_RESOURCE_TYPE[access_view],
@@ -523,7 +529,7 @@ class FabAuthManager(BaseAuthManager[User]):
523
529
  def _is_authorized(
524
530
  self,
525
531
  *,
526
- method: ResourceMethod,
532
+ method: ExtendedResourceMethod,
527
533
  resource_type: str,
528
534
  user: User,
529
535
  ) -> bool:
@@ -594,7 +600,7 @@ class FabAuthManager(BaseAuthManager[User]):
594
600
  return len(authorized_dags) > 0
595
601
 
596
602
  @staticmethod
597
- def _get_fab_action(method: ResourceMethod) -> str:
603
+ def _get_fab_action(method: ExtendedResourceMethod) -> str:
598
604
  """
599
605
  Convert the method to a FAB action.
600
606
 
@@ -1551,7 +1551,7 @@ class FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
1551
1551
  ---------------
1552
1552
  """
1553
1553
 
1554
- def get_resource(self, name: str) -> Resource:
1554
+ def get_resource(self, name: str) -> Resource | None:
1555
1555
  """
1556
1556
  Return a resource record by name, if it exists.
1557
1557
 
@@ -1559,7 +1559,7 @@ class FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
1559
1559
  """
1560
1560
  return self.get_session.query(self.resource_model).filter_by(name=name).one_or_none()
1561
1561
 
1562
- def create_resource(self, name) -> Resource:
1562
+ def create_resource(self, name) -> Resource | None:
1563
1563
  """
1564
1564
  Create a resource with the given name.
1565
1565
 
@@ -1628,6 +1628,9 @@ class FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
1628
1628
  if perm:
1629
1629
  return perm
1630
1630
  resource = self.create_resource(resource_name)
1631
+ if resource is None:
1632
+ log.error(const.LOGMSG_ERR_SEC_ADD_PERMVIEW, f"Resource creation failed {resource_name}")
1633
+ return None
1631
1634
  action = self.create_action(action_name)
1632
1635
  perm = self.permission_model()
1633
1636
  perm.resource_id, perm.action_id = resource.id, action.id
@@ -46,10 +46,7 @@ from airflow.utils.net import get_hostname
46
46
  if TYPE_CHECKING:
47
47
  from airflow.api_fastapi.auth.managers.base_auth_manager import ResourceMethod
48
48
  from airflow.api_fastapi.auth.managers.models.batch_apis import (
49
- IsAuthorizedConnectionRequest,
50
49
  IsAuthorizedDagRequest,
51
- IsAuthorizedPoolRequest,
52
- IsAuthorizedVariableRequest,
53
50
  )
54
51
  from airflow.models import DagRun, Pool, TaskInstance, Variable
55
52
  from airflow.models.connection import Connection
@@ -170,15 +167,13 @@ def has_access_connection(method: ResourceMethod) -> Callable[[T], T]:
170
167
  @wraps(func)
171
168
  def decorated(*args, **kwargs):
172
169
  connections: set[Connection] = set(args[1])
173
- requests: Sequence[IsAuthorizedConnectionRequest] = [
174
- {
175
- "method": method,
176
- "details": ConnectionDetails(conn_id=connection.conn_id),
177
- }
170
+ is_authorized = all(
171
+ get_auth_manager().is_authorized_connection(
172
+ method=method,
173
+ details=ConnectionDetails(conn_id=connection.conn_id),
174
+ user=get_auth_manager().get_user(),
175
+ )
178
176
  for connection in connections
179
- ]
180
- is_authorized = get_auth_manager().batch_is_authorized_connection(
181
- requests, user=get_auth_manager().get_user()
182
177
  )
183
178
  return _has_access(
184
179
  is_authorized=is_authorized,
@@ -284,15 +279,11 @@ def has_access_pool(method: ResourceMethod) -> Callable[[T], T]:
284
279
  @wraps(func)
285
280
  def decorated(*args, **kwargs):
286
281
  pools: set[Pool] = set(args[1])
287
- requests: Sequence[IsAuthorizedPoolRequest] = [
288
- {
289
- "method": method,
290
- "details": PoolDetails(name=pool.pool),
291
- }
282
+ is_authorized = all(
283
+ get_auth_manager().is_authorized_pool(
284
+ method=method, details=PoolDetails(name=pool.pool), user=get_auth_manager().get_user()
285
+ )
292
286
  for pool in pools
293
- ]
294
- is_authorized = get_auth_manager().batch_is_authorized_pool(
295
- requests, user=get_auth_manager().get_user()
296
287
  )
297
288
  return _has_access(
298
289
  is_authorized=is_authorized,
@@ -310,23 +301,15 @@ def has_access_variable(method: ResourceMethod) -> Callable[[T], T]:
310
301
  def has_access_decorator(func: T):
311
302
  @wraps(func)
312
303
  def decorated(*args, **kwargs):
313
- if len(args) == 1:
314
- # No items provided
315
- is_authorized = get_auth_manager().is_authorized_variable(
316
- method=method, user=get_auth_manager().get_user()
317
- )
318
- else:
319
- variables: set[Variable] = set(args[1])
320
- requests: Sequence[IsAuthorizedVariableRequest] = [
321
- {
322
- "method": method,
323
- "details": VariableDetails(key=variable.key),
324
- }
325
- for variable in variables
326
- ]
327
- is_authorized = get_auth_manager().batch_is_authorized_variable(
328
- requests, user=get_auth_manager().get_user()
304
+ variables: set[Variable] = set(args[1])
305
+ is_authorized = all(
306
+ get_auth_manager().is_authorized_variable(
307
+ method=method,
308
+ details=VariableDetails(key=variable.key),
309
+ user=get_auth_manager().get_user(),
329
310
  )
311
+ for variable in variables
312
+ )
330
313
  return _has_access(
331
314
  is_authorized=is_authorized,
332
315
  func=func,
@@ -18,7 +18,7 @@ from __future__ import annotations
18
18
 
19
19
  import logging
20
20
 
21
- import pendulum
21
+ from pendulum import local_timezone
22
22
 
23
23
  import airflow
24
24
  from airflow.api_fastapi.app import get_auth_manager
@@ -33,7 +33,10 @@ def init_jinja_globals(app, enable_plugins: bool):
33
33
  """Add extra globals variable to Jinja context."""
34
34
  server_timezone = conf.get("core", "default_timezone")
35
35
  if server_timezone == "system":
36
- server_timezone = pendulum.local_timezone().name # type: ignore[operator]
36
+ if callable(local_timezone):
37
+ server_timezone = local_timezone().name
38
+ else:
39
+ raise ValueError("`local_timezone` is not callable")
37
40
  elif server_timezone == "utc":
38
41
  server_timezone = "UTC"
39
42