Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for array of permissions in lookup entity v2 #1691

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

ankitsheoran1
Copy link

@ankitsheoran1 ankitsheoran1 commented Oct 12, 2024

Summary by CodeRabbit

  • New Features

    • Introduced two new API endpoints for permissions:
      • POST /v1/tenants/{tenant_id}/permissions/lookup-entities
      • POST /v1/tenants/{tenant_id}/permissions/lookup-entities-stream
    • Enhanced validation for permission-related requests and responses.
  • Bug Fixes

    • Improved handling of permissions in integration tests for various services.
  • Documentation

    • Updated API documentation to reflect new endpoints and request/response structures.

Copy link

coderabbitai bot commented Oct 12, 2024

Walkthrough

The changes in this pull request introduce significant enhancements to the Permify API, particularly in the area of permissions management. Two new endpoints, /lookup-entities and /lookup-entities-stream, have been added to facilitate entity lookups based on permissions. Additionally, several modifications have been made to the integration tests and internal engines to support these new functionalities. The validation logic for requests and responses has also been updated to ensure compliance with specified constraints.

Changes

File Path Change Summary
docs/api-reference/apidocs.swagger.json Added new endpoints: POST /v1/tenants/{tenant_id}/permissions/lookup-entities and lookup-entities-stream. Updated definitions for PermissionsLookupEntityResponse, PermissionsLookupEntityStreamResponse, LookupEntitiesBody, and LookupEntitiesStreamBody.
integration-test/usecases/facebook_groups_test.go, .../google_docs_test.go, .../notion_test.go Updated permissionClient.LookupEntity method to accept multiple permissions and modified response handling in tests.
internal/engines/bulk.go, .../entityFilter.go, .../lookup.go Enhanced BulkChecker, EntityFilter, and LookupEngine classes with new parameters and methods for handling permissions.
internal/invoke/invoke.go, internal/servers/permissionServer.go Added LookupEntities and LookupEntitiesStream methods to the Invoke interface and PermissionServer.
pkg/pb/base/v1/service.pb.validate.go, .../health.pb.validate.go Introduced validation logic for PermissionsLookupEntityRequest, PermissionsLookupEntityResponse, and health check messages.

Possibly related PRs

  • feat: update API requests and client-side calls with improved formatting #1488: This PR updates API requests and client-side calls, including modifications to the apidocs.swagger.json file, which is directly related to the changes made in the main PR regarding the API documentation for new endpoints and response structures.
  • feat: add Health Proto and Update gRPC/HTTP Health Registration #1632: This PR introduces a new health check protocol and updates the API documentation accordingly, which aligns with the changes in the main PR that also involve modifications to the health-related API documentation.
  • revert: health api #1642: This PR reverts the health API changes, including the removal of health check endpoints and related documentation, which directly relates to the changes made in the main PR regarding the health check functionality in the API documentation.

Suggested reviewers

  • tolgaOzen

Poem

🐰 In the realm of permissions, we hop with cheer,
New endpoints are here, bringing entities near.
With validations in place, our checks are so bright,
A leap towards clarity, in the API's light!
So let’s celebrate changes, both big and small,
For the power of permissions, we now can enthrall! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Outside diff range and nitpick comments (11)
integration-test/usecases/notion_test.go (1)

114-116: LGTM! Consider enhancing test coverage and error handling.

The changes align well with the expected modifications to the PermissionLookupEntityRequest structure and response handling. The use of Permissions as a slice and the updated response processing improve flexibility and robustness.

To further strengthen the test case:

  1. Consider adding assertions to verify the structure of res.GetEntityIds() to ensure it contains the expected permissions as keys.
  2. Implement error handling for the case when res.GetEntityIds()[permission] is not found, rather than silently continuing with an empty slice.
  3. Add logging statements to provide more context in case of test failures.

Here's a suggested enhancement:

for permission, expected := range filter.Assertions {
    res, err := permissionClient.LookupEntity(ctx, &base.PermissionLookupEntityRequest{
        // ... (existing code)
    })

    Expect(err).ShouldNot(HaveOccurred())
    
    // New assertion to check if the response contains the expected permission
    Expect(res.GetEntityIds()).To(HaveKey(permission), "Response should contain results for permission: %s", permission)

    var responseIdsForPermission []string
    if res, ok := res.GetEntityIds()[permission]; ok {
        responseIdsForPermission = res.Ids
    } else {
        // Log a warning if the permission is not found in the response
        GinkgoWriter.Printf("Warning: No entity IDs found for permission: %s\n", permission)
    }

    // Existing assertion
    Expect(IsSameArray(responseIdsForPermission, expected)).Should(Equal(true), 
        "Mismatch in entity IDs for permission %s. Got: %v, Expected: %v", 
        permission, responseIdsForPermission, expected)
}

This enhancement adds more comprehensive assertions and improves error reporting, making the test more robust and easier to debug.

Also applies to: 120-124

integration-test/usecases/facebook_groups_test.go (1)

114-124: LGTM! The changes improve the test case's clarity and flexibility.

The modifications to the LookupEntity method call and response handling are well-implemented:

  1. The EntityType parameter is now explicitly set, which improves clarity.
  2. Changing Permission to Permissions as a slice allows testing multiple permissions, enhancing flexibility.
  3. The new response handling correctly extracts entity IDs for the specific permission, accommodating the updated API structure.

These changes align well with the updated API and provide a more robust test case.

For further improvement, consider:

  1. Adding a test case with multiple permissions to fully utilize the new Permissions slice capability.
  2. Documenting the expected structure of the LookupEntity response, perhaps as a comment, to clarify the need for the new handling logic.
internal/servers/permissionServer.go (1)

133-152: Minor improvement for consistency

The LookupEntitiesStream method is well-implemented and consistent with the existing codebase structure. It correctly handles context tracing, request validation, error handling, and invoker interaction.

For improved consistency with other stream methods in the file (e.g., LookupEntityStream), consider returning the validation error directly instead of wrapping it in a status error.

Apply this small change to line 140:

- return v
+ return status.Error(GetStatus(v), v.Error())

This change will make the error handling consistent across all methods in the file.

internal/engines/utils.go (1)

397-409: LGTM! Consider adding a comment for clarity.

The ConvertToPermissionsLookupEntityRequest function correctly converts a PermissionLookupEntityRequest to a PermissionsLookupEntityRequest. The implementation is straightforward and handles the conversion of the single permission to an array of permissions as expected.

Consider adding a brief comment explaining the purpose of this function, especially highlighting the conversion from a single permission to an array of permissions. This would improve code readability and maintainability. For example:

// ConvertToPermissionsLookupEntityRequest converts a PermissionLookupEntityRequest to a PermissionsLookupEntityRequest.
// It preserves all fields and converts the single Permission to an array of Permissions.
func ConvertToPermissionsLookupEntityRequest(req *base.PermissionLookupEntityRequest) *base.PermissionsLookupEntityRequest {
    // ... (existing implementation)
}
pkg/cmd/validate.go (1)

367-371: Improved result comparison logic

The changes enhance the accuracy of result comparison by correctly handling empty results and using the isSameArray function for non-empty comparisons. This should reduce false negatives in the validation process.

Consider extracting the condition res.GetEntityIds() == nil && len(expected) == 0 into a named boolean variable for improved readability. For example:

-if res.GetEntityIds() == nil && len(expected) == 0 {
+isEmptyResult := res.GetEntityIds() == nil && len(expected) == 0
+if isEmptyResult {
docs/api-reference/openapiv2/apidocs.swagger.json (2)

768-824: New endpoint /lookup-entities looks good, with some suggestions.

The new /lookup-entities endpoint is well-structured and consistent with the existing API design. It includes proper documentation, parameters, and code samples. However, consider the following suggestions:

  1. The tenant_id parameter description could be more specific to this endpoint's functionality.
  2. Ensure that the #/definitions/LookupEntitiesBody schema is properly defined in the definitions section.
  3. Review the PermissionsLookupEntityResponse schema for consistency with other response structures in the API.

Consider updating the tenant_id parameter description to be more specific to the /lookup-entities endpoint functionality.


825-885: New streaming endpoint /lookup-entities-stream looks good, with some suggestions.

The new /lookup-entities-stream endpoint is well-structured and consistent with the existing API design. It properly implements a streaming response and includes documentation and code samples. However, consider the following suggestions:

  1. The tenant_id parameter description could be more specific to this endpoint's streaming functionality.
  2. Ensure that the #/definitions/LookupEntitiesStreamBody schema is properly defined in the definitions section.
  3. Review the PermissionsLookupEntityStreamResponse schema for consistency with other streaming response structures in the API.
  4. Add a cURL example for this endpoint to maintain consistency with other endpoint documentation and provide an easy way for users to test the API from the command line.

Consider updating the tenant_id parameter description to be more specific to the /lookup-entities-stream endpoint functionality.

Add a cURL example for the /lookup-entities-stream endpoint to improve consistency and usability of the API documentation. Here's a template you can use:

curl --location --request POST 'localhost:3476/v1/tenants/{tenant_id}/permissions/lookup-entities-stream' \
--header 'Content-Type: application/json' \
--data-raw '{
  "metadata": {
    "snap_token": "",
    "schema_version": "",
    "depth": 20
  },
  "entity_type": "document",
  "permissions": ["view"],
  "subject": {
    "type": "user",
    "id": "1"
  },
  "page_size": 20,
  "continuous_token": ""
}'

Note: Adjust the request body parameters as needed to match the exact requirements of the endpoint.

internal/schema/linkedSchema.go (2)

7-7: Organize imports by grouping standard library packages

The import statement for the "sync" package should be grouped with other standard library imports for better readability.

Reorganize the imports as follows:

 package schema

 import (
+	"errors"
+	"sync"

 	"github.com/Permify/permify/pkg/dsl/utils"
 	base "github.com/Permify/permify/pkg/pb/base/v1"
 )

Line range hint 374-388: Handle errors consistently in findEntranceRewrite

In the findEntranceRewrite function, when an error occurs, ensure that it's properly returned and that all code paths handle errors consistently.

Review the error handling logic to make sure that all errors are propagated correctly and that the function does not suppress any potential errors.

internal/engines/lookup.go (1)

Line range hint 217-226: Unused 'permission' parameter in callback functions.

In the callback functions defined in LookupEntityStream and LookupSubject, the permission parameter is not used within the function body:

callback := func(entityID, permission, token string) {
    // 'permission' parameter is unused
}

If the permission parameter is not required, consider omitting it or prefixing it with an underscore to indicate it's unused:

callback := func(entityID, _ string, token string) {
    // Updated function signature
}

Also applies to: 361-366

internal/invoke/invoke.go (1)

344-344: Potential performance impact when logging large permission slices

In the LookupEntities method, the tracing attribute logs request.GetPermissions() using attribute.StringSliceValue. If the permissions slice is large, this could affect performance or clutter the trace logs. Consider summarizing the permissions or limiting the number of permissions logged.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e4aacca and 6f1bd1b.

⛔ Files ignored due to path filters (5)
  • pkg/pb/base/v1/health.pb.go is excluded by !**/*.pb.go
  • pkg/pb/base/v1/health_grpc.pb.go is excluded by !**/*.pb.go
  • pkg/pb/base/v1/service.pb.go is excluded by !**/*.pb.go
  • pkg/pb/base/v1/service.pb.gw.go is excluded by !**/*.pb.gw.go
  • pkg/pb/base/v1/service_grpc.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (16)
  • docs/api-reference/apidocs.swagger.json (4 hunks)
  • docs/api-reference/openapiv2/apidocs.swagger.json (4 hunks)
  • integration-test/usecases/facebook_groups_test.go (1 hunks)
  • integration-test/usecases/google_docs_test.go (1 hunks)
  • integration-test/usecases/notion_test.go (1 hunks)
  • internal/engines/bulk.go (6 hunks)
  • internal/engines/entityFilter.go (18 hunks)
  • internal/engines/lookup.go (11 hunks)
  • internal/engines/utils.go (1 hunks)
  • internal/invoke/invoke.go (4 hunks)
  • internal/schema/linkedSchema.go (11 hunks)
  • internal/servers/permissionServer.go (1 hunks)
  • pkg/cmd/validate.go (1 hunks)
  • pkg/pb/base/v1/health.pb.validate.go (1 hunks)
  • pkg/pb/base/v1/service.pb.validate.go (8 hunks)
  • proto/base/v1/service.proto (5 hunks)
🧰 Additional context used
🔇 Additional comments (32)
integration-test/usecases/google_docs_test.go (1)

114-124: Approve changes to LookupEntity request and response handling

The modifications to the LookupEntity method call and response handling look good. These changes align with the new support for an array of permissions in the lookup entity functionality. Here's a breakdown of the improvements:

  1. Request changes:

    • The EntityType is now explicitly set, improving clarity.
    • The Permissions field now accepts a slice of strings, allowing multiple permissions to be checked in a single request.
  2. Response handling:

    • The new logic correctly extracts entity IDs for a specific permission from the response.
    • This change accommodates the new response structure where entity IDs are grouped by permission.

These updates enhance the test's ability to verify the new multi-permission lookup functionality.

internal/servers/permissionServer.go (2)

112-131: LGTM: LookupEntities method implementation

The LookupEntities method is well-implemented and consistent with the existing codebase structure. It correctly handles context tracing, request validation, error handling, and invoker interaction. The implementation follows best practices and maintains consistency with other methods in the file.


112-152: Summary of changes: New LookupEntities methods

The addition of LookupEntities and LookupEntitiesStream methods to the PermissionServer struct enhances its functionality by providing new capabilities for entity lookups based on permissions. These methods are well-implemented, following the established patterns in the codebase for error handling, tracing, and invoker interaction.

The changes align with the PR objectives of supporting an array of permissions in lookup entity v2. They extend the API's capabilities while maintaining consistency with existing code structures.

pkg/cmd/validate.go (2)

Line range hint 472-476: Simplified result comparison logic

The changes streamline the result comparison process by directly using the isSameArray function in the condition. This simplification improves code readability and maintainability without altering the functionality.


Line range hint 1-624: Overall assessment of changes

The modifications in this file focus on improving the result comparison logic in both entity and subject filter processing sections. These changes enhance the accuracy of the validation process and improve code readability. The core functionality remains intact, and the changes are well-aligned with the file's purpose.

docs/api-reference/openapiv2/apidocs.swagger.json (1)

768-885: New endpoints successfully added, with a recommendation for schema verification.

The addition of the /lookup-entities and /lookup-entities-stream endpoints has been implemented correctly and consistently with the existing API structure. These new endpoints extend the API's functionality for looking up entities with permissions, including a streaming option.

To ensure complete correctness of these additions:

  1. Verify that the following schemas are properly defined in the definitions section of this file:

    • LookupEntitiesBody
    • LookupEntitiesStreamBody
    • PermissionsLookupEntityResponse
    • PermissionsLookupEntityStreamResponse
  2. Consider updating the tenant_id parameter descriptions to be more specific to each endpoint's functionality.

  3. Add a cURL example for the /lookup-entities-stream endpoint to maintain consistency with other endpoint documentation.

Overall, these additions enhance the API's capabilities and are well-integrated into the existing structure.

To confirm the existence and correctness of the new schema definitions, run the following script:

This script will help ensure that all necessary schema definitions for the new endpoints are present in the file.

✅ Verification successful

Schema definitions confirmed and verified successfully.

All necessary schemas (LookupEntitiesBody, LookupEntitiesStreamBody, PermissionsLookupEntityResponse, and PermissionsLookupEntityStreamResponse) are present in the apidocs.swagger.json file at the specified lines. This ensures that the newly added endpoints are properly supported by their respective schema definitions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for the existence of new schema definitions

echo "Checking for new schema definitions..."

grep -n '"LookupEntitiesBody"' docs/api-reference/openapiv2/apidocs.swagger.json
grep -n '"LookupEntitiesStreamBody"' docs/api-reference/openapiv2/apidocs.swagger.json
grep -n '"PermissionsLookupEntityResponse"' docs/api-reference/openapiv2/apidocs.swagger.json
grep -n '"PermissionsLookupEntityStreamResponse"' docs/api-reference/openapiv2/apidocs.swagger.json

echo "If all schemas are found, their line numbers will be displayed above."
echo "If any schema is missing, there will be no output for that schema."

Length of output: 918

docs/api-reference/apidocs.swagger.json (3)

2409-2452: Review of LookupEntitiesStreamBody definition

The LookupEntitiesStreamBody definition has been added to support the new /lookup-entities-stream endpoint. While the consistency with LookupEntitiesBody is commendable, there are some points to consider:

  1. Duplication: The LookupEntitiesStreamBody is identical to LookupEntitiesBody. This duplication might lead to maintenance issues if these structures evolve differently in the future.

  2. Naming Inconsistency: The description still refers to "PermissionsLookupEntityRequest" instead of "LookupEntitiesStreamBody".

Consider the following improvements:

  1. To reduce duplication and improve maintainability, consider creating a common base type that both LookupEntitiesBody and LookupEntitiesStreamBody can extend or reference. This would centralize any future changes to the shared structure.

  2. Update the description to use "LookupEntitiesStreamBody" instead of "PermissionsLookupEntityRequest".

  3. If there are any stream-specific considerations (e.g., timeout handling, reconnection logic), consider adding documentation about these aspects in the description of LookupEntitiesStreamBody.

Here's a suggested refactoring approach:

"LookupEntitiesBaseBody": {
  "type": "object",
  "properties": {
    // ... all common properties ...
  }
},
"LookupEntitiesBody": {
  "allOf": [
    { "$ref": "#/definitions/LookupEntitiesBaseBody" },
    {
      "type": "object",
      "properties": {
        // ... any properties specific to non-streaming lookup ...
      }
    }
  ]
},
"LookupEntitiesStreamBody": {
  "allOf": [
    { "$ref": "#/definitions/LookupEntitiesBaseBody" },
    {
      "type": "object",
      "properties": {
        // ... any properties specific to streaming lookup ...
      }
    }
  ]
}

Let's verify the similarity between LookupEntitiesBody and LookupEntitiesStreamBody:

#!/bin/bash

# Compare the two definitions
echo "Comparing LookupEntitiesBody and LookupEntitiesStreamBody:"
diff <(sed -n '/LookupEntitiesBody/,/}/p' docs/api-reference/apidocs.swagger.json) <(sed -n '/LookupEntitiesStreamBody/,/}/p' docs/api-reference/apidocs.swagger.json)

# Check for any references to PermissionsLookupEntityRequest
echo "\nChecking for references to PermissionsLookupEntityRequest:"
grep -n "PermissionsLookupEntityRequest" docs/api-reference/apidocs.swagger.json

This script will help us confirm the similarity between the two definitions and identify any remaining references to the incorrect name.


2870-2903: 🛠️ Refactor suggestion

⚠️ Potential issue

Review of PermissionsLookupEntityResponse and PermissionsLookupEntityStreamResponse definitions

The new response structures for the lookup entities endpoints have been added. While they provide the necessary information, there are several points to address:

  1. Naming Inconsistency: The prefix Permissions is used instead of Permission, which is inconsistent with other similar definitions in the API.

  2. Complex Structure: The entity_ids field in PermissionsLookupEntityResponse is an object with EntityIds as values, which seems unnecessarily complex compared to the previous PermissionLookupEntityResponse that used a simple array of strings.

  3. Inconsistent Fields: The streaming response includes a permission field, which is not present in the batch response. This inconsistency might confuse API consumers.

Consider the following improvements:

  1. Rename the responses to PermissionLookupEntitiesResponse and PermissionLookupEntitiesStreamResponse for consistency with other endpoint naming conventions.

  2. Simplify the entity_ids structure in PermissionLookupEntitiesResponse:

"PermissionLookupEntitiesResponse": {
  "type": "object",
  "properties": {
    "entity_ids": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "List of entity IDs that match the lookup criteria."
    },
    "continuous_token": {
      "type": "string",
      "description": "Token for retrieving the next page of results."
    }
  }
}
  1. Consider adding the permission field to the batch response as well, or remove it from the streaming response, depending on the intended use case. If it's kept only in the streaming response, provide a clear explanation of why it's needed there but not in the batch response.

  2. Update the descriptions to clearly explain the difference between the batch and streaming responses.

Let's verify the current structure and usage of these response types:

#!/bin/bash

# Check the structure of PermissionsLookupEntityResponse
echo "Structure of PermissionsLookupEntityResponse:"
sed -n '/PermissionsLookupEntityResponse/,/}/p' docs/api-reference/apidocs.swagger.json

# Check the structure of PermissionsLookupEntityStreamResponse
echo "\nStructure of PermissionsLookupEntityStreamResponse:"
sed -n '/PermissionsLookupEntityStreamResponse/,/}/p' docs/api-reference/apidocs.swagger.json

# Check for any references to these response types in the API endpoints
echo "\nReferences to the response types in API endpoints:"
grep -n "PermissionsLookupEntityResponse\|PermissionsLookupEntityStreamResponse" docs/api-reference/apidocs.swagger.json

This script will help us confirm the current structure of the response types and their usage in the API specification, allowing us to make informed decisions about the suggested improvements.


768-885: New endpoints added for entity lookup operations

Two new endpoints have been added to the Permify API:

  1. /v1/tenants/{tenant_id}/permissions/lookup-entities (POST)
  2. /v1/tenants/{tenant_id}/permissions/lookup-entities-stream (POST)

These endpoints provide functionality for looking up entities based on permissions. The stream version allows for handling large result sets more efficiently.

The addition of these endpoints enhances the API's capabilities for permission-based entity lookups. The implementation follows the existing patterns in the API specification, which is good for consistency.

However, there are a few points to consider:

  1. Documentation: While the endpoints have basic descriptions, it would be beneficial to add more detailed documentation about their usage, especially regarding the streaming functionality.

  2. Error Responses: The error responses are using the default Status object. Consider adding specific error codes and messages for these endpoints to help API consumers handle errors more effectively.

  3. Pagination: The page_size and continuous_token parameters are included, which is good for handling large result sets. Ensure that the API implementation properly handles these pagination parameters.

Consider the following architectural aspects:

  1. Caching: For frequently accessed permissions or entities, implement caching mechanisms to improve performance.

  2. Rate Limiting: Ensure that appropriate rate limiting is in place, especially for the streaming endpoint, to prevent abuse and ensure fair usage of resources.

  3. Monitoring: Add proper logging and monitoring for these new endpoints to track usage patterns and identify potential issues quickly.

To ensure the consistency and correctness of the new endpoints, let's verify their integration with the existing API structure:

This script will help us verify the proper integration of the new endpoints and their associated definitions within the API specification.

✅ Verification successful

Verification Successful: New Endpoints Properly Integrated

The new /lookup-entities and /lookup-entities-stream endpoints are properly integrated with the existing permission-related endpoints. All necessary request and response bodies are defined, and references to these endpoints are consistent throughout the API specification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash

# Check if the new endpoints are properly integrated with the existing permission-related endpoints
echo "Checking integration of new endpoints:"
grep -n "/v1/tenants/{tenant_id}/permissions/" docs/api-reference/apidocs.swagger.json

# Verify that the new request and response bodies are properly defined
echo "\nChecking new request and response body definitions:"
grep -n "LookupEntitiesBody\|LookupEntitiesStreamBody\|PermissionsLookupEntityResponse\|PermissionsLookupEntityStreamResponse" docs/api-reference/apidocs.swagger.json

# Check for any references to the new endpoints in other parts of the API specification
echo "\nChecking references to new endpoints:"
grep -n "lookup-entities\|lookupEntities" docs/api-reference/apidocs.swagger.json

Length of output: 7573

pkg/pb/base/v1/health.pb.validate.go (1)

1-245: LGTM: Generated validation code is appropriate

The validation code for HealthCheckRequest and HealthCheckResponse has been correctly generated using protoc-gen-validate. Since there are no specific validation rules defined in the .proto file for the fields, the generated Validate and ValidateAll methods appropriately handle these cases by returning nil when no violations are found.

internal/engines/bulk.go (1)

268-283: Correct implementation of multiple permissions handling in Publish

The Publish method now iterates over multiple permissions from s.request.GetPermissions(), submitting a PermissionCheckRequest for each permission. This change appropriately extends the functionality to handle an array of permissions, ensuring comprehensive permission checks.

internal/engines/lookup.go (2)

10-10: Importing 'sync' package is appropriate.

The addition of the "sync" package is necessary due to the use of mutexes for thread-safe operations.


128-148: Proper synchronization of 'entityIDsByPermission' map.

The use of sync.Mutex to protect access to the entityIDsByPermission map ensures thread safety when multiple goroutines invoke the callback function concurrently.

internal/engines/entityFilter.go (17)

40-59: Direct match logic correctly identifies and publishes entities

The added code efficiently checks for direct matches between the subject and entrances. By publishing the result upon a match and breaking the loop, it avoids unnecessary processing.


66-69: Ensure correct parameters are passed to LinkedEntrances

In the call to cn.LinkedEntrances, the parameters have been updated to include request.GetEntrances() and the subject's entrance. Verify that this change aligns with the method's expected parameters and handles multiple entrances appropriately.


Line range hint 89-110: Update method calls to include the new permissionChecks parameter

Methods relationEntrance, lt, attributeEntrance, and tupleToUserSetEntrance now include the additional permissionChecks *VisitsMap parameter. Ensure that all calls to these methods have been updated accordingly and that the parameter is properly utilized within each method.


164-169: Review pagination logic for correctness in attributeEntrance

The pagination settings are now determined within a loop over request.GetEntrances() to match the target entrance type. Ensure that this logic correctly handles pagination for multiple entrances and does not introduce unintended behavior.


203-203: Ensure correct parameter passed to la method

In the goroutine within attributeEntrance, verify that the correct VisitsMap parameter (permissionChecks if renamed) is passed to the la method.


218-218: Confirm proper use of permissionChecks in relationEntrance

The relationEntrance method now includes permissionChecks *VisitsMap. Ensure that this parameter is utilized correctly within the method to prevent redundant permission checks.


256-261: Validate pagination logic in relationEntrance

The pagination logic has been adjusted to dynamically set the pagination based on entrance types. Verify that this implementation correctly applies pagination and does not affect data retrieval.


295-295: Pass permissionChecks correctly to lt in relationEntrance

Within the goroutine, ensure that permissionChecks is correctly passed to the lt method to maintain consistent permission checking.


315-316: Ensure consistent parameter naming in tupleToUserSetEntrance

The tupleToUserSetEntrance method now accepts permissionChecks *VisitsMap. Confirm that this parameter is consistently named and used similarly to other methods.


354-359: Review pagination adjustments in tupleToUserSetEntrance

The pagination logic has been modified to accommodate multiple entrances. Verify that the changes correctly handle pagination and align with the intended functionality.


393-393: Confirm correct passing of permissionChecks to lt in tupleToUserSetEntrance

In the goroutine, ensure that permissionChecks is passed to the lt method to prevent redundant permission evaluations.


407-407: Verify usage of permissionChecks in lt method

The lt method signature now includes permissionChecks *VisitsMap. Ensure that this parameter is correctly used within the method to track permission checks effectively.


419-422: Check parameters in LinkedEntrances call within lt

Verify that passing request.GetEntrances() and the subject's entrance to cn.LinkedEntrances correctly retrieves the necessary linked entrances.


430-439: Logic for handling no linked entrances is appropriately implemented

The added code correctly handles cases where no linked entrances are found by checking for direct matches and publishing the entity if necessary.


Line range hint 448-459: Ensure recursive call to EntityFilter includes permissionChecks

In the goroutine within the lt method, confirm that the recursive call to EntityFilter includes the permissionChecks parameter and that the request is constructed properly.


481-481: Verify proper usage of permissionChecks in la method

Ensure that after renaming, the permissionChecks parameter is correctly utilized in the la method to manage permission checks.


37-37: Verify all calls to EntityFilter include the new permissionChecks parameter

The EntityFilter method signature now includes a new parameter permissionChecks *VisitsMap. Please ensure that all invocations of this method have been updated to include this parameter to prevent compilation errors.

Run the following script to verify:

✅ Verification successful

All calls to EntityFilter include the new permissionChecks parameter.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to 'EntityFilter' that may be missing the 'permissionChecks' parameter.

# Search for calls to 'EntityFilter' with the old parameter count (4 parameters).
rg --type go --no-heading --line-number \
  'engine\.EntityFilter\(\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+\s*\)' \
  -- 'internal/**/*.go' | grep -v 'func (engine \*EntityFilter) EntityFilter('

Length of output: 240


Script:

#!/bin/bash
# Description: Find all calls to 'EntityFilter' that may be missing the 'permissionChecks' parameter.

# Search for calls to 'EntityFilter' with the old parameter count (4 parameters) across all Go files.
rg --type go --no-heading --line-number \
  'EntityFilter\(\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+\s*\)' \
  -- '**/*.go' | grep -v 'func (engine \*EntityFilter) EntityFilter('

Length of output: 214


Script:

#!/bin/bash
# Description: Using fd to locate all .go files and rg to find 'EntityFilter' calls missing the 'permissionChecks' parameter.

# Find all .go files and search for 'EntityFilter' with four parameters
fd --extension go --type file --hidden | xargs rg --no-heading --line-number \
  'EntityFilter\(\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+\s*\)' | grep -v 'func (engine \*EntityFilter) EntityFilter('

Length of output: 190

pkg/pb/base/v1/service.pb.validate.go (1)

1731-1752: Verify the regex pattern for permission validation

The regex pattern used to validate permissions in the Permissions field is ^[a-zA-Z_][a-zA-Z0-9_]*$. This pattern requires that each permission starts with a letter or underscore, followed by any combination of letters, digits, or underscores. Ensure that this regex aligns with the intended permission naming conventions in your application.

internal/invoke/invoke.go (1)

52-53: New methods added to the Lookup interface are properly defined

The methods LookupEntities and LookupEntitiesStream are correctly added to the Lookup interface with consistent signatures, aligning with existing methods.

Comment on lines +2364 to +2407
"LookupEntitiesBody": {
"type": "object",
"properties": {
"metadata": {
"$ref": "#/definitions/PermissionLookupEntityRequestMetadata",
"description": "Metadata associated with this request, required."
},
"entity_type": {
"type": "string",
"description": "Type of the entity to lookup, required, must start with a letter and can include alphanumeric and underscore, max 64 bytes."
},
"permissions": {
"type": "array",
"items": {
"type": "string"
},
"description": "Name of the permission to check, required, must start with a letter and can include alphanumeric and underscore, max 64 bytes."
},
"subject": {
"$ref": "#/definitions/Subject",
"description": "Subject for which to check the permission, required."
},
"context": {
"$ref": "#/definitions/Context",
"description": "Context associated with this request."
},
"scope": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/StringArrayValue"
},
"description": "Scope: A map that associates entity types with lists of identifiers. Each entry\nhelps filter requests by specifying which entities are relevant to the operation."
},
"page_size": {
"type": "integer",
"format": "int64",
"description": "page_size is the number of entities to be returned in the response.\nThe value should be between 1 and 100."
},
"continuous_token": {
"type": "string",
"description": "continuous_token is an optional parameter used for pagination.\nIt should be the value received in the previous response."
}
},
"description": "PermissionsLookupEntityRequest is the request message for the LookupEntities method in the Permission service."
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistency Detected in LookupEntitiesBody Definition

The description within LookupEntitiesBody incorrectly references PermissionsLookupEntityRequest. This inconsistency can lead to confusion and should be corrected to maintain clarity in the API documentation.

  • Action Required: Update the description to use "LookupEntitiesBody" instead of "PermissionsLookupEntityRequest".

    Example:

    "description": "LookupEntitiesBody is the request message for the LookupEntities method in the Permission service."
  • Further Investigation: Review other parts of the codebase to ensure that PermissionsLookupEntityRequest is no longer in use or appropriately updated to prevent residual inconsistencies.

🔗 Analysis chain

Review of LookupEntitiesBody definition

The LookupEntitiesBody definition has been added to support the new /lookup-entities endpoint. Overall, the structure is well-defined and includes necessary fields for the lookup operation. However, there are a few points to address:

  1. The permissions field is an array, which differs from the single permission field in similar endpoints. This change allows for checking multiple permissions at once, which can be more efficient. However, ensure that this is intentional and documented clearly for API consumers.

  2. The scope field is a new addition. While it's described as a map for filtering entities, it might benefit from a more detailed explanation or examples in the documentation to clarify its usage.

  3. The description at the end of the definition refers to "PermissionsLookupEntityRequest", which is inconsistent with the actual name "LookupEntitiesBody". This should be corrected to maintain consistency.

Consider the following improvements:

  1. Update the description to use "LookupEntitiesBody" instead of "PermissionsLookupEntityRequest".
  2. Add more detailed documentation for the scope field, possibly including examples of its usage.
  3. Ensure that the API documentation clearly explains the difference between this endpoint (which accepts multiple permissions) and other similar endpoints that might only accept a single permission.

Let's verify the consistency of the LookupEntitiesBody definition:

This script will help us identify any inconsistencies in naming, verify the permissions field definition, and check the usage of the new scope field across the API specification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash

# Check for any inconsistencies in naming
echo "Checking for naming inconsistencies:"
grep -n "PermissionsLookupEntityRequest" docs/api-reference/apidocs.swagger.json

# Verify that the permissions field is consistently defined as an array
echo "\nChecking permissions field definition:"
grep -n '"permissions":' docs/api-reference/apidocs.swagger.json

# Check for any other definitions using the scope field
echo "\nChecking usage of scope field in other definitions:"
grep -n '"scope":' docs/api-reference/apidocs.swagger.json

Length of output: 3643

@@ -54,7 +54,7 @@ type BulkChecker struct {

// callback is a function that handles the result of each permission check.
// It is called with the entity ID and the result of the permission check (e.g., allowed or denied).
callback func(entityID, ct string)
callback func(entityID, permission, ct string)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update all implementations of callback to match the new signature

The callback function in BulkChecker now includes an additional permission parameter: func(entityID, permission, ct string). Ensure that all implementations and invocations of this callback function are updated to accept and handle the new permission parameter correctly.

@@ -76,7 +76,7 @@
// engine: the CheckEngine to use for permission checks
// callback: a callback function that handles the result of each permission check
// concurrencyLimit: the maximum number of concurrent permission checks
func NewBulkChecker(ctx context.Context, checker invoke.Check, typ BulkCheckerType, callback func(entityID, ct string), concurrencyLimit int) *BulkChecker {
func NewBulkChecker(ctx context.Context, checker invoke.Check, typ BulkCheckerType, callback func(entityID, permission, ct string), concurrencyLimit int) *BulkChecker {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Synchronize NewBulkChecker invocations with updated callback signature

The NewBulkChecker constructor now expects a callback function with the updated signature func(entityID, permission, ct string). Verify that all calls to NewBulkChecker across the codebase provide a callback function matching this new signature to prevent runtime errors.

@@ -246,13 +250,13 @@
type BulkEntityPublisher struct {
bulkChecker *BulkChecker

request *base.PermissionLookupEntityRequest
request *base.PermissionsLookupEntityRequest
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure the correct request type is used in BulkEntityPublisher

The request field in BulkEntityPublisher has been updated to use *base.PermissionsLookupEntityRequest. Confirm that all instances where BulkEntityPublisher is instantiated pass a PermissionsLookupEntityRequest and that the previous PermissionLookupEntityRequest references are updated accordingly.

// context to manage goroutines and cancellation
ctx context.Context
}

// NewBulkEntityPublisher creates a new BulkStreamer instance.
func NewBulkEntityPublisher(ctx context.Context, request *base.PermissionLookupEntityRequest, bulkChecker *BulkChecker) *BulkEntityPublisher {
func NewBulkEntityPublisher(ctx context.Context, request *base.PermissionsLookupEntityRequest, bulkChecker *BulkChecker) *BulkEntityPublisher {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Adjust NewBulkEntityPublisher calls to accept the new request type

The NewBulkEntityPublisher function now expects a *base.PermissionsLookupEntityRequest as its request parameter. Make sure that all calls to this constructor provide the correct type to prevent type mismatch errors.

Comment on lines +2352 to +2381
// Validate checks the field values on EntityIds with the rules defined in the
// proto definition for this message. If any rules are violated, the first
// error encountered is returned, or nil if there are no violations.
func (m *EntityIds) Validate() error {
return m.validate(false)
}

// ValidateAll checks the field values on PermissionLookupEntityResponse with
// the rules defined in the proto definition for this message. If any rules
// are violated, the result is a list of violation errors wrapped in
// PermissionLookupEntityResponseMultiError, or nil if none found.
func (m *PermissionLookupEntityResponse) ValidateAll() error {
// ValidateAll checks the field values on EntityIds with the rules defined in
// the proto definition for this message. If any rules are violated, the
// result is a list of violation errors wrapped in EntityIdsMultiError, or nil
// if none found.
func (m *EntityIds) ValidateAll() error {
return m.validate(true)
}

func (m *PermissionLookupEntityResponse) validate(all bool) error {
func (m *EntityIds) validate(all bool) error {
if m == nil {
return nil
}

var errors []error

// no validation rules for ContinuousToken

if len(errors) > 0 {
return PermissionLookupEntityResponseMultiError(errors)
return EntityIdsMultiError(errors)
}

return nil
}

// PermissionLookupEntityResponseMultiError is an error wrapping multiple
// validation errors returned by PermissionLookupEntityResponse.ValidateAll()
// if the designated constraints aren't met.
type PermissionLookupEntityResponseMultiError []error
// EntityIdsMultiError is an error wrapping multiple validation errors returned
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure EntityIds validation is implemented if required

The Validate method for EntityIds is currently empty:

func (m *EntityIds) validate(all bool) error {
    if m == nil {
        return nil
    }

    var errors []error

    if len(errors) > 0 {
        return EntityIdsMultiError(errors)
    }

    return nil
}

If EntityIds should have validation rules (e.g., checking for empty IDs), consider implementing the necessary validation logic to enforce data integrity.

Comment on lines +2577 to +2594
if m == nil {
return nil
}

var errors []error

// no validation rules for EntityId

// no validation rules for Permission

// no validation rules for ContinuousToken

if len(errors) > 0 {
return PermissionsLookupEntityStreamResponseMultiError(errors)
}

return nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add validation rules for fields in PermissionsLookupEntityStreamResponse

Currently, the Validate method for PermissionsLookupEntityStreamResponse contains comments indicating that there are no validation rules for EntityId, Permission, and ContinuousToken. If these fields are critical for the application's functionality, consider adding appropriate validation checks to ensure they contain valid data.

Example:

func (m *PermissionsLookupEntityStreamResponse) validate(all bool) error {
    if m == nil {
        return nil
    }

    var errors []error

+   if m.GetEntityId() == "" {
+       err := PermissionsLookupEntityStreamResponseValidationError{
+           field:  "EntityId",
+           reason: "value is required",
+       }
+       if !all {
+           return err
+       }
+       errors = append(errors, err)
+   }

    // Additional validation rules...

    if len(errors) > 0 {
        return PermissionsLookupEntityStreamResponseMultiError(errors)
    }

    return nil
}

Committable suggestion was skipped due to low confidence.

@@ -245,7 +247,7 @@ func (invoker *DirectInvoker) LookupEntity(ctx context.Context, request *base.Pe
ctx, span := tracer.Start(ctx, "lookup-entity", trace.WithAttributes(
attribute.KeyValue{Key: "tenant_id", Value: attribute.StringValue(request.GetTenantId())},
attribute.KeyValue{Key: "entity_type", Value: attribute.StringValue(request.GetEntityType())},
attribute.KeyValue{Key: "permission", Value: attribute.StringValue(request.GetPermission())},
attribute.KeyValue{Key: "permissions", Value: attribute.StringValue(request.GetPermission())},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent attribute key: change "permissions" to "permission"

In the LookupEntity method, the tracing attribute key has been changed to "permissions", but request.GetPermission() returns a single permission. To maintain clarity and consistency, consider reverting the key back to "permission".

@@ -292,7 +294,7 @@
ctx, span := tracer.Start(ctx, "lookup-entity-stream", trace.WithAttributes(
attribute.KeyValue{Key: "tenant_id", Value: attribute.StringValue(request.GetTenantId())},
attribute.KeyValue{Key: "entity_type", Value: attribute.StringValue(request.GetEntityType())},
attribute.KeyValue{Key: "permission", Value: attribute.StringValue(request.GetPermission())},
attribute.KeyValue{Key: "permissions", Value: attribute.StringValue(request.GetPermission())},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent attribute key: change "permissions" to "permission"

Similarly, in the LookupEntityStream method, the attribute key should be "permission" instead of "permissions" since it deals with a single permission.

Comment on lines +375 to +379
duration := time.Since(start)
invoker.lookupEntityDurationHistogram.Record(ctx, duration.Microseconds())

// Increase the lookup entity count in the metrics.
invoker.lookupEntityCounter.Add(ctx, 1)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define separate metrics for LookupEntities methods

The LookupEntities and LookupEntitiesStream methods are using invoker.lookupEntityDurationHistogram and incrementing invoker.lookupEntityCounter. To accurately monitor these new methods separately from LookupEntity, consider creating distinct metrics like lookupEntitiesDurationHistogram and lookupEntitiesCounter.

Also applies to: 422-426

@ucatbas
Copy link
Contributor

ucatbas commented Oct 14, 2024

Hey @ankitsheoran1, Thank you for updating the PR and rebasing it to latest version. There are some issues with naming and BulkChecker method. I have another PR affecting it. I wanted to make sure I highlight the other PR related to the bulk-checker. Here’s the link: feat: bulk permission check api is added.

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