diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e346c420..7c01147e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -5,7 +5,7 @@ ARG DEBIAN_FRONTEND=noninteractive USER root WORKDIR /root ENV HOME="/root" -# TODO: Remove after GitHub issue #113 is done. Also remove build-essential from the apt-get install command below too. +# Need to set CGO_ENABLED=1 to enable race detection in the tests. This is required for the tests to run correctly. ENV CGO_ENABLED=1 RUN apt-get update && apt-get install -y \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40d50374..01488f53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,11 +25,6 @@ jobs: cache: true cache-dependency-path: go.sum - - name: Install C dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential - - name: Build run: make build @@ -48,11 +43,6 @@ jobs: cache: true cache-dependency-path: go.sum - - name: Install C dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential - - name: Run tests run: make test @@ -112,11 +102,6 @@ jobs: cache: true cache-dependency-path: go.sum - - name: Install C dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential - - name: Run go vet run: make vet diff --git a/Dockerfile b/Dockerfile index 96b06b9d..561f9e50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # ------------------- FROM golang:1.26.4-alpine AS builder -RUN apk add --no-cache git ca-certificates build-base +RUN apk add --no-cache git ca-certificates WORKDIR /app @@ -12,7 +12,7 @@ RUN go mod download COPY . ./ -RUN CGO_ENABLED=1 GOOS=linux go build \ +RUN CGO_ENABLED=0 GOOS=linux go build \ -ldflags="-s -w" \ -o server ./cmd/main.go diff --git a/Makefile b/Makefile index 44d946d5..bab9b2b4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ APP_NAME=authula BINARY_PATH=./tmp/$(APP_NAME) MIGRATE_CONFIG?=./config.toml MIGRATE_ARGS?= -MIGRATE_CMD=CGO_ENABLED=1 go run ./cmd/migrate +MIGRATE_CMD=CGO_ENABLED=0 go run ./cmd/migrate OPENAPI_EXPORT_BINARY=./tmp/openapi-export .PHONY: help build build-exe run dev test clean install setup @@ -19,30 +19,31 @@ help: # Display this help screen # Build commands` build: # Build the package (library) @echo "Building $(APP_NAME) package..." - @go build ./... + @CGO_ENABLED=0 go build ./... @echo "Build complete!" build-exe: # Build the binary executable @echo "Building $(APP_NAME) binary..." @mkdir -p ./tmp @rm -rf ./tmp/$(APP_NAME) - @go build -o $(BINARY_PATH) ./cmd/main.go + @CGO_ENABLED=0 go build -o $(BINARY_PATH) ./cmd/main.go @echo "Binary built: $(BINARY_PATH)" run: # Run the application @rm -f ./tmp/$(APP_NAME) - @CGO_ENABLED=1 go run ./cmd/main.go + @CGO_ENABLED=0 go run ./cmd/main.go dev: # Run the application with live reloading using air @rm -f ./tmp/$(APP_NAME) - @CGO_ENABLED=1 ./bin/air --build.cmd "go build -o ./tmp/$(APP_NAME) ./cmd/main.go" --build.entrypoint "./tmp/$(APP_NAME)" + @CGO_ENABLED=0 ./bin/air --build.cmd "go build -o ./tmp/$(APP_NAME) ./cmd/main.go" --build.entrypoint "./tmp/$(APP_NAME)" openapi-export: @echo "Exporting OpenAPI spec..." - @go run ./cmd/openapi/ $(ARGS) + @CGO_ENABLED=0 go run ./cmd/openapi/ $(ARGS) @echo "Done!" # Test commands +# CGO_ENABLED=1 is required by the race detector, not by any dependency of the build. test: # Run all tests @echo "Running tests..." @CGO_ENABLED=1 go test -race -v ./... diff --git a/core/repositories/bun_session_repository_test.go b/core/repositories/bun_session_repository_test.go index 382da6e3..30edd6f3 100644 --- a/core/repositories/bun_session_repository_test.go +++ b/core/repositories/bun_session_repository_test.go @@ -7,16 +7,17 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" "github.com/Authula/authula/models" ) // Helper function to create an in-memory SQLite database for testing func newTestSessionDB(t *testing.T) bun.IDB { - sqldb, err := sql.Open("sqlite3", ":memory:") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) if err != nil { t.Fatalf("failed to create test database: %v", err) } diff --git a/go.mod b/go.mod index d9b0332e..d02e6dad 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( github.com/lestrrat-go/jwx/v3 v3.1.1 github.com/lib/pq v1.12.3 github.com/lmittmann/tint v1.2.0 - github.com/mattn/go-sqlite3 v1.14.44 github.com/redis/go-redis/v9 v9.22.0 github.com/resend/resend-go/v4 v4.3.0 github.com/spf13/cobra v1.10.2 @@ -40,7 +39,7 @@ require ( github.com/wneessen/go-mail v0.8.1 golang.org/x/crypto v0.57.0 golang.org/x/oauth2 v0.37.0 - modernc.org/sqlite v1.51.0 + modernc.org/sqlite v1.58.0 zombiezen.com/go/sqlite v1.4.2 ) @@ -161,7 +160,7 @@ require ( google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - modernc.org/libc v1.72.5 // indirect + modernc.org/libc v1.75.6 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.11.0 // indirect + modernc.org/memory v1.12.1 // indirect ) diff --git a/go.sum b/go.sum index 04d8c1cd..a90aad1c 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo= +github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -222,8 +222,6 @@ github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= -github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8= -github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -460,30 +458,30 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY= -modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= -modernc.org/ccgo/v4 v4.34.2 h1:mxsy2FdrB6+qG3NfXefz1AmWv0ehOSDO4jxgxd7h9yo= -modernc.org/ccgo/v4 v4.34.2/go.mod h1:1L7us56+kAKu04p25EATpmBBvhbcqqZ85ibqWVwVgog= +modernc.org/cc/v4 v4.29.2 h1:h6+9ciCnPKutf4I03CvheAvDLX7+IHlqR6Iy6J+cgd8= +modernc.org/cc/v4 v4.29.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI= +modernc.org/ccgo/v4 v4.35.0 h1:F+TUsmw09QxLzmi3aeYYGxjAXarmZaKgj3mKQHNaA8w= +modernc.org/ccgo/v4 v4.35.0/go.mod h1:qrVGs9S3Sr2Ztcg9ve+kTAYMp5a3YvWjo+SoN06kJ5I= modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc= -modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.5 h1:21ldfPfRYE31Tb7B3mwAK8gy1AxP4+dKjrOQPfqakoc= +modernc.org/gc/v3 v3.1.5/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.72.5 h1:m2OGx9Ser1VvTS4Z9ZJlWs+CBMxutLaTiAWkNz+NB9U= -modernc.org/libc v1.72.5/go.mod h1:np0N7KDJ7eUtMZmOqVZNldrZyG+DHLl2B5pg8Hbar3U= +modernc.org/libc v1.75.6 h1:yKk8qo+Di4gkmvRboK8ocCqH22FiUCR6jRy2OwtCRus= +modernc.org/libc v1.75.6/go.mod h1:bO5o2ztHxBb2rjz0PgdHN0sSMw57CgxGFLZ3Qd/QpVQ= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= -modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/memory v1.12.1 h1:nFMiWrpStgZczNl6XI9GnIk/rWhYIyHGUaR04pGbp9g= +modernc.org/memory v1.12.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg= modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.51.0 h1:aH/MMSoayAIhozZ7uJbVTT9QO/VhzBf0J9tymmmuC/U= -modernc.org/sqlite v1.51.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM= +modernc.org/sqlite v1.58.0 h1:38u40/bwkfM7f0Myhosl+SEMltSDxnGdQf8o6Kjmys0= +modernc.org/sqlite v1.58.0/go.mod h1:rsD2CckafgObKC4DhBlGBf+RiHxkc3hINGt1Xw32tVY= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/bootstrap/database.go b/internal/bootstrap/database.go index f9a933c1..0550158c 100644 --- a/internal/bootstrap/database.go +++ b/internal/bootstrap/database.go @@ -10,7 +10,7 @@ import ( _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" + _ "modernc.org/sqlite" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/mysqldialect" @@ -19,6 +19,7 @@ import ( "github.com/uptrace/bun/extra/bundebug" "github.com/Authula/authula/env" + "github.com/Authula/authula/internal/sqlitedsn" "github.com/Authula/authula/models" ) @@ -65,7 +66,7 @@ func InitDatabase(opts DatabaseOptions, logger models.Logger, logLevel string) ( } } - sqlDB, err = sql.Open("sqlite3", databaseURL) + sqlDB, err = sql.Open("sqlite", sqlitedsn.Build(databaseURL)) if err != nil { return nil, err } diff --git a/internal/sqlitedsn/sqlitedsn.go b/internal/sqlitedsn/sqlitedsn.go new file mode 100644 index 00000000..8452d046 --- /dev/null +++ b/internal/sqlitedsn/sqlitedsn.go @@ -0,0 +1,73 @@ +// Package sqlitedsn builds SQLite connection strings carrying the defaults +// Authula relies on, so that every SQLite connection - application or test - +// behaves the same way. +package sqlitedsn + +import ( + "net/url" + "strings" +) + +// Query parameters understood by the modernc.org/sqlite driver. Each default +// also lists the driver's alias for the same setting so a caller supplied +// alias is not silently duplicated. +const ( + busyTimeoutParam = "_busy_timeout" + busyTimeoutAlias = "_timeout" + timezoneParam = "_timezone" +) + +// The driver applies no busy timeout of its own, so a pooled writer that finds +// the database locked fails immediately with SQLITE_BUSY instead of waiting. +const defaultBusyTimeout = "5000" + +// Timestamps are scanned with time.Parse, which resolves a zero UTC offset to +// the process local zone. Pinning the connection to UTC keeps scanned values +// in the zone they were written in, regardless of where the process runs. +const defaultTimezone = "UTC" + +var defaults = []struct { + param string + alias string + value string +}{ + {param: busyTimeoutParam, alias: busyTimeoutAlias, value: defaultBusyTimeout}, + {param: timezoneParam, value: defaultTimezone}, +} + +// Build turns a SQLite target - a file path, ":memory:", or an existing "file:" +// URI with or without query parameters - into a DSN with Authula's defaults +// applied. Parameters already present in the target are left untouched, so a +// caller can always override a default. +func Build(target string) string { + base, query, _ := strings.Cut(target, "?") + + params, err := url.ParseQuery(query) + if err != nil { + // An unparsable query is the caller's to fix; rewriting it here would + // only obscure the driver's error. + return target + } + + for _, d := range defaults { + if params.Has(d.param) || (d.alias != "" && params.Has(d.alias)) { + continue + } + params.Set(d.param, d.value) + } + + return uri(base) + "?" + params.Encode() +} + +// uri renders base as a SQLite "file:" URI. Only the characters that would +// otherwise terminate or misdelimit the path need escaping; escaping the rest +// would break URIs such as "file::memory:". +func uri(base string) string { + if strings.HasPrefix(base, "file:") { + return base + } + + replacer := strings.NewReplacer("%", "%25", "#", "%23") + + return "file:" + replacer.Replace(base) +} diff --git a/internal/sqlitedsn/sqlitedsn_test.go b/internal/sqlitedsn/sqlitedsn_test.go new file mode 100644 index 00000000..78edbd29 --- /dev/null +++ b/internal/sqlitedsn/sqlitedsn_test.go @@ -0,0 +1,96 @@ +package sqlitedsn_test + +import ( + "net/url" + "strings" + "testing" + + "github.com/Authula/authula/internal/sqlitedsn" +) + +func TestBuild(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + target string + wantBase string + wantParams map[string]string + }{ + { + name: "in memory target", + target: ":memory:", + wantBase: "file::memory:", + wantParams: map[string]string{"_busy_timeout": "5000", "_timezone": "UTC"}, + }, + { + name: "relative file path", + target: "./data/authula.db", + wantBase: "file:./data/authula.db", + wantParams: map[string]string{"_busy_timeout": "5000", "_timezone": "UTC"}, + }, + { + name: "existing file uri keeps its parameters", + target: "file:shared.db?mode=memory&cache=shared", + wantBase: "file:shared.db", + wantParams: map[string]string{"mode": "memory", "cache": "shared", "_busy_timeout": "5000", "_timezone": "UTC"}, + }, + { + name: "caller parameters win over defaults", + target: "file:authula.db?_busy_timeout=250&_timezone=Local", + wantBase: "file:authula.db", + wantParams: map[string]string{"_busy_timeout": "250", "_timezone": "Local"}, + }, + { + name: "driver alias suppresses the default it duplicates", + target: "file:authula.db?_timeout=250", + wantBase: "file:authula.db", + wantParams: map[string]string{"_timeout": "250", "_timezone": "UTC"}, + }, + { + name: "path delimiters are escaped", + target: "./data/rate#1.db", + wantBase: "file:./data/rate%231.db", + wantParams: map[string]string{"_busy_timeout": "5000", "_timezone": "UTC"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got := sqlitedsn.Build(tc.target) + + base, query, found := strings.Cut(got, "?") + if !found { + t.Fatalf("expected query parameters in %q", got) + } + if base != tc.wantBase { + t.Fatalf("expected base %q, got %q", tc.wantBase, base) + } + + params, err := url.ParseQuery(query) + if err != nil { + t.Fatalf("unexpected error parsing %q: %v", query, err) + } + if len(params) != len(tc.wantParams) { + t.Fatalf("expected %d parameters, got %d in %q", len(tc.wantParams), len(params), query) + } + for key, want := range tc.wantParams { + if got := params.Get(key); got != want { + t.Fatalf("expected %s=%q, got %q", key, want, got) + } + } + }) + } +} + +func TestBuildLeavesUnparsableQueryUntouched(t *testing.T) { + t.Parallel() + + target := "file:authula.db?%zz" + + if got := sqlitedsn.Build(target); got != target { + t.Fatalf("expected %q to be returned unchanged, got %q", target, got) + } +} diff --git a/internal/tests/db_helpers.go b/internal/tests/db_helpers.go index 29ce62e5..0a8e5f94 100644 --- a/internal/tests/db_helpers.go +++ b/internal/tests/db_helpers.go @@ -11,7 +11,6 @@ import ( _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" "github.com/testcontainers/testcontainers-go" tcmysql "github.com/testcontainers/testcontainers-go/modules/mysql" tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres" @@ -20,6 +19,8 @@ import ( "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/dialect/sqlitedialect" _ "modernc.org/sqlite" + + "github.com/Authula/authula/internal/sqlitedsn" ) func NewSQLiteIntegrationDB(t *testing.T) *bun.DB { @@ -134,14 +135,7 @@ func NewIntegrationTestDBFromEnv(t *testing.T) (*bun.DB, string) { } func openSQLiteForTests(dsn string) (*sql.DB, error) { - if sqlite3DB, err := sql.Open("sqlite3", dsn); err == nil { - if pingErr := sqlite3DB.PingContext(context.Background()); pingErr == nil { - return sqlite3DB, nil - } - _ = sqlite3DB.Close() - } - - sqliteDB, err := sql.Open("sqlite", dsn) + sqliteDB, err := sql.Open("sqlite", sqlitedsn.Build(dsn)) if err != nil { return nil, err } diff --git a/migrations/migrator_test.go b/migrations/migrator_test.go index 582bf289..fe15fb63 100644 --- a/migrations/migrator_test.go +++ b/migrations/migrator_test.go @@ -10,8 +10,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" - _ "github.com/mattn/go-sqlite3" + "github.com/Authula/authula/internal/sqlitedsn" ) type testLogger struct { @@ -27,7 +28,7 @@ func newTestDB(t *testing.T) *bun.DB { t.Helper() dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", strings.ReplaceAll(t.Name(), "/", "_")) - sqlDB, err := sql.Open("sqlite3", dsn) + sqlDB, err := sql.Open("sqlite", sqlitedsn.Build(dsn)) assert.NoError(t, err) t.Cleanup(func() { _ = sqlDB.Close() diff --git a/plugins/access-control/tests/test_helpers.go b/plugins/access-control/tests/test_helpers.go index 8bf90269..bf1e4e54 100644 --- a/plugins/access-control/tests/test_helpers.go +++ b/plugins/access-control/tests/test_helpers.go @@ -6,11 +6,12 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/mock" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" internaltests "github.com/Authula/authula/internal/tests" "github.com/Authula/authula/migrations" "github.com/Authula/authula/models" @@ -188,7 +189,7 @@ func (m *MockUserPermissionsRepository) HasPermissions(ctx context.Context, user func SetupRepoDB(t *testing.T) *bun.DB { t.Helper() - sqldb, err := sql.Open("sqlite3", ":memory:") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) if err != nil { t.Fatalf("failed to open sqlite: %v", err) } diff --git a/plugins/admin/repositories/user_state_repository_test.go b/plugins/admin/repositories/user_state_repository_test.go index 55592d8d..ceaf4c6c 100644 --- a/plugins/admin/repositories/user_state_repository_test.go +++ b/plugins/admin/repositories/user_state_repository_test.go @@ -5,17 +5,18 @@ import ( "database/sql" "testing" - _ "github.com/mattn/go-sqlite3" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" "github.com/Authula/authula/plugins/admin/repositories" "github.com/Authula/authula/plugins/admin/types" ) func setupRepo(t *testing.T) (*repositories.BunUserStateRepository, func()) { t.Helper() - sqldb, err := sql.Open("sqlite3", ":memory:") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) if err != nil { t.Fatalf("failed to open sqlite: %v", err) } diff --git a/plugins/api-key/repositories/bun_api_key_repository_test.go b/plugins/api-key/repositories/bun_api_key_repository_test.go index b65f385c..1c9a30f9 100644 --- a/plugins/api-key/repositories/bun_api_key_repository_test.go +++ b/plugins/api-key/repositories/bun_api_key_repository_test.go @@ -8,10 +8,11 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" "github.com/Authula/authula/plugins/api-key/types" ) @@ -19,7 +20,7 @@ func newTestApiKeyDB(t *testing.T) *bun.DB { t.Helper() dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", strings.ReplaceAll(t.Name(), "/", "_")) - sqlDB, err := sql.Open("sqlite3", dsn) + sqlDB, err := sql.Open("sqlite", sqlitedsn.Build(dsn)) if err != nil { t.Fatalf("failed to open sqlite db: %v", err) } diff --git a/plugins/organizations/tests/repositories.go b/plugins/organizations/tests/repositories.go index 3af4d825..733d30da 100644 --- a/plugins/organizations/tests/repositories.go +++ b/plugins/organizations/tests/repositories.go @@ -4,9 +4,9 @@ import ( "context" "reflect" - _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/mock" "github.com/uptrace/bun" + _ "modernc.org/sqlite" "github.com/Authula/authula/plugins/organizations/repositories" "github.com/Authula/authula/plugins/organizations/types" diff --git a/plugins/organizations/tests/test_helpers.go b/plugins/organizations/tests/test_helpers.go index 35d29577..8e6ce197 100644 --- a/plugins/organizations/tests/test_helpers.go +++ b/plugins/organizations/tests/test_helpers.go @@ -7,11 +7,12 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" internaltests "github.com/Authula/authula/internal/tests" "github.com/Authula/authula/migrations" "github.com/Authula/authula/models" @@ -25,7 +26,7 @@ func Actor(userID string) *models.Actor { func SetupRepoDB(t *testing.T) *bun.DB { t.Helper() - sqlDB, err := sql.Open("sqlite3", ":memory:") + sqlDB, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) require.NoError(t, err) sqlDB.SetMaxOpenConns(1) t.Cleanup(func() { _ = sqlDB.Close() }) diff --git a/plugins/secondary-storage/database_secondary_storage_test.go b/plugins/secondary-storage/database_secondary_storage_test.go index b7b50074..b3a3624c 100644 --- a/plugins/secondary-storage/database_secondary_storage_test.go +++ b/plugins/secondary-storage/database_secondary_storage_test.go @@ -8,14 +8,16 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + + "github.com/Authula/authula/internal/sqlitedsn" ) // Helper function to create an in-memory SQLite database for testing func newTestDB(t *testing.T) bun.IDB { - sqldb, err := sql.Open("sqlite3", ":memory:") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) if err != nil { t.Fatalf("failed to create test database: %v", err) } @@ -403,7 +405,7 @@ func TestDatabaseStorage_MultipleKeys(t *testing.T) { func TestDatabaseStorage_ConcurrentReads(t *testing.T) { // Use file-based SQLite for concurrent tests as :memory: doesn't handle concurrency well - sqldb, err := sql.Open("sqlite3", "file::memory:?cache=shared") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build("file::memory:?cache=shared")) if err != nil { t.Fatalf("failed to create test database: %v", err) } @@ -696,7 +698,7 @@ func TestDatabaseStorage_DifferentValueTypes(t *testing.T) { func TestDatabaseStorage_PersistenceAcrossInstances(t *testing.T) { // Create a persistent DB (not in-memory) - sqldb, err := sql.Open("sqlite3", ":memory:") + sqldb, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) if err != nil { t.Fatalf("failed to create test database: %v", err) } diff --git a/plugins/totp/plugin_test.go b/plugins/totp/plugin_test.go index 4187987a..f6f02750 100644 --- a/plugins/totp/plugin_test.go +++ b/plugins/totp/plugin_test.go @@ -8,13 +8,14 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" "github.com/Authula/authula/internal/tests" "github.com/Authula/authula/migrations" "github.com/Authula/authula/models" @@ -76,7 +77,7 @@ func buildTestPlugin(t *testing.T) (*TOTPPlugin, *tests.MockUserService, *tests. func newHookTestDB(t *testing.T) *bun.DB { t.Helper() - sqlDB, err := sql.Open("sqlite3", ":memory:") + sqlDB, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) require.NoError(t, err) t.Cleanup(func() { _ = sqlDB.Close() }) diff --git a/plugins/totp/repository/totp_repository_test.go b/plugins/totp/repository/totp_repository_test.go index 28a99cfb..0a08a6e1 100644 --- a/plugins/totp/repository/totp_repository_test.go +++ b/plugins/totp/repository/totp_repository_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" + "github.com/Authula/authula/internal/sqlitedsn" internaltests "github.com/Authula/authula/internal/tests" "github.com/Authula/authula/migrations" totpplugin "github.com/Authula/authula/plugins/totp" @@ -21,7 +22,7 @@ import ( func newTestTOTPDB(t *testing.T) *bun.DB { t.Helper() - sqlDB, err := sql.Open("sqlite3", ":memory:") + sqlDB, err := sql.Open("sqlite", sqlitedsn.Build(":memory:")) require.NoError(t, err) t.Cleanup(func() { _ = sqlDB.Close() })