Skip to content

Development

This page covers how to build, test, and contribute to DBCrust.

  • Rust — stable toolchain
  • mise 2026.8.16+ — manages Commitizen, the Mr Boxington build cache and the other tools, and runs every task. You don’t have to install it: the repository’s ./bin/mise wrapper downloads a pinned mise on first use.
  • Python 3.10+ — only needed for the Python bindings
Terminal window
# From the project root — install all managed tools
mise install
# No mise? Use the committed wrapper the same way, for every command on this page
./bin/mise install
./bin/mise run build:dev

On first use in a clone, mise asks you to trust mise.toml (or run mise trust). ./bin/mise keeps its mise binary and tools in mise’s usual directories, so they are shared with a mise you install later. On Windows, run bin\mise.cmd.

mise install reads mise.toml and sets up:

ToolPurpose
Mr Boxington (mbx)Shared Cargo build cache — see Build cache
BunJavaScript runtime for the documentation site
CommitizenConventional commit helper
pklConfiguration language
hkGit hooks

The project-scoped mise wrapper routes Cargo through Mr Boxington. mise run tasks use it automatically; activate mise in your shell if you also want plain cargo commands to use the cache.

Terminal window
mbx doctor # verify Cargo and cache integration
mbx cache stats # inspect cache usage
mbx gc --dry-run # preview automatic cleanup

Set MBX_DISABLE=1 for a one-off uncached Cargo command.

Terminal window
mise run build:dev # debug build (fast compile)
mise run build # release build (optimized)
cargo run -- <url> # run directly without installing
cargo install --path . # install to ~/.cargo/bin

The binary is named dbcrust. A short alias dbc is also built (see src/bin/dbc.rs).

Terminal window
mise run gui:dev # run the app (dev build, optimised dependencies)
mise run gui:build # release build
mise run gui:test # backend tests (dbcrust-gui-core, no GPUI needed)
mise run gui:lint # clippy on both GUI crates
mise run gui:screenshots # regenerate the docs/README screenshots headlessly
mise run gui:bundle # macOS DBCrust.app

The app is two crates: gui/core (dbcrust-gui-core, plain Rust — workers, storage, models) and gui (dbcrust-gui, the GPUI Kit views). See gui/ARCHITECTURE.md.

See Desktop GUI for full details.

Terminal window
mise run py:dev # maturin develop (editable install)
mise run py:build # build wheel
mise run py:test # run pytest
pip install -e ./python # alternative: pip editable install

The root crate (dbcrust) is split into Cargo features so a build only contains the engines and add-ons it needs. The default build is bundled: every engine and add-on DBCrust has shipped so far. Release binaries and Python wheels use bundled; the desktop app enables the same engines on dbcrust-drivers.

FeatureWhat it enablesPulls in
bundled (default)Everything below—
standardpostgres + mysql + sqlite (the slim preset)sqlx
postgresPostgreSQLsqlx, pgvector
mysqlMySQL / MariaDBsqlx
sqliteSQLitesqlx (bundled libsqlite3)
mongodbMongoDBmongodb, bson
clickhouseClickHouseclickhouse (pinned =0.15.1)
elasticsearchElasticsearchelasticsearch SDK
white-dragonWhite Dragon search SQL over HTTPreqwest only
redisRedis / Valkey (redis://, rediss://) — in bundled, not in standardredis (tokio + rustls/ring)
mssqlSQL Server / Azure SQL (mssql://, sqlserver://) — in bundled, not in standardvendored tiberius 0.13.0 (third_party/tiberius: rustls on ring only, see below)
redshiftAmazon Redshift (redshift://) — in bundled, not in standardsqlx PostgreSQL protocol (no extra crate)
libsqllibSQL / Turso over HTTP (libsql://, turso://, libsql+http://) — in bundled, not in standardreqwest only (hand-written Hrana client)
influxdbInfluxDB v1/v2/v3 (influxdb://, influxdb2://, influxdb3://) — in bundled, not in standardreqwest (rustls/ring) and csv-core, both already in the tree
s3Amazon S3, Cloudflare R2, MinIO (s3://, r2://, minio://) — opt-in: not in bundled, not in standard; needs Rust ≥ 1.94.1AWS SDK (aws-config, aws-sdk-s3, aws-smithy-http-client), rustls on ring only
dynamodbAmazon DynamoDB (dynamodb://, dynamodb+http://, ddb://) — opt-in: not in bundled, not in standard; needs Rust ≥ 1.94.1AWS SDK (aws-config, aws-sdk-dynamodb, aws-smithy-http-client), rustls on ring only
cloudwatchAmazon CloudWatch Logs (cloudwatch://, cloudwatch+http://, cwlogs://) — opt-in: not in bundled, not in standard; needs Rust ≥ 1.94.1AWS SDK (aws-config, aws-sdk-cloudwatchlogs, aws-smithy-http-client), rustls on ring only
awsthe AWS connectors as a group (s3, dynamodb, cloudwatch) — opt-in, Rust ≥ 1.94.1the three above on one shared base
filesParquet, CSV and JSON filesApache DataFusion / Arrow / Parquet
duckdbDuckDB database files, :memory: and DuckLake (duckdb://) — opt-in: not in bundled, not in standard (a C++ engine, see below)duckdb =1.10506.1 (engine 1.5.6) with bundled, Parquet and JSON; a zip stand-in (third_party/zip-stub)
dockerdocker:// URLs, \docker, container completionbollard
ai??, ???, \ai, the Python AI functionsgenai, reqwest 0.13
explain-tui\x plan TUI and the \sv schema browserratatui, textwrap
clipboard\ecopyarboard
pythonPyO3 bindings (maturin passes it)pyo3
Terminal window
# the default, everything
cargo install --path . --locked
# the slim preset: PostgreSQL, MySQL, SQLite
cargo install --path . --locked --no-default-features --features standard
mise run build:slim # release build of the slim preset
mise run install:slim # install it
# a custom build: SQLite and ClickHouse with Docker discovery
cargo build --no-default-features --features sqlite,clickhouse,docker
# the default build plus the opt-in DuckDB engine (a C++17 compiler is required)
cargo install --path . --locked --features duckdb
# type-check the whole matrix (what CI does)
mise run check:features

Cost of each feature, as unique crates added to the normal dependency tree (cargo tree -p dbcrust --no-default-features --features <x> -e normal), against 216 crates for the zero-engine build:

FeatureAdded cratesFeatureAdded crates
files+107ai+34
mongodb+53explain-tui+22
mysql+46clickhouse+16
postgres+35elasticsearch+15
sqlite+21redis+12
docker, clipboard+7 eachmssql+17

standard is 272 crates against 487 for bundled (redshift and libsql add no crate: they share sqlx with postgres and reqwest with the HTTP engines, see below); the dev-profile binary drops from about 327 MB (201 MB stripped) to 77 MB (49 MB stripped). DataFusion is by far the heaviest piece, which is why files is the first thing to drop.

mssql adds 7 crates to the lockfile (tiberius, tiberius-macros, asynchronous-codec, connection-string, futures-timer, pretty-hex, secrecy), roughly +1.2 MB of stripped release binary, and no C build: upstream tiberius 0.13.0 hard-codes the aws-lc-rs TLS provider (a cmake/C compile) and 0.12.3 sits on a rustls with three open RustSec advisories, so DBCrust vendors 0.13.0 with a small patch that selects ring like the rest of the tree (plus a one-line fix that lets it compile for the i686 wheels). third_party/tiberius/DBCRUST_PATCH.md records the original archive checksum, the exact diff, how to re-vendor on a release and the text of the upstream proposal; cargo tree --locked -i aws-lc-rs must keep reporting nothing.

influxdb adds no registry crate to the lockfile: the HTTP client is hand-written on the reqwest 0.12 the other HTTP drivers use, and the Flux CSV is read with csv-core, already locked through DataFusion’s csv. The influxdb crate was rejected because it wraps reqwest 0.13 with the aws-lc provider and speaks neither Flux nor v3. Its cost in the normal dependency tree is 2 crates (the driver and csv-core).

s3, dynamodb, cloudwatch (and the aws umbrella) are the opt-in AWS connectors. They are not in bundled, so release binaries, wheels and the desktop app do not contain it, and it needs Rust 1.94.1 or newer because the AWS SDK crates declare that rust-version (the workspace stays on 1.91). The new crates, dbcrust-aws (shared credentials/region/HTTP foundation), dbcrust-driver-s3, dbcrust-driver-dynamodb and dbcrust-driver-cloudwatch, declare rust-version = "1.94.1" in their own manifests; the CI job rust-aws pins that exact toolchain and checks them with the root crate. cargo install --features aws on an older compiler stops with cargo’s “requires rustc 1.94.1” message; a default build never compiles an AWS crate (CI checks cargo tree -p dbcrust for aws-*).

It adds 31 crates to the lockfile (23 aws-*/aws-smithy-*, plus base64-simd, bytes-utils, crc-fast, outref, regex-lite, urlencoding, vsimd, xmlparser) and bumps itoa, ryu and tokio-util to versions the SDK requires (34 new Cargo.lock entries in all; the normal dependency tree of bundled goes from 524 to 558 nodes, the two DBCrust crates included). Of the 34 lock entries, 29 are the shared AWS base (aws-config, the credential chain, SSO, STS and the ring HTTP client) and 5 are S3 itself (aws-sdk-s3, aws-smithy-checksums, aws-smithy-eventstream, crc-fast, the tokio-util bump); DynamoDB and CloudWatch Logs add one registry crate each on the same base (aws-sdk-dynamodb 1.130.0, aws-sdk-cloudwatchlogs 1.156.0; they share the locked aws-smithy-*, aws-types, aws-runtime, aws-smithy-eventstream and tokio-util with aws-sdk-s3, so no existing entry moved). Normal dependency tree of the bundled build (524 nodes, the DBCrust crates included): s3 → 558 (+34), dynamodb → 554 (+30), cloudwatch → 555 (+31), all three (aws) → 562 (+38: S3’s +34 and two SDK crates and two DBCrust driver crates). The dev-profile dbcrust binary goes from 338.2 MB to 360.0 MB with --features s3 (+21.7 MB), 359.1 MB with dynamodb (+20.8), 358.0 MB with cloudwatch (+19.8) and 367.3 MB with --features aws (+29.0 MB, +7.3 MB over S3 alone); after strip -x 283.7 MB → 301.2 MB (s3) and 307.1 MB (aws, +23.4 MB, +5.9 MB over S3 alone). There is no C build: everything is pure Rust, and compile time is dominated by the generated SDK crates.

TLS is rustls on ring only. The SDK’s defaults enable aws-smithy-runtime/default-https-client, which pulls aws-lc-rs (a C/cmake build); every AWS crate here is built with default-features = false, aws-smithy-http-client with its rustls-ring feature only, and dbcrust-aws builds that HTTP client and injects it into every SDK configuration. cargo tree --locked --workspace --target all -i aws-lc-rs (and aws-lc-sys, openssl, native-tls) must keep reporting nothing, with and without --features aws; CI checks it. The legacy hyper 0.14 / rustls 0.21 client (legacy-https-client) must not be enabled either. The SDK’s test-util (replay clients) is not used: it adds about fifteen test-only crates to the lockfile, so the AWS connector tests run the real SDK against an in-process HTTP server instead (S3’s REST, DynamoDB’s JSON 1.0, CloudWatch Logs’ JSON 1.1).

duckdb is the one connector that compiles a C++ engine: libduckdb-sys builds DuckDB’s amalgamation (plus the Parquet and JSON extensions, which DuckLake and the file functions need) with the cc crate, so a C++17 compiler is required. Measured on a loaded 12-core machine:

Cold dev build of the DuckDB crates (no debuginfo)4 min 12 s wall, 917 s of user CPU (about 15 CPU-minutes); the figures of the release probe were 2 min 40 s wall / 18 CPU-minutes. Mr Boxington cannot cache the engine’s build script, so repeat builds in a shared target directory can redo it: use a dedicated CARGO_TARGET_DIR (the CI workflow does)
Dev binary, standard → standard,duckdb58.0 MiB → 165.2 MiB unstripped (+107 MiB), 54.3 MiB → 131.1 MiB stripped (+77 MiB): the dev profile compiles the C++ unoptimised. The release probe measured +19 MB stripped (+22.5 MB with Parquet and JSON)
Crates in the normal treebundled 490 → 496 (duckdb, libduckdb-sys, dbcrust-driver-duckdb, cast, fallible-iterator, fallible-streaming-iterator); standard 272 → 300, because standard carries no Arrow
Lockfile+19 registry packages: duckdb, libduckdb-sys, cast and the two fallible-*; a second crossterm (two versions: one for Windows), rustix and linux-raw-sys (through comfy-table, which duckdb enables with its terminal feature); and the build-script-only ureq, ureq-proto, utf8-zero, tar, filetime, xattr, zip, nix, typed-path, zopfli (used by the non-bundled download mode)

Until 1.10506.1, libduckdb-sys depended on zip = "^6", whose releases are all yanked, and DBCrust patched in a stand-in crate; 1.10506.1 moved to zip 9 and the stand-in is gone. cargo tree --locked --workspace -i aws-lc-rs must keep reporting nothing with the connector in the tree, and DuckDB is excluded from the 32-bit Python check and from the release binaries and wheels (bundled does not contain it).

A disabled engine is still a DatabaseType: config files, sessions and recent.toml written by a full build keep parsing. Connecting to it fails with a message that names the feature, e.g. “MongoDB support is not compiled into this build (enable the mongodb cargo feature, or install a full build)”; dbcrust-drivers exposes is_compiled, compiled_engines and required_feature for code that has to adapt. URL-scheme completion only offers the schemes the build can serve, and the credential broker refuses to enrol an engine the build does not contain (unsupported_engine, same hint).

  1. A dbcrust-driver-<name> crate (depends on dbcrust-core and its SDK only).
  2. In dbcrust-drivers: an optional dependency, a same-named feature, and one row in the connectors! table ("<feature>" => Engine => path::Client;). The matches have no wildcard, so a missing row is a compile error.
  3. In the root Cargo.toml: <name> = ["dbcrust-drivers/<name>"].
  4. Decide where it lives:
    • Light (small SDK, no heavy transitive tree): add it to bundled explicitly, with a changelog note, so the default build gains it.
    • Heavy (DuckDB, AWS SDKs …): leave it out of bundled; users opt in with --features <name>. Never add a connector to bundled silently.
  5. Add it to the matrix in .github/workflows/ci.yml (rust-features) and to mise run check:features. A connector whose cargo check is itself expensive (DuckDB compiles C++ in its build script) gets a dedicated path-filtered workflow instead of a matrix slot (.github/workflows/duckdb.yml), and stays out of the 32-bit Python check.
Terminal window
mise run test # all tests
cargo test -- --nocapture # with stdout
cargo test test_name # specific test
cargo test --lib module_name # specific module
cargo test --test "*" # integration tests only
mise run py:test # Python tests
Terminal window
mise run fmt # cargo fmt
mise run lint # clippy (correctness, suspicious, perf as errors; style, complexity as warnings)
mise run check # fmt + lint + test in sequence

Cargo commands run through mise — for the CLI, the desktop app and the Python bindings alike — go through Mr Boxington (mbx), the Cargo build cache by mise’s author. mise.toml installs a pinned mbx and declares a project-scoped cargo wrapper ([wrappers.cargo], mise 2026.8.16 or newer — ./bin/mise already is), so you keep typing plain cargo commands:

  • Compilations are cached in one store and reused across worktrees and branches: building one checkout warms the next.
  • target/ becomes a link to a managed directory with a disk budget; old targets and cache entries are collected automatically, and more aggressively when the disk runs low.
  • Builds running at the same time share one CPU and memory budget.

Cargo uses mbx when it runs through mise: mise run tasks, mise exec -- cargo …, or a shell with mise activation or shims on PATH. Check with mise exec -- mbx doctor. Editors and coding agents that call ~/.cargo/bin/cargo directly bypass the cache: point them at mise exec, and see rust-analyzer setup to route editor checks through mbx.

Terminal window
mise run cache:stats # savings and disk use
mise run cache:gc -- --dry-run # preview what collection would reclaim
mise run cache:gc # reclaim space now

CI uses the same cache through jdx/mr-boxington-action, pinned to a commit and an mbx version. Release builds don’t use it.

Treat updates as code changes, not automatic trust decisions. Review upstream release notes, repository/maintainer changes, advisories, and added transitive crates before building. Avoid blanket cargo update; review breaking upgrades separately. A cooldown reduces exposure to freshly published compromises but cannot prove a package is safe.

Every new release must be at least 24 hours old, including security fixes. Weekly Dependabot version PRs have a one-day cooldown and are not auto-merged. Because Dependabot exempts security PRs, CI also checks every new external Cargo.lock entry against the PR base (or the previous push), including transitive, optional, and platform-specific dependencies. The guard verifies crates.io publication timestamps, checksums, and yank status; missing metadata or new non-crates.io sources fail closed. Retry a failed check after the cooldown expires or the registry recovers. Make Rust · dependency audit a required check in branch protection to prevent merging around it.

From the project root, using Python 3.11+ for the stdlib-only guard:

Terminal window
# After reviewing a specific upstream release and its publication date:
cargo update -p CRATE --precise VERSION
python3 .github/scripts/check_cargo_cooldown.py --base HEAD
cargo audit
cargo machete --with-metadata
cargo +nightly udeps --workspace --all-targets --all-features --locked
cargo test --all-features --locked
cargo clippy --all-targets --all-features --locked -- -D warnings

For committed changes use --base origin/main (fetch that ref first). Use --locked when validating/building so Cargo cannot silently resolve newer, unreviewed versions. Both workspace members share the root lockfile. The guard does not replace review or constrain arbitrary local cargo update commands.

cargo audit (cargo-audit 0.22.1, 1422 advisories) failed on main with 9 vulnerabilities published between 2026-10-16 and 2026-11-02, plus 12 unsoundness warnings and 2 yanked versions. Every one was fixed by a targeted cargo update -p CRATE --precise VERSION inside the ranges the manifests already allow. No manifest changed and no new crate entered the lockfile: there are 27 new registry versions, all of them more than 24 hours old, with matching checksums, and none yanked.

CrateOld → newAdvisories fixed
rustls-webpki0.103.15 → 0.103.16RUSTSEC-2026-0382 (distrusted emSign intermediates accepted)
webpki-roots1.0.2 → 1.0.10RUSTSEC-2026-0381 (same emSign distrust)
webpki-root-certs1.0.7 → 1.0.10RUSTSEC-2026-0383 (same emSign distrust; AI client’s platform verifier)
ctutils0.4.2 → 0.4.4RUSTSEC-2026-0385 (non-constant-time masks; via digest 0.11 → hmac/sha2/pbkdf2/md-5/sha1 in MongoDB and the AWS SDK)
zstd0.13.3 → 0.13.4RUSTSEC-2026-0391
zstd-safe7.2.4 → 7.4.0RUSTSEC-2026-0398, -0403; unsound -0395 to -0397, -0399 to -0402, -0404 to -0406
zstd-sys2.0.16 → 2.1.2 (zstd 1.5.7)RUSTSEC-2026-0410 (wasm32 allocator shim)
parquet + all 14 arrow* crates58.1.0 → 58.4.1arrow-data: RUSTSEC-2026-0442 (unsound RunEndEncoded validation)
thrift (via parquet 58.4.1)0.17.0 → 0.23.0RUSTSEC-2026-0435 (unbounded allocation in read_bytes)
tokio1.53.1 → 1.53.3RUSTSEC-2026-0386 (unsound AsyncFd constructors)
async-executor1.14.0 → 1.14.11.14.0 yanked (GPUI / zbus stack)
clipboard-win5.4.1 → 5.4.25.4.1 yanked (arboard, Windows only)

Notes on the choices:

  • Arrow/Parquet stay on 58. parquet 58.4.1 already requires thrift 0.23 and arrow 58.4.1, so the fix is a minor update. The arrow crates were moved together because arrow-rs releases them in lockstep. DataFusion stays at 53.1.0 (it requires ^58.0.0), and DuckDB’s arrow ^58 shares the same crates. No DataFusion/Arrow major migration was needed. thrift 0.23 swaps ordered-float 2.10.1 for 3.9.2, and it was published by the Apache Thrift release manager (Jens-G), not the 0.17 publisher.
  • zstd-sys 2.1.2, not 2.0.17. 2.0.17 has the same wasm shim fix in its source, but the advisory lists only >= 2.1.2 as patched. zstd-safe 7.4.0 accepts ^2.0.17, so 2.1.2 fits under it. 2.1.2 ships byte-identical zstd 1.5.7 C sources and the same default build (bundled, cc, hidden symbols). Its pre-generated bindings differ only in doc comments. Its new optional cmake/vendored features, and bindgen (no longer a default), are not enabled. zstd 0.14 / zstd-safe 8 would need parquet 60, which no DataFusion release uses yet.
  • License change: zstd 0.13.4, zstd-safe 7.4.0 and zstd-sys 2.1.2 moved from MIT / MIT-or-Apache-2.0 to BSD-3-Clause, the bundled C library’s license. It is permissive and compatible with DBCrust’s MIT license.
  • Smallest patched version everywhere: tokio 1.53.3 rather than 1.54.x, ctutils 0.4.4 (0.4.5 to 0.4.8 only add APIs and harden Thumb-1/RISC-V 32), and clipboard-win 5.4.2 (5.4.1’s code with doc fixes; 5.4.3 changes the retry sleep).
  • cargo tree --locked --workspace --target all -i aws-lc-rs stays empty. The ClickHouse =0.15.1 pin and the vendored tiberius are untouched.

cargo audit passes again. The only exception is still RUSTSEC-2023-0071, and 9 informational “unmaintained” warnings remain, with no replacement crate needed:

  • pin-utils (RUSTSEC-2026-0441, new on 2026-11-02) reaches the CLI through hyper 1.7.0 and the opt-in AWS connectors through aws-smithy-http, -runtime and -types. hyper 1.9+ no longer uses it, but the AWS crates would keep it in the lockfile, so it was not bumped for this.
  • paste (proc-macro) comes from DataFusion/parquet, genai and ClickHouse 0.15.1 (pinned; through polonius-the-crab → higher-kinded-types), plus the desktop app (gpui-component, metal, and image → exr → pulp).
  • instant, rustls-pemfile, rustybuzz and ttf-parser come only from the desktop app’s GPUI Kit stack.
  • zvariant, zvariant_derive and zbus_names come from GPUI’s Linux accessibility and portal layer (accesskit → atspi, ashpd, zbus).
  • duckdb/libduckdb-sys 1.10506.1 (same DuckDB 1.5.6 engine) moved its build dependency to zip 9, so the stand-in zip 6.0.0 crate DBCrust had patched in is gone: cargo audit matched it against RUSTSEC-2026-0367/0368/0369 (archive extraction in the real zip 6, code the stand-in never had). The bump adds zip 9.0.4, nix, typed-path and zopfli 0.8.3 (build-script only, zopfli held at 0.8.3 so bumpalo/crc32fast/simd-adler32 stay put) and moves libc to 0.2.186, the minimum nix accepts.
  • cargo audit passes with 8 informational warnings, all “unmaintained”: instant, paste, rustls-pemfile, rustybuzz, ttf-parser and, new on 2026-10-16, zvariant, zvariant_derive and zbus_names. All but paste come only from the desktop app’s GPUI Kit stack (the last three through its Linux accessibility layer, accesskit → atspi); paste (a proc-macro) also reaches the CLI through the ClickHouse and DataFusion drivers.
  • Selected updates include PyO3 0.29.2 (with binding migration), Ratatui 0.30.2, usage-rs 6.8.0, MongoDB 3.9.0, DataFusion 53.1.0, and Tauri 2.11.5, plus compatible security fixes. All 160 new registry versions passed the one-day age check; none were yanked.
  • Fixed 14 vulnerability findings affecting HTTP/2, Python bindings, XML, QUIC, archive validation, TLS certificate validation, and time parsing. Removed four unsoundness warnings and the yanked spin version as well.
  • cargo audit passes with one documented exception: RUSTSEC-2023-0071 (rsa via SQLx/MySQL). There is no patched release; this code path only encrypts credentials with a public key, not the vulnerable private-key operations. Reassess the exception when that dependency tree changes.
  • 20 informational warnings remain, predominantly inherited from Tauri’s GTK3 dependencies, plus unmaintained paste, fxhash, and Unicode helpers. These include unsoundness advisories for glib and build-time rand 0.7.3. They are not silently suppressed or claimed fixed. cargo deny check is not a passing gate: the project has no license allowlist/deny configuration, and deny also reports the remaining advisories.
  • No unused direct dependencies were found by cargo machete --with-metadata or workspace/all-feature cargo udeps on macOS. prettytable-rs is used under the library name prettytable. Platform-specific usage still needs review before any removal.
  • Deferred genai 0.7.0-beta.23 (published that day) and breaking updates such as SQLx 0.9, DataFusion 55, BSON 3, Reqwest 0.13, and keyring 4.

The v0.37.1 release attempt exposed a ClickHouse 0.15.2 regression: its new Native reader unconditionally compiles const SAFE_ALLOCATION_LIMIT: usize = 1 << 32, which overflows on i686 even though DBCrust does not use the Native API. ClickHouse is therefore exactly pinned to 0.15.1 (published 2026-06-04, not yanked). The remaining security updates are retained; the restored transitive dependencies are checked by the same cooldown/audit policy.

CI now checks the actual Python extension library for i686-unknown-linux-gnu, not just 64-bit hosts. Confirm Rust · 32-bit Python compatibility passes before tagging a dependency release. Keep the pin until an upstream fix passes that check; do not drop the i686 wheel to hide a failure.

To reproduce the check on an x86_64 Debian/Ubuntu development host:

Terminal window
sudo apt-get install gcc-multilib g++-multilib
rustup target add i686-unknown-linux-gnu
PYO3_NO_PYTHON=1 cargo check --locked -p dbcrust --lib --features python \
--target i686-unknown-linux-gnu

PYO3_NO_PYTHON=1 uses the configured abi3-py310 ABI instead of trying to use a 64-bit Python interpreter for the 32-bit target. This is a compile check; the release workflow still builds and packages the real i686 wheel.

All tasks are defined in mise.toml. Run mise tasks to list them.

TaskDescription
buildcargo build --release
build:devcargo build
build:slimRelease build of the slim preset (--no-default-features --features standard)
install:slimInstall the slim preset into ~/.cargo/bin
testcargo test
lintClippy with strict settings
fmtcargo fmt
checkfmt → lint → test
check:featurescargo check of the zero-engine build, standard and each feature alone
gui:devRun the desktop app (dev build, optimised dependencies)
gui:buildOptimised build of the desktop app (target/gui-release)
gui:installInstall dbcrust-gui into ~/.cargo/bin
gui:bundlemacOS DBCrust.app bundle
gui:testBackend tests (dbcrust-gui-core)
gui:lintClippy on both GUI crates
gui:screenshotsRender docs screenshots headlessly
gui:cleanRemove GUI build artifacts
cache:statsBuild-cache savings and disk use (mbx stats)
cache:gcReclaim build-cache disk space (mbx gc)
py:devmaturin develop
py:buildmaturin build --release
py:testpython -m pytest
all:buildBuild CLI + GUI + Python
all:cleanClean everything
├── src/ # `dbcrust` (root crate): CLI, REPL, terminal UI, PyO3 bindings
│ ├── main.rs # tokio entry point
│ ├── lib.rs # public API (re-exports the crates below under their old paths) + PyO3 bindings
│ ├── cli.rs # argument parsing (usage-rs derive)
│ ├── cli_core.rs # REPL loop, one-shot mode and command dispatch
│ ├── commands.rs # backslash command enum (strum-driven)
│ ├── config_editor.rs # interactive `\config` menu + tunnel manager (schema: dbcrust-app)
│ ├── terminal_ui.rs # inquire / ratatui prompts and viewers `Database` asks for
│ ├── drivers.rs # facade over dbcrust-drivers
│ ├── completion.rs # SQL autocompletion engine
│ ├── command_completion.rs # backslash command completion
│ ├── shell_completion.rs # shell completion generation (bash/zsh/fish/powershell)
│ ├── prompt.rs # reedline custom prompt
│ ├── highlighter.rs # SQL syntax highlighting
│ ├── sql_validator.rs # reedline validator (Enter submits or continues)
│ ├── sql_parser_*.rs # per-engine parsers used by completion
│ ├── url_scheme.rs # URL scheme parsing and normalization
│ ├── named_queries.rs # named query parameter substitution
│ ├── history_manager.rs # per-session history
│ ├── script.rs, pager.rs # external editor integration, output paging
│ ├── logging.rs # tracing setup
│ ├── update.rs # `--update`
│ ├── secrets_cli/ # `dbcrust secrets` status / audit / migrate
│ ├── broker/ # `dbcrust broker …` front end (prompts, arguments, e2e tests)
│ ├── explain_tui/ # interactive EXPLAIN TUI (ratatui + crossterm; feature `explain-tui`)
│ └── schema_tui/ # interactive schema browser TUI (feature `explain-tui`)
├── crates/
│ ├── core/ # dbcrust-core: client traits, model DTOs, SQL/format/display, safety, password sanitizer
│ ├── app/ # dbcrust-app: config + storage, `\config` schema, `Database`, SSH/Vault/pgpass (shared by CLI and GUI)
│ ├── secrets/ # dbcrust-secrets: keychain / Argon2id file store, legacy readers, config-dir/test-mode paths
│ ├── drivers/ # dbcrust-drivers: engine registry, `create_database_client`, one cargo feature per engine
│ ├── driver-postgres/ # one crate per engine: -mysql, -sqlite, -mongodb, -clickhouse,
│ │ # -elasticsearch, -white-dragon, -files (DataFusion: Parquet/CSV/JSON)
│ ├── docker/ # dbcrust-docker: daemon selection, discovery, route probing, `docker exec` relay (bollard)
│ ├── ai/ # dbcrust-ai: genai assistant, agent loop, ChatGPT sign-in, `AiSession` trait
│ ├── broker/ # dbcrust-broker: credential broker core (registry, admin, gateway, audit, socket server)
│ ├── agent-protocol/ # wire protocol shared by the broker and the thin agent client
│ └── agent/ # dbcrust-agent: credential-free client for AI coding agents
├── gui/ # desktop app (GPUI Kit)
│ ├── core/ # dbcrust-gui-core: workers, storage, models (no GPUI)
│ ├── src/ # dbcrust-gui: views, workspace, commands
│ └── ARCHITECTURE.md # module map and design language
├── python/ # Python package (PyO3 + maturin)
├── docs/ # MkDocs Material documentation
├── mise.toml # tool + task definitions
├── bin/mise # mise wrapper: runs a pinned mise without installing it (bin/mise.cmd on Windows)
├── Cargo.toml # workspace root
├── pyproject.toml # Python package metadata
└── mkdocs.yml # docs site config
  • Command system: All backslash commands are variants of a Command enum. The CommandShortcut enum (with strum::EnumIter) auto-generates help text, completion, and dispatch. Never use hardcoded arrays for command lists.
  • Database abstraction: The DatabaseClient and MetadataProvider traits in database.rs define the interface. Each database has its own implementation file.
  • Async: Database operations use tokio + async-trait. Shared state uses Arc<Mutex<T>>.
  • Desktop app: gui/core (dbcrust-gui-core) runs each connection on its own thread with a current-thread runtime + LocalSet (DBCrust futures are !Send and sqlx pools must stay on their runtime); the GPUI views in gui/src await its Send futures. Cancellation is per request via dbcrust_core::database::set_thread_interrupt_flag. The app depends on the shared crates (dbcrust-app, dbcrust-core, dbcrust-drivers, dbcrust-docker, dbcrust-secrets), never on the CLI crate: logic both front ends need goes in those crates.
  • Error handling: thiserror for custom error types. User-facing prompts use inquire.
  • Config: serde with #[serde(default)] for backward compatibility. Separate TOML files for settings, sessions, named queries, and recent connections.

The project uses Commitizen for conventional commits:

Terminal window
cz commit # interactive commit
cz bump # bump version based on commit history