Repository navigation
[CXH-2344] - Add Grant/Revoke provisioning for Groups, User Groups, Roles, Sites, and Managed Devices - #31
Conversation
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
Blocking issues found — see the full review report
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
Stale — all blocking findings resolved as of 83d0c17 (bot confirmed 0 blocking issues remain).
- jamfDeviceAssignHandlerWithCurrent now requires the /detail suffix for the mobile-devices GET match, so a regression back to the plain (flat-shape) endpoint fails loudly instead of silently passing - Add TestManagedDeviceRevoke_MobileDevice_ClearsUsername, the mobile counterpart of TestManagedDeviceRevoke_ClearsUsername, covering the case where the PATCH is actually sent Addresses review suggestion on PR #31 (#31 (comment)) Fixes CXH-2344 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The newer golangci-lint used in CI reports the three literals that appear three times each (goconst). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…imitations Adds the Jamf privileges each operation needs (verified one capability at a time with a Custom account), the opt-in Managed Devices requirements, authentication notes and the per-resource Grant/Revoke limits, and fixes stale statements (no Grant/Revoke, provisioning flag scope, help output). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Device Grant/Revoke match the assignee by username when it is set (a stale email no longer turns a Grant into a no-op or lets a Revoke clear another user) and report a missing device as already revoked (Revoke) or NotFound (Grant). - GrantAlreadyExists is returned with nil grants everywhere; shared helpers replace duplicated principal and id checks. - Adds tests for device client requests and user group request wiring, uses the response shapes Jamf returns in fixtures, and trims or corrects comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Models the verified side effects (group removal when an account is PUT or deleted, expanded privilege lists for built-in sets, Group Access accounts, all-or-nothing user group changes, 201 on every Classic PUT, user site list semantics) and keeps the privilege catalog and accepted names distinct so the "Jamf drops this name" path is reachable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Role Grant/Revoke now read and write the account or group through getRolePrincipal and updateRolePrincipal instead of an interface with one implementation per principal type. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ade48f3 to
a5712f5
Compare
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
…by email Group/Role Grant and Revoke no longer re-read after a successful write to verify it landed; they return/report success optimistically, matching the rest of the connector's provisioning paths. Group Revoke now treats an empty members read the same way Grant already does: rather than reporting a possibly-still-a-member principal as revoked, it returns a retryable error so the platform retries instead of recording a false success that a later sync would otherwise just bring back. User Group and Site Grant/Revoke treat a 409 on the write as a real failure instead of re-fetching to disambiguate it — the pre-write read already performs the idempotency check, so a 409 past that point means something else actually went wrong. Fixed managedDevice Revoke: a grant whose principal was matched by email only (no username) failed to clear the device's assignee whenever the device also reported a username, because the match was keyed off the device's username being present rather than the principal's.
Introduce an assignee{username, email} type in managedDevice.go to carry a
device's assignee identity end to end (recording, matching, and resolving
grant ids), replacing the loose username/email string pairs threaded through
currentAssignedUser, principalIdentityForRevoke, Grant and Revoke. A shared
assigneePrincipal helper now backs both deviceGrants and replacedGrantID's
principal resolution, and replacedGrantID drops its GetUserByName fast path
in favor of always going through the cached user index. Username/email
preference logic moves onto jamf.User as LoginName()/PrimaryEmail().
Extract membershipIDs as the common Grant/Revoke preamble (principal-type
check plus container/principal id parsing) shared by group.go, userGroup.go
and site.go. Add rolePrincipal.requireDirectPrivileges to replace the
duplicated Group Access check in role.go's Grant/Revoke, and drop the
redundant upfront principal-id validation there now that getRolePrincipal's
own InvalidArgument errors are passed through unwrapped.
On the client side, collapse UpdateAccountPrivileges/UpdateGroupPrivileges
onto one private updatePrivileges helper and a single XML body type, move
Site Grant/Revoke's read-modify-write out of AddUserSite/RemoveUserSite and
into site.go (matching how group.go/userGroup.go already work), drop the
sections parameter from GetComputersInventory now that the v4 endpoint is
confirmed to ignore it, and merge a few structurally-identical XML/JSON
helper types (memberUsers, the mobile-device location type, Privileges.Map).
Shorten doc comments across helpers.go, managedDevice.go, userGroup.go, client.go and device_client.go to focus on the WHY rather than narrating the refactor history, and drop repeated explanations (ctx/WithFreshReads, the Jamf PATCH/PUT body semantics) in favor of keeping each one in a single place. In docs/connector.mdx, trim the Managed Devices opt-in note back to a brief mention of --sync-resource-types instead of spelling out cloud vs. self-hosted mechanics, and drop the new Authentication section entirely.
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
Blocking issues found — see the full review report
The remaining finding is the optimistic-write approach requested in review: Role and Group writes no longer re-read after the PUT (an unknown privilege or member can't come from the synced catalog, and the next sync reflects the real state). The empty-group Revoke and the device Revoke issues are fixed, and CI is green.
- Managed devices: assignee carries the full identity (realname, position, phone too); resolvePrincipalUser returns it and setAssignedUser maps it to jamf.ComputerAssignedUserFields only at the client call. - Drop the stale re-read note on rolePrincipal and the broken doRequestWithMethod reference on UserSitesUpdateBody.
Superseded — see the current review report for commit
|
Connector PR Review: [CXH-2344] - Add Grant/Revoke provisioning for Groups, User Groups, Roles, Sites, and Managed DevicesBlocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0 Review SummaryThe new commit is a refactor plus comment cleanup. In I scanned the full PR diff (32 files) for security and correctness. I did not re-read all ~7.9k lines line by line: I checked the incremental hunks in full, re-checked every prior finding against the current code, and pattern-scanned the rest. The incremental diff dropped no paths. How the repo-local criteria applied:
The PR description now describes Group and Role writes as optimistic (no re-read after the PUT). That resolves the earlier mismatch between the description and the code. Security IssuesNone found. Correctness IssuesNone found. Suggestions
Resolved prior findings
Prompt for AI agentsReviewed commit: |
There was a problem hiding this comment.
No blocking issues found — see the full review report
Intent (verbatim from the ticket)
Fixes CXH-2344
What this adds
Grant/Revoke provisioning (
ResourceProvisionerV2) for the Jamf resources that have an assignablerelationship:
userAccount(Group Access accounts only)useruserAccount,groupuseruserBehavior worth reviewing
Groups. The group is written with a minimal body (
name+members); the last member is removedwith an explicit empty
<members></members>. Jamf can return a member list that looks empty, so aread with no members is never written back: Grant aborts with
FailedPrecondition, and Revokereturns a retryable
Unavailableerror without writing (it doesn't report the member as removed).Writes are optimistic: Grant returns the grant after a successful PUT, without re-reading.
Roles.
Administrator,Auditor,Enrollment Only) and every individual privilegeis grantable to accounts and groups.
Customwith an empty privilege block, which is thelowest Jamf allows (it always keeps
Read License Information). Individual privileges can only begranted/revoked while the principal is
Custom; granting a set again leavesCustom.name,privilege_set, and the privilege block whenCustom) and neversend
siteormembers, so a group role change cannot touch membership. Any transition toCustomsends an explicit privilege block, otherwise Jamf copies the previous set's whole privilegelist into it.
the group instead). Changing the role of a Full/Site Access account removes it from admin groups it
was listed in; that membership does not grant such an account anything.
catalog, so an unknown privilege name can't reach a write; the next sync shows the real state.
User Groups. Reads the group first and skips the write when the membership already matches. Jamf
answers 409 when removing a non-member or adding an unknown user (for example, one deleted after the
sync); since membership is checked before the write, a 409 is returned as
FailedPreconditioninsteadof being treated as "already exists".
Sites. A user's sites are read-modify-written as a list (Jamf replaces the whole list on PUT); the
connector reads and checks, and the client only writes the list (
UpdateUserSites). A 409 on the writeis returned as
FailedPrecondition.This PR also fixes how a user's sites are decoded: Jamf returns a flat list while the model expected
each entry wrapped under
site, so every site id was read as 0 (sync emitted no user-to-site grantsand a second grant failed with 409). Note for the release: user-to-site grants now appear in sync.
Managed Devices.
computers-inventoryAPI (v1 and v3 are deprecated). Grant writesusername, name, email, position and phone from the new user's record in one PATCH (Jamf never
fills those in for computers); Revoke clears all five.
location.username; Jamf derives the rest from the directory user andclears it all when the username is cleared.
when the grant only carries an email, as for assignees that aren't synced Jamf users).
section=values; without them Jamf returns onlygeneral.managedDeviceto be selected as a synced resource type, like the sync.Reads before writes. The SDK HTTP client caches GET responses for an hour. Every provisioning
entry point now reads with the cache bypassed (
jamf.WithFreshReads) so idempotency checks andread-modify-write bodies never use stale data.
Docs and tooling.
README.md,docs/connector.mdxanddocs/docs-info.mdnow list the Jamf privileges each capability needs, using the names verified on the tenant. Classic API denials come back as 401 and Pro API denials as 403. Managed Devices are opt-in through--sync-resource-types. The Instance URL field description now says to includehttps://. The mock server intest-server/models the Jamf behavior observed on the tenant, so CI covers the same paths as the unit tests. Managed Devices are not mocked there.How it was verified
Grant, Revoke, idempotent repeats, deleted principals, wrong principal types and the guards above,
checking the real state of each object after every step. The behavior that Jamf's docs leave
undefined (merge vs replace on PUT, clearing fields, empty member lists, what a Custom set keeps)
was observed on the tenant and is what the bodies above rely on.
Roles refactors, device Revoke by email), the full Grant/Revoke flow was run again on the tenant,
including Managed Devices on test computer and mobile-device records.
Known limitations (documented in
docs/connector.mdx)not shown in sync.
userprincipal.assignedentitlement.🤖 Generated with Claude Code