Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions cmd/internal/migrations/v3/basicauth_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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*})`)

Comment on lines +17 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Scope leak: basicauth migration must not remove ContextKey (belongs to other middlewares).

Including ContextKey here risks deleting fields in unrelated configs (e.g., csrf/keyauth/session) when only running the basicauth migration. Keep basicauth focused on ContextUsername and ContextPassword only.

Apply this minimal fix:

- // 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`)
+ // Remove ContextUsername/ContextPassword when they are on their own line (with optional trailing comment).
+ reCtxKeyLine := regexp.MustCompile(`(?m)^\s*Context(?:Username|Password):\s*[^,\n}]+,?\s*(//[^\n]*)?\n`)
- reCtxKeyInline := regexp.MustCompile(`(?m)\s*Context(?:Username|Password|Key):\s*[^,\n}]+(?:,\s*)?(?://[^\n]*)?(\s*})`)
+ reCtxKeyInline := regexp.MustCompile(`(?m)\s*Context(?:Username|Password):\s*[^,\n}]+(?:,\s*)?(?://[^\n]*)?(\s*})`)
📝 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
// 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*})`)
// Remove ContextUsername/ContextPassword when they are on their own line (with optional trailing comment).
reCtxKeyLine := regexp.MustCompile(`(?m)^\s*Context(?:Username|Password):\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):\s*[^,\n}]+(?:,\s*)?(?://[^\n]*)?(\s*})`)
🤖 Prompt for AI Agents
In cmd/internal/migrations/v3/basicauth_config.go around lines 17 to 24, the
current regexes also match ContextKey which can remove unrelated config fields;
update both patterns to only target ContextUsername and ContextPassword so the
basicauth migration does not delete ContextKey from other middlewares.
Specifically, remove `Key` from the alternation in both reCtxKeyLine and
reCtxKeyInline so they only use `(?:Username|Password)`, and keep the rest of
the regex behavior (optional trailing comma/comment and capture of the closing
brace) unchanged.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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., Config{Foo:1, ContextUsername:"u", Bar:2}) unless another pass happens to move it to tail. Also, patterns aren’t scoped to basicauth.Config{...} blocks, so similar field names in other structs could be touched.

Refactor to operate only within basicauth.Config{...} literals and remove fields using the common parser (removeConfigField) which already handles comments and nested values.

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

‼️ 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
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:]
}
🤖 Prompt for AI Agents
In cmd/internal/migrations/v3/basicauth_config.go around lines 29 to 36, the
current regex-only loop that strips inline ContextKey/ContextUsername fields can
miss mid-list fields and accidentally touch non-basicauth structs; change the
logic to find only basicauth.Config{...} composite literals and within each
literal call the existing removeConfigField parser helper for the ContextKey and
ContextUsername fields so removals respect comments, nested values and ordering;
ensure you iterate each matched basicauth.Config block and replace its content
with the removeConfigField result rather than using global regex replacements.


content = reUsers.ReplaceAllStringFunc(content, func(m string) string {
sub := reUsers.FindStringSubmatch(m)
Expand Down
60 changes: 60 additions & 0 deletions cmd/internal/migrations/v3/basicauth_config_test.go
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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 ContextKey in removal, add a safety test to ensure basicauth migration leaves other middlewares intact.

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

‼️ 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 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")
}
// Add this new test to cmd/internal/migrations/v3/basicauth_config_test.go
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"}`)
}
🤖 Prompt for AI Agents
In cmd/internal/migrations/v3/basicauth_config_test.go around lines 40 to 60,
add a safety subtest that creates a separate temp source file containing a
different middleware config that uses ContextKey (e.g., another middleware
package), run v3.MigrateBasicauthConfig against the directory, then read that
file and assert it still contains "ContextKey" (and other original identifiers)
to ensure the basicauth migration doesn't remove or alter ContextKey in
non-basicauth configs; implement using the same temp dir helpers, run migration
once, and add asserts that the unrelated file remains unchanged.

109 changes: 85 additions & 24 deletions cmd/internal/migrations/v3/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: removeConfigField can match inside comments/strings and corrupt code.

Because the regex isn’t constrained to code context, field: inside strings or comments can be “removed,” slicing arbitrary text. This is high-risk for false positives across the repo.

Adopt a context-aware finder that ignores strings and comments and returns the index right after field:\s* (mirrors old loc[1]), then reuse the existing removal logic.

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
In cmd/internal/migrations/v3/common.go around lines 62-71 (and similarly for
93-147), remove the current regex-based loop because it can match inside
strings/comments and corrupt code; add the provided
findFieldIndexOutsideLiterals(src, field, from) function to this file (outside
the current range) which scans while ignoring string literals and both
line/block comments and returns the start index of the field and the index
immediately after the trailing colon+whitespace; then replace the regex
FindStringIndex usage with calls to findFieldIndexOutsideLiterals to get start
and k (end) and reuse the existing depth-based removal logic exactly as before,
using the returned indices to perform the slice removals.

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
Expand All @@ -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++
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/internal/migrations/v3/config_listener_fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ func MigrateConfigListenerFields(cmd *cobra.Command, cwd string, _, _ *semver.Ve
var disableStartup string
var enablePrint string

reField := regexp.MustCompile(`\s*(Prefork|Network|DisableStartupMessage|EnablePrintRoutes):\s*([^,}]+),?`)
reField := regexp.MustCompile(`\s*(Prefork|Network|DisableStartupMessage|EnablePrintRoutes):\s*([^,}]+),?\s*(//[^\n]*)?`)
Comment thread
ReneWerner87 marked this conversation as resolved.
changed1, err := internal.ChangeFileContent(cwd, func(content string) string {
reConfig := regexp.MustCompile(`fiber\.Config\{[^}]*\}`)
return reConfig.ReplaceAllStringFunc(content, func(cfg string) string {
inner := cfg[len("fiber.Config{") : len(cfg)-1]
inner = reField.ReplaceAllStringFunc(inner, func(f string) string {
sub := reField.FindStringSubmatch(f)
if len(sub) == 3 {
if len(sub) >= 3 {
name := sub[1]
val := strings.TrimSpace(sub[2])
switch name {
Expand Down
28 changes: 28 additions & 0 deletions cmd/internal/migrations/v3/config_listener_fields_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,31 @@ func main() {
assert.Contains(t, content, `go app.Listen(":3000", fiber.ListenConfig{DisableStartupMessage: true})`)
assert.Contains(t, buf.String(), "Migrating listener related config fields")
}

func Test_MigrateConfigListenerFields_WithComment(t *testing.T) {
t.Parallel()

dir, err := os.MkdirTemp("", "mconf_comment")
require.NoError(t, err)
defer func() { require.NoError(t, os.RemoveAll(dir)) }()

file := writeTempFile(t, dir, `package main
import "github.com/gofiber/fiber/v2"
var prod bool
func main() {
app := fiber.New(fiber.Config{
Prefork: prod, // comment
})
app.Listen(":3000")
}`)

var buf bytes.Buffer
cmd := newCmd(&buf)
require.NoError(t, v3.MigrateConfigListenerFields(cmd, dir, nil, nil))

content := readFile(t, file)
assert.Contains(t, content, "fiber.New(fiber.Config{})")
assert.NotContains(t, content, "// comment")
assert.Contains(t, content, `app.Listen(":3000", fiber.ListenConfig{EnablePrefork: prod})`)
assert.Contains(t, buf.String(), "Migrating listener related config fields")
}
2 changes: 1 addition & 1 deletion cmd/internal/migrations/v3/csrfconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

func MigrateCSRFConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reConfig := regexp.MustCompile(`csrf\.Config{`)
reSession := regexp.MustCompile(`(?m)\s*SessionKey:\s*[^,]+,?\n`)
reSession := regexp.MustCompile(`(?m)\s*SessionKey:\s*[^,\n]+,?\s*(//[^\n]*)?\n`)
changed, err := internal.ChangeFileContent(cwd, func(content string) string {
matches := reConfig.FindAllStringIndex(content, -1)
if len(matches) == 0 {
Expand Down
25 changes: 25 additions & 0 deletions cmd/internal/migrations/v3/csrfconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ var _ = csrf.New(csrf.Config{
assert.Contains(t, buf.String(), "Migrating CSRF middleware configs")
}

func Test_MigrateCSRFConfig_SessionKeyWithComment(t *testing.T) {
t.Parallel()

dir, err := os.MkdirTemp("", "mcsrfskc")
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/csrf"
)
var _ = csrf.New(csrf.Config{
SessionKey: "csrf", // session comment
})`)

var buf bytes.Buffer
cmd := newCmd(&buf)
require.NoError(t, v3.MigrateCSRFConfig(cmd, dir, nil, nil))

content := readFile(t, file)
assert.NotContains(t, content, "SessionKey")
assert.NotContains(t, content, "session comment")
assert.Contains(t, buf.String(), "Migrating CSRF middleware configs")
}

func Test_MigrateCSRFConfig_KeyLookup(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 2 additions & 2 deletions cmd/internal/migrations/v3/healthcheck_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ func MigrateHealthcheckConfig(cmd *cobra.Command, cwd string, _, _ *semver.Versi
body = bodyMatch[1]
}

reLE := regexp.MustCompile(`(?m)\s*LivenessEndpoint:\s*([^,\n}]+),?`)
reLE := regexp.MustCompile(`(?m)\s*LivenessEndpoint:\s*([^,\n}]+),?\s*(//[^\n]*)?\n?`)
if m := reLE.FindStringSubmatch(body); len(m) > 1 {
lEndpoint = strings.TrimSpace(m[1])
}
body = reLE.ReplaceAllString(body, "")

reRE := regexp.MustCompile(`(?m)\s*ReadinessEndpoint:\s*([^,\n}]+),?`)
reRE := regexp.MustCompile(`(?m)\s*ReadinessEndpoint:\s*([^,\n}]+),?\s*(//[^\n]*)?\n?`)
if m := reRE.FindStringSubmatch(body); len(m) > 1 {
rEndpoint = strings.TrimSpace(m[1])
}
Expand Down
31 changes: 31 additions & 0 deletions cmd/internal/migrations/v3/healthcheck_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,34 @@ var cfg = healthcheck.Config{
assert.NotContains(t, content, "ReadinessEndpoint")
assert.Contains(t, buf.String(), "Migrating healthcheck middleware configs")
}

func Test_MigrateHealthcheckConfig_WithComments(t *testing.T) {
t.Parallel()

dir, err := os.MkdirTemp("", "mhealthc")
require.NoError(t, err)
defer func() { require.NoError(t, os.RemoveAll(dir)) }()

file := writeTempFile(t, dir, `package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/healthcheck"
)
func main() {
app := fiber.New()
app.Use(healthcheck.New(healthcheck.Config{
LivenessEndpoint: "/live", // live comment
ReadinessEndpoint: "/ready", // ready comment
}))
}`)

var buf bytes.Buffer
cmd := newCmd(&buf)
require.NoError(t, v3.MigrateHealthcheckConfig(cmd, dir, nil, nil))

content := readFile(t, file)
assert.Contains(t, content, `app.Get("/live"`)
assert.Contains(t, content, `app.Get("/ready"`)
assert.NotContains(t, content, "live comment")
assert.NotContains(t, content, "ready comment")
}
5 changes: 3 additions & 2 deletions cmd/internal/migrations/v3/middleware_locals.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ func MigrateMiddlewareLocals(cmd *cobra.Command, cwd string, _, _ *semver.Versio
reComma := regexp.MustCompile(`(\w+)\s*,\s*(\w+)\s*:=\s*([\w\.]+FromContext\([^\)]+\))`)
content = reComma.ReplaceAllString(content, "$1, $2 := $3, true")

reCtxKey := regexp.MustCompile(`\s*Context(?:Username|Password|Key):\s*[^,}\n]+,?`)
content = reCtxKey.ReplaceAllString(content, "")
content = removeConfigField(content, "ContextKey")
content = removeConfigField(content, "ContextUsername")
content = removeConfigField(content, "ContextPassword")

return content
})
Expand Down
Loading
Loading