Skip to content

feat(governance): enforcement-mode config, policy models, deps#120

Merged
aditik0303 merged 4 commits into
feat/agentic-governancefrom
feat/governance-foundation
Jun 19, 2026
Merged

feat(governance): enforcement-mode config, policy models, deps#120
aditik0303 merged 4 commits into
feat/agentic-governancefrom
feat/governance-foundation

Conversation

@aditik0303

Copy link
Copy Markdown

Stacked PR 1/7 — part of splitting feat/governance-core into reviewable slices. Base: feat/agentic-governance. One logical slice (branch is cumulative so CI is green). Merge in order #1#7 and delete each branch on merge so the next PR auto-retargets onto feat/agentic-governance. feat/governance-core kept untouched as backup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the initial “governance core” slice in uipath-runtime, introducing runtime-scoped enforcement-mode state, a native policy model, and the baseline dependency/test scaffolding needed to support policy evaluation in subsequent stacked PRs.

Changes:

  • Add EnforcementMode resolution + caching APIs in uipath.runtime.governance.config (defaulting to AUDIT with env/programmatic overrides).
  • Introduce dataclass-based native policy models (Rule, Check, Condition, PolicyIndex, etc.) under uipath.runtime.governance.native.
  • Add governance-related dependencies and baseline tests/fixtures for enforcement-mode behavior.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Updates the lockfile to include new governance-related dependencies and bumps uipath-core.
pyproject.toml Adds runtime deps (pyyaml, vaderSentiment, chardet) and dev dep (types-PyYAML), plus mypy overrides for missing stubs.
src/uipath/runtime/governance/config.py New module implementing runtime enforcement-mode resolution/caching.
src/uipath/runtime/governance/native/models.py New dataclass model layer for native governance policies and indexing.
tests/test_enforcement_mode_default.py Adds unit tests validating enforcement-mode resolution order and caching behavior.
tests/conftest.py Adds an autouse fixture intended to reset governance-related process state between tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/conftest.py Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/native/models.py Outdated
… forward refs in docstrings, guard backend_client import in conftest

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/config.py Outdated
Comment thread src/uipath/runtime/governance/native/models.py Outdated
name: str
clause: str
hook: LifecycleHook
action: Action

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we also have an action per check. what happens if

  Rule.action = Action.AUDIT
  Check.action = Action.DENY 

?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Rule.action = AUDIT, Check.action = DENY: the matched check's action wins, so the rule resolves to DENY. Then enforcement mode decides: ENFORCE blocks it, AUDIT downgrades it to log-only, DISABLED skips.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, thanks.
I would include this in a docstring as well



@dataclass
class CheckContext:

@radu-mocanu radu-mocanu Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of a dataclass with a large bag of fields we should use hook-specific contexts as pydantic objects

  BeforeAgentContext
  AfterAgentContext
  BeforeModelContext
  ToolCallContext
  AfterToolContext

and create a union type for them. this will provide out-of-the-box model validation so one can t write stuff like:

  CheckContext(
      hook=LifecycleHook.TOOL_CALL,
      agent_output="some output",
      tool_name=""
  )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting CheckContext into per hook Pydantic types plus a union touches multiple files: the models definition, every hook construction site in the evaluator, the places reading the context fields, and the context tests. Since it spans the stack, I'll track it in the parent PR and do it once these get merged.

Comment on lines +78 to +82
agent_input: str = ""
agent_output: str = ""
model_input: str = ""
model_output: str = ""
model_name: str = (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CheckContext narrows most runtime payloads to str, but runtime inputs/outputs/tool results are often structured objects. should these be Any/dict/message types, or should serialization happen explicitly in the evaluator?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll pick this up together with the per-hook context split, since both touch the same CheckContext types and evaluator serialization. The fields are typed str today but the evaluator already stringifies, so I'll widen them to accept structured payloads and add explicit serialization in the evaluator as part of that refactor.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#129
created an issue for better tracking

Comment thread src/uipath/runtime/governance/native/models.py Outdated
- config.py: enforcement mode no longer reads the UIPATH_GOVERNANCE_MODE env
  var directly (the backend /runtime/policy response is the source); default
  is AUDIT. Mode state lives in a holder object instead of a module global
  (no `global` statements). The test-only reset helper moved out to
  tests/_helpers.py so test concerns stay in the test tree.
- models.py: Check.logic is now the Logic(str, Enum) instead of a free-form
  string; tidy the CheckContext.model_name field.
- pyproject: add dependency upper bounds (pyyaml<7, vaderSentiment<4,
  chardet<8); remove the [[tool.mypy.overrides]] block.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/uipath/runtime/governance/config.py Outdated
from enum import Enum


class EnforcementMode(str, Enum):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to either delete this class now and update the uipath-core dependency once this PR gets merged, or at least leave a ToDo comment here and delete this class in a subsequent PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising the uipath-core PR: UiPath/uipath-python#1727. I'll raise the runtime changes once the uipath-core changes are merged.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted the class

# The enforcement mode is owned by the backend: the policy loader applies
# the mode from the ``/runtime/policy`` response via
# :func:`set_enforcement_mode`.
_state = _EnforcementModeState()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still leaves enforcement mode as process-global state in this PR, just behind _state instead of a global variable. shouldn t the resolved mode live under the evaluator instance?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I'll move the resolved mode onto the evaluator instance in a follow up

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#130
created an issue for better tracking

EnforcementMode is a shared governance contract, so it now lives in
uipath.core.governance (uipath-core 0.5.19) and is re-exported from
config.py — runtime callers keep importing it from one place, but the
value type is owned by the lower abstraction level (per radu's review).
Bumps the uipath-core floor to 0.5.19.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aditik0303 aditik0303 merged commit fe2294c into feat/agentic-governance Jun 19, 2026
78 of 120 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants