Skip to content

Session rework for containerization#34

Merged
johnallers merged 18 commits intomainfrom
jallers/session-rework
Dec 19, 2025
Merged

Session rework for containerization#34
johnallers merged 18 commits intomainfrom
jallers/session-rework

Conversation

@johnallers
Copy link
Contributor

@johnallers johnallers commented Dec 17, 2025

Description

  • Simplified cache management for grants. Role, privilege, and folder grants are now emitted directly when listing collaborator grants, removing the need to process them separately under their respective resource types.
  • Added missing base privileges. (Fixes BB-1321)

Summary by CodeRabbit

  • Bug Fixes

    • Corrected spelling in collaborator entitlement descriptions.
  • New Features

    • Expanded privilege catalog with several new categories (Policies; Dashboard & logs; API platform; Collections & endpoints; Data tables; Settings; Client & access profiles).
    • Enhanced collaborator grant generation to include role- and privilege-based grants.
  • Changes

    • Streamlined collaborator cache and session-backed collaborator lookup.
    • Adjusted role and folder grant/entitlement behavior, including an opt-out for custom-role sync and new grant-skipping annotations.

✏️ Tip: You can customize this high-level summary in your review settings.

@johnallers johnallers requested a review from a team December 17, 2025 19:39
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

Implements collaborator Grants, simplifies collaborator cache to session-backed reads/writes, threads disableCustomRolesSync through builders, updates several builder and cache signatures, adjusts role grant behavior and adds role-by-name cache, and expands the Workato privilege catalog.

Changes

Cohort / File(s) Summary
Collaborator builder
pkg/connector/collaborator.go
Implemented Grants(ctx, resource, attr) to parse collaborator ID, fetch collaborator via session-backed cache, compute role-based grants (collaboratorRoleGrants), and build privilege and folder grants (with immutable annotation). Added helper grant constructors, updated collaboratorBuilder fields and newCollaboratorBuilder to accept disableCustomRolesSync, and adjusted imports.
Collaborator cache
pkg/connector/collaborator_cache.go
Replaced env-bound multi-lookup cache with a simplified session-backed cache. New ctor newCollaboratorCache(workatoClient *client.WorkatoClient). Added setCollaboratorsCache(ctx, sessionStorage, collaborators) and getCollaborator(ctx, sessionStorage, collaboratorId) for storing/reading collaborators in session storage; removed env field.
Connector wiring
pkg/connector/connector.go
Threaded disableCustomRolesSync into builders: newCollaboratorBuilder(d.client, d.env, d.disableCustomRolesSync) and newFolderBuilder(d.client, d.disableCustomRolesSync). Updated calls to match new builder signatures.
Folder builder & entitlements
pkg/connector/folder.go
Removed env parameter from newFolderBuilder(client, disableCustomRolesSync). Fixed collaborator entitlement text typos. Removed collaborator-grants generation flow and initial collaborator bag entry for folder grants.
Privilege builder
pkg/connector/privilege.go
Grants now returns nil (removed per-collaborator grant generation). Updated cache ctor usage to newCollaboratorCache(client) and removed grant package import.
Role builder & behavior
pkg/connector/role.go
Added interface assertions for connectorbuilder types. Adjusted method signatures (List now names parentResourceID; Entitlements/Grants accept attr rs.SyncOpAttrs). Grants now emits base-role privilege grants and may early-return for non-base roles when disableCustomRolesSync is set. newRoleBuilder updated to accept disableCustomRolesSync and uses newCollaboratorCache(client).
Role cache
pkg/connector/role_cache.go
Added roles_by_name cache prefix and getRoleByName. setRolesCache populates a roles-by-name map and uses constants for cache prefixes; improved logging with IDs.
Resource types
pkg/connector/resource_types.go
Removed Annotations from collaboratorResourceType. Added SkipGrants annotation to privilegeResourceType and SkipEntitlementsAndGrants to projectResourceType.
Privileges catalog
pkg/connector/workato/privileges.go
Expanded static privilege groups and privilege entries (Policies; Dashboard & logs; Manage locked projects; API platform; Collections & endpoints; Data tables; Settings; Client & access profiles).
Tests
pkg/connector/workato/privileges_test.go
Updated expected privilege count in TestAllCompoundPrivileges from 80 to 105.

Sequence Diagram(s)

sequenceDiagram
  participant Syncer as ResourceSyncer
  participant Builder as collaboratorBuilder
  participant Cache as collaboratorCache (session)
  participant Client as WorkatoClient
  participant Logger as ContextLogger

  Syncer->>Builder: Grants(ctx, resource, attr)
  Builder->>Logger: extract logger from ctx
  Builder->>Cache: getCollaborator(ctx, session, collaboratorId)
  alt collaborator found
    Cache-->>Builder: collaborator
    Builder->>Client: fetch collaborator roles & privileges
    Client-->>Builder: roles, privileges
    Builder->>Builder: compute collaboratorRoleGrants(roles)
    Builder->>Builder: build collaboratorPrivilegeGrant(privileges)
    opt env allows folder grants
      Builder->>Builder: build collaboratorFolderGrant(folder)
    end
    Builder-->>Syncer: []*v2.Grant, results, nil
  else not found / error
    Cache-->>Builder: error
    Builder-->>Syncer: nil, results, error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Inspect collaborator Grants implementation for ID parsing, error handling, env checks, and immutable grant annotation usage.
  • Validate session-based collaborator cache write/read semantics and consistency with removed env-binding.
  • Verify disableCustomRolesSync is consistently threaded and its effect on role grant generation.
  • Review role_cache additions (roles_by_name) for correct persistence and lookups.
  • Scan privilege catalog expansion for typos and test coverage updates.

Possibly related PRs

Suggested reviewers

  • laurenleach
  • luisina-santos
  • mateoHernandez123
  • JavierCarnelli-ConductorOne
  • sergiocorral-conductorone
  • FeliLucero1

Poem

🐰 I hopped through sessions, found collaborators true,

Roles and privileges stitched into each view,
Flags kept in order, caches tidy and small,
Grants built with care, and errors caught for all —
Hop, sync, and nibble: code carrots for the crew!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Session rework for containerization' is vague and does not clearly reflect the actual changes in the PR. The changeset focuses on redesigning collaborator and privilege grant handling, simplifying cache architecture, and adding privileges—not containerization. Revise the title to accurately describe the main changes, such as 'Simplify collaborator grant handling and cache architecture' or 'Refactor cache design and restructure grant emission for roles/privileges'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jallers/session-rework

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/connector/role_cache.go (1)

53-67: Same log format issue in getRoleByName.

Remove the %s placeholder from the error message at line 58.

-		l.Error("failed to get role by name from session storage %s", zap.String("role_name", roleName), zap.Error(err))
+		l.Error("failed to get role by name from session storage", zap.String("role_name", roleName), zap.Error(err))
pkg/connector/collaborator.go (1)

247-249: Duplicate WithUserLogin call.

Line 248 duplicates line 247 - this appears to be a copy-paste error.

 		resource.WithEmail(collaborator.Email, true),
 		resource.WithUserLogin(collaborator.Email),
-		resource.WithUserLogin(collaborator.Email),
 		resource.WithCreatedAt(collaborator.CreatedAt),
🧹 Nitpick comments (1)
pkg/connector/privilege.go (1)

68-73: Consider removing the unused cache field.

The cache field is initialized but never used since Grants now returns nil immediately. This is dead code that can be cleaned up.

 type privilegeBuilder struct {
 	client *client.WorkatoClient
-	cache  *collaboratorCache
 }
 
 func newPrivilegeBuilder(client *client.WorkatoClient, env workato.Environment) *privilegeBuilder {
 	return &privilegeBuilder{
 		client: client,
-		cache:  newCollaboratorCache(client),
 	}
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0acc593 and 9d7721a.

📒 Files selected for processing (9)
  • pkg/connector/collaborator.go (2 hunks)
  • pkg/connector/collaborator_cache.go (1 hunks)
  • pkg/connector/connector.go (1 hunks)
  • pkg/connector/folder.go (2 hunks)
  • pkg/connector/privilege.go (1 hunks)
  • pkg/connector/resource_types.go (2 hunks)
  • pkg/connector/role.go (7 hunks)
  • pkg/connector/role_cache.go (4 hunks)
  • pkg/connector/workato/privileges.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
pkg/connector/resource_types.go (1)
pkg/connector/connector.go (1)
  • New (68-93)
pkg/connector/collaborator_cache.go (2)
pkg/connector/client/client.go (1)
  • WorkatoClient (28-33)
pkg/connector/client/models.go (1)
  • Collaborator (35-49)
pkg/connector/role_cache.go (2)
pkg/connector/client/models.go (1)
  • Role (65-73)
pkg/connector/workato/roles.go (1)
  • Role (7-10)
pkg/connector/collaborator.go (4)
pkg/connector/client/client.go (1)
  • WorkatoClient (28-33)
pkg/connector/workato/env.go (1)
  • Environment (10-10)
pkg/connector/workato/privileges.go (1)
  • PrivilegeId (21-23)
pkg/connector/workato/roles.go (2)
  • IsBaseRole (18-25)
  • GetBaseRole (27-38)
pkg/connector/role.go (2)
pkg/connector/client/client.go (1)
  • WorkatoClient (28-33)
pkg/connector/workato/env.go (1)
  • Environment (10-10)
🪛 GitHub Actions: ci
pkg/connector/collaborator.go

[error] 97-97: revive: line-length-limit: line is 227 characters, out of limit 200 (revive)

🔇 Additional comments (13)
pkg/connector/collaborator_cache.go (2)

41-51: LGTM!

The getCollaborator method correctly retrieves a collaborator from session storage with proper error handling and uses appropriate gRPC status codes for the not-found case.


29-39: Remove unnecessary comment – loop variable semantics are correct in Go 1.25.2

This code is correct. The project declares go 1.25.2 in go.mod, which is well beyond Go 1.22. The new for loop semantics apply when the package being compiled is from a module that contains a go line declaring Go 1.22 or later. Since Go 1.25.2 is declared, each loop body effectively starts with k := k and v := v for each range variable, making each &collaborator point to a distinct memory location for each iteration.

The workaround suggested in the review (collaborator := collaborator) is not needed and can be removed. The code at lines 29-39 is already correct as written.

Likely an incorrect or invalid review comment.

pkg/connector/resource_types.go (2)

15-19: LGTM!

Adding SkipGrants annotation to privilegeResourceType aligns with the refactoring where privilege grants are now generated from the collaborator builder instead.


32-36: LGTM!

Adding SkipEntitlementsAndGrants annotation to projectResourceType is appropriate if projects don't have entitlements or grants to sync.

pkg/connector/privilege.go (1)

64-66: LGTM!

The Grants method now returns nil which aligns with the SkipGrants annotation added to privilegeResourceType. Grant generation has been moved to the collaborator builder.

pkg/connector/workato/privileges.go (1)

430-545: LGTM!

The expansion of the Privileges catalog with new groups (Policies, Dashboard & logs, Manage locked projects, API platform, Collections & endpoints, Data tables, Settings, Client & access profiles) follows the established pattern and provides comprehensive coverage of Workato's privilege system.

pkg/connector/connector.go (1)

28-36: LGTM!

The ResourceSyncers method correctly propagates the disableCustomRolesSync flag to the collaborator and folder builders. The removal of env from newFolderBuilder aligns with the session rework refactoring.

pkg/connector/role_cache.go (1)

92-94: Loop variable pointer capture issue.

Storing &role captures a pointer to the loop variable, which will point to the same memory location for all iterations. In Go 1.22+, this is fixed, but for compatibility with earlier versions, create a copy.

Please verify the Go version used in this project. If using Go < 1.22, apply this fix:

+		copyRoleByName := role
-		mapRolesByName[role.Name] = &role
+		mapRolesByName[role.Name] = &copyRoleByName
pkg/connector/folder.go (1)

173-178: LGTM!

The signature simplification removing the env parameter aligns with the session rework goal. The cache initialization correctly uses the updated newCollaboratorCache(client) signature.

pkg/connector/collaborator.go (1)

68-117: LGTM on Grants implementation.

The new Grants method correctly handles environment filtering, role-based grants, privilege grants, and folder grants. The error handling with gRPC status codes for NotFound is appropriate.

pkg/connector/role.go (3)

27-28: LGTM!

Interface assertions provide compile-time verification that roleBuilder implements the required interfaces. This is a good practice.


139-147: Good refactoring of Grants control flow.

The early return for base roles (line 139) cleanly separates the two code paths. The subsequent custom role handling (lines 142-179) is now gated by disableCustomRolesSync, making the sync behavior explicit and controllable.


257-264: LGTM!

The constructor correctly initializes the cache with the simplified newCollaboratorCache(client) signature, consistent with the session rework changes in other builders.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
pkg/connector/folder.go (1)

101-102: Typo fixes applied.

The typos in the entitlement descriptions have been corrected as noted in previous review comments.

pkg/connector/collaborator.go (2)

187-187: Remove printf-style placeholder from structured log.

The log message uses a %s placeholder that won't be interpolated with zap's structured logging. The role name is already provided as a structured field.

Apply this diff:

-				l.Error("failed to get base role %s", zap.String("role_name", role.RoleName), zap.Error(err))
+				l.Error("failed to get base role", zap.String("role_name", role.RoleName), zap.Error(err))

208-208: Remove printf-style placeholder from structured log.

Same issue: the %s placeholder won't be interpolated. The role name is already provided as a structured field.

Apply this diff:

-			l.Debug("skipping role %s because it is not a base role and custom roles sync is disabled", zap.String("role_name", role.RoleName))
+			l.Debug("skipping role because it is not a base role and custom roles sync is disabled", zap.String("role_name", role.RoleName))
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d7721a and d1a0f7f.

📒 Files selected for processing (3)
  • pkg/connector/collaborator.go (2 hunks)
  • pkg/connector/folder.go (2 hunks)
  • pkg/connector/role_cache.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
pkg/connector/folder.go (1)
pkg/connector/client/client.go (1)
  • WorkatoClient (28-33)
pkg/connector/collaborator.go (4)
pkg/connector/client/client.go (1)
  • WorkatoClient (28-33)
pkg/connector/workato/env.go (1)
  • Environment (10-10)
pkg/connector/workato/privileges.go (1)
  • PrivilegeId (21-23)
pkg/connector/workato/roles.go (2)
  • IsBaseRole (18-25)
  • GetBaseRole (27-38)
pkg/connector/role_cache.go (2)
pkg/connector/client/models.go (1)
  • Role (65-73)
pkg/connector/workato/roles.go (1)
  • Role (7-10)
🔇 Additional comments (13)
pkg/connector/folder.go (2)

173-178: Constructor signature simplified correctly.

The removal of the env parameter and the simplified cache initialization align with the PR's objective to reduce cache complexity. The environment context has been appropriately moved to the collaborator level.


110-171: Grants method correctly refactored to role-based grants.

The simplified grants logic appropriately handles only role-based grants for folders, with proper pagination and expandable grant annotations. The move of collaborator-specific grants to the collaborator builder reduces complexity as intended.

pkg/connector/collaborator.go (5)

68-121: Grants implementation looks solid.

The new Grants method correctly:

  • Parses and validates the collaborator ID
  • Retrieves role-based grants
  • Handles the NotFound case gracefully for collaborator privileges
  • Filters grants by environment type
  • Generates both privilege and folder grants appropriately

123-139: Folder grant helper correctly marks grants as immutable.

The immutable annotation is appropriate since folder access for collaborators is determined by their assigned roles. The grant construction is correct.


141-158: Privilege grant helper implemented correctly.

The function properly constructs privilege grants using the workato.PrivilegeId helper. The logic aligns with the role-based privilege model.


196-206: Consider handling missing custom roles gracefully.

Line 199 returns an error if a custom role is not found. This could cause sync failures if a role is deleted after being assigned to a collaborator. If this is intentional (to surface data inconsistencies), the current behavior is fine. Otherwise, consider logging a warning and skipping the role instead.

Would you like this to fail fast on missing custom roles, or should it skip them with a warning?


225-231: Constructor correctly updated with new parameters.

The signature properly threads through the env and disableCustomRolesSync parameters needed for the grants logic. The cache initialization is consistent with the simplified cache API.

pkg/connector/role_cache.go (6)

15-19: LGTM: Cache prefix constants are well-organized.

The new rolesByNameCachePrefix constant follows the established pattern and improves maintainability.


26-26: Log format issue resolved.

The printf-style %s placeholder has been correctly removed, addressing the previous review comment.


37-51: Improved error handling and log format.

The explicit nil returns for both error and not-found cases improve clarity. The log format issue has also been resolved.


53-67: LGTM: New function follows established patterns.

The getRoleByName function correctly mirrors getRoleById with appropriate cache prefix and error handling.


71-71: LGTM: Cache prefix constants improve maintainability.

Good use of constants instead of hard-coded strings for cache prefixes. The new roles-by-name cache follows the same pattern as existing caches.

Also applies to: 97-97, 103-109


78-78: Document or enforce the assumption that role names are unique.

The mapRolesByName map uses role.Name as the key without validating uniqueness. If duplicate role names exist in Workato, this would silently overwrite previous entries, causing getRoleByName to return an incorrect role. Either add validation to detect and handle duplicates, document that Workato guarantees unique role names per workspace, or use role.Id as the primary cache key instead.

@johnallers johnallers requested a review from a team December 17, 2025 22:29

users, found, err := session.GetJSON[[]*CompoundUser](ctx, sessionStorage, folderId, sessions.WithPrefix(folderToUserCachePrefix))
// getCollaborator gets a collaborator from the cache by id.
// It is assumed that the cache is populated when listing resources and is only used when listing grants.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't like this assumption, but I was trying to avoid a bunch of additional session store calls to remove the assumption. We make the same assumptions with the role_cache.

I'm open to suggestions here.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is an ok assumption as long as we don't do incremental sync and don't enable parallel sync (which will be off by default whenever it gets shipped in baton-sdk).

Choose a reason for hiding this comment

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

I agree. Seems ok to make this assumption with the current process, since this function will be called when creating Grants, and that will be executed only after the List process of the resource (when the cache gets populated)

var privilegeResourceType = &v2.ResourceType{
Id: "privilege",
DisplayName: "Privilege",
Annotations: annotations.New(&v2.SkipGrants{}),
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm glad we added this annotation and that people are using it.

Ideally we should skip grants/entitlements based on whether these methods exist, but that would require some changes to interfaces. :/

}

// Grants returns collaborator-has grants and derived privilege grants for base and custom roles.
// Grants always returns an empty slice for users since they don't have any entitlements.

Choose a reason for hiding this comment

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

nit: should remove entirely since we are emitting grants here


// Entitlements always returns an empty slice for users.
func (o *roleBuilder) Entitlements(_ context.Context, resource *v2.Resource, _ rs.SyncOpAttrs) ([]*v2.Entitlement, *rs.SyncOpResults, error) {
func (o *roleBuilder) Entitlements(_ context.Context, resource *v2.Resource, attr rs.SyncOpAttrs) ([]*v2.Entitlement, *rs.SyncOpResults, error) {

Choose a reason for hiding this comment

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

nit: we can leave attr as _ since i dont see it being used

// List returns all the users from the database as resource objects.
// Users include a UserTrait because they are the 'shape' of a standard user.
func (o *roleBuilder) List(ctx context.Context, _ *v2.ResourceId, attr rs.SyncOpAttrs) ([]*v2.Resource, *rs.SyncOpResults, error) {
func (o *roleBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId, attr rs.SyncOpAttrs) ([]*v2.Resource, *rs.SyncOpResults, error) {

Choose a reason for hiding this comment

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

nit: can leave as _


collaboratorRoles, err := o.client.GetCollaboratorPrivileges(ctx, collaboratorId)
if err != nil {
if status.Code(err) != codes.NotFound {

Choose a reason for hiding this comment

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

nit: I understand that this is evaluating the case where response.Data len is 0, but could it be confused with the actual response returning a 404 (which I guess it would mean the collabolator wasn't found)? I guess in any case is probably safe to ignore and continue

@agustin-conductor agustin-conductor requested a review from a team December 18, 2025 18:23

users, found, err := session.GetJSON[[]*CompoundUser](ctx, sessionStorage, folderId, sessions.WithPrefix(folderToUserCachePrefix))
// getCollaborator gets a collaborator from the cache by id.
// It is assumed that the cache is populated when listing resources and is only used when listing grants.

Choose a reason for hiding this comment

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

I agree. Seems ok to make this assumption with the current process, since this function will be called when creating Grants, and that will be executed only after the List process of the resource (when the cache gets populated)

@@ -63,38 +62,13 @@ func (o *privilegeBuilder) Entitlements(_ context.Context, resource *v2.Resource

// Grants always returns an empty slice for users since they don't have any entitlements.

Choose a reason for hiding this comment

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

Nit: This is not important at all but this comment is misplaced

@@ -36,7 +40,7 @@ func (o *roleBuilder) ResourceType(ctx context.Context) *v2.ResourceType {

// List returns all the users from the database as resource objects.

Choose a reason for hiding this comment

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

Nit: Another absolutely not important thing - commentary misplaced

@johnallers johnallers merged commit e7ff5c5 into main Dec 19, 2025
4 checks passed
@JavierCarnelli-ConductorOne JavierCarnelli-ConductorOne deleted the jallers/session-rework branch December 19, 2025 12:35
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