Skip to content

Commit 98236a7

Browse files
arpitjain099jkjell
authored andcommitted
Parse the MySQL address with net.SplitHostPort
ConfigFromMySQL split dbConfig.Addr on ":" and indexed element 1. go-sql-driver's ParseDSN only fills in a default port when Net is "tcp", so a unix socket DSN leaves Addr as a bare socket path with no colon: user:pass@unix(/tmp/mysql.sock)/testify panic: runtime error: index out of range [1] with length 1 NewEntClient and RewriteConnectionStringForIAM both call this with the configured connection string, so the server binary crashed at startup instead of reporting a bad configuration. The same split mis-handled a bracketed IPv6 host, leaving Host as "[" and failing with an empty-port Atoi error. net.SplitHostPort handles both, and a non-tcp network is now an explicit error naming what is supported. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
1 parent e7211a0 commit 98236a7

2 files changed

Lines changed: 69 additions & 3 deletions

File tree

pkg/metadatastorage/sqlstore/utils.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package sqlstore
1717
import (
1818
"context"
1919
"fmt"
20+
"net"
2021
"strconv"
2122
"strings"
2223

@@ -69,9 +70,18 @@ func ConfigFromMySQL(connectionString string) (c *driver.Config, user, password
6970
return nil, "", "", fmt.Errorf("parsing connection string: %w", err)
7071
}
7172

72-
addr := strings.Split(dbConfig.Addr, ":")
73-
dc.Host = addr[0]
74-
port, err := strconv.Atoi(addr[1])
73+
// ParseDSN only fills in a default port for tcp, so a unix socket DSN leaves
74+
// Addr as a bare path with no colon. Splitting on ":" and indexing element 1
75+
// panicked on that, and mis-parsed a bracketed IPv6 host.
76+
if dbConfig.Net != "tcp" {
77+
return nil, "", "", fmt.Errorf("unsupported mysql network %q: only tcp is supported", dbConfig.Net)
78+
}
79+
host, portStr, err := net.SplitHostPort(dbConfig.Addr)
80+
if err != nil {
81+
return nil, "", "", fmt.Errorf("could not parse mysql address %q: %w", dbConfig.Addr, err)
82+
}
83+
dc.Host = host
84+
port, err := strconv.Atoi(portStr)
7585
if err != nil {
7686
return nil, "", "", fmt.Errorf("could not parse mysql port: %w", err)
7787
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2025 The Archivista Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sqlstore
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
func TestConfigFromMySQL(t *testing.T) {
25+
t.Run("tcp host and port", func(t *testing.T) {
26+
c, user, password, err := ConfigFromMySQL("user:pass@tcp(127.0.0.1:3306)/testify")
27+
require.NoError(t, err)
28+
assert.Equal(t, "127.0.0.1", c.Host)
29+
assert.Equal(t, 3306, c.Port)
30+
assert.Equal(t, "testify", c.DB)
31+
assert.Equal(t, "user", user)
32+
assert.Equal(t, "pass", password)
33+
})
34+
35+
t.Run("bracketed IPv6 host", func(t *testing.T) {
36+
// Splitting on ":" left Host as "[" and the port empty.
37+
c, _, _, err := ConfigFromMySQL("user:pass@tcp([::1]:3306)/testify")
38+
require.NoError(t, err)
39+
assert.Equal(t, "::1", c.Host)
40+
assert.Equal(t, 3306, c.Port)
41+
})
42+
43+
t.Run("unix socket is rejected, not a panic", func(t *testing.T) {
44+
// ParseDSN only defaults a port for tcp, so Addr here is a bare path
45+
// with no colon at all.
46+
_, _, _, err := ConfigFromMySQL("user:pass@unix(/tmp/mysql.sock)/testify")
47+
require.Error(t, err)
48+
assert.Contains(t, err.Error(), "only tcp is supported")
49+
})
50+
51+
t.Run("unparseable dsn", func(t *testing.T) {
52+
_, _, _, err := ConfigFromMySQL("not a dsn")
53+
require.Error(t, err)
54+
assert.Contains(t, err.Error(), "parsing connection string")
55+
})
56+
}

0 commit comments

Comments
 (0)