[CXH-389, CXH-903] - Sync group descriptions to resources and membership entitlements - Okta Connector - #199
Conversation
…t descriptions The Okta group description was only written into the group profile map, so the group resource carried no description and the membership entitlement always used a generated "Member of <group> group in Okta" template. C1 surfaces the entitlement description on access-request forms, in access reviews and in CSV exports, so the guidance admins write in Okta never reached the people deciding on the request. Set the description on the group resource and reuse it for the member entitlement, falling back to the generated text when the group has none. Descriptions are clamped to the protocol's 2048-byte budget on a character boundary: Okta caps group descriptions at 1024 UTF-16 units, which is up to 3072 bytes of UTF-8, and an over-long value fails validation and aborts the whole sync. The profile key keeps carrying Okta's raw value, since that is an already-shipped contract. The entitlement id, slug and display name are unchanged, so no existing grant is re-keyed. Co-authored-by: Cursor <cursoragent@cursor.com>
Connector PR Review: [CXH-389, CXH-903] - Sync group descriptions to resources and membership entitlements - Okta ConnectorBlocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0 Review SummaryScanned the full PR diff ( Verified specifically: the clamp backs off to a character boundary and cannot loop past an empty string; Security IssuesNone found. Correctness IssuesNone found. SuggestionsNone. |
… budget An over-budget description was clamped silently, so a description that renders cut off in ConductorOne could not be confirmed from a sync log. The log lives in List rather than in groupDescription so the mapping helper stays pure and no call site changes signature, matching how the rest of the connector logs skip and mapping decisions. Co-authored-by: Cursor <cursoragent@cursor.com>
The log check trimmed the description again even though groupDescription already trimmed it while building the resource, so every group paid for a second TrimSpace during sync. Trimming only ever shortens, so the raw length now gates the check and the trim happens only for a description that is actually over budget. Comparing the trimmed length against the stored one also makes the condition exact: it fires when the value really was clamped, not merely when it was long. Co-authored-by: Cursor <cursoragent@cursor.com>
Description
Okta group descriptions were being synced into the group profile map but never onto the resource itself, and the membership entitlement always used a generated
Member of <group> group in Oktatemplate. That template is what ConductorOne shows on access-request forms, in access reviews and in CSV exports, so the guidance admins write in Okta never reached the people who needed it.This makes the connector use the group's real Okta description in both places: on
Resource.Descriptionfor the group resource, and as thememberentitlement's description. Groups with no description in Okta keep the generated template, so nothing regresses for tenants that never filled the field in.CXH-389 (Allvue, DoorDash) is the entitlement half — the description shown on the request form. CXH-903 (PsiQuantum) is the resource half — they run several groups with the same name and the description is the only thing that tells them apart. They are the same change: following the pattern Active Directory shipped in CXH-1157, the entitlement reads
resource.Description, so the resource has to carry it first.Sync:
group) — the resource now carries the Okta group description, and thememberentitlement uses it instead of the generated template. Whitespace-only descriptions are treated as unset and fall back to the template.user) — unchanged surfacerole) — unchanged surfaceapp) — unchanged surfaceresource_sets) — unchanged surface (see Architecture highlights for why)Provisioning:
unchanged
Auth:
unchanged — no new config flag, no new scope or permission. The group description is already returned by the same
GET /api/v1/groupscall the connector makes today (GroupProfile.Descriptionin the vendored Okta SDK), so this adds no API calls.Architecture highlights:
group:<okta-group-id>:member— the SDK derives it from the resource ID and the slug, not the description — and the slug and display name are unchanged. Existing grants keep pointing at the same entitlement. A unit test pins all three so a future change cannot drift.Resource.DescriptionandEntitlement.Descriptionat 2048 bytes and enforces it through the gRPC validation interceptor. Okta caps group descriptions at 1024 UTF-16 units, not bytes, so a 1024-character CJK description is accepted by Okta at 3072 bytes of UTF-8. Without the clamp a single such group aborts the entire sync withInvalidArgument: value length must be between 1 and 2048 bytes. The clamp backs off to the last complete character so the value stays valid UTF-8.descriptionkey is left carrying Okta's raw value. That key is an already-shipped contract, so the trim and the clamp apply only to the new resource-level description; a test asserts the profile still holds the untouched Okta string.baton-okta-ciamregisters no group syncer and never emits a group entitlement, so it cannot show this. (baton-okta-ciam-workforceis a different catalog product that does carry the same template; nobody has reported it and it is not named in the ticket. Reasoning is written up on CXH-389.)user_edited_mask; on a later sync a differing connector description sets the mask instead of updating the field. So on a tenant whose group entitlements already exist, this change will not rewrite them — newly created entitlements get the real description. The resource description has no such limit and updates on every sync. Validated against a live Okta tenant and a full C1 stack, including an A/B between this branch andmainon the same tenant.Useful links: