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

Add CORS to the connectRPC server #146

Merged
merged 4 commits into from
Nov 22, 2024
Merged

Add CORS to the connectRPC server #146

merged 4 commits into from
Nov 22, 2024

Conversation

neilnaveen
Copy link
Member

@neilnaveen neilnaveen commented Nov 19, 2024

  • Also change dependencies outputted from the API, to be an array of id's instead of a base64 encoded string

Summary by CodeRabbit

  • New Features

    • Enhanced server support for Cross-Origin Resource Sharing (CORS), allowing for better handling of cross-origin requests.
  • Improvements

    • Updated data structure for dependencies and dependents in API responses to use arrays, improving data representation.
  • Chores

    • Updated module dependencies to include new CORS handling libraries.
  • Tests

    • Added new tests for validating CORS behavior and server command creation, enhancing overall test coverage.
    • Removed reliance on the roaring package in service tests, simplifying dependency management.

Copy link
Contributor

coderabbitai bot commented Nov 19, 2024

Walkthrough

The changes in this pull request focus on modifying the serialization of node relationships in the NodeToServiceNode function within api/v1/service.go, switching from ToBase64() to ToArray() for Dependencies and Dependents fields. Additionally, the Node message in api/v1/service.proto is updated to change these fields from string to repeated uint32. CORS support is introduced in cmd/server/server.go, enhancing the server's ability to manage cross-origin requests. The go.mod file is also updated to include new dependencies for CORS handling.

Changes

File Change Summary
api/v1/service.go Modified NodeToServiceNode function to use ToArray() for Dependencies and Dependents.
api/v1/service.proto Changed dependencies and dependents fields from string to repeated uint32 in Node.
cmd/server/server.go Added withCORS function to implement CORS middleware for multiple service handlers.
cmd/server/server_test.go Added tests for withCORS and server command creation; modified existing tests for validation.
go.mod Updated to include new dependencies: connectrpc.com/cors v0.1.0 and github.com/rs/cors v1.11.1.

Possibly related PRs

  • Included additional tests #106: The changes in this PR involve modifications to the Query method in api/v1/service.go, which is related to the overall functionality of the service methods, including the handling of node relationships that are also addressed in the main PR.
  • Refactor server cmd #119: This PR introduces a new method Check in api/v1/service.go, which enhances the service's functionality. The overall structure and error handling in the service methods remain consistent with the changes made in the main PR.
  • Change ingestion to use the API #128: This PR adds several new methods to the Service struct in api/v1/service.go, including IngestSBOM, which relates to the modifications in how node relationships are represented in the main PR.
  • Changed e2e to use the API #142: This PR modifies the cmd/server/server.go file, which includes changes to the service structure that could impact how the service interacts with the node relationships defined in the main PR.

Poem

🐰 In the garden of code, we hop and play,
With nodes and services, we shape the way.
Dependencies now in arrays so neat,
CORS wraps our handlers, a cross-origin treat!
With every change, our project will grow,
A fluffy new feature, a joyful show! 🌼


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 40f05ae and d007e0b.

📒 Files selected for processing (1)
  • api/v1/service_test.go (0 hunks)
💤 Files with no reviewable changes (1)
  • api/v1/service_test.go

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
Contributor

@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: 2

🧹 Outside diff range and nitpick comments (4)
go.mod (1)

Line range hint 3-3: Fix invalid Go version

The Go version 1.23.1 is invalid as Go follows semantic versioning. The latest stable version is 1.22.1.

Apply this diff to fix the Go version:

-go 1.23.1
+go 1.22.1
api/v1/service.proto (1)

25-26: Breaking change: Field type modifications require careful migration

The change from string to repeated uint32 for dependencies and dependents is a good improvement that:

  • Provides better type safety and validation
  • Improves efficiency by avoiding base64 encoding/decoding
  • Makes the API more developer-friendly with direct numeric IDs

However, this is a breaking change that requires careful handling.

Consider the following recommendations:

  1. Version the API appropriately (e.g., bump major version)
  2. Document the migration steps for existing clients
  3. Consider supporting both formats temporarily through a migration period

Would you like me to help draft the migration guide or version bump strategy?

cmd/server/server.go (1)

14-14: Consider consolidating CORS packages

The code imports both connectrpc.com/cors and github.com/rs/cors. While connectrpc.com/cors provides Connect-specific CORS configurations, the implementation only uses its constants with the github.com/rs/cors middleware. Consider if both packages are necessary, or if the Connect-specific CORS package alone could handle all requirements.

Also applies to: 19-19

api/v1/service.go (1)

34-35: Consider performance implications of array vs base64.

While the change to array format is more straightforward, consider the following performance aspects:

  1. Memory usage: Arrays of uint32 vs base64 strings
  2. Network bandwidth: Raw integers vs encoded strings
  3. Serialization/deserialization overhead

Consider benchmarking both approaches if performance is critical.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc9391 and 84d785a.

⛔ Files ignored due to path filters (2)
  • gen/api/v1/service.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • api/v1/service.go (1 hunks)
  • api/v1/service.proto (1 hunks)
  • cmd/server/server.go (3 hunks)
  • go.mod (2 hunks)
🔇 Additional comments (4)
go.mod (1)

7-7: LGTM on CORS dependencies!

The added CORS dependencies look good:

  • connectrpc.com/cors v0.1.0 is the official CORS package for connectRPC
  • github.com/rs/cors v1.11.1 is correctly marked as indirect

Also applies to: 51-51

api/v1/service.proto (1)

25-26: Verify handling of dependencies/dependents across the codebase

Let's ensure all consumers of this API are ready for the new array format.

✅ Verification successful

Based on the search results, I can generate the final response as I have sufficient information to verify the impact of the changes:

No impact on consumers - array field type is already in use

The codebase is already using the array field type (repeated uint32) for dependencies and dependents. The search results show:

  • The Node message fields are accessed as arrays in Go code (e.g., deps.ToArray(), dependencies.ToArray())
  • No string-to-base64 conversions are used for these fields except in tests
  • The field access patterns in packages like pkg/graph, pkg/tools all handle these fields as integer arrays
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find potential areas needing updates due to the Node message changes

# Find proto imports that might be using the Node message
echo "=== Finding potential Node message consumers ==="
rg -l "import.*api/v1/service\.proto"

# Find direct references to dependencies/dependents fields
echo -e "\n=== Finding field access patterns ==="
rg -A 2 "dependencies|dependents" --type go

# Look for potential string-to-base64 conversions that might need updating
echo -e "\n=== Finding potential base64 conversions ==="
rg "ToBase64|FromBase64" --type go

Length of output: 24342

cmd/server/server.go (1)

185-187: Verify CORS headers with the new array response format

Since the API is changing from base64 to array format for dependencies, ensure that CORS headers properly support the new response format and any metadata headers.

✅ Verification successful

CORS configuration is properly set up for the new array response format

The CORS configuration is using the standard Connect framework's CORS settings through connectcors package, which automatically handles the necessary headers for both binary and JSON responses. The service definitions show that:

  1. The server uses standard Connect/gRPC responses with proper content negotiation
  2. All endpoints support both binary Protobuf and JSON codecs by default
  3. Compression (gzip) is enabled by default for all responses

The change from base64 to array format is handled at the protocol level and doesn't require any special CORS configuration since it's part of the standard response payload.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify CORS headers configuration matches API requirements

# Check if any custom headers are used in the API responses
echo "Checking for custom headers in API handlers..."
rg -n "Header\.(Set|Add)" --type go

# Check if the Connect service definitions include any custom metadata
echo "Checking for response metadata in service definitions..."
rg -n "rpc.*returns" --type proto

Length of output: 329


Script:

#!/bin/bash
# Let's verify CORS configuration and response handling

# Check CORS configuration
echo "Checking CORS configuration..."
rg -n "AllowedHeaders|ExposedHeaders|AllowedMethods" --type go -A 2 -B 2

# Check response handling in the codebase
echo "Checking response handling..."
rg -n "json:|proto:" --type go

# Look for any custom middleware or response wrappers
echo "Checking middleware and response wrappers..."
ast-grep --pattern 'func $_($_) http.Handler {
  $$$
}'

Length of output: 11630


Script:

#!/bin/bash
# Let's check the Connect CORS configuration and response types

# Check the connectcors package implementation
echo "Checking connectcors package..."
rg -n "func (AllowedMethods|AllowedHeaders|ExposedHeaders)" --type go -A 5

# Check Connect service definitions for response types
echo "Checking Connect service definitions..."
fd -e go -x grep -l "Connect" {} \; | xargs rg "type.*Service.*interface" -A 10

# Check for any response transformations
echo "Checking response transformations..."
ast-grep --pattern 'func $_($_ *connect.Response) {
  $$$
}'

Length of output: 14645

api/v1/service.go (1)

34-35: Verify API compatibility for dependency format change.

The switch from ToBase64() to ToArray() for Dependencies and Dependents aligns with the PR objectives. However, this change requires careful consideration:

  1. This is a breaking change for API consumers expecting base64 encoded strings
  2. Need to ensure the proto file changes (repeated uint32) are deployed simultaneously
  3. Consider documenting the new format in API documentation

Let's verify the proto file changes and any existing consumers:

✅ Verification successful

Based on the verification results, I can now provide a final response:

Change to array format is compatible with proto definition

The switch from ToBase64() to ToArray() for Dependencies and Dependents is aligned with the proto definition which uses repeated uint32 fields. The proto file shows:

message Node {
  uint32 id = 1;
  string name = 2;
  string type = 3;
  repeated uint32 dependencies = 4;
  repeated uint32 dependents = 5;
}

This confirms that:

  1. The change maintains API compatibility as it matches the proto contract
  2. The array format is the correct representation for the repeated fields
  3. No documentation updates are needed since this aligns with the proto spec
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify proto definition and API consumers
# Check proto definition
rg -A 5 "message Node" api/v1/service.proto

# Look for potential API consumers that might be affected
rg -l "ToBase64|Dependencies.*string|Dependents.*string"

Length of output: 244


Script:

#!/bin/bash
# Let's verify the changes more thoroughly

# Check the implementation of ToArray() method
rg -A 3 "func.*ToArray" 

# Look for any tests that might be affected
rg -l "TestNode.*Dependencies|TestNode.*Dependents"

# Check for any documentation changes
fd README.md --exec grep -l "Dependencies\|Dependents" {} \;

# Look for any API examples or usage patterns
fd -e md -e txt -e yaml -e json --exec grep -l "Dependencies\|Dependents" {} \;

Length of output: 268


Script:

#!/bin/bash
# Let's check the content of the scorecards file and look for the ToArray implementation in a different way
cat ./testdata/scorecards/scorecards.json

# Try finding ToArray implementation using ast-grep
ast-grep --pattern 'func ($node) ToArray() $ret {
  $$$
}'

# Look for the struct definition that contains ToArray
rg -B 5 -A 1 "type.*struct.*{.*Children.*Parents"

Length of output: 3028


Script:

#!/bin/bash
# Fix the regex and try one last search for the implementation
rg -B 5 "type.*struct.*\{.*Children"

# Look for any interface definitions that might specify ToArray
rg "interface.*\{" -A 10

# Check for any test files that might show the expected behavior
fd -e test.go --exec cat {} \;

Length of output: 106695

cmd/server/server.go Outdated Show resolved Hide resolved
cmd/server/server.go Outdated Show resolved Hide resolved
neilnaveen and others added 3 commits November 21, 2024 10:30
- Also change dependencies outputted from the API, to be an array of
  id's instead of a base64 encoded string

Signed-off-by: neilnaveen <42328488+neilnaveen@users.noreply.github.com>
Signed-off-by: naveensrinivasan <172697+naveensrinivasan@users.noreply.github.com>
Signed-off-by: naveensrinivasan <172697+naveensrinivasan@users.noreply.github.com>
Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (3)
cmd/server/server.go (2)

50-55: Enhance the CORS flag description

While the current description is good, consider making it more explicit about accepting multiple origins and providing more examples.

-		"Allowed origins for CORS (e.g., 'https://app.bitbom.dev')",
+		"Comma-separated list of allowed origins for CORS (e.g., 'http://localhost:8089,https://app.bitbom.dev')",

188-199: Consider adding CORS origin validation

While the current implementation is secure, consider adding validation for CORS origins to prevent accidental misconfiguration.

 func withCORS(h http.Handler, o *options) http.Handler {
+	// Validate CORS origins
+	for _, origin := range o.CORS {
+		if origin == "*" {
+			log.Printf("Warning: Wildcard CORS origin (*) detected. This is not recommended for production.")
+		}
+		if !strings.HasPrefix(origin, "http://") && !strings.HasPrefix(origin, "https://") {
+			log.Printf("Warning: Invalid CORS origin format: %s. Origins should start with http:// or https://", origin)
+		}
+	}
+
 	middleware := cors.New(cors.Options{
 		AllowedOrigins:   o.CORS,
 		AllowedMethods:   connectcors.AllowedMethods(),
cmd/server/server_test.go (1)

206-265: Enhance CORS test coverage with additional test cases.

While the current test cases cover basic CORS functionality, consider adding the following scenarios for comprehensive coverage:

  1. OPTIONS preflight requests
  2. Empty CORS array behavior
  3. Wildcard origin "*"
  4. Additional CORS headers (Allow-Methods, Allow-Headers)

Here's a suggested addition to the test cases:

 testCases := []struct {
     name           string
     options        options
     requestOrigin  string
+    requestMethod  string
     expectedOrigin string
+    expectedHeaders map[string]string
 }{
     // ... existing test cases ...
+    {
+        name: "Preflight Request",
+        options: options{
+            CORS: []string{"http://localhost:3000"},
+        },
+        requestOrigin: "http://localhost:3000",
+        requestMethod: "OPTIONS",
+        expectedOrigin: "http://localhost:3000",
+        expectedHeaders: map[string]string{
+            "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE",
+            "Access-Control-Allow-Headers": "Content-Type,Authorization",
+        },
+    },
+    {
+        name: "Wildcard Origin",
+        options: options{
+            CORS: []string{"*"},
+        },
+        requestOrigin: "http://any-domain.com",
+        expectedOrigin: "*",
+    },
+    {
+        name: "Empty CORS Array",
+        options: options{
+            CORS: []string{},
+        },
+        requestOrigin: "http://localhost:3000",
+        expectedOrigin: "",
+    },
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5e05035 and 40f05ae.

⛔ Files ignored due to path filters (2)
  • gen/api/v1/service.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • api/v1/service.go (1 hunks)
  • api/v1/service.proto (1 hunks)
  • cmd/server/server.go (5 hunks)
  • cmd/server/server_test.go (2 hunks)
  • go.mod (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/v1/service.go
  • api/v1/service.proto
  • go.mod
🔇 Additional comments (4)
cmd/server/server.go (3)

14-14: LGTM: Import statements are correctly structured

The new CORS-related imports are properly organized and aliased to avoid naming conflicts.

Also applies to: 19-19


33-33: LGTM: CORS field properly added to options struct

The CORS field is correctly typed as []string to support multiple allowed origins.


128-128: LGTM: CORS wrapper correctly applied at the mux level

The implementation properly applies CORS at a single level, following best practices and previous review feedback.

cmd/server/server_test.go (1)

206-327: Verify CORS security implementation.

Please ensure the CORS implementation follows security best practices:

  1. Origin validation should be case-sensitive
  2. Avoid using wildcards (*) in production
  3. Set appropriate security headers

Let's verify the CORS implementation in the main server code:

✅ Verification successful

Let me gather more information about the CORS implementation by checking the actual server code:


Let me check one more thing to understand which CORS package is being used and its imports:


CORS implementation follows security best practices

The CORS implementation is secure and well-implemented:

  1. Uses rs/cors package with connectrpc.com/cors for standardized headers
  2. No wildcards in origin configuration - origins are explicitly listed in o.CORS
  3. Implements secure defaults:
    • Case-sensitive origin validation (inherent in rs/cors)
    • Proper security headers (AllowedMethods, AllowedHeaders, ExposedHeaders)
    • Reasonable MaxAge (3600)
    • Explicit AllowedOrigins list
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check CORS implementation for security best practices

# Check for case-sensitive origin comparison
rg -A 3 'Origin.*==' cmd/server/

# Check for wildcard usage
rg -A 3 '\*' cmd/server/

# Check for security headers
rg -A 5 'Access-Control-' cmd/server/

Length of output: 7526


Script:

#!/bin/bash
# Check the actual CORS implementation in server.go
rg -A 10 'withCORS' cmd/server/server.go

# Check if we're using any CORS middleware
rg -l 'cors\.' cmd/server/

# Check imports to identify the CORS package
rg -A 3 'import.*cors' cmd/server/

Length of output: 811


Script:

#!/bin/bash
# Check all imports in server.go to identify the CORS package
rg -A 20 '^import \(' cmd/server/server.go

# Check for any CORS-related configuration or constants
rg -B 2 -A 2 'connectcors\.' cmd/server/

Length of output: 936

cmd/server/server_test.go Show resolved Hide resolved
Signed-off-by: naveensrinivasan <172697+naveensrinivasan@users.noreply.github.com>
Copy link

codecov bot commented Nov 21, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Files with missing lines Coverage Δ
api/v1/service.go 59.24% <100.00%> (+1.11%) ⬆️
cmd/server/server.go 63.77% <100.00%> (+15.13%) ⬆️

🚨 Try these New Features:

@naveensrinivasan naveensrinivasan merged commit 8564d12 into main Nov 22, 2024
14 checks passed
@naveensrinivasan naveensrinivasan deleted the neil/addCORS branch November 22, 2024 00: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.

2 participants