Skip to content

CXH-1928: add group membership provisioning - #35

Merged
al-conductorone merged 3 commits into
mainfrom
cxh-1928-group-membership-provisioning
Aug 26, 2026
Merged

CXH-1928: add group membership provisioning#35
al-conductorone merged 3 commits into
mainfrom
cxh-1928-group-membership-provisioning

Conversation

@al-conductorone

Copy link
Copy Markdown
Contributor

Users can now be added to and removed from Atlassian groups through C1 access requests, instead of managing group membership by hand in the Atlassian admin console.

@linear-code

linear-code Bot commented Aug 21, 2026

Copy link
Copy Markdown

CXH-1928

Comment thread pkg/connector/groups.go
Comment thread pkg/client/client.go
Comment thread pkg/client/client.go
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Connector PR Review: CXH-1928: add group membership provisioning

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 93fb23da6312.
Review mode: full
View review run: https://github.com/ConductorOne/baton-atlassian/actions/runs/32770798007

Review Summary

Reviewed the full PR diff (8 files: client, helper, model, groups.go, capabilities JSON, README, and both docs files) for security, correctness, provisioning entity-source rules, and breaking changes; no new issues found. All four prior findings are verified fixed in the current tree: Grant now returns GrantAlreadyExists on codes.AlreadyExists (pkg/connector/groups.go:216), GetGroupDirectoryID rejects a 200 response with an empty directoryId (pkg/client/client.go:331), the MethodDelete branch passes uhttp.WithErrorResponse (pkg/client/client.go:572) — and since BaseHttpClient.Do returns a joined error whose first element carries the mapped gRPC code, status.Code still resolves through it, so IsNotFound behaviour is unchanged — and a 404 from the group lookup in Revoke maps to GrantAlreadyRevoked (pkg/connector/groups.go:235). The remaining prior suggestion (the extra GetGroupDirectoryID round trip per grant/revoke when ListGroups already returns directoryId, plus no test coverage for the new client methods) is still open and is not re-filed here.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None new. Prior open suggestion: pkg/connector/groups.go:209 and :233 — cache Group.DirectoryId in the group resource profile at sync time to drop the per-operation lookup, and add tests for AddUserToGroup/RemoveUserFromGroup/Grant/Revoke.

@github-actions github-actions Bot 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.

No blocking issues found.

@FeliLucero1 FeliLucero1 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.

Ran a deep review on this — mostly good, a couple idempotency gaps worth fixing before merge (see inline comments). Also small heads up: docs/docs-info.md still says only User Roles are provisionable, might want to update that too even though it is not part of this diff.

Comment thread pkg/connector/groups.go
Comment thread pkg/connector/groups.go
Comment thread pkg/connector/groups.go
Address review feedback on PR #35:
- Grant now treats an already-existing membership (HTTP 409 ->
  codes.AlreadyExists) as success, mirroring Revoke's not-found handling.
- Revoke now treats a 404 from GetGroupDirectoryID (group deleted upstream)
  as GrantAlreadyRevoked, since a missing group means the membership is gone.
- docs-info.md now lists Group Memberships as a provisionable resource.
Address review-bot feedback on PR #35:
- GetGroupDirectoryID now returns codes.Internal when a 200 response omits
  directoryId, instead of silently building a wrong membership URL from an
  empty path segment.
- The DELETE branch of doRequest now passes uhttp.WithErrorResponse, so revoke
  failures keep the Atlassian error detail. IsNotFound still resolves through
  the resulting joined error, so revoke idempotency is unchanged.

@github-actions github-actions Bot 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.

No blocking issues found.

@mateoHernandez123 mateoHernandez123 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.

Verified the group-membership provisioning end to end. The DELETE endpoint matches Atlassian's v2 org-directory API (/v2/orgs/{orgId}/directories/{directoryId}/groups/{groupId}/memberships/{accountId}, keyed on accountId), the directoryId is resolved up front, and idempotency is symmetric — Grant returns GrantAlreadyExists on a 409, and Revoke returns GrantAlreadyRevoked on a 404 for both the directory lookup and the membership delete. Error wrapping and the DELETE WithErrorResponse are correct, there are no Warn logs, and the extra per-op GET to resolve the directory is a fair tradeoff given the service-mode re-keying constraint you called out (a profile-cached directoryId would be empty on the provisioning path, and encoding it into the resource ID would re-key existing grants). LGTM.

Two non-blocking follow-ups:

  • The new client methods and Grant/Revoke ship without unit coverage — worth adding when this connector grows a test harness.
  • #33 is a duplicate of this PR for the same ticket and should be closed as superseded.

@al-conductorone
al-conductorone merged commit 2286dd5 into main Aug 26, 2026
9 checks passed
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