diff --git a/plugins/ui/src/deephaven/ui/object_types/ElementType.py b/plugins/ui/src/deephaven/ui/object_types/ElementType.py index 02d07ad8e..e4695a0da 100644 --- a/plugins/ui/src/deephaven/ui/object_types/ElementType.py +++ b/plugins/ui/src/deephaven/ui/object_types/ElementType.py @@ -1,9 +1,15 @@ -from typing import Any +from typing import Any, Literal from deephaven.plugin.object_type import BidirectionalObjectType, MessageStream from ..elements import Element from .ElementMessageStream import ElementMessageStream +# Escape-hatch configuration property. When set to true, deephaven.ui declares no authorization export behavior +# ("unset"), deferring to the server's default policy instead of enforcing the transform. +_DISABLE_AUTHORIZATION_EXPORT_TRANSFORM_PROPERTY = ( + "deephaven.ui.disableAuthorizationExportTransform" +) + class ElementType(BidirectionalObjectType): """ @@ -14,6 +20,30 @@ class ElementType(BidirectionalObjectType): def name(self) -> str: return "deephaven.ui.Element" + @property + def authorization_export_behavior(self) -> Literal["transform", "unset"]: + """Declares that deephaven.ui must export its references through the authorization transform. + + Server objects (tables, etc.) handed to the client via a deephaven.ui component are run through the + authorization transform in the viewer's context, so they carry the viewer's ACLs rather than the query + owner's. Setting the configuration property ``deephaven.ui.disableAuthorizationExportTransform`` to true + reverts to the server's default ("unset") behavior. If the configuration cannot be read, the transform is + enforced (fail secure). + """ + try: + # deephaven.configuration only exists in the 42.x server package; the import is conditional to + # maintain compatibility with 41.x, where ImportError is caught and the transform is enforced. + from deephaven.configuration import get_configuration # type: ignore[import-untyped,import-not-found] + + if get_configuration().get_bool( + _DISABLE_AUTHORIZATION_EXPORT_TRANSFORM_PROPERTY, False + ): + return "unset" + except Exception: + # Fail secure: if the escape hatch cannot be evaluated, enforce the transform. + pass + return "transform" + def is_type(self, obj: Any) -> bool: return isinstance(obj, Element)