Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/uipath/runtime/governance/_audit/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ def emit_rule_evaluation(
"""Convenience method to emit a rule evaluation event.

``enforcement_mode`` travels on the event so sinks don't have to
read a process-global. With instance-scoped loaders the global
read a process-global. With instance-scoped runtimes the global
wouldn't be authoritative anyway — parallel runtimes can run in
different modes simultaneously.
"""
Expand Down Expand Up @@ -599,7 +599,7 @@ def emit_session_start(

Same ``enforcement_mode: EnforcementMode`` contract as
:meth:`emit_rule_evaluation` and :meth:`emit_hook_summary`
— every governance event carries the per-loader mode so sinks
— every governance event carries the per-runtime mode so sinks
don't depend on a process-global.
"""
self.emit(
Expand Down
11 changes: 6 additions & 5 deletions src/uipath/runtime/governance/_audit/traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ def _resolve_mode(event: AuditEvent) -> EnforcementMode:
"""Read the enforcement mode the evaluator stamped on the event.

Mode travels with the event (set by :meth:`AuditManager.emit_rule_evaluation`
/ :meth:`emit_hook_summary` from the loader's per-instance mode) so
the sink doesn't read a process-global that wouldn't be authoritative
in a parallel-runtime setup.
/ :meth:`emit_hook_summary` from the per-runtime
:attr:`GovernanceRuntime.enforcement_mode`) so the sink doesn't
read a process-global that wouldn't be authoritative in a
parallel-runtime setup.

Falls back to ``AUDIT`` only when the field is missing — that's a
contract violation by the emitter (every governance event must carry
Expand Down Expand Up @@ -212,7 +213,7 @@ def _emit_hook_span(self, event: AuditEvent) -> None:
# multiple SDKs / governance backends co-exist.
span.set_attribute(f"{NS}.source", GOVERNANCE_SOURCE)
# Hook summary attributes. Mode comes from the event — the
# evaluator stamps it from the per-loader instance, so the
# evaluator stamps it from the per-runtime instance, so the
# sink is correct for parallel runtimes running different
# modes.
mode = _resolve_mode(event)
Expand Down Expand Up @@ -272,7 +273,7 @@ def _emit_rule_span(self, event: AuditEvent) -> None:

# Derive the spec-vocabulary verdict pair from the raw
# (matched, configured action, mode) tuple. Mode comes
# from the event (per-loader instance) so parallel
# from the event (per-runtime instance) so parallel
# runtimes running different modes don't cross-contaminate.
# Single source of truth for the emitted attributes below
# AND the verbosityLevel/Status decision further down.
Expand Down
15 changes: 9 additions & 6 deletions src/uipath/runtime/governance/native/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
"""Native UiPath governance policy evaluator.

YAML-defined rules evaluated in-process at each agent lifecycle hook.
Reads policies through a :class:`GovernancePolicyProvider` (the provider
owns the wire transport) and runs the deterministic detectors backing
ISO 42001 controls.
The host fetches the policy pack via the
:class:`GovernancePolicyProvider` protocol and compiles it into a
:class:`PolicyIndex` with :func:`build_policy_index_from_yaml` *before*
constructing :class:`GovernanceRuntime` — so the runtime layer never
performs I/O at construction time.

This subpackage owns:

- :class:`GovernanceEvaluator` – the evaluator implementation.
- :class:`PolicyLoader` – the instance-scoped policy cache + prefetch.
- :func:`build_policy_index_from_yaml` – pure YAML → :class:`PolicyIndex`
compiler.
- The native policy model: :class:`Rule`, :class:`Check`,
:class:`Condition`, :class:`PolicyIndex`.

Shared output types (``Action``, ``AuditRecord``, …) live in
:mod:`uipath.core.governance`.
"""

from ._yaml_to_index import build_policy_index_from_yaml
from .evaluator import GovernanceEvaluator
from .loader import PolicyLoader
from .models import (
Check,
CheckContext,
Expand All @@ -30,7 +33,7 @@

__all__ = [
"GovernanceEvaluator",
"PolicyLoader",
"build_policy_index_from_yaml",
# Native policy model
"Check",
"CheckContext",
Expand Down
11 changes: 6 additions & 5 deletions src/uipath/runtime/governance/native/_yaml_to_index.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Runtime YAML → PolicyIndex parser.
Mirrors the shape produced by ``packs/compile_packs.py`` but builds the
PolicyIndex directly from parsed YAML data rather than generating Python
source. Used by :mod:`uipath.runtime.governance.native.loader` to
compile the YAML body returned by the registered policy provider into
an in-memory index at startup.
Mirrors the shape produced by ``packs/compile_packs.py`` but builds
the :class:`PolicyIndex` directly from parsed YAML data rather than
generating Python source. The platform host calls this to compile the
YAML body returned by :meth:`GovernancePolicyProvider.get_policy_async`
into an in-memory index, then hands the index to
:class:`GovernanceRuntime`.
Accepts either a single YAML document (one pack) or a multi-document
stream (``---``-separated packs). Unknown check types and malformed
Expand Down
11 changes: 7 additions & 4 deletions src/uipath/runtime/governance/native/evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,16 @@ def __init__(

Args:
policy_index: The compiled :class:`PolicyIndex` to evaluate.
Typically sourced from the owning runtime's
:class:`PolicyLoader`.
Typically read from :attr:`GovernanceRuntime.policy_index`
— the host built it from the provider's
:class:`PolicyResponse` via
:func:`build_policy_index_from_yaml`.
enforcement_mode: Mode the evaluator applies. Defaults to
``AUDIT`` — the safe default for callers that don't
explicitly opt in to ENFORCE. The wiring layer should
pass ``policy_loader.enforcement_mode`` here so the
evaluator and loader agree on a single source of truth.
pass ``runtime.enforcement_mode`` here so the evaluator
and the wrapping :class:`GovernanceRuntime` agree on a
single source of truth.
audit_manager: Per-runtime :class:`AuditManager`. When
``None`` the evaluator runs silently (no audit events
emitted). Tests that don't care about emission can
Expand Down
Loading
Loading