diff --git a/CHANGELOG.md b/CHANGELOG.md index 1358bcb..8643547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.7] - 2026-06-10 + ### Added - **Parameter binding over the wire (`$1`..`$N`).** Clients can send a query template plus positional values instead of interpolating untrusted input diff --git a/Cargo.lock b/Cargo.lock index f23488b..2699774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1820,7 +1820,7 @@ dependencies = [ [[package]] name = "powdb-auth" -version = "0.4.6" +version = "0.4.7" dependencies = [ "argon2", "serde", @@ -1832,7 +1832,7 @@ dependencies = [ [[package]] name = "powdb-backup" -version = "0.4.6" +version = "0.4.7" dependencies = [ "blake3", "powdb-query", @@ -1843,7 +1843,7 @@ dependencies = [ [[package]] name = "powdb-bench" -version = "0.4.6" +version = "0.4.7" dependencies = [ "criterion", "powdb-query", @@ -1854,7 +1854,7 @@ dependencies = [ [[package]] name = "powdb-cli" -version = "0.4.6" +version = "0.4.7" dependencies = [ "powdb-auth", "powdb-backup", @@ -1869,7 +1869,7 @@ dependencies = [ [[package]] name = "powdb-compare" -version = "0.4.6" +version = "0.4.7" dependencies = [ "mysql", "postgres", @@ -1881,7 +1881,7 @@ dependencies = [ [[package]] name = "powdb-query" -version = "0.4.6" +version = "0.4.7" dependencies = [ "powdb-storage", "rustc-hash", @@ -1892,7 +1892,7 @@ dependencies = [ [[package]] name = "powdb-server" -version = "0.4.6" +version = "0.4.7" dependencies = [ "bytes", "powdb-auth", @@ -1912,7 +1912,7 @@ dependencies = [ [[package]] name = "powdb-storage" -version = "0.4.6" +version = "0.4.7" dependencies = [ "bytes", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index bbc90a5..c6612b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["crates/*"] [workspace.package] -version = "0.4.6" +version = "0.4.7" edition = "2021" rust-version = "1.93" license = "MIT" diff --git a/README.md b/README.md index a4bbe94..8824b58 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ Before exposing `powdb-server` beyond `127.0.0.1`: - [ ] Enable TLS via `POWDB_TLS_CERT` and `POWDB_TLS_KEY` (or run behind a TLS-terminating proxy). Set `POWDB_REQUIRE_TLS=1` to make the server refuse to start with a password but no TLS, so credentials can never transit in cleartext by misconfiguration. - [ ] Bind to a specific interface with `--bind` rather than `0.0.0.0` if you can. - [ ] Mount `POWDB_DATA` on a persistent, durable volume. WAL replay assumes the directory is not wiped between restarts. -- [ ] Pin the version (`cargo install powdb-server --version 0.4.6 --locked` or the matching ghcr tag). PowDB is pre-1.0; minor bumps may change on-disk formats. +- [ ] Pin the version (`cargo install powdb-server --version 0.4.7 --locked` or the matching ghcr tag). PowDB is pre-1.0; minor bumps may change on-disk formats. - [ ] Wrap bulk loads and write bursts in a transaction (`begin` … `commit`) — one fsync per batch instead of per row, ~50x write throughput with identical durability. See [Write throughput & durability](#write-throughput--durability). - [ ] Size `POWDB_QUERY_MEMORY_LIMIT` for your host's RAM: it bounds a **single** query's materialization, not aggregate concurrent usage, so the 256 MiB default times many simultaneous connections can still exceed the process ceiling and get OOM-killed on memory-capped hosts (Railway/Fly/small AWS). Lower it accordingly. diff --git a/RELEASES.md b/RELEASES.md index 07abc25..03d9a7d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3,7 +3,7 @@ Every PowDB release ships to the following registries and platforms. When cutting a release, follow the checklist at the bottom. -> **Current release: v0.4.6** (all six crates live on crates.io). +> **Current release: v0.4.7** (all six crates live on crates.io). > **v0.4.1, v0.4.2, and v0.4.3 are yanked** for crash-recovery data-loss bugs; > 0.4.4 fixed them and added a standing durability regression suite. See > `CHANGELOG.md`. diff --git a/SECURITY.md b/SECURITY.md index 3d45e94..c951fbe 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,8 @@ | Version | Supported | | --------------- | ------------------ | -| 0.4.6 | :white_check_mark: | +| 0.4.7 | :white_check_mark: | +| 0.4.6 | :x: (superseded) | | 0.4.5 | :x: (superseded) | | 0.4.4 | :x: (superseded) | | 0.4.1 – 0.4.3 | :x: (yanked) | @@ -16,7 +17,7 @@ > **v0.4.1, v0.4.2, and v0.4.3 are yanked** for data-loss bugs in crash > recovery and have been replaced by **v0.4.4**, which adds a permanent > durability regression suite. If you are on any of those three versions, -> upgrade to the latest release (0.4.6). See `CHANGELOG.md` for details. +> upgrade to the latest release (0.4.7). See `CHANGELOG.md` for details. ## Reporting a Vulnerability diff --git a/crates/backup/Cargo.toml b/crates/backup/Cargo.toml index ab8763f..7252fc8 100644 --- a/crates/backup/Cargo.toml +++ b/crates/backup/Cargo.toml @@ -12,10 +12,10 @@ categories = ["database", "database-implementations"] documentation = "https://docs.rs/powdb-backup" [dependencies] -powdb-storage = { version = "0.4.6", path = "../storage" } +powdb-storage = { version = "0.4.7", path = "../storage" } serde.workspace = true serde_json.workspace = true blake3.workspace = true [dev-dependencies] -powdb-query = { version = "0.4.6", path = "../query" } +powdb-query = { version = "0.4.7", path = "../query" } diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b97dc43..87666ee 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -12,11 +12,11 @@ categories = ["database", "command-line-utilities"] documentation = "https://docs.rs/powdb-cli" [dependencies] -powdb-storage = { version = "0.4.6", path = "../storage" } -powdb-query = { version = "0.4.6", path = "../query" } -powdb-server = { version = "0.4.6", path = "../server" } -powdb-backup = { version = "0.4.6", path = "../backup" } -powdb-auth = { version = "0.4.6", path = "../auth" } +powdb-storage = { version = "0.4.7", path = "../storage" } +powdb-query = { version = "0.4.7", path = "../query" } +powdb-server = { version = "0.4.7", path = "../server" } +powdb-backup = { version = "0.4.7", path = "../backup" } +powdb-auth = { version = "0.4.7", path = "../auth" } rustyline = "15" tokio = { version = "1", features = ["rt", "rt-multi-thread", "net", "io-util", "macros"] } tracing.workspace = true diff --git a/crates/query/Cargo.toml b/crates/query/Cargo.toml index eeef277..da91b72 100644 --- a/crates/query/Cargo.toml +++ b/crates/query/Cargo.toml @@ -12,7 +12,7 @@ categories = ["database", "database-implementations", "parser-implementations"] documentation = "https://docs.rs/powdb-query" [dependencies] -powdb-storage = { version = "0.4.6", path = "../storage" } +powdb-storage = { version = "0.4.7", path = "../storage" } thiserror.workspace = true tracing.workspace = true rustc-hash.workspace = true diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 3cbd394..60deeb0 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -12,9 +12,9 @@ categories = ["database", "database-implementations", "network-programming"] documentation = "https://docs.rs/powdb-server" [dependencies] -powdb-storage = { version = "0.4.6", path = "../storage" } -powdb-query = { version = "0.4.6", path = "../query" } -powdb-auth = { version = "0.4.6", path = "../auth" } +powdb-storage = { version = "0.4.7", path = "../storage" } +powdb-query = { version = "0.4.7", path = "../query" } +powdb-auth = { version = "0.4.7", path = "../auth" } tokio = { version = "1", features = ["rt-multi-thread", "net", "io-util", "macros", "sync", "time", "signal"] } tokio-rustls = "0.26" rustls-pemfile = "2" diff --git a/crates/server/src/handler.rs b/crates/server/src/handler.rs index 884826e..af7045f 100644 --- a/crates/server/src/handler.rs +++ b/crates/server/src/handler.rs @@ -204,6 +204,7 @@ const SAFE_ERROR_PREFIXES: &[&str] = &[ "already exists", "permission denied", "row too large", + "unique constraint violation", ]; /// Sanitize an error message before sending it to the client. @@ -666,6 +667,26 @@ mod tests { assert_eq!(value_to_display(&Value::Empty), "null"); } + // ---- Error sanitization allowlist ---- + + #[test] + fn unique_violation_error_surfaces_to_remote_clients() { + // The storage layer reports the actionable message; the server must + // not replace it with the generic "query execution error". + assert_eq!( + sanitize_error("unique constraint violation on User.email"), + "unique constraint violation on User.email" + ); + } + + #[test] + fn internal_errors_stay_generic() { + assert_eq!( + sanitize_error("some internal io panic detail"), + "query execution error" + ); + } + // ---- Role enforcement (Fix: readonly role was not enforced) ---- fn parsed(q: &str) -> powdb_query::ast::Statement { diff --git a/docs/getting-started.md b/docs/getting-started.md index f457087..aa4106c 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -44,7 +44,7 @@ cargo run --release -p powdb-cli You should see: ``` -PowDB v0.4.6 — embedded mode +PowDB v0.4.7 — embedded mode Data directory: ./powdb_data Type PowQL queries. Use Ctrl-D to exit. @@ -445,9 +445,9 @@ cargo run --release -p powdb-cli -- --remote localhost:5433 Output: ``` -PowDB v0.4.6 — remote mode +PowDB v0.4.7 — remote mode Connecting to localhost:5433 ... -Connected to db `main` (server v0.4.6) +Connected to db `main` (server v0.4.7) Type PowQL queries. Use Ctrl-D to exit. powql> diff --git a/docs/powdb-vs-sqlite.md b/docs/powdb-vs-sqlite.md index 85513b3..641ce86 100644 --- a/docs/powdb-vs-sqlite.md +++ b/docs/powdb-vs-sqlite.md @@ -138,7 +138,7 @@ Results land in `crates/compare/results.csv`. ## Caveats and roadmap - **PowDB is pre-1.0.** The on-disk format may shift across minor versions. - Pin a version (`cargo install powdb-cli --version 0.4.6 --locked`) and + Pin a version (`cargo install powdb-cli --version 0.4.7 --locked`) and expect to re-bench / re-import on upgrades until 1.0. - **SQLite is the safe default.** Decades of production exposure, an enormous test suite, and tools everywhere. If you're not sure, you diff --git a/examples/deploy/README.md b/examples/deploy/README.md index 7b25d3d..31d38cc 100644 --- a/examples/deploy/README.md +++ b/examples/deploy/README.md @@ -40,13 +40,13 @@ docker run -d --name powdb \ -e POWDB_DATA=/data \ -e POWDB_BIND=0.0.0.0 \ -e POWDB_PASSWORD=change-me \ - ghcr.io/zvn-dev/powdb:v0.4.6 + ghcr.io/zvn-dev/powdb:v0.4.7 ``` ## AWS ECS Fargate + EFS [`aws-ecs/`](./aws-ecs/) is a Terraform module that provisions an ECS -cluster, a single Fargate task running `ghcr.io/zvn-dev/powdb:v0.4.6`, and +cluster, a single Fargate task running `ghcr.io/zvn-dev/powdb:v0.4.7`, and an EFS file system backing `POWDB_DATA`. Read [`aws-ecs/README.md`](./aws-ecs/README.md) for trade-offs (single-writer, EFS fsync latency) before applying. diff --git a/examples/deploy/aws-ecs/README.md b/examples/deploy/aws-ecs/README.md index 431cfdf..02b14ca 100644 --- a/examples/deploy/aws-ecs/README.md +++ b/examples/deploy/aws-ecs/README.md @@ -1,6 +1,6 @@ # PowDB on AWS ECS Fargate + EFS -A minimal Terraform module that runs `ghcr.io/zvn-dev/powdb:v0.4.6` as a +A minimal Terraform module that runs `ghcr.io/zvn-dev/powdb:v0.4.7` as a single Fargate task with persistent storage on EFS. This is a starting point, not a turnkey production deploy — read the trade-offs below before you `terraform apply`. @@ -71,7 +71,7 @@ front for a stable DNS name. | Name | Default | Notes | |---|---|---| | `powdb_password_secret_arn` | _(required)_ | Secrets Manager ARN holding `POWDB_PASSWORD`. | -| `powdb_image` | `ghcr.io/zvn-dev/powdb:v0.4.6` | Pin to a digest in production. | +| `powdb_image` | `ghcr.io/zvn-dev/powdb:v0.4.7` | Pin to a digest in production. | | `powdb_port` | `5433` | TCP wire protocol port. | | `task_cpu` | `512` (0.5 vCPU) | Fargate CPU units. | | `task_memory` | `1024` MiB | Must satisfy Fargate cpu↔memory ratios. | diff --git a/examples/deploy/aws-ecs/variables.tf b/examples/deploy/aws-ecs/variables.tf index d31d999..9e86d37 100644 --- a/examples/deploy/aws-ecs/variables.tf +++ b/examples/deploy/aws-ecs/variables.tf @@ -13,7 +13,7 @@ variable "name_prefix" { variable "powdb_image" { description = "Container image for powdb-server." type = string - default = "ghcr.io/zvn-dev/powdb:v0.4.6" + default = "ghcr.io/zvn-dev/powdb:v0.4.7" } variable "powdb_port" { diff --git a/examples/deploy/cloudflare-tunnel/README.md b/examples/deploy/cloudflare-tunnel/README.md index 72f3676..c23fc41 100644 --- a/examples/deploy/cloudflare-tunnel/README.md +++ b/examples/deploy/cloudflare-tunnel/README.md @@ -6,7 +6,7 @@ no static IP needed. Clients connect through Cloudflare's edge. ## What this example does -- Runs `ghcr.io/zvn-dev/powdb:v0.4.6` on an internal docker network. +- Runs `ghcr.io/zvn-dev/powdb:v0.4.7` on an internal docker network. - Runs `cloudflare/cloudflared` as a sidecar that establishes an outbound-only tunnel to Cloudflare. - Routes the hostname you own (e.g. `powdb.example.com`) over TCP into diff --git a/examples/deploy/cloudflare-tunnel/docker-compose.yml b/examples/deploy/cloudflare-tunnel/docker-compose.yml index e9a6729..2a6e474 100644 --- a/examples/deploy/cloudflare-tunnel/docker-compose.yml +++ b/examples/deploy/cloudflare-tunnel/docker-compose.yml @@ -20,7 +20,7 @@ services: powdb-server: - image: ghcr.io/zvn-dev/powdb:v0.4.6 + image: ghcr.io/zvn-dev/powdb:v0.4.7 container_name: powdb-server restart: unless-stopped environment: diff --git a/site/getting-started.html b/site/getting-started.html index 1ceb4c7..4cd88c7 100644 --- a/site/getting-started.html +++ b/site/getting-started.html @@ -55,7 +55,7 @@

2Start the REPL

cargo run --release -p powdb-cli

You should see:

-
PowDB v0.4.6 -- embedded mode +
PowDB v0.4.7 -- embedded mode Data directory: ./powdb_data Type PowQL queries. Use Ctrl-D to exit. @@ -208,9 +208,9 @@

Start the server

Connect from a client

powdb-cli --remote localhost:5433
-
PowDB v0.4.6 -- remote mode +
PowDB v0.4.7 -- remote mode Connecting to localhost:5433 ... -Connected to db `main` (server v0.4.6) +Connected to db `main` (server v0.4.7) Type PowQL queries. Use Ctrl-D to exit. powql>