diff --git a/.goreleaser.yml b/.goreleaser.yml index 22f702c33..a9d6e42a2 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -10,7 +10,7 @@ builds: - id: litestream main: ./cmd/litestream binary: litestream - # The fork's mattn/go-sqlite3 driver builds SQLCipher (CGO, links + # The 0xCarbon/go-sqlite3 fork builds SQLCipher (CGO, links # libcrypto); pure-Go builds are no longer possible. Windows, macOS, and # 32-bit ARM targets are dropped until cross-CGO toolchains with libcrypto # are wired up; fork consumers are Linux. diff --git a/AGENTS.md b/AGENTS.md index 901c2e061..d4fceb500 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md - Litestream AI Agent Guide -Litestream is a disaster recovery tool for SQLite that runs as a background process, monitors the WAL, converts changes to immutable LTX files, and replicates them to cloud storage. This fork uses `mattn/go-sqlite3` (via the 0xCarbon fork with bundled SQLCipher) — CGO is required and libcrypto is linked. +Litestream is a disaster recovery tool for SQLite that runs as a background process, monitors the WAL, converts changes to immutable LTX files, and replicates them to cloud storage. This fork uses `github.com/0xCarbon/go-sqlite3` (the mattn-lineage fork with bundled SQLCipher) — CGO is required and libcrypto is linked. ## Before You Start @@ -76,22 +76,24 @@ Before submitting changes: This fork tracks upstream `benbjohnson/litestream` and adds: -- **Driver**: per-database `mattn/go-sqlite3` driver instances (registered as - `litestream-sqlite3-`), each carrying its database's SQLCipher key; - see `registerSQLiteDriver` in `litestream.go`. +- **Driver**: per-database `github.com/0xCarbon/go-sqlite3` driver instances + (private `sql.OpenDB` connectors, see `newSQLiteDriver`/`newSQLitePool` in + `litestream.go`), each carrying its database's SQLCipher key. - **Encryption**: `DB.EncryptionKey` (string: bare `x'…'` raw-key blob is auto-quoted; quoted literals `'passphrase'`/`"x'…'"` pass through) and - `DB.EncryptionKeyBytes` (raw bytes; takes precedence). Keys are applied as - the first statement of every pooled connection; set before Open. + `DB.EncryptionKeyBytes` (raw bytes; takes precedence; must be exactly 32, + 48, or 80 bytes — other lengths are rejected at the first connection). + Keys are applied as the first statement of every pooled connection; set + before Open. - **VFS**: `VFS.SkipJournalPatch` / `VFSFile.SkipJournalPatch` disable the page-1 journal-mode emulation patch, required for SQLCipher databases (plaintext bytes 18-19/24-28 must not be rewritten on ciphertext pages). -- **Mandatory consumer replace**: Go ignores this module's `replace` - directives when litestream is imported as a dependency. Every consuming - module MUST carry its own replace or the build fails with - `EncryptionKey`/`EncryptionKeyBytes` undefined on the upstream driver: - - replace github.com/mattn/go-sqlite3 => github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260515201505-c8f057756220 +- **Driver dependency**: litestream requires the 0xCarbon SQLCipher fork + directly (`github.com/0xCarbon/go-sqlite3`) — no `replace` directive is + needed or used. Consumers must use the same module path for their own + direct sqlite use: importing both `github.com/mattn/go-sqlite3` and + `github.com/0xCarbon/go-sqlite3` in one binary registers the "sqlite3" + driver twice and panics at init. - **Pin policy**: consumer modules pin this fork via the `pin/` branches (e.g. `pin/7a606e384ee9`); never force-push or delete them. @@ -102,7 +104,7 @@ This fork tracks upstream `benbjohnson/litestream` and adds: stock runners do not provide; fork consumers are Linux. - **Durability**: litestream's own connections run `synchronous=FULL` (DSN `_sync=FULL`), matching upstream's modernc default. Consumer connections - through the mattn fork default to `synchronous=NORMAL` — pass `_sync=FULL` + through the 0xCarbon fork (mattn-lineage) default to `synchronous=NORMAL` — pass `_sync=FULL` in your DSN if you need the stricter behavior. - **CLI**: the `litestream` binary is encryption-blind — there is no key configuration; SQLCipher is a library-only feature via `DB.EncryptionKey` diff --git a/_examples/library/basic/main.go b/_examples/library/basic/main.go index eb456ca1b..51525c94d 100644 --- a/_examples/library/basic/main.go +++ b/_examples/library/basic/main.go @@ -16,7 +16,7 @@ import ( "syscall" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" "github.com/benbjohnson/litestream/file" diff --git a/_examples/library/library_example_test.go b/_examples/library/library_example_test.go index de2c6826a..7cba4430d 100644 --- a/_examples/library/library_example_test.go +++ b/_examples/library/library_example_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" "github.com/benbjohnson/litestream/file" diff --git a/_examples/library/s3/main.go b/_examples/library/s3/main.go index 731daa16f..a6e17abc5 100644 --- a/_examples/library/s3/main.go +++ b/_examples/library/s3/main.go @@ -27,7 +27,7 @@ import ( "syscall" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" "github.com/benbjohnson/litestream/s3" diff --git a/cmd/litestream-test/load.go b/cmd/litestream-test/load.go index 7426d9c44..9847ebda9 100644 --- a/cmd/litestream-test/load.go +++ b/cmd/litestream-test/load.go @@ -15,7 +15,7 @@ import ( "syscall" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) type LoadCommand struct { diff --git a/cmd/litestream-test/populate.go b/cmd/litestream-test/populate.go index 483e52bf9..4ffcde06e 100644 --- a/cmd/litestream-test/populate.go +++ b/cmd/litestream-test/populate.go @@ -11,7 +11,7 @@ import ( "os" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) type PopulateCommand struct { diff --git a/cmd/litestream-test/shrink.go b/cmd/litestream-test/shrink.go index ddd2b224e..f0ab3e763 100644 --- a/cmd/litestream-test/shrink.go +++ b/cmd/litestream-test/shrink.go @@ -9,7 +9,7 @@ import ( "os" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) type ShrinkCommand struct { diff --git a/cmd/litestream-test/validate.go b/cmd/litestream-test/validate.go index da46ca072..cea420ff1 100644 --- a/cmd/litestream-test/validate.go +++ b/cmd/litestream-test/validate.go @@ -13,7 +13,7 @@ import ( "strings" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) type ValidateCommand struct { diff --git a/cmd/litestream-vfs/main_test.go b/cmd/litestream-vfs/main_test.go index 65492f116..21a17d688 100644 --- a/cmd/litestream-vfs/main_test.go +++ b/cmd/litestream-vfs/main_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - sqlite3 "github.com/mattn/go-sqlite3" + sqlite3 "github.com/0xCarbon/go-sqlite3" "github.com/psanford/sqlite3vfs" "github.com/stretchr/testify/require" diff --git a/cmd/litestream-vfs/time_travel_test.go b/cmd/litestream-vfs/time_travel_test.go index ed2dd6c63..971b9b2fe 100644 --- a/cmd/litestream-vfs/time_travel_test.go +++ b/cmd/litestream-vfs/time_travel_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/psanford/sqlite3vfs" "github.com/stretchr/testify/require" diff --git a/cmd/litestream-vfs/vfs_soak_test.go b/cmd/litestream-vfs/vfs_soak_test.go index 79767d461..eb11b9e79 100644 --- a/cmd/litestream-vfs/vfs_soak_test.go +++ b/cmd/litestream-vfs/vfs_soak_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream/file" "github.com/benbjohnson/litestream/internal/testingutil" diff --git a/cmd/litestream/main.go b/cmd/litestream/main.go index 275c26634..0ba09704c 100644 --- a/cmd/litestream/main.go +++ b/cmd/litestream/main.go @@ -18,8 +18,8 @@ import ( "strings" "time" + _ "github.com/0xCarbon/go-sqlite3" "github.com/dustin/go-humanize" - _ "github.com/mattn/go-sqlite3" "github.com/superfly/ltx" _ "golang.org/x/crypto/x509roots/fallback" "gopkg.in/yaml.v2" diff --git a/db.go b/db.go index c449b219c..5c174fdae 100644 --- a/db.go +++ b/db.go @@ -19,7 +19,7 @@ import ( "syscall" "time" - "github.com/mattn/go-sqlite3" + "github.com/0xCarbon/go-sqlite3" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/superfly/ltx" @@ -198,8 +198,11 @@ type DB struct { EncryptionKey string // EncryptionKeyBytes is the raw SQLCipher key for this database. When - // non-empty it takes precedence over EncryptionKey. Applied to every - // connection of this DB's registered driver. + // non-empty it takes precedence over EncryptionKey. Must be exactly 32, + // 48, or 80 bytes (SQLCipher raw-key forms: key / key+salt / + // key+HMAC+salt); other lengths are rejected at the first connection by + // the 0xCarbon fork. Applied to every connection of this DB's driver; + // set before Open. EncryptionKeyBytes []byte // sqliteDriver is this DB's own driver instance, carrying its SQLCipher @@ -1037,7 +1040,7 @@ func (db *DB) init(ctx context.Context) (err error) { dsn := db.path // _sync=FULL restores the durability litestream had with modernc: the - // mattn driver defaults every connection to synchronous=NORMAL, which + // go-sqlite3 fork defaults every connection to synchronous=NORMAL, which // can lose the newest commits on power loss in WAL mode. dsn += fmt.Sprintf("?_busy_timeout=%d&_sync=FULL", db.BusyTimeout.Milliseconds()) diff --git a/db_internal_test.go b/db_internal_test.go index 533367a68..8e0c8cb10 100644 --- a/db_internal_test.go +++ b/db_internal_test.go @@ -22,7 +22,7 @@ import ( "github.com/superfly/ltx" "golang.org/x/sync/semaphore" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream/internal" ) @@ -4689,3 +4689,39 @@ func TestDB_InitSetsSyncFull(t *testing.T) { t.Fatalf("litestream pool connections must run synchronous=FULL (2), got %d", sync) } } + +// TestDB_EncryptionKeyBytesLengthRejected asserts the driver's raw-key +// length contract surfaces through litestream's own pool: SQLCipher honors +// raw keys only at 32/48/80 bytes; the 0xCarbon fork rejects other lengths +// at connection open instead of silently KDF-falling-back. +func TestDB_EncryptionKeyBytesLengthRejected(t *testing.T) { + dbPath := filepath.Join(t.TempDir(), "db") + setup, err := sql.Open("sqlite3", dbPath) + if err != nil { + t.Fatal(err) + } + if _, err := setup.Exec(`CREATE TABLE t (v TEXT);`); err != nil { + t.Fatal(err) + } + setup.Close() + + db := NewDB(dbPath) + db.EncryptionKeyBytes = make([]byte, 16) // invalid: not 32/48/80 + client := &testReplicaClient{dir: t.TempDir()} + r := NewReplicaWithClient(db, client) + r.MonitorEnabled = false + db.Replica = r + if err := db.Open(); err != nil { + t.Fatal(err) + } + defer func() { _ = db.Close(context.Background()) }() + + // db.Open does not connect; the first pooled connection (init) fails fast. + err = db.init(context.Background()) + if err == nil { + t.Fatal("expected invalid raw key length to be rejected") + } + if !strings.Contains(err.Error(), "invalid raw key length") || !strings.Contains(err.Error(), "must be 32, 48, or 80 bytes") { + t.Fatalf("unexpected error: %v", err) + } +} diff --git a/docs/PATTERNS.md b/docs/PATTERNS.md index 365ab0e9a..c0fa73b3e 100644 --- a/docs/PATTERNS.md +++ b/docs/PATTERNS.md @@ -439,7 +439,7 @@ Lock page numbers by page size: **Responsibilities:** -- Manages SQLite database connection (via `mattn/go-sqlite3`; CGO required, SQLCipher supported) +- Manages SQLite database connection (via `0xCarbon/go-sqlite3`; CGO required, SQLCipher supported) - Monitors WAL for changes - Performs checkpoints - Maintains long-running read transaction diff --git a/docs/SQLITE_INTERNALS.md b/docs/SQLITE_INTERNALS.md index 2e70b7300..2475d0737 100644 --- a/docs/SQLITE_INTERNALS.md +++ b/docs/SQLITE_INTERNALS.md @@ -437,7 +437,7 @@ Litestream uses both database/sql and direct SQLite APIs: // Using database/sql for queries db, err := sql.Open("sqlite3", "database.db") -// Using mattn/go-sqlite3 for low-level access (CGO) +// Using 0xCarbon/go-sqlite3 for low-level access (CGO) conn, err := sqlite3.Open("database.db") // Direct page access (requires special builds) diff --git a/docs/VFS.md b/docs/VFS.md index e85779dde..ddc290c7a 100644 --- a/docs/VFS.md +++ b/docs/VFS.md @@ -166,7 +166,7 @@ import ( "database/sql" "os" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func main() { diff --git a/encryption_test.go b/encryption_test.go index 2c145aae9..8821a209e 100644 --- a/encryption_test.go +++ b/encryption_test.go @@ -1,16 +1,18 @@ package litestream_test import ( + "bytes" "context" "database/sql" "encoding/hex" "fmt" + "os" "path/filepath" "sync" "sync/atomic" "testing" - "github.com/mattn/go-sqlite3" + "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" "github.com/benbjohnson/litestream/file" @@ -186,6 +188,68 @@ func TestDB_ConcurrentDifferentKeys(t *testing.T) { wg.Wait() } +// sqlcipher414FixtureKey is the raw key of testdata/sqlcipher-v4.14.0/fixture.db. +func sqlcipher414FixtureKey() []byte { + key := make([]byte, 32) + for i := range key { + key[i] = byte(i*7 + 3) + } + return key +} + +// TestSQLCipher414FixtureDecrypts pins the cross-version ciphertext +// contract: databases written by the previous driver pin (0xCarbon fork +// c8f057756220, SQLCipher 4.14.0 / SQLite 3.51.3) must keep opening under +// the current pin (SQLCipher 4.17.0) with unchanged kdf/HMAC defaults. +// Regenerate the fixture only with a deliberate compatibility decision. +func TestSQLCipher414FixtureDecrypts(t *testing.T) { + fixturePath := filepath.Join("testdata", "sqlcipher-v4.14.0", "fixture.db") + fixture, err := os.ReadFile(fixturePath) + if err != nil { + t.Fatalf("read fixture: %v", err) + } + // Guard against an accidentally-plaintext fixture. + if bytes.Equal(fixture[:15], []byte("SQLite format 3")) { + t.Fatal("fixture is plaintext; regenerate with the recorded generator") + } + + dbPath := filepath.Join(t.TempDir(), "db") + if err := os.WriteFile(dbPath, fixture, 0o600); err != nil { + t.Fatal(err) + } + + // Litestream's own path: init reads the database with the key. + db := litestream.NewDB(dbPath) + db.EncryptionKeyBytes = sqlcipher414FixtureKey() + client := file.NewReplicaClient(t.TempDir()) + r := litestream.NewReplicaWithClient(db, client) + r.MonitorEnabled = false + db.Replica = r + if err := db.Open(); err != nil { + t.Fatal(err) + } + if err := db.Sync(context.Background()); err != nil { + t.Fatalf("sync over 4.14-written database: %v", err) + } + if err := db.Close(context.Background()); err != nil { + t.Fatal(err) + } + + // And the data survives intact through the current driver. + verifier, err := sql.Open(registerKeyedSQLite(t, sqlcipher414FixtureKey()), dbPath) + if err != nil { + t.Fatal(err) + } + defer verifier.Close() + var payload string + if err := verifier.QueryRow(`SELECT payload FROM fixture ORDER BY id LIMIT 1`).Scan(&payload); err != nil { + t.Fatalf("read fixture rows: %v", err) + } + if payload != "sqlcipher-4.14-compat" { + t.Fatalf("payload = %q", payload) + } +} + // TestDB_EncryptionKeyStringForms verifies the accepted string key forms // through a full replicate/restore round trip. The driver interpolates the // string into `PRAGMA key = %s;`, so the bare blob form must be auto-quoted diff --git a/go.mod b/go.mod index 4a63fb9ce..6dd779115 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/mark3labs/mcp-go v0.32.0 github.com/mattn/go-shellwords v1.0.12 - github.com/mattn/go-sqlite3 v1.14.24 github.com/nats-io/nats.go v1.44.0 github.com/pkg/sftp v1.13.6 github.com/prometheus/client_golang v1.17.0 @@ -51,6 +50,7 @@ require ( ) require ( + github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260817152354-d1c4d3294fa8 github.com/lmittmann/tint v1.1.3 github.com/mattn/go-isatty v0.0.20 github.com/pierrec/lz4/v4 v4.1.23 @@ -131,5 +131,3 @@ require ( google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/mattn/go-sqlite3 => github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260515201505-c8f057756220 diff --git a/go.sum b/go.sum index 87df8501d..a4becdfc8 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ cloud.google.com/go/pubsub v1.34.0 h1:ZtPbfwfi5rLaPeSvDC29fFoE20/tQvGrUS6kVJZJvk cloud.google.com/go/pubsub v1.34.0/go.mod h1:alj4l4rBg+N3YTFDDC+/YyFTs6JAjam2QfYsddcAW4c= cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= -github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260515201505-c8f057756220 h1:6mAhRjRjEXizhq0G7k3LnXFzyuMp4vR4L62RL95Bt9w= -github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260515201505-c8f057756220/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260817152354-d1c4d3294fa8 h1:dSe2JsAQq07u4+dt94EyyDm5tVEmmxD0YeA9rA7mlxo= +github.com/0xCarbon/go-sqlite3 v1.14.38-0.20260817152354-d1c4d3294fa8/go.mod h1:ANMAfeds95Wt2uetNKPPPenXJ6XqHK53ltmgttIvtnQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.2 h1:Hr5FTipp7SL07o2FvoVOX9HRiRH3CR3Mj8pxqCcdD5A= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.2/go.mod h1:QyVsSSN64v5TGltphKLQ2sQxe4OBQg0J1eKRcVBnfgE= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 h1:MhRfI58HblXzCtWEZCO0feHs8LweePB3s90r7WaR1KU= @@ -203,6 +203,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= diff --git a/litestream.go b/litestream.go index 41c31794e..b1f889b93 100644 --- a/litestream.go +++ b/litestream.go @@ -16,7 +16,7 @@ import ( "strconv" "strings" - "github.com/mattn/go-sqlite3" + "github.com/0xCarbon/go-sqlite3" "github.com/superfly/ltx" ) @@ -38,7 +38,7 @@ func normalizeEncryptionKey(key string) string { var blobKeyRe = regexp.MustCompile(`^x'[0-9a-fA-F]+'$`) -// newSQLiteDriver builds a mattn/go-sqlite3 driver bound to one database's +// newSQLiteDriver builds a 0xCarbon/go-sqlite3 (mattn-lineage) driver bound to one database's // SQLCipher key. The key is applied as the first statement of every new // connection; the connect hook applies Litestream's per-connection settings. func newSQLiteDriver(encryptionKey string, encryptionKeyBytes []byte) *sqlite3.SQLiteDriver { @@ -54,7 +54,7 @@ func newSQLiteDriver(encryptionKey string, encryptionKeyBytes []byte) *sqlite3.S } // Litestream owns checkpointing; disable SQLite's automatic WAL // checkpoints (upstream disables this via modernc's _pragma= DSN, - // which mattn/go-sqlite3 does not support). + // which the go-sqlite3 fork does not support). if _, err := conn.Exec("PRAGMA wal_autocheckpoint = 0;", nil); err != nil { return fmt.Errorf("cannot disable wal_autocheckpoint: %w", err) } diff --git a/litestream_test.go b/litestream_test.go index 3addaf47b..fa3e736c5 100644 --- a/litestream_test.go +++ b/litestream_test.go @@ -11,7 +11,7 @@ import ( "github.com/superfly/ltx" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" ) diff --git a/replica.go b/replica.go index 6a9d02a84..f1bc9b3b2 100644 --- a/replica.go +++ b/replica.go @@ -14,7 +14,7 @@ import ( "sync/atomic" "time" - "github.com/mattn/go-sqlite3" + "github.com/0xCarbon/go-sqlite3" "github.com/superfly/ltx" "golang.org/x/sync/semaphore" diff --git a/replica_internal_test.go b/replica_internal_test.go index 68735d181..35c0eea5f 100644 --- a/replica_internal_test.go +++ b/replica_internal_test.go @@ -14,7 +14,7 @@ import ( "testing" "time" - "github.com/mattn/go-sqlite3" + "github.com/0xCarbon/go-sqlite3" "github.com/superfly/ltx" ) diff --git a/skills/litestream/SKILL.md b/skills/litestream/SKILL.md index ea06992f1..e71791e40 100644 --- a/skills/litestream/SKILL.md +++ b/skills/litestream/SKILL.md @@ -20,7 +20,7 @@ metadata: Litestream is a standalone disaster recovery tool for SQLite. It runs as a background process, monitors the SQLite WAL (Write-Ahead Log), converts changes to immutable LTX files, and replicates them to cloud storage. It uses -`mattn/go-sqlite3` with bundled SQLCipher (CGO required; links libcrypto). +`github.com/0xCarbon/go-sqlite3` with bundled SQLCipher (CGO required; links libcrypto). ## Quick Start diff --git a/skills/litestream/references/ARCHITECTURE.md b/skills/litestream/references/ARCHITECTURE.md index 26c392911..f645fa0bc 100644 --- a/skills/litestream/references/ARCHITECTURE.md +++ b/skills/litestream/references/ARCHITECTURE.md @@ -26,7 +26,7 @@ The heart of Litestream. Manages a single SQLite database. Key fields: - `path` / `metaPath`: Database and metadata paths -- `db *sql.DB`: SQLite connection (via mattn/go-sqlite3, CGO + SQLCipher) +- `db *sql.DB`: SQLite connection (via 0xCarbon/go-sqlite3, CGO + SQLCipher) - `f *os.File`: Long-running file descriptor - `rtx *sql.Tx`: Long-running read transaction (prevents checkpoint past read point) - `pageSize int`: Database page size (critical for lock page calculation) diff --git a/testdata/sqlcipher-v4.14.0/fixture.db b/testdata/sqlcipher-v4.14.0/fixture.db new file mode 100644 index 000000000..d057f49fd Binary files /dev/null and b/testdata/sqlcipher-v4.14.0/fixture.db differ diff --git a/tests/integration/boundary_test.go b/tests/integration/boundary_test.go index d1725c015..ddf362c2f 100644 --- a/tests/integration/boundary_test.go +++ b/tests/integration/boundary_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func Test1GBBoundary(t *testing.T) { diff --git a/tests/integration/concurrent_test.go b/tests/integration/concurrent_test.go index d40f5bf9a..ed1818eda 100644 --- a/tests/integration/concurrent_test.go +++ b/tests/integration/concurrent_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func TestRapidCheckpoints(t *testing.T) { diff --git a/tests/integration/directory_watcher_helpers.go b/tests/integration/directory_watcher_helpers.go index 2b0b8cb61..926223067 100644 --- a/tests/integration/directory_watcher_helpers.go +++ b/tests/integration/directory_watcher_helpers.go @@ -13,7 +13,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // DirWatchTestDB extends TestDB with directory-specific functionality diff --git a/tests/integration/fixtures.go b/tests/integration/fixtures.go index 4a553e067..16a68bfa1 100644 --- a/tests/integration/fixtures.go +++ b/tests/integration/fixtures.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) type LoadPattern string diff --git a/tests/integration/helpers.go b/tests/integration/helpers.go index eeebd8718..24f3e6b06 100644 --- a/tests/integration/helpers.go +++ b/tests/integration/helpers.go @@ -17,7 +17,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" ) diff --git a/tests/integration/minio_soak_test.go b/tests/integration/minio_soak_test.go index ba61c7a94..798f1ec25 100644 --- a/tests/integration/minio_soak_test.go +++ b/tests/integration/minio_soak_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // TestMinIOSoak runs a soak test against local MinIO S3-compatible server using Docker. diff --git a/tests/integration/overnight_s3_soak_test.go b/tests/integration/overnight_s3_soak_test.go index 72cc7fe7b..893f45c61 100644 --- a/tests/integration/overnight_s3_soak_test.go +++ b/tests/integration/overnight_s3_soak_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // TestOvernightS3Soak runs an 8-hour overnight soak test against real AWS S3. diff --git a/tests/integration/overnight_test.go b/tests/integration/overnight_test.go index fbc576afc..f5339cab2 100644 --- a/tests/integration/overnight_test.go +++ b/tests/integration/overnight_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func TestOvernightFile(t *testing.T) { diff --git a/tests/integration/profile_test.go b/tests/integration/profile_test.go index 015bd22f3..8d54cae8f 100644 --- a/tests/integration/profile_test.go +++ b/tests/integration/profile_test.go @@ -15,7 +15,7 @@ import ( "strconv" "testing" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" "github.com/benbjohnson/litestream/file" diff --git a/tests/integration/quick_test.go b/tests/integration/quick_test.go index a6b7ea61d..4b57f4307 100644 --- a/tests/integration/quick_test.go +++ b/tests/integration/quick_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func TestQuickValidation(t *testing.T) { diff --git a/tests/integration/s3_restore_connection_drop_test.go b/tests/integration/s3_restore_connection_drop_test.go index 480afa4b1..61df1e3ab 100644 --- a/tests/integration/s3_restore_connection_drop_test.go +++ b/tests/integration/s3_restore_connection_drop_test.go @@ -16,7 +16,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // TestRestore_S3ConnectionDrop verifies restore can recover from dropped S3-compatible connections. diff --git a/tests/integration/scenario_test.go b/tests/integration/scenario_test.go index 42edf7450..11f4ff9bf 100644 --- a/tests/integration/scenario_test.go +++ b/tests/integration/scenario_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) func TestFreshStart(t *testing.T) { diff --git a/tests/integration/shutdown_retry_test.go b/tests/integration/shutdown_retry_test.go index ae9bf027e..1c0236758 100644 --- a/tests/integration/shutdown_retry_test.go +++ b/tests/integration/shutdown_retry_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // TestShutdownSyncRetry_429Errors tests that Litestream retries syncing LTX files diff --git a/tests/integration/soak_replicate_restore_test.go b/tests/integration/soak_replicate_restore_test.go index 4d26f28bf..4a9cd5131 100644 --- a/tests/integration/soak_replicate_restore_test.go +++ b/tests/integration/soak_replicate_restore_test.go @@ -16,7 +16,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" ) // TestSoakReplicateRestore reproduces issue #1164: intermittent database corruption diff --git a/tests/integration/upgrade_test.go b/tests/integration/upgrade_test.go index d312cfb74..d9b4eaa56 100644 --- a/tests/integration/upgrade_test.go +++ b/tests/integration/upgrade_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - _ "github.com/mattn/go-sqlite3" + _ "github.com/0xCarbon/go-sqlite3" "github.com/benbjohnson/litestream" )