Skip to content

Commit becb52b

Browse files
feat(governance): add Governance getPolicyTraces service (#464)
* feat(governance): add Governance getPolicyEvaluationTraces service Onboards the first method on a new modular Governance service surfacing the Insights Real-Time Dashboards policy evaluation traces endpoint. Exposed via `@uipath/uipath-typescript/governance`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(governance): use camelCase traceId in test overrides `createMockRawPolicyEvaluationTrace({ TraceId: ... })` was a silent no-op — the `RawPolicyEvaluationTraceItem` field is `traceId` (camelCase), matching the live API. The PascalCase override was dropped at runtime, so every item in the "exactly full page" and "round-trip cursor" tests shared the default `traceId` instead of having a unique one per row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(governance): rename getPolicyEvaluationTraces to getTraces Per code review feedback, shorten the public method name. Inside the `governance` namespace, `getTraces` reads naturally. Cascades the rename through the type system to keep everything symmetric: getPolicyEvaluationTraces -> getTraces PolicyEvaluationTrace -> Trace PolicyEvaluationTracesGetAllOptions -> TracesGetAllOptions RawPolicyEvaluationTraceItem -> RawTraceItem RawPolicyEvaluationTracesResponse -> RawTracesResponse `PolicyEvaluationResult` (the filter enum) is unchanged — its values are owned by the AuthZ contract package, not by the SDK naming. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(governance): rename getTraces back to getPolicyTraces Per follow-up review feedback, `getPolicyTraces` is the agreed name — shorter than the original `getPolicyEvaluationTraces` but still carries the 'policy' qualifier so it (a) doesn't collide with the OpenTelemetry meaning of 'trace' (each row already exposes a `traceId` field) and (b) leaves room for symmetric `getPolicySummary` / `getOperationSummary` naming on the remaining two governance endpoints. Cascades the rename through the type system to keep the surface symmetric: getTraces -> getPolicyTraces Trace -> PolicyTrace TracesGetAllOptions -> PolicyTracesGetAllOptions RawTraceItem -> RawPolicyTraceItem RawTracesResponse -> RawPolicyTracesResponse `PolicyEvaluationResult` (filter enum) and PascalCase `TraceId` assertions in tests are unchanged — the former is owned by the AuthZ contract, the latter is a literal API field name we intentionally assert is absent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(governance): drop misleading Snowflake-format mock constants The mock used `EVALUATION_RESULT_ACTIVE_DENY: 'Active_Deny'`, which is the *Snowflake column key* (per the request → SQL mapping in the spec), not anything the API actually returns in the response. The C# DTO is `string?` with no enum constraint, and the OpenAPI response schema is just `type: string` with no documented values — so the response value is genuinely unknown until we can pull live data. Renames the one used constant to `EVALUATION_RESULT_DENY: 'Deny'`, which is the most plausible response shape (matches the request-side `PolicyEvaluationResult` enum that the API does document). Removes the unused `EVALUATION_RESULT_ACTIVE_ALLOW` constant (zero references). No assertions depend on this value — the change is cosmetic and removes a misleading breadcrumb for future readers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(governance): extract GovernanceFilterOptions base type Pull endTime and fullOrganization into a shared GovernanceFilterOptions interface so other governance endpoints can reuse them, and compose it into PolicyTracesGetAllOptions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(governance): rename PolicyTracesGetAllOptions to PolicyTraceGetAllOptions Use the singular entity prefix to match the SDK options-type convention ({Entity}GetAllOptions), consistent with TaskGetAllOptions and QueueGetAllOptions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(governance): make raw startTime required and trim internal-types JSDoc * fix(governance): drop RawPolicyTracesResponse from test mock Align the mock with the service after removing the named envelope type; createMockRawPolicyTracesResponse now returns the inline { items } shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(governance): trim implementation detail from service JSDoc Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(governance): clarify trace row description * docs(governance): trim implementation detail from service JSDoc * docs(governance): clarify filter value mapping * docs(governance): trim redundant trace row JSDoc * docs(governance): clarify getPolicyTraces example comment * docs(governance): clarify bare-minimum example comment * refactor(governance): route getPolicyTraces through shared pagination helper Replace hand-rolled offset pagination in getPolicyTraces with PaginationHelpers.getAll(), adding a zeroBased offset option to the shared OFFSET path for 0-based page-number APIs. Type the response cast as the declared return type instead of `as any`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(governance): expand getPolicyTraces JSDoc summary Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(governance): derive excludeFromPrefix from request keys Replace the hardcoded POLICY_TRACE_BODY_KEYS list with Object.keys(apiOptions) so every non-OData body field is exempt from the $ prefix automatically, with no list to keep in sync. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(governance): clarify getPolicyTraces JSDoc and field descriptions Describe per-policy row semantics and result ordering, and tighten the finalEnforcement/policyStatus field docs. Keep service-class and ServiceModel JSDoc in sync. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(governance): fix run-on sentence in getPolicyTraces JSDoc Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(governance): type policyEvaluationResult as string to match API contract The API contract defines policyEvaluationResult as a free-form string, so typing the PolicyTrace response field as the PolicyEvaluationResult enum over-asserted a shape the contract does not guarantee. The enum is retained for the evaluationResult filter input, where the constrained value set is appropriate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(governance): fix misleading test names for getPolicyTraces getPolicyTraces passes no transformFn to PaginationHelpers.getAll, so items flow through untouched (the governance API already returns camelCase). - Remove the "should transform API fields" integration test: it asserted PascalCase absence, which passed trivially off the API's native shape rather than any SDK transform. The honestly-named unit test already covers the real guarantee (camelCase preserved, no transform). - Rename three validation unit tests from "should throw ValidationError" to "should throw error" for pageSize/jumpToPage/cursor — those are thrown as a plain Error by the pagination helper, not ValidationError. Only the startTime check throws a real ValidationError, matching the convention in tests/unit/utils/pagination/helpers.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(governance): prefix governance types and mocks with Governance, clarify fullOrganization Namespace the governance surface consistently: - PolicyTrace -> GovernancePolicyTrace (public) - PolicyTraceGetAllOptions -> GovernancePolicyTraceGetAllOptions (public) - RawPolicyTraceItem -> RawGovernancePolicyTraceItem (internal) - createMockRawPolicyTrace -> createMockRawGovernancePolicyTrace (test mock) - createMockRawPolicyTracesResponse -> createMockRawGovernancePolicyTracesResponse (test mock) Also expand the fullOrganization JSDoc to document the tenant-scoped default and the org-admin/403 behavior for each value (omitted / false / true). The renamed public types are unreleased (service still in review), so no backward-compat shim is needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(governance): link to Automation Ops governance policies guide Add a reference from the GovernanceServiceModel docs to the Automation Ops "Define governance policies" guide so users can see how the policies the service inspects are configured. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(governance): add @default tag to fullOrganization Document the default value (false — tenant-scoped) with a @default tag so it renders as a Default Value entry on the GovernanceFilterOptions docs page. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 389671b commit becb52b

25 files changed

Lines changed: 813 additions & 2 deletions

File tree

docs/oauth-scopes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ The `ConversationalAgents` scope is required for real-time WebSocket sessions (`
194194
| `getById()` | `Traces.Api` |
195195
| `getSpansByIds()` | `Traces.Api` |
196196

197+
## Governance
198+
199+
| Method | OAuth Scope |
200+
|--------|-------------|
201+
| `getPolicyTraces()` | `Insights.RealTimeData Insights OR.Folders.Read` |
202+
197203
## Processes
198204

199205
| Method | OAuth Scope |

docs/pagination.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,4 @@ console.log(`Total count: ${allAssets.totalCount}`);
136136
| Feedback | `getCategories()` | ✅ Yes |
137137
| Traces | `getById()` | ❌ No |
138138
| Traces | `getSpansByIds()` | ❌ No |
139+
| Governance | `getPolicyTraces()` | ✅ Yes |

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ nav:
195195
- Entities:
196196
- api/interfaces/entity/index.md
197197
- Choice Sets: api/interfaces/ChoiceSetServiceModel.md
198+
- Governance: api/interfaces/GovernanceServiceModel.md
198199
- Maestro:
199200
- Processes: api/interfaces/MaestroProcessesServiceModel.md
200201
- Process Instances: api/interfaces/ProcessInstancesServiceModel.md

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,16 @@
175175
"types": "./dist/document-understanding/index.d.ts",
176176
"default": "./dist/document-understanding/index.cjs"
177177
}
178+
},
179+
"./governance": {
180+
"import": {
181+
"types": "./dist/governance/index.d.ts",
182+
"default": "./dist/governance/index.mjs"
183+
},
184+
"require": {
185+
"types": "./dist/governance/index.d.ts",
186+
"default": "./dist/governance/index.cjs"
187+
}
178188
}
179189
},
180190
"files": [

rollup.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ const serviceEntries = [
208208
name: 'document-understanding',
209209
input: 'src/models/document-understanding/index.ts',
210210
output: 'document-understanding/index'
211+
},
212+
{
213+
name: 'governance',
214+
input: 'src/services/governance/index.ts',
215+
output: 'governance/index'
211216
}
212217
];
213218

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export * from './models/action-center';
1818
export * from './models/conversational-agent';
1919
export * from './models/agents';
2020
export * from './models/document-understanding';
21+
export * from './models/governance';
2122

2223
// Export error handling functionality (public API only)
2324
export * from './core/errors';
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Raw policy evaluation trace item as returned by API before transformation.
3+
*/
4+
export interface RawGovernancePolicyTraceItem {
5+
tenantId?: string;
6+
startTime: string;
7+
finalEnforcement?: string;
8+
policyId?: string;
9+
policyEnforcement?: string;
10+
policyEvaluationResult?: string;
11+
policyName?: string;
12+
policyStatus?: string;
13+
policyEvaluationDetails?: string;
14+
actorProcessId?: string;
15+
actorProcessType?: string;
16+
actorIdentityId?: string;
17+
resourceId?: string;
18+
resourceType?: string;
19+
folderKey?: string;
20+
traceId?: string;
21+
processKey?: string;
22+
jobKey?: string;
23+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import type {
2+
GovernancePolicyTrace,
3+
GovernancePolicyTraceGetAllOptions,
4+
} from './governance.types';
5+
import type {
6+
PaginatedResponse,
7+
NonPaginatedResponse,
8+
HasPaginationOptions,
9+
} from '../../utils/pagination';
10+
11+
/**
12+
* Service for inspecting governance policy enforcement on the UiPath platform.
13+
*
14+
* See [Define governance policies](https://docs.uipath.com/automation-ops/automation-cloud/latest/user-guide/define-governance-policies)
15+
* for how governance policies are configured in Automation Ops.
16+
*
17+
* All methods require the caller to be an organization administrator.
18+
*
19+
* ### Usage
20+
*
21+
* Prerequisites: Initialize the SDK first - see [Getting Started](/uipath-typescript/getting-started/#import-initialize)
22+
*
23+
* ```typescript
24+
* import { Governance } from '@uipath/uipath-typescript/governance';
25+
*
26+
* const governance = new Governance(sdk);
27+
* const traces = await governance.getPolicyTraces(new Date('2024-01-01'));
28+
* ```
29+
*/
30+
export interface GovernanceServiceModel {
31+
/**
32+
* Gets per-policy enforcement decisions across the requested time range.
33+
*
34+
* Each result row represents one policy's verdict within a single governance enforcement event.
35+
* A single user action can produce multiple rows when multiple policies were consulted.
36+
* Results are ordered by event start time, descending.
37+
*
38+
* @param startTime - Inclusive lower bound on the trace start time.
39+
* @param options - Optional filters and pagination options
40+
* @returns Promise resolving to {@link NonPaginatedResponse} of {@link GovernancePolicyTrace}
41+
* without pagination options, or {@link PaginatedResponse} of
42+
* {@link GovernancePolicyTrace} when pagination options are used.
43+
*
44+
* @example
45+
* ```typescript
46+
* import { Governance, PolicyEvaluationResult } from '@uipath/uipath-typescript/governance';
47+
*
48+
* const governance = new Governance(sdk);
49+
*
50+
* // Get all policy traces from the specified start time
51+
* const recent = await governance.getPolicyTraces(new Date('2024-01-01'));
52+
* console.log(recent.items.length);
53+
*
54+
* // Get all denied decisions across the whole organization
55+
* const page1 = await governance.getPolicyTraces(
56+
* new Date('2024-01-01'),
57+
* {
58+
* endTime: new Date(),
59+
* evaluationResult: [PolicyEvaluationResult.Deny, PolicyEvaluationResult.SimulatedDeny],
60+
* fullOrganization: true,
61+
* pageSize: 25,
62+
* },
63+
* );
64+
*
65+
* if (page1.hasNextPage) {
66+
* const page2 = await governance.getPolicyTraces(
67+
* new Date('2024-01-01'),
68+
* { cursor: page1.nextCursor },
69+
* );
70+
* }
71+
* ```
72+
*/
73+
getPolicyTraces<T extends GovernancePolicyTraceGetAllOptions = GovernancePolicyTraceGetAllOptions>(
74+
startTime: Date,
75+
options?: T,
76+
): Promise<
77+
T extends HasPaginationOptions<T>
78+
? PaginatedResponse<GovernancePolicyTrace>
79+
: NonPaginatedResponse<GovernancePolicyTrace>
80+
>;
81+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Governance Service Types
3+
*
4+
* Public types exposed via `@uipath/uipath-typescript/governance`.
5+
*/
6+
7+
import { PaginationOptions } from '../../utils/pagination/types';
8+
9+
export enum PolicyEvaluationResult {
10+
/** Active policy permitted the action. */
11+
Allow = 'Allow',
12+
/** Active policy blocked the action. */
13+
Deny = 'Deny',
14+
/** Simulated (NoOp) policy would have permitted the action. */
15+
SimulatedAllow = 'SimulatedAllow',
16+
/** Simulated (NoOp) policy would have blocked the action. */
17+
SimulatedDeny = 'SimulatedDeny',
18+
}
19+
20+
/**
21+
* Each trace row represents one policy's verdict within a governance
22+
* enforcement event. One enforcement event can produce multiple trace rows
23+
* when multiple policies contributed to the final verdict.
24+
*/
25+
export interface GovernancePolicyTrace {
26+
/** Tenant the trace was recorded in. Present even when `fullOrganization` is `true`. */
27+
tenantId?: string;
28+
/** The start time of governance enforcement event. */
29+
startTime: string;
30+
/** Final enforcement verdict for the parent governance event. */
31+
finalEnforcement?: string;
32+
/** ID of the policy this trace row evaluates. */
33+
policyId?: string;
34+
/** This individual policy's enforcement contribution to the parent verdict. */
35+
policyEnforcement?: string;
36+
/** The outcome of one policy evaluation — whether it allowed or denied the action, and whether that decision was actively enforced or just simulated (NoOp). */
37+
policyEvaluationResult?: string;
38+
/** Display name of the policy. */
39+
policyName?: string;
40+
/** Enforcement mode of the policy at the time of evaluation. */
41+
policyStatus?: string;
42+
/** Opaque details payload describing the evaluation result. */
43+
policyEvaluationDetails?: string;
44+
/** Process or executable that triggered the evaluation. */
45+
actorProcessId?: string;
46+
/** Type of the actor process (e.g. coded agent, RPA process). */
47+
actorProcessType?: string;
48+
/** Identity (user/principal) that triggered the evaluation. */
49+
actorIdentityId?: string;
50+
/** Resource being acted on. */
51+
resourceId?: string;
52+
/** Type of the resource being acted on. */
53+
resourceType?: string;
54+
/** Orchestrator folder key associated with the evaluation, if any. */
55+
folderKey?: string;
56+
/** Distributed-tracing ID covering the governance enforcement event. */
57+
traceId?: string;
58+
/** Process key associated with the evaluation, if any. */
59+
processKey?: string;
60+
/** Job key associated with the evaluation, if any. */
61+
jobKey?: string;
62+
}
63+
64+
/**
65+
* Common filter options shared across Governance APIs.
66+
*
67+
* Holds filters that are not specific to any single governance resource, so
68+
* other governance endpoints can reuse them.
69+
*/
70+
export interface GovernanceFilterOptions {
71+
/**
72+
* Inclusive upper bound on trace start time. When omitted, the upper bound
73+
* is open.
74+
*/
75+
endTime?: Date;
76+
/**
77+
* Whether to query the whole organization instead of just the current tenant.
78+
*
79+
* Defaults to tenant-scoped:
80+
* - omitted → tenant-scoped (default)
81+
* - `false` → tenant-scoped (explicit, same result)
82+
* - `true` → org-wide across all tenants; requires an organization admin,
83+
* otherwise the request returns 403
84+
*
85+
* @default false
86+
*/
87+
fullOrganization?: boolean;
88+
}
89+
90+
/**
91+
* Filter and pagination options for fetching policy traces.
92+
*
93+
* All filters combine with AND semantics. Array filters match any value in
94+
* the array (OR within a single filter).
95+
*/
96+
export type GovernancePolicyTraceGetAllOptions = PaginationOptions & GovernanceFilterOptions & {
97+
/** Filter by one or more policy evaluation results. */
98+
evaluationResult?: PolicyEvaluationResult[];
99+
/** Filter by one or more policy IDs. */
100+
policyId?: string[];
101+
/** Filter by one or more actor process IDs. */
102+
actorProcessId?: string[];
103+
/** Filter by one or more actor process types (e.g. coded agent, RPA process). */
104+
actorProcessType?: string[];
105+
/** Filter by one or more actor identity IDs. */
106+
actorIdentityId?: string[];
107+
/** Filter by one or more resource IDs. */
108+
resourceId?: string[];
109+
/** Filter by one or more resource types. */
110+
resourceType?: string[];
111+
/** Filter by one or more distributed-trace IDs. */
112+
traceId?: string[];
113+
};

src/models/governance/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Governance Types
3+
*
4+
* Public type surface for the Governance service.
5+
*/
6+
7+
export * from './governance.types';
8+
export * from './governance.models';

0 commit comments

Comments
 (0)