Skip to content

feat(governance): add Governance getPolicyTraces service#464

Merged
ashishupadhyay88 merged 26 commits into
mainfrom
feat/sdk-governance-policy-traces
Jun 8, 2026
Merged

feat(governance): add Governance getPolicyTraces service#464
ashishupadhyay88 merged 26 commits into
mainfrom
feat/sdk-governance-policy-traces

Conversation

@ashishupadhyay88

@ashishupadhyay88 ashishupadhyay88 commented May 26, 2026

Copy link
Copy Markdown
Contributor

Method Added

Layer Method Signature
Service governance.getPolicyTraces() getPolicyTraces<T extends PolicyTraceGetAllOptions>(startTime: Date, options?: T): Promise<T extends HasPaginationOptions<T> ? PaginatedResponse<PolicyTrace> : NonPaginatedResponse<PolicyTrace>>

Endpoint Called

Method HTTP Endpoint OAuth Scope
getPolicyTraces() POST insightsrtm_/Governance/policy/traces Insights.RealTimeData Insights OR.Folders.Read
  • New Governance service — extends BaseService. All methods require the caller to be an organization administrator.
  • Exposed as a modular subpath export: @uipath/uipath-typescript/governance.
  • startTime is a required positional Date; all filters and pagination live in the optional options object.
  • Pagination: page-number-based OFFSET pagination via the shared PaginationHelpers.getAll(). The API is 0-based, so the SDK's 1-based page number is sent as pageNumber - 1 (new zeroBased option on the shared OFFSET path). The API returns no total count, so hasNextPage is inferred from whether the current page is full.

Example Usage

import { UiPath } from '@uipath/uipath-typescript/core';
import { Governance, PolicyEvaluationResult } from '@uipath/uipath-typescript/governance';

const sdk = new UiPath(config);
await sdk.initialize();
const governance = new Governance(sdk);

// Get all policy traces from the specified start time
const recent = await governance.getPolicyTraces(new Date('2024-01-01'));
console.log(recent.items.length);

// Get all denied decisions across the whole organization, paginated
const page1 = await governance.getPolicyTraces(
  new Date('2024-01-01'),
  {
    endTime: new Date(),
    evaluationResult: [PolicyEvaluationResult.Deny, PolicyEvaluationResult.SimulatedDeny],
    fullOrganization: true,
    pageSize: 25,
  },
);

if (page1.hasNextPage) {
  const page2 = await governance.getPolicyTraces(
    new Date('2024-01-01'),
    { cursor: page1.nextCursor },
  );
}

API Response vs SDK Response

Transform pipeline

No transform. The API already returns camelCase keys, so trace rows are passed through unchanged — no pascalToCamelCaseKeys, no field-rename map, no value mapping. Date inputs (startTime, endTime) are serialized to ISO 8601 on the request side only.

Field mapping

API Response SDK Response Change Reason
(all fields) (identical) None API emits camelCase; SDK returns rows as-is

policyEvaluationResult is typed as the PolicyEvaluationResult enum. Live data confirms the response only ever returns Allow / Deny (simulation is tracked separately in policyStatus); the SimulatedAllow / SimulatedDeny enum members apply to the request-side evaluationResult filter, which the server maps to its composite verdict keys.

Sample SDK Response

getPolicyTraces()
{
  "items": [
    {
      "tenantId": "e367ca54-053b-4b86-89a2-6b9e89e85e7a",
      "startTime": "2026-04-15T16:55:41.794",
      "finalEnforcement": "NoOp",
      "policyId": "9f99cf09-ba63-472e-858e-e80bee3b66fb",
      "policyEnforcement": "NoOp",
      "policyEvaluationResult": "Allow",
      "policyName": "ghcbxvb",
      "policyStatus": "Simulated",
      "policyEvaluationDetails": "[]",
      "actorProcessId": "e0bdb365-defb-45eb-9105-abe5748df6bb",
      "actorProcessType": "Flow",
      "actorIdentityId": "",
      "resourceId": "615068c4-3b66-4d33-b2c4-3df5807e1903",
      "resourceType": "Agent",
      "folderKey": "5ff02b94-316c-404d-ab56-301834767f63",
      "traceId": "2351eee9-cb4f-43af-a877-dde65c2ee116",
      "processKey": "e0bdb365-defb-45eb-9105-abe5748df6bb",
      "jobKey": ""
    },
    {
      "tenantId": "e367ca54-053b-4b86-89a2-6b9e89e85e7a",
      "startTime": "2026-04-15T16:55:41.794",
      "finalEnforcement": "NoOp",
      "policyId": "a7c68eea-4d11-4f08-81ba-f391b9a8c45d",
      "policyEnforcement": "NoOp",
      "policyEvaluationResult": "Allow",
      "policyName": "hjytj",
      "policyStatus": "Simulated",
      "policyEvaluationDetails": "[]",
      "actorProcessId": "e0bdb365-defb-45eb-9105-abe5748df6bb",
      "actorProcessType": "Flow",
      "actorIdentityId": "",
      "resourceId": "615068c4-3b66-4d33-b2c4-3df5807e1903",
      "resourceType": "Agent",
      "folderKey": "5ff02b94-316c-404d-ab56-301834767f63",
      "traceId": "2351eee9-cb4f-43af-a877-dde65c2ee116",
      "processKey": "e0bdb365-defb-45eb-9105-abe5748df6bb",
      "jobKey": ""
    }
  ]
}

Truncated to 2 items — full response returns one row per policy evaluated within each governance enforcement event.

Files

Area Files
Endpoint src/utils/constants/endpoints/governance.ts, src/utils/constants/endpoints/index.ts
Types src/models/governance/governance.types.ts, src/models/governance/governance.internal-types.ts
Constants src/utils/constants/common.ts
Models src/models/governance/governance.models.ts, src/models/governance/index.ts
Service src/services/governance/governance.ts, src/services/governance/index.ts
Pagination (shared) src/services/base.ts, src/utils/pagination/helpers.ts, src/utils/pagination/internal-types.ts
Build package.json, rollup.config.js
Barrel exports src/index.ts
Unit tests tests/unit/services/governance/governance.test.ts (16 tests)
Integration tests tests/integration/shared/governance/governance.integration.test.ts (5 tests), tests/integration/config/unified-setup.ts
Test utils tests/utils/constants/governance.ts, tests/utils/constants/index.ts, tests/utils/mocks/governance.ts, tests/utils/mocks/index.ts
Docs docs/oauth-scopes.md, docs/pagination.md, mkdocs.yml

🤖 Auto-generated using onboarding skills

Comment thread tests/unit/services/governance/governance.test.ts Outdated
Comment thread tests/unit/services/governance/governance.test.ts Outdated
@claude

claude Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Review summary - 1 bug (2 locations)

tests/unit/services/governance/governance.test.ts lines 144 and 173

{ TraceId: trace-${i} } passes a PascalCase key as an override to createMockRawPolicyEvaluationTrace(), but RawPolicyEvaluationTraceItem declares traceId (camelCase). Two consequences:

  1. TypeScript error — excess property check rejects an unknown key on Partial<RawPolicyEvaluationTraceItem>, so npm run typecheck will fail.
  2. Silent no-op — the override does nothing at runtime; the default mock traceId value survives unchanged.

Fix: use traceId (lowercase t) in both Array.from calls.

Comment thread docs/oauth-scopes.md Outdated
Comment thread tests/integration/shared/governance/governance.integration.test.ts
@claude

claude Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding

tests/integration/shared/governance/governance.integration.test.ts line 9

The governance service calls insightsrtm_ endpoints, which reject PAT tokens entirely (401 regardless of scopes) and require OAuth. Per CLAUDE.md, integration tests for these endpoints must use describe.skip.each with a comment explaining the PAT auth limitation, so CI does not fail on PAT-authenticated runs and the test structure is preserved for when OAuth is wired in.


Previously raised threads (TraceId casing in unit tests) remain open — the current diff already shows traceId (camelCase), so those threads can be resolved once confirmed.

@ashishupadhyay88 ashishupadhyay88 changed the title feat(governance): add Governance getPolicyEvaluationTraces service feat(governance): add Governance getTraces service May 26, 2026
@ashishupadhyay88 ashishupadhyay88 changed the title feat(governance): add Governance getTraces service feat(governance): add Governance getPolicyTraces service May 26, 2026
Comment thread src/models/governance/governance.types.ts
@claude

claude Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

Comment thread src/models/governance/governance.types.ts
@claude

claude Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding + 1 re-opened thread

Re-opened: src/models/governance/governance.types.ts line 64 — PolicyStatus enum

The previous thread requesting a PolicyStatus enum for the policyStatus field was resolved, but the field still reads policyStatus?: string. Re-opened so it stays visible.


New: src/models/governance/governance.types.ts line 114 — options type name

PolicyTracesGetAllOptions should be PolicyTraceGetAllOptions — CLAUDE.md specifies {Entity}GetAllOptions with the singular entity name (PolicyTrace). The rename needs to flow through governance.ts and the unit-test import/cast.

@claude

claude Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

@ninja-shreyash ninja-shreyash left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pls address open claude comments

Comment thread src/models/governance/governance.internal-types.ts Outdated
Comment thread src/models/governance/governance.internal-types.ts Outdated
Comment thread src/models/governance/governance.internal-types.ts Outdated
Comment thread src/models/governance/governance.internal-types.ts Outdated
Comment thread src/models/governance/governance.models.ts Outdated
@ashishupadhyay88

Copy link
Copy Markdown
Contributor Author

Pls address open claude comments

I have resolved now. already addressed required ones.

Comment thread tests/utils/mocks/governance.ts Outdated
@claude

claude Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding

tests/utils/mocks/governance.ts line 4 — RawPolicyTracesResponse missing from internal-types

The mock imports RawPolicyTracesResponse from governance.internal-types.ts, but that file only exports RawPolicyTraceItem. npm run typecheck will fail with "Module has no exported member 'RawPolicyTracesResponse'". The type was likely removed from governance.internal-types.ts when addressing the earlier reviewer request (thread PRRT_kwDOOpObr86FBCAy), but the mock wasn't updated to match.

Comment thread src/services/governance/governance.ts Outdated
@claude

claude Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding + 1 re-opened thread

Re-opened: src/models/governance/governance.models.ts line 15 — internal span names

Thread PRRT_kwDOOpObr86FBK-R (originally from @ninja-shreyash) asked to remove governanceEvaluation and policyEvaluation from the class-level JSDoc. The author replied "I have removed technical details" but the current code still contains both terms on line 15. Re-opened so it stays visible.


New: src/services/governance/governance.ts line 87 — cursor + jumpToPage mutual exclusion not enforced

CLAUDE.md flags this as a "Critical constraint": cursor and jumpToPage are mutually exclusive. When both options are passed the else if structure silently drops jumpToPage, producing confusing behaviour. A ValidationError guard (and a matching unit test) should be added before the branching block.

Comment thread src/models/governance/governance.types.ts Outdated
@claude

claude Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding

src/models/governance/governance.types.ts line 35 — internal span names in PolicyTrace JSDoc

The PolicyTrace interface JSDoc references policyEvaluation and governanceEvaluation span names, which are internal BE tracing implementation details. The same concern was raised and resolved for governance.models.ts (PRRT_kwDOOpObr86FBK-R), but the same terms persisted in the public-facing types file where they feed into the generated API docs.

Comment thread src/models/governance/governance.types.ts Outdated
@claude

claude Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding + 1 re-opened thread

Re-opened: src/models/governance/governance.types.tsPolicyTrace JSDoc still contains governanceEvaluation

Thread PRRT_kwDOOpObr86Fmu9u requested removing the internal BE span name governanceEvaluation from the public PolicyTrace JSDoc. It was resolved, but the current code still contains it — and worse, the description is garbled: the suggested replacement text was prepended but the old text (starting with the mid-sentence fragment "joined to its parent governance enforcement decision (a governanceEvaluation span)") was not removed. Re-opened.


New: src/models/governance/governance.types.ts line 13 — "Snowflake key" leaks internal storage technology

The PolicyEvaluationResult enum JSDoc says "composite Snowflake key" — Snowflake is the internal data warehouse backing this endpoint and should not appear in the public SDK docs (same spirit as the earlier @ninja-shreyash feedback about removing internal BE details). Replace with "composite verdict string".

Comment thread src/models/governance/governance.types.ts Outdated
@claude

claude Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review summary — 1 new finding

src/models/governance/governance.types.ts lines 35–39 — duplicate sentence in PolicyTrace JSDoc

The description has two near-identical sentences:

"One enforcement event can produce multiple trace rows when multiple policies contributed to the final verdict."
"One enforcement event can produce multiple trace rows when multiple policies fed into the final verdict."

The second sentence is a redundant restatement and should be removed (suggestion posted inline). This appears to be a side-effect of applying the previous fix for internal span names — the suggested replacement text was added but the original duplicate sentence wasn't deleted.

ashishupadhyay88 and others added 24 commits June 8, 2026 16:53
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>
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>
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>
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>
…GetAllOptions

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>
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>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… 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>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ontract

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>
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>
…ce, 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>
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>
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>
@ashishupadhyay88 ashishupadhyay88 force-pushed the feat/sdk-governance-policy-traces branch from 5ef8916 to fdf3c0d Compare June 8, 2026 11:25
@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

@claude

claude Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

@ashishupadhyay88 ashishupadhyay88 merged commit becb52b into main Jun 8, 2026
18 checks passed
@ashishupadhyay88 ashishupadhyay88 deleted the feat/sdk-governance-policy-traces branch June 8, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants