-
Notifications
You must be signed in to change notification settings - Fork 21
Handle commented config fields across migrations #188
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,14 +14,26 @@ import ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func MigrateBasicauthConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reCtxUser := regexp.MustCompile(`\s*ContextUsername:\s*[^,]+,?\n`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reCtxPass := regexp.MustCompile(`\s*ContextPassword:\s*[^,]+,?\n`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove ContextKey/Username/Password when they are on their own line (with optional trailing comment). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reCtxKeyLine := regexp.MustCompile(`(?m)^\s*Context(?:Username|Password|Key):\s*[^,\n}]+,?\s*(//[^\n]*)?\n`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Also remove inline occurrences immediately before a closing '}' (with optional comma/comment), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // e.g. basicauth.Config{ContextUsername: "user"}) or {..., ContextPassword: "pass"}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Keep the closing brace via a capture group. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reCtxKeyInline := regexp.MustCompile(`(?m)\s*Context(?:Username|Password|Key):\s*[^,\n}]+(?:,\s*)?(?://[^\n]*)?(\s*})`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reUsers := regexp.MustCompile(`Users:\s*map\[string\]string{([^}]*)}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reEntry := regexp.MustCompile(`("[^"]+")\s*:\s*"((?:[^"\\]|\\.)*)"`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| changed, err := internal.ChangeFileContent(cwd, func(content string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = reCtxUser.ReplaceAllString(content, "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = reCtxPass.ReplaceAllString(content, "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = reCtxKeyLine.ReplaceAllString(content, "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| newContent := reCtxKeyInline.ReplaceAllString(content, "$1") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if newContent == content { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = newContent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Regex-only removal still misses non-tail inline fields and can affect non-basicauth structs; make removal struct-aware. The iterative “remove if immediately before '}'” works for “last field” cases, but fails when the target field appears mid-list (e.g., Refactor to operate only within Proposed change: - content = reCtxKeyLine.ReplaceAllString(content, "")
- for {
- newContent := reCtxKeyInline.ReplaceAllString(content, "$1")
- if newContent == content {
- break
- }
- content = newContent
- }
+ // Limit removals strictly to basicauth.Config blocks and handle any position (head/mid/tail).
+ reCfgOpen := regexp.MustCompile(`basicauth\.Config\s*\{`)
+ for {
+ m := reCfgOpen.FindStringIndex(content)
+ if m == nil {
+ break
+ }
+ // m[1] points just after '{'
+ end := extractBlock(content, m[1], '{', '}')
+ if end <= m[1] {
+ // malformed, bail out of this occurrence
+ // continue searching after '{' to avoid infinite loop
+ content = content[:m[1]] + content[m[1]:]
+ continue
+ }
+ inner := content[m[1] : end-1]
+ inner = removeConfigField(inner, "ContextUsername")
+ inner = removeConfigField(inner, "ContextPassword")
+ content = content[:m[0]] + "basicauth.Config{" + inner + "}" + content[end:]
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = reUsers.ReplaceAllStringFunc(content, func(m string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sub := reUsers.FindStringSubmatch(m) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package v3_test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bytes" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "os" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "testing" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/stretchr/testify/assert" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/stretchr/testify/require" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/gofiber/cli/cmd/internal/migrations/v3" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func Test_MigrateBasicauthConfig_WithComments(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Parallel() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dir, err := os.MkdirTemp("", "mbasiccfg") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.NoError(t, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defer func() { require.NoError(t, os.RemoveAll(dir)) }() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file := writeTempFile(t, dir, `package main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import "github.com/gofiber/fiber/v2/middleware/basicauth" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var _ = basicauth.New(basicauth.Config{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ContextUsername: "user", // username comment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ContextPassword: "pass", // password comment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var buf bytes.Buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd := newCmd(&buf) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.NoError(t, v3.MigrateBasicauthConfig(cmd, dir, nil, nil)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content := readFile(t, file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "ContextUsername") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "ContextPassword") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "username comment") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "password comment") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.Contains(t, buf.String(), "Migrating basicauth configs") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func Test_MigrateBasicauthConfig_Inline(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Parallel() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dir, err := os.MkdirTemp("", "mbasiccfg_inline") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.NoError(t, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defer func() { require.NoError(t, os.RemoveAll(dir)) }() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file := writeTempFile(t, dir, `package main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import "github.com/gofiber/fiber/v2/middleware/basicauth" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var _ = basicauth.New(basicauth.Config{ContextUsername: "user", ContextPassword: "pass"})`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var buf bytes.Buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd := newCmd(&buf) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.NoError(t, v3.MigrateBasicauthConfig(cmd, dir, nil, nil)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content := readFile(t, file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "ContextUsername") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NotContains(t, content, "ContextPassword") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.Contains(t, content, "basicauth.Config{}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.Contains(t, buf.String(), "Migrating basicauth configs") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Guard against cross-migration effects: ensure basicauth migration does not touch ContextKey in other configs. Given the prior inclusion of Add: +func Test_MigrateBasicauthConfig_DoesNotTouch_OtherContextKey(t *testing.T) {
+ t.Parallel()
+ dir, err := os.MkdirTemp("", "mbasiccfg_scope")
+ require.NoError(t, err)
+ t.Cleanup(func() { require.NoError(t, os.RemoveAll(dir)) })
+
+ file := writeTempFile(t, dir, `package main
+import (
+ "github.com/gofiber/fiber/v2/middleware/basicauth"
+ "github.com/gofiber/fiber/v2/middleware/csrf"
+)
+var _ = basicauth.New(basicauth.Config{ContextUsername: "user", ContextPassword: "pass"})
+var _ = csrf.New(csrf.Config{ContextKey: "token"})
+`)
+ var buf bytes.Buffer
+ cmd := newCmd(&buf)
+ require.NoError(t, v3.MigrateBasicauthConfig(cmd, dir, nil, nil))
+ content := readFile(t, file)
+ assert.NotContains(t, content, "ContextUsername")
+ assert.NotContains(t, content, "ContextPassword")
+ assert.Contains(t, content, `csrf.Config{ContextKey: "token"}`)
+}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,13 +13,38 @@ var ( | |
| ) | ||
|
|
||
| // skipCommaSuffix advances the index past a comma and any trailing | ||
| // whitespace or newline characters. | ||
| // whitespace, comments, or newline characters. | ||
| func skipCommaSuffix(src string, i int) int { | ||
| i++ | ||
| for i < len(src) { | ||
| switch src[i] { | ||
| case ' ', '\t': | ||
| i++ | ||
| case '/': | ||
| if i+1 < len(src) { | ||
| if src[i+1] == '/' { // line comment | ||
| i += 2 | ||
| for i < len(src) && src[i] != '\n' { | ||
| i++ | ||
| } | ||
| if i < len(src) { | ||
| return i + 1 | ||
| } | ||
| return i | ||
| } | ||
| if src[i+1] == '*' { // block comment | ||
| i += 2 | ||
| for i+1 < len(src) && !(src[i] == '*' && src[i+1] == '/') { | ||
| i++ | ||
| } | ||
| if i+1 < len(src) { | ||
| i += 2 | ||
| continue | ||
| } | ||
| return i | ||
| } | ||
| } | ||
| return i | ||
| case '\n': | ||
| return i + 1 | ||
| default: | ||
|
|
@@ -34,13 +59,37 @@ func skipCommaSuffix(src string, i int) int { | |
| // multi-line function literals or function calls with arguments that contain | ||
| // commas. | ||
| func removeConfigField(src, field string) string { | ||
| re := regexp.MustCompile(`(?m)^\s*` + field + `:\s*`) | ||
| re := regexp.MustCompile(field + `:\s*`) | ||
| for { | ||
| loc := re.FindStringIndex(src) | ||
| if loc == nil { | ||
| break | ||
| } | ||
|
|
||
| start := loc[0] | ||
| // include any leading whitespace and comma | ||
| for start > 0 { | ||
|
Comment on lines
+62
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: removeConfigField can match inside comments/strings and corrupt code. Because the regex isn’t constrained to code context, Adopt a context-aware finder that ignores strings and comments and returns the index right after Patch: - func removeConfigField(src, field string) string {
- re := regexp.MustCompile(field + `:\s*`)
- for {
- loc := re.FindStringIndex(src)
- if loc == nil {
- break
- }
-
- start := loc[0]
+ func removeConfigField(src, field string) string {
+ for {
+ start, i := findFieldIndexOutsideLiterals(src, field, 0)
+ if start < 0 {
+ break
+ }
- i := loc[1]Add the scanner (outside the selected range; same file): // findFieldIndexOutsideLiterals scans src starting at from and returns the
// start index of 'field' and the index just after 'field:\s*' while ignoring
// occurrences inside comments and string literals. If not found, returns -1,-1.
func findFieldIndexOutsideLiterals(src, field string, from int) (int, int) {
inStr := false
var quote byte
inLine, inBlock := false, false
for i := from; i+len(field)+1 <= len(src); i++ {
ch := src[i]
if inLine {
if ch == '\n' {
inLine = false
}
continue
}
if inBlock {
if ch == '*' && i+1 < len(src) && src[i+1] == '/' {
inBlock = false
i++
}
continue
}
if inStr {
if ch == '\\' {
i++
continue
}
if ch == quote {
inStr = false
}
continue
}
// enter literal/comment
if ch == '"' || ch == '\'' || ch == '`' {
inStr = true
quote = ch
continue
}
if ch == '/' && i+1 < len(src) {
if src[i+1] == '/' {
inLine = true
i++
continue
}
if src[i+1] == '*' {
inBlock = true
i++
continue
}
}
// candidate: field name followed by ':'
if strings.HasPrefix(src[i:], field) && i+len(field) < len(src) && src[i+len(field)] == ':' {
// ensure reasonable left boundary: start, comma, '{', or newline/space
j := i - 1
for j >= 0 && (src[j] == ' ' || src[j] == '\t') {
j--
}
if j >= 0 && src[j] != '{' && src[j] != ',' && src[j] != '\n' && src[j] != '\r' {
continue
}
// skip 'field:' and any following spaces/tabs
k := i + len(field) + 1
for k < len(src) && (src[k] == ' ' || src[k] == '\t') {
k++
}
return i, k
}
}
return -1, -1
}This preserves your depth-based removal and makes matches safe and precise. Also applies to: 93-147 🤖 Prompt for AI Agents |
||
| switch src[start-1] { | ||
| case ' ', '\t': | ||
| start-- | ||
| case ',': | ||
| start-- | ||
| for start > 0 && (src[start-1] == ' ' || src[start-1] == '\t') { | ||
| start-- | ||
| } | ||
| goto leadDone | ||
| case '\n': | ||
| start-- | ||
| for start > 0 && (src[start-1] == ' ' || src[start-1] == '\t') { | ||
| start-- | ||
| } | ||
| goto leadDone | ||
| default: | ||
| goto leadDone | ||
| } | ||
| } | ||
| leadDone: | ||
|
|
||
| i := loc[1] | ||
| depth := 0 | ||
| inString := false | ||
|
|
@@ -54,29 +103,41 @@ func removeConfigField(src, field string) string { | |
| if ch == '"' { | ||
| inString = false | ||
| } | ||
| } else { | ||
| switch ch { | ||
| case '"': | ||
| inString = true | ||
| case '(', '{', '[': | ||
| depth++ | ||
| case ')', '}', ']': | ||
| if depth > 0 { | ||
| depth-- | ||
| } | ||
| case ',': | ||
| if depth == 0 { | ||
| i = skipCommaSuffix(src, i) | ||
| src = src[:start] + src[i:] | ||
| goto nextField | ||
| } | ||
| case '\n': | ||
| if depth == 0 { | ||
| i++ | ||
| src = src[:start] + src[i:] | ||
| goto nextField | ||
| } | ||
| i++ | ||
| continue | ||
| } | ||
|
|
||
| switch ch { | ||
| case '"': | ||
| inString = true | ||
| case '(', '{', '[': | ||
| depth++ | ||
| case ')', '}', ']': | ||
| if depth > 0 { | ||
| depth-- | ||
| i++ | ||
| continue | ||
| } | ||
| if ch == '}' { | ||
| src = src[:start] + src[i:] | ||
| goto nextField | ||
| } | ||
| case ',': | ||
| if depth > 0 { | ||
| i++ | ||
| continue | ||
| } | ||
| i = skipCommaSuffix(src, i) | ||
| src = src[:start] + src[i:] | ||
| goto nextField | ||
| case '\n': | ||
| if depth > 0 { | ||
| i++ | ||
| continue | ||
| } | ||
| i++ | ||
| src = src[:start] + src[i:] | ||
| goto nextField | ||
| } | ||
| i++ | ||
| } | ||
|
|
||
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.
Scope leak: basicauth migration must not remove ContextKey (belongs to other middlewares).
Including
ContextKeyhere risks deleting fields in unrelated configs (e.g., csrf/keyauth/session) when only running the basicauth migration. Keep basicauth focused onContextUsernameandContextPasswordonly.Apply this minimal fix:
📝 Committable suggestion
🤖 Prompt for AI Agents