Skip to content

Conversation

@russellhaering
Copy link
Contributor

@russellhaering russellhaering commented Jan 10, 2026

When revoking namespace entitlements, "downgrade" to the next entitlement in the hierarchy instead of removing access entirely. For example, when revoking write access, downgrade to read instead of removing access entirely. This is consistent with how other connectors such as baton-github handle hierarchical entitlements.

Summary by CodeRabbit

  • New Features

    • Permission revocation now uses hierarchical downgrade: admin permissions downgrade to write level, write to read level, then complete removal.
  • Bug Fixes

    • Improved validation and error handling for permission revocation operations with enhanced error messages for invalid permission formats.
  • Tests

    • Added comprehensive test coverage for permission downgrade logic and permission string parsing validation.

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

Instead of removing all namespace access when revoking a permission,
downgrade to the next lower permission level in the hierarchy:
Admin → Write → Read → remove access entirely.

Also validates that the user actually has the permission being revoked.
@russellhaering russellhaering requested a review from a team January 10, 2026 02:58
@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Walkthrough

Introduces a hierarchical permission-downgrade helper function for namespace access and modifies the Revoke operation to validate entitlement IDs, check current access levels, and conditionally downgrade permissions (ADMIN→WRITE→READ→removal) rather than immediately revoking access.

Changes

Cohort / File(s) Change Summary
Permission hierarchy helper
pkg/connector/helpers.go
New nextLowerNamespacePermission() function defining permission downgrade transitions: ADMIN→WRITE, WRITE→READ, READ→UNSPECIFIED
Helper tests
pkg/connector/helpers_test.go
Added TestNextLowerNamespacePermission validating downgrade logic and TestNamespaceAccessPermissionFromString validating string-to-permission parsing with case-insensitivity and error handling
Namespace revoke logic
pkg/connector/namespaces.go
Enhanced Revoke function: validates/parses entitlement ID, checks current access matches revoked permission, implements hierarchical downgrade (deletes on final step or updates to lower permission), updated error messages

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A permission so grand must gracefully fall,
From ADMIN to WRITE, from WRITE down to READ,
No sudden erasure—just hierarchy's call,
Each step down the ladder, exactly we need.
With validation and checks, the safe path is clear,

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Hierarchical Namespace Entitlement Revocation' accurately reflects the main change: implementing hierarchical downgrade logic for namespace permission revocation instead of complete removal.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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: 0

🧹 Nitpick comments (3)
pkg/connector/helpers.go (1)

238-249: Make downgrade mapping explicit (READ/UNSPECIFIED) to match comment and reduce ambiguity.
Current implementation works, but default implicitly includes READ and any future enum values; being explicit keeps intent clear and safer to maintain.

Proposed diff
 func nextLowerNamespacePermission(current identityv1.NamespaceAccess_Permission) identityv1.NamespaceAccess_Permission {
 	switch current {
 	case identityv1.NamespaceAccess_PERMISSION_ADMIN:
 		return identityv1.NamespaceAccess_PERMISSION_WRITE
 	case identityv1.NamespaceAccess_PERMISSION_WRITE:
 		return identityv1.NamespaceAccess_PERMISSION_READ
-	default:
+	case identityv1.NamespaceAccess_PERMISSION_READ:
+		return identityv1.NamespaceAccess_PERMISSION_UNSPECIFIED
+	case identityv1.NamespaceAccess_PERMISSION_UNSPECIFIED:
+		return identityv1.NamespaceAccess_PERMISSION_UNSPECIFIED
+	default:
 		return identityv1.NamespaceAccess_PERMISSION_UNSPECIFIED
 	}
 }
pkg/connector/namespaces.go (2)

219-229: Tighten entitlement ID validation (prefix + namespace match), not just “3 parts”.
Right now any x:y:z with a valid permission in z passes; validating enIDParts[0] and enIDParts[1] prevents accidental mismatches between entitlementID and namespaceID.

Proposed diff
 	enIDParts := strings.Split(entitlementID, ":")
-	if len(enIDParts) != 3 {
+	if len(enIDParts) != 3 || enIDParts[0] != "namespace" || enIDParts[1] != namespaceID {
 		return nil, fmt.Errorf("baton-temporalcloud: invalid entitlement ID %s", entitlementID)
 	}

236-258: Add nil-guard for currentAccess and prefer mutating existing entry on downgrade.
This avoids a potential panic if the map value is nil, and future-proofs if NamespaceAccess gains additional fields beyond Permission.

Proposed diff
 	currentAccess, ok := spec.GetAccess().GetNamespaceAccesses()[namespaceID]
-	if !ok {
+	if !ok || currentAccess == nil {
 		annos := annotations.New(&v2.GrantAlreadyRevoked{})
 		return annos, fmt.Errorf("baton-temporalcloud: grant does not exist for user")
 	}
@@
 	nextPerm := nextLowerNamespacePermission(revokedPerm)
 	if nextPerm == identityv1.NamespaceAccess_PERMISSION_UNSPECIFIED {
 		// Read permission: remove access entirely
 		delete(spec.Access.NamespaceAccesses, namespaceID)
 	} else {
 		// Downgrade to the next lower permission level
-		spec.Access.NamespaceAccesses[namespaceID] = &identityv1.NamespaceAccess{Permission: nextPerm}
+		currentAccess.Permission = nextPerm
 	}

The updated async failure message at Line 280 looks good/clearer for the revoke path.

Also applies to: 280-281

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfdd592 and b6a63d2.

📒 Files selected for processing (3)
  • pkg/connector/helpers.go
  • pkg/connector/helpers_test.go
  • pkg/connector/namespaces.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (2)
pkg/connector/helpers_test.go (2)

72-111: No change needed: Go 1.25 includes the range-variable capture fix.

The repository targets Go 1.25, which fixed the range-variable capture bug introduced in earlier Go versions. The code is already safe as written. The defensive tc := tc capture is not required.

Likely an incorrect or invalid review comment.


113-167: This is not a bug in Go 1.22 and later versions.

Go 1.22 (released March 2024) automatically fixed the loop variable capture issue. Each iteration now gets its own scope for the loop variable, eliminating the need for manual shadowing (tc := tc). Since this project uses Go 1.25, the code is correct as written and does not require the proposed fix.

Likely an incorrect or invalid review comment.

// If they have a different permission level, this grant doesn't exist.
if currentAccess.GetPermission() != revokedPerm {
annos := annotations.New(&v2.GrantAlreadyRevoked{})
return annos, fmt.Errorf("baton-temporalcloud: user does not have %s permission on namespace", revokedPermStr)

Choose a reason for hiding this comment

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

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.

3 participants