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

Improve version checking system #506

Merged
merged 1 commit into from
Feb 19, 2025
Merged

Improve version checking system #506

merged 1 commit into from
Feb 19, 2025

Conversation

mkysel
Copy link
Collaborator

@mkysel mkysel commented Feb 18, 2025

We were depending on a hardcoded value that does not automatically update when we release.

Instead, determine the version internally.

Add more tests.

Summary by CodeRabbit

  • New Features

    • Introduced enhanced version validation to ensure authentication tokens meet compatibility requirements.
  • Refactor

    • Consolidated version checking logic and improved error handling during authentication processes.
  • Tests

    • Expanded and reorganized test suites to cover additional version scenarios, including prerelease and future versions.
  • Chores

    • Updated testing utilities and restructured test packages to streamline version retrieval and verification processes.

@mkysel mkysel requested a review from a team as a code owner February 18, 2025 18:21
Copy link

coderabbitai bot commented Feb 18, 2025

Walkthrough

This pull request refactors version claim validation by introducing a new ClaimValidator type that encapsulates the version compatibility logic. The changes remove the static version constraint and instead dynamically generate constraints using a sanitized server version. The update propagates into the verifier and server initialization, ensuring that tests and API setup use the new signature requiring a semver.Version. Additionally, the test suite has been restructured, with package renaming and updated function calls to accurately reflect the new versioning approach.

Changes

File(s) Change Summary
pkg/authn/claims.go, pkg/authn/verifier.go Introduced new ClaimValidator type; moved version claim validation logic into a method; removed constant constraints; updated constructors and method signatures to accept a *semver.Version, initializing version constraints dynamically.
pkg/authn/claims_test.go, pkg/authn/signingMethod_test.go, pkg/authn/tokenFactory_test.go, pkg/authn/verifier_test.go Refactored test files: renamed packages to _test; updated instantiations to use explicit authn references; modified test function names and parameters to include server version handling; improved error handling in test setups.
pkg/server/server.go, pkg/server/server_test.go, pkg/testutils/api/api.go Updated server initialization routines by adding a serverVersion parameter; modified JWT verifier creation to incorporate versioning and error management; adjusted tests to pass version information using testutils.GetLatestVersion(t).
pkg/testutils/versioning.go Introduced new test utility functions GetLatestTag and GetLatestVersion to retrieve and parse Git tags into semantic version objects using the semver library.

Sequence Diagram(s)

sequenceDiagram
    participant RS as ReplicationServer
    participant AS as APIServer
    participant RV as RegistryVerifier
    participant CV as ClaimValidator

    RS->>AS: startAPIServer(ctx, serverVersion)
    AS->>RV: NewRegistryVerifier(..., serverVersion)
    RV->>CV: NewClaimValidator(serverVersion)
    CV-->>RV: Return ClaimValidator instance or error
    RV->>CV: ValidateVersionClaimIsCompatible(claims)
    CV-->>RV: Return compatibility result (success/error)
Loading

Possibly related PRs

  • JWT Version Checks #364: Involves similar modifications to the version compatibility checks using the semver.Version type and updates on version validation logic.

Suggested reviewers

  • richardhuaaa
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

@mkysel mkysel force-pushed the mkysel/improveClaims branch from 2c01f95 to 8912326 Compare February 18, 2025 18:24
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: 3

🧹 Nitpick comments (5)
pkg/authn/claims.go (3)

13-15: Add documentation for ClaimValidator type.

The type needs documentation explaining its purpose and responsibility.

Add this documentation:

+// ClaimValidator handles version compatibility checks using semver constraints.
+// It ensures that client versions are compatible with the server version.
 type ClaimValidator struct {
 	constraint semver.Constraints
 }

17-35: Add documentation and improve error messages in NewClaimValidator.

The constructor needs documentation and more descriptive error messages.

Consider these improvements:

+// NewClaimValidator creates a new validator that ensures version compatibility
+// using the caret range comparison (^) with the given server version.
+// It returns an error if the server version is nil or invalid.
 func NewClaimValidator(serverVersion *semver.Version) (*ClaimValidator, error) {
 	if serverVersion == nil {
-		return nil, fmt.Errorf("serverVersion is nil")
+		return nil, fmt.Errorf("server version cannot be nil")
 	}
 	sanitizedVersion, err := serverVersion.SetPrerelease("")
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to sanitize server version: %w", err)
 	}
 
 	// https://github.com/Masterminds/semver?tab=readme-ov-file#caret-range-comparisons-major
 	constraintStr := fmt.Sprintf("^%s", sanitizedVersion.String())
 
 	constraint, err := semver.NewConstraint(constraintStr)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to create version constraint: %w", err)
 	}
 
 	return &ClaimValidator{constraint: *constraint}, nil
 }

36-53: Add documentation for ValidateVersionClaimIsCompatible method.

The method needs documentation explaining its behavior and return values.

Add this documentation:

+// ValidateVersionClaimIsCompatible checks if the version in the claims is compatible
+// with the server version using semver caret range comparison.
+// It returns nil if the claims version is nil or compatible, and an error otherwise.
 func (cv *ClaimValidator) ValidateVersionClaimIsCompatible(claims *XmtpdClaims) error {
pkg/authn/tokenFactory_test.go (1)

29-36: Add more test cases for version compatibility.

The current test cases could be expanded to cover more edge cases.

Add these test cases:

 	tests := []struct {
 		name    string
 		version string
+		wantErr bool
 	}{
 		{"current-ish", "0.1.3"},
 		{"future-ish", "11.7.3"},
 		{"with-git-describe", "0.1.0-15-gdeadbeef"},
+		{"invalid-version", "invalid", true},
+		{"empty-version", "", true},
+		{"pre-release", "1.0.0-alpha", false},
 	}
pkg/server/server.go (1)

175-176: Consider adding nil check for serverVersion.

The serverVersion parameter should be validated before being used in NewRegistryVerifier to prevent potential nil pointer dereferences.

 func startAPIServer(
   ctx context.Context,
   log *zap.Logger,
   options config.ServerOptions,
   s *ReplicationServer,
   writerDB *sql.DB,
   blockchainPublisher blockchain.IBlockchainPublisher,
   listenAddress string,
   serverVersion *semver.Version,
 ) error {
   var err error
+  if serverVersion == nil {
+    return fmt.Errorf("serverVersion cannot be nil")
+  }

Also applies to: 248-252

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ffc98e and 8912326.

📒 Files selected for processing (10)
  • pkg/authn/claims.go (2 hunks)
  • pkg/authn/claims_test.go (5 hunks)
  • pkg/authn/signingMethod_test.go (5 hunks)
  • pkg/authn/tokenFactory_test.go (3 hunks)
  • pkg/authn/verifier.go (3 hunks)
  • pkg/authn/verifier_test.go (10 hunks)
  • pkg/server/server.go (3 hunks)
  • pkg/server/server_test.go (1 hunks)
  • pkg/testutils/api/api.go (1 hunks)
  • pkg/testutils/versioning.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Test (Node)
🔇 Additional comments (9)
pkg/authn/signingMethod_test.go (1)

1-76: LGTM! Package qualification changes look good.

The changes to use qualified package names improve code organization and clarity.

pkg/authn/verifier.go (2)

28-39: LGTM! Clean error handling in the constructor.

The updated constructor properly initializes the version validator and handles potential errors. The use of semver for version handling adds type safety and standardization.


118-118: LGTM! Good separation of concerns.

Delegating version validation to a dedicated validator improves modularity and maintainability.

pkg/authn/claims_test.go (1)

66-96: LGTM! Comprehensive version compatibility testing.

Excellent test coverage including:

  • Current version compatibility
  • Pre-release and metadata handling
  • Future version incompatibility
  • Specific version checks (0.1.3, 0.1.4)
pkg/testutils/api/api.go (1)

118-123: LGTM! Proper error handling in verifier initialization.

The changes correctly integrate version checking and handle potential initialization errors.

pkg/authn/verifier_test.go (1)

24-37: LGTM! Well-structured test helper with proper error handling.

The buildVerifier function properly integrates version checking and handles initialization errors.

pkg/server/server.go (2)

54-63: LGTM! Good addition of version compatibility checks.

The addition of serverVersion parameter and its propagation to dependent components enhances version compatibility validation.


248-255: LGTM! Good addition of error handling.

The error handling for JWT verifier initialization is a good improvement.

pkg/server/server_test.go (1)

78-78: LGTM! Good test coverage with version information.

The test setup correctly uses testutils.GetLatestVersion(t) to provide version information, ensuring proper testing of the version checking system.

Comment on lines +27 to +33
func GetLatestVersion(t *testing.T) *semver.Version {
tag := GetLatestTag(t)
v, err := semver.NewVersion(tag)
require.NoError(t, err)

return v
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for version parsing in GetLatestVersion.

The function should validate that the tag can be parsed into a valid semver version.

Consider this improvement:

 func GetLatestVersion(t *testing.T) *semver.Version {
 	tag := GetLatestTag(t)
+	// Remove 'v' prefix if present for semver parsing
+	tag = strings.TrimPrefix(tag, "v")
+	
 	v, err := semver.NewVersion(tag)
-	require.NoError(t, err)
+	require.NoError(t, err, "Failed to parse version from tag: %s", tag)
 
 	return v
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func GetLatestVersion(t *testing.T) *semver.Version {
tag := GetLatestTag(t)
v, err := semver.NewVersion(tag)
require.NoError(t, err)
return v
}
func GetLatestVersion(t *testing.T) *semver.Version {
tag := GetLatestTag(t)
// Remove 'v' prefix if present for semver parsing
tag = strings.TrimPrefix(tag, "v")
v, err := semver.NewVersion(tag)
require.NoError(t, err, "Failed to parse version from tag: %s", tag)
return v
}

Comment on lines +12 to +25
func GetLatestTag(t *testing.T) string {
// Prepare the command
cmd := exec.Command("git", "describe", "--tags", "--abbrev=0")

// Capture the output
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out

// Run the command
err := cmd.Run()
require.NoError(t, err, out.String())
return strings.TrimSpace(out.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

Improve error handling and security in GetLatestTag.

The function has several potential issues:

  1. Command execution in tests can be unreliable if git is not available
  2. No validation of stderr output separately from stdout
  3. No validation that the tag follows semver format before returning

Consider these improvements:

 func GetLatestTag(t *testing.T) string {
+	// Ensure git is available
+	if _, err := exec.LookPath("git"); err != nil {
+		t.Skip("git not available")
+	}
+
 	// Prepare the command
 	cmd := exec.Command("git", "describe", "--tags", "--abbrev=0")
 
 	// Capture the output
-	var out bytes.Buffer
+	var stdout, stderr bytes.Buffer
 	cmd.Stdout = &out
-	cmd.Stderr = &out
+	cmd.Stderr = &stderr
 
 	// Run the command
 	err := cmd.Run()
-	require.NoError(t, err, out.String())
-	return strings.TrimSpace(out.String())
+	if err != nil {
+		t.Fatalf("Failed to get latest tag: %v\nStderr: %s", err, stderr.String())
+	}
+
+	tag := strings.TrimSpace(stdout.String())
+	// Validate tag format
+	if !strings.HasPrefix(tag, "v") {
+		t.Fatalf("Invalid tag format: %s", tag)
+	}
+	return tag
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +159 to +163
"future-patch-accepts-us",
currentVersion,
currentVersion.IncPatch(),
true,
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect test expectation.

The test case "future-patch-accepts-us" expects an error (wantErr: true) when the server is on a future patch version. This seems incorrect as patch version differences should be backward compatible according to semver.

Apply this fix:

-			"wantErr":       true,
+			"wantErr":       false,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"future-patch-accepts-us",
currentVersion,
currentVersion.IncPatch(),
true,
},
{
"future-patch-accepts-us",
currentVersion,
currentVersion.IncPatch(),
wantErr: false,
},
Suggested change
"future-patch-accepts-us",
currentVersion,
currentVersion.IncPatch(),
true,
},
"future-patch-accepts-us",
currentVersion,
currentVersion.IncPatch(),
false,
},

}

c, err := semver.NewConstraint(XMTPD_COMPATIBLE_VERSION_CONSTRAINT)
// https://github.com/Masterminds/semver?tab=readme-ov-file#caret-range-comparisons-major
constraintStr := fmt.Sprintf("^%s", sanitizedVersion.String())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably in the future we might want to move this constraint on-chain to the XMTP Node Registry.

@mkysel mkysel merged commit 21f814f into main Feb 19, 2025
7 checks passed
@mkysel mkysel deleted the mkysel/improveClaims branch February 19, 2025 12:14
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