-
Notifications
You must be signed in to change notification settings - Fork 16
Fix KeyLookup migrator handling for complex values #179
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
Conversation
|
Warning Rate limit exceeded@ReneWerner87 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 6 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (10)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request primarily focuses on enhancing the migration process for KeyLookup configurations within various middleware (CSRF, KeyAuth, Session) to correctly handle complex and deeply nested struct values. It introduces robust parsing utilities to ensure accurate migration of these fields and improves the overall error reporting for migrations. Additionally, a flaky development test has been stabilized.
Highlights
- Improved KeyLookup Migration: Enhanced the migration logic for KeyLookup fields in CSRF, KeyAuth, and Session configurations to correctly parse and transform complex or nested values, including those defined by functions or multiple sources.
- Robust Go Code Parsing Utilities: Introduced new internal utilities (replaceKeyLookup, extractBlock) to accurately parse Go struct literals, handle nested delimiters, and manage quoted strings, which are crucial for reliable code migrations.
- Enhanced Migration Error Handling: The DoMigration function now collects and reports all migration errors using errors.Join instead of stopping on the first error, providing a more comprehensive overview of migration issues.
- Test Suite Expansion: Added comprehensive regression tests for KeyLookup migrations across CSRF, KeyAuth, and Session middleware to ensure the new parsing logic works as expected for various scenarios.
- Development Test Stabilization: Addressed flakiness in the dev_test.go by adjusting sleep timings, making the test more reliable.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively addresses the handling of complex values in KeyLookup migrations by introducing robust parsing for nested struct blocks. The use of extractBlock is a solid improvement. The changes are well-supported by new regression tests, which is great to see. My feedback includes a suggestion to improve the robustness of one migration for consistency and to refactor some duplicated code for better maintainability.
| func MigrateKeyAuthConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error { | ||
| reConfig := regexp.MustCompile(`keyauth\.Config{[^}]*}`) | ||
| reKeyLookup := regexp.MustCompile(`(?m)(\s*)KeyLookup:\s*("[^"]+")(,?)(\n?)`) | ||
| reConfig := regexp.MustCompile(`keyauth\.Config{(?:[^{}]|{[^{}]*})*}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex to find keyauth.Config blocks is less robust than the extractBlock approach used in other migrations in this PR (e.g., MigrateCSRFConfig). It only handles one level of nested braces and might fail for more complex, deeply nested struct literals.
For consistency and robustness, I recommend refactoring this migration to use regexp.MustCompile(keyauth\.Config{) to find the start of the block, and then use extractBlock to find its end. This would align it with MigrateCSRFConfig, MigrateSessionConfig, and MigrateSessionExtractor.
Here is an example of how MigrateKeyAuthConfig could be refactored:
func MigrateKeyAuthConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reConfig := regexp.MustCompile(`keyauth\\.Config{`)
reAuthScheme := regexp.MustCompile(`(?m)\\s*AuthScheme:\\s*([^,\\n]+)`)
changed, err := internal.ChangeFileContent(cwd, func(content string) string {
matches := reConfig.FindAllStringIndex(content, -1)
if len(matches) == 0 {
return content
}
var b strings.Builder
last := 0
for _, m := range matches {
if _, err := b.WriteString(content[last:m[0]]); err != nil {
return content
}
start := m[0]
end := extractBlock(content, m[1], '{', '}')
cfg := content[start:end]
cfg = replaceKeyLookup(cfg, func(indent, val, comma, comment, newline string) string {
scheme := "Bearer"
if am := reAuthScheme.FindStringSubmatch(cfg); len(am) > 1 {
scheme = strings.TrimSpace(am[1])
if uq, err := strconv.Unquote(scheme); err == nil {
scheme = uq
}
}
parts := strings.Split(val, ",")
var extractors []string
for _, p := range parts {
p = strings.TrimSpace(p)
switch {
case strings.HasPrefix(p, "header:"):
header := strings.TrimPrefix(p, "header:")
if strings.EqualFold(header, "Authorization") {
extractors = append(extractors, fmt.Sprintf("keyauth.FromAuthHeader(%q, %q)", header, scheme))
} else {
extractors = append(extractors, fmt.Sprintf("keyauth.FromHeader(%q)", header))
}
case strings.HasPrefix(p, "query:"):
extractors = append(extractors, fmt.Sprintf("keyauth.FromQuery(%q)", strings.TrimPrefix(p, "query:")))
case strings.HasPrefix(p, "param:"):
extractors = append(extractors, fmt.Sprintf("keyauth.FromParam(%q)", strings.TrimPrefix(p, "param:")))
case strings.HasPrefix(p, "form:"):
extractors = append(extractors, fmt.Sprintf("keyauth.FromForm(%q)", strings.TrimPrefix(p, "form:")))
case strings.HasPrefix(p, "cookie:"):
extractors = append(extractors, fmt.Sprintf("keyauth.FromCookie(%q)", strings.TrimPrefix(p, "cookie:")))
default:
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
}
}
extractor := ""
if len(extractors) == 1 {
extractor = extractors[0]
} else if len(extractors) > 1 {
extractor = fmt.Sprintf("keyauth.Chain(%s)", strings.Join(extractors, ", "))
}
if extractor == "" {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
}
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline)
})
cfg = removeConfigField(cfg, "AuthScheme")
if _, err := b.WriteString(cfg); err != nil {
return content
}
last = end
}
if _, err := b.WriteString(content[last:]); err != nil {
return content
}
return b.String()
})
if err != nil {
return fmt.Errorf("failed to migrate keyauth configs: %w", err)
}
if !changed {
return nil
}
cmd.Println("Migrating keyauth middleware configs")
return nil
}| var extractor string | ||
| switch { | ||
| case strings.HasPrefix(val, "header:"): | ||
| extractor = fmt.Sprintf("Extractor: csrf.FromHeader(%q)", strings.TrimPrefix(val, "header:")) | ||
| case strings.HasPrefix(val, "form:"): | ||
| extractor = fmt.Sprintf("Extractor: csrf.FromForm(%q)", strings.TrimPrefix(val, "form:")) | ||
| case strings.HasPrefix(val, "query:"): | ||
| extractor = fmt.Sprintf("Extractor: csrf.FromQuery(%q)", strings.TrimPrefix(val, "query:")) | ||
| default: | ||
| if comment != "" { | ||
| comment = " " + comment | ||
| } | ||
| return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline) | ||
| } | ||
|
|
||
| return fmt.Sprintf("%s%s%s%s", indent, extractor, comma, newline) | ||
| }) | ||
| if comment != "" { | ||
| comment = " " + comment | ||
| } | ||
| return fmt.Sprintf("%s%s%s%s%s", indent, extractor, comma, comment, newline) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic to prepend a space to the comment if it exists is duplicated. You can simplify this by handling it once at the start of the function.
if comment != "" {
comment = " " + comment
}
var extractor string
switch {
case strings.HasPrefix(val, "header:"):
extractor = fmt.Sprintf("Extractor: csrf.FromHeader(%q)", strings.TrimPrefix(val, "header:"))
case strings.HasPrefix(val, "form:"):
extractor = fmt.Sprintf("Extractor: csrf.FromForm(%q)", strings.TrimPrefix(val, "form:"))
case strings.HasPrefix(val, "query:"):
extractor = fmt.Sprintf("Extractor: csrf.FromQuery(%q)", strings.TrimPrefix(val, "query:"))
default:
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
}
return fmt.Sprintf("%s%s%s%s%s", indent, extractor, comma, comment, newline)| if comment != "" { | ||
| comment = " " + comment | ||
| } | ||
| return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline) | ||
| } | ||
| } | ||
|
|
||
| parts := strings.Split(val, ",") | ||
| var extractors []string | ||
| for _, p := range parts { | ||
| p = strings.TrimSpace(p) | ||
| switch { | ||
| case strings.HasPrefix(p, "cookie:"): | ||
| extractors = append(extractors, fmt.Sprintf("session.FromCookie(%q)", strings.TrimPrefix(p, "cookie:"))) | ||
| case strings.HasPrefix(p, "header:"): | ||
| extractors = append(extractors, fmt.Sprintf("session.FromHeader(%q)", strings.TrimPrefix(p, "header:"))) | ||
| case strings.HasPrefix(p, "query:"): | ||
| extractors = append(extractors, fmt.Sprintf("session.FromQuery(%q)", strings.TrimPrefix(p, "query:"))) | ||
| default: | ||
| return "" | ||
| if len(extractors) == 0 { | ||
| if comment != "" { | ||
| comment = " " + comment | ||
| } | ||
| return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline) | ||
| } | ||
| } | ||
|
|
||
| if len(extractors) == 0 { | ||
| return "" | ||
| } | ||
| extractor := extractors[0] | ||
| if len(extractors) > 1 { | ||
| extractor = fmt.Sprintf("session.Chain(%s)", strings.Join(extractors, ", ")) | ||
| } | ||
|
|
||
| extractor := extractors[0] | ||
| if len(extractors) > 1 { | ||
| extractor = fmt.Sprintf("session.Chain(%s)", strings.Join(extractors, ", ")) | ||
| if comment != "" { | ||
| comment = " " + comment | ||
| } | ||
| return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic to prepend a space to the comment if it exists is duplicated. This can be simplified by handling it once.
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
}
}
if comment != "" {
comment = " " + comment
}
if len(extractors) == 0 {
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
}
extractor := extractors[0]
if len(extractors) > 1 {
extractor = fmt.Sprintf("session.Chain(%s)", strings.Join(extractors, ", "))
}
return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline)
Summary
KeyLookupeven when session configs contain nested structsKeyLookupwith regression testsTesting
make lintmake testhttps://chatgpt.com/codex/tasks/task_e_68a9fd340f648326afb03608e21e15d6