Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Runtime abstractions and interfaces for building agents and autom
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
dependencies = [
"uipath-core>=0.5.19, <0.6.0",
"uipath-core>=0.5.21, <0.6.0",
"pyyaml>=6.0, <7.0",
"vaderSentiment>=3.3.2, <4.0",
"chardet>=5.2.0, <8.0",
Expand Down
38 changes: 19 additions & 19 deletions src/uipath/runtime/governance/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
The feature-flag gate (``is_governance_enabled``) lives in
:mod:`uipath.core.governance.config` because it is process-level and
must be resolvable by callers that do not depend on
``uipath-runtime``. The enforcement mode is *per-policy* — owned by the
backend and delivered on each policy fetch via the ``/runtime/policy``
endpoint — and therefore lives here in the runtime package alongside the
policy loader that applies it.
``uipath-runtime``. The enforcement mode is *per-policy* —
provider-supplied on each policy load — and therefore lives here in
the runtime package alongside the policy loader that applies it via
:func:`set_enforcement_mode`.
"""

from __future__ import annotations
Expand All @@ -23,38 +23,38 @@ class _EnforcementModeState:

A single module-level instance backs the get/set/reset helpers, so the
mode is updated by mutating an attribute rather than rebinding a module
global. ``mode is None`` means "not yet set by the backend" — until
then (and if the backend omits a mode) governance defaults to AUDIT.
global. ``mode is None`` means "no provider has supplied a mode yet" —
until then (and if the provider omits a mode) governance defaults to
AUDIT.
"""

def __init__(self) -> None:
self.mode: EnforcementMode | None = None


# The enforcement mode is owned by the backend: the policy loader applies
# the mode from the ``/runtime/policy`` response via
# :func:`set_enforcement_mode`.
# The enforcement mode is supplied by the policy provider on each load;
# the loader applies it via :func:`set_enforcement_mode`.
_state = _EnforcementModeState()


def get_enforcement_mode() -> EnforcementMode:
"""Return the current enforcement mode.

The canonical source is the backend ``/runtime/policy`` response,
applied by the policy loader via :func:`set_enforcement_mode`. Until
that fetch lands (or if the backend returns no mode), the default is
:attr:`EnforcementMode.AUDIT` — evaluate and log without blocking.
Defaulting to AUDIT avoids the chicken-and-egg where a DISABLED
default would short-circuit evaluation before the background policy
fetch could ever opt the tenant in.
The canonical source is whatever the policy provider supplied on
the most recent load, applied via :func:`set_enforcement_mode`.
Until that load lands (or if the provider returns no mode), the
default is :attr:`EnforcementMode.AUDIT` — evaluate and log without
blocking. Defaulting to AUDIT avoids the chicken-and-egg where a
DISABLED default would short-circuit evaluation before the
background policy load could ever opt the tenant in.
"""
return _state.mode if _state.mode is not None else EnforcementMode.AUDIT


def set_enforcement_mode(mode: EnforcementMode) -> None:
"""Set the enforcement mode programmatically.

The policy loader calls this with the backend-supplied mode on each
fetch so the evaluator picks up the platform-controlled value.
The policy loader calls this with the provider-supplied mode on
each load so the evaluator picks up the platform-controlled value.
"""
_state.mode = mode
_state.mode = mode
Loading
Loading