datastore.com is a dead domain (the debrand pass sed'd clickhouse.com into a
domain we do not own). Point every reference at the Hanzo brand, keeping paths:
datastore.com/cloud -> hanzo.ai/datastore (Datastore cloud product page)
datastore.com/docs/* -> docs.hanzo.ai/* (Hanzo docs site)
datastore.com/blog/* -> hanzo.ai/blog/*
*.datastore.com -> *.hanzo.ai (packages, presentations)
[email protected] -> [email protected]
datastore.com -> hanzo.ai (homepage, company, slack)
26 files, 80 references. config.xml still parses; no double-rewrites.
Co-authored-by: Hanzo Dev <[email protected]>
Runtime regression from the final lowercase pass: it renamed <clickhouse> opening tags to
<datastore> but the / exclusion (protecting /clickhouse paths) left </clickhouse> closing tags,
so embedded + shipped configs became <datastore>...</clickhouse> -> SAXParseException 'Tag
mismatch' at runtime (compile was fine; XML is data). Renamed all <clickhouse/</clickhouse XML
tags -> datastore (101 closes across configs, embedded strings, keeper configs). Path strings
(/var/lib/clickhouse) have no angle bracket and are untouched. Build compiled; this fixes runtime
config parsing.
The prior sweep kept " in the exclusion set to guard the SQL keyword "clickhouse", which
over-protected ALL quoted display strings ("clickhouse " << app in --help, install-tool defaults
like DEFAULT_..._SERVER_USER="clickhouse"/getpwnam("clickhouse")/binary-name fallbacks). Redid the
pass dropping " from the exclusion while still skipping the 4 SQL dict-source keyword lines, URLs,
and /clickhouse + .clickhouse.hash paths (kept . / - in the boundary). Renamed the 2 fuzzer files
clickhouse_fuzzer.cpp / clickhouse-template.g (not built; completeness).
Remaining lowercase clickhouse (526) = URLs, SQL SOURCE(CLICKHOUSE) keyword, and ZK/fs path
conventions (/var/lib/clickhouse, /clickhouse/tables) + internal .clickhouse.hash ELF section —
all protocol/external/convention, intentionally kept.
The correct, safe broad rebrand: renames "ClickHouse" only as a whole word (boundary on
BOTH sides), so it rewrites display strings/messages/comments but leaves every compound
C++ symbol intact — `ClickHouseDictionarySource`, `getInfoIfClickHouseDictionarySource`,
`mainEntryClickHouseServer`, `ClickHouseRevision`, `ClickHouse_SOURCE_DIR` are untouched
(an earlier one-sided heuristic mangled suffix symbols like `manageClickHouse`; reverted).
1677 occurrences across 482 files. Compile-safe (string/comment content; symbols preserved).
Still NOT renamed (would be a build-coupled symbol rename, needs build-host iteration): the
199 compound identifiers containing ClickHouse, the `DB::` namespace, the `clickhouse_*`
CMake targets/macros, the lowercase `clickhouse` SQL dictionary-source keyword. Needs build
verification.
Per reviewer feedback: extract `createClickHouseDatabase` and
`runInitScripts` as separate static functions that return `false`
immediately on the first error. Replace the `init_ok` flag with
short-circuit `&&`. Server cleanup is always performed.
Matches the `set -e` fail-fast semantics of the original
`entrypoint.sh` more clearly.
`clang-analyzer-deadcode.DeadStores` flagged the `init_ok = false` writes
inside the init-script loop because `initClickHouseDB` returned `void` —
the flag was set but never read after the loop exited.
Change `initClickHouseDB` to return `bool`:
- early-skip paths (`database_exists`, no files, `shutdown_requested`)
return `true`
- fork-failure and server-not-ready paths return `false`
- end of function returns `init_ok`
Caller checks the result and returns `1` on failure, matching the
fail-fast behaviour of the other init functions.
- `manageClickHouseUser`: return `bool` instead of `void`; return `false`
on invalid `CLICKHOUSE_USER`/`CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT` so
the caller exits non-zero instead of silently starting with a wrong auth
config.
- `createDirectoryAndChown`: check return value at all call sites (keeper
dirs, server data/log/tmp/disk dirs) and `return 1` on failure.
- `initClickHouseDB`: check `runCommand`/`runPipeline` exit codes for
`CREATE DATABASE` and every init script; stop on first failure (matches
the `set -e` behavior of the original `entrypoint.sh`). Also fixes a
use-after-free UB: the `runPipeline` `.sql.gz` call now uses a named
`decompress_args` variable instead of a brace-initializer temporary.
- `docker-init.cpp`: fix passthrough mode for short tool names ("client",
"local", etc.) — prepend "clickhouse-" since distroless images only have
"clickhouse-*" symlinks, not bare names
- `Dockerfile.distroless` (server, keeper): replace `printf '%b' ... \n ...`
with individual `printf` calls per line to avoid portability ambiguity
- `Dockerfile.distroless` (keeper): add `clickhouse-keeper` to PACKAGES so
the default `/etc/clickhouse-keeper/keeper_config.xml` is present in
the image; copy it to /output during assembly
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Fix 1: The `.sql.gz` filename escaping used backslash-escape (`\'`)
which is not valid ClickHouse SQL. Changed to doubled-quote (`''`)
which is the correct SQL escape for single quotes inside string
literals.
Fix 2: Added `setgroups(0, nullptr)` before `setgid`/`setuid` in the
fork+setuid directory creation path. This clears supplementary groups
before dropping privileges, preventing potential group-based privilege
leakage.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Escape single quotes in `.sql.gz` file paths before interpolating into
the `file()` SQL function, preventing injection via crafted filenames
in `/docker-entrypoint-initdb.d/`
- Install `SIGTERM`/`SIGINT` handlers before `initClickHouseDB` so that
`docker stop` during the init phase triggers graceful shutdown instead
of being silently dropped (Linux ignores unhandled signals for PID 1).
The handler forwards the signal to the temporary init server and sets
a flag that breaks the health-check polling loop.
- When `CLICKHOUSE_DO_NOT_CHOWN=1` and running as root, fork a child
that drops to the target UID/GID before calling `fs::create_directories`.
This matches the bash entrypoint behavior (`clickhouse su … mkdir`) and
fixes directory creation on NFS mounts where root is mapped to nobody.
Distroless has no `mkdir` binary, so the child uses the C++ filesystem
library directly after `setuid`/`setgid`.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Validate `CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT` is exactly "0" or "1"
before embedding in XML, preventing injection via the env variable
- Handle EINTR in all `waitpid` calls so signals don't cause spurious
child-process failure reports
- Use `ends_with` instead of manual `substr` for init-script file
extension matching
- Use CTAD for `clickhouse_tools` array to avoid hardcoded size
- Remove deprecated `version` field from distroless docker-compose.yml
Co-Authored-By: Claude Opus 4.6 <[email protected]>
ClickHouse server uses Poco for CLI parsing. Options before "--" must
be registered; unregistered options trigger "Unknown option specified".
The "--" separator marks positional args, which ClickHouse treats as
config.xml overrides (as documented in the server --help output).
Without "--", starting the initdb temp server fails immediately:
Unknown option specified: listen_host=127.0.0.1
This matches the pattern used in entrypoint.sh (line 191):
clickhouse su USER:GROUP clickhouse-server --config-file=... -- --listen_host=127.0.0.1
Fixes: clickhouse-initdb-skip-user-setup [4/6] and
clickhouse-override-tcp-port [6/6] Docker server image tests.
When do_chown is false (running as uid 101, non-root), createDirectoryAndChown
was delegating to 'clickhouse su UID:GID mkdir -p DIR'. The distroless image
has no mkdir binary, so this always failed, silently leaving coordination
subdirectories and server runtime paths uncreated.
Since we are already running as the target user, fs::create_directories works
directly — no user-switch or external binary is needed. The NFS root-squash
concern that motivated the clickhouse-su-mkdir approach does not apply when
the process is already non-root.
The docker-library `override-cmd` test runs:
docker run "$image" echo "Hello $random"
With the ENTRYPOINT `["/usr/bin/clickhouse", "docker-init"]`, docker-init
receives `["echo", "Hello ..."]` as extra_args. Previously, `echo` was not
in the explicit passthrough list, so docker-init started the full server,
which ran indefinitely — causing a ~4.5-hour timeout in CI.
Fix: mirror `entrypoint.sh` behaviour: if the first extra argument does not
start with `--`, exec it directly without server startup. For recognized
ClickHouse tool names (client, local, etc.) the bin_dir path is used for
correct argv[0]-based dispatch; for generic commands (echo, date, bash, …)
PATH resolution via execvp handles it.
Two bugs addressed:
1. `Dockerfile.distroless` — `cp -r` without `-p` preserves mode bits but
resets ownership to root:root. `clickhouse install` sets `config.xml` to
mode 0400 owned by `clickhouse:clickhouse`; after the copy the file becomes
`root:root 0400`, which uid 101 cannot read (errno 13 EACCES). Fix: expand
the `chown -R clickhouse:clickhouse` target from just `users.d` to the
entire `/output/etc/clickhouse-server` tree.
2. `docker-init.cpp` — the official Docker-library test suite runs client
queries by spawning a second container from the same image:
`docker run "$image" clickhouse-client --host ... --query ...`
Because the distroless ENTRYPOINT is `clickhouse docker-init`, the
client tool name and its arguments land in `extra_args` and were being
forwarded to `clickhouse-server`, causing "Unknown option specified" errors.
Fix: before any server-startup logic, detect a recognised client-side
subcommand as the first extra arg (`clickhouse-client`, `clickhouse-local`,
`clickhouse-keeper-client`, and their short forms) and exec it directly
via its `/usr/bin/` symlink, bypassing server initialisation entirely.
- Replace `#include <signal.h>` with `#include <csignal>` (deprecated C header)
- Remove `#include <sstream>`; replace `std::istringstream` with manual newline split
- Wrap all `close()`/`dup2()` calls with `(void)` (return value must be acknowledged)
- Split `int lhs_status = 0, rhs_status = 0;` into two declarations
(readability-isolate-declaration)
- Replace loop-runs-once `has_init_files` detection with iterator comparison
(clang-diagnostic-unreachable-code-loop-increment)
- Add `// NOLINT(concurrency-mt-unsafe)` to `strerror` and `sleep` call sites
- Rename `initClickHouseDb` → `initClickHouseDB` (abbreviations must be all-caps)
- Add `clickhouse docker-init` C++ subcommand that replaces `entrypoint.sh`
for shell-free distroless environments (fork/exec, POSIX-only, no shell deps)
- Add `docker/server/Dockerfile.distroless` and `docker/keeper/Dockerfile.distroless`
as parallel build targets alongside existing ubuntu/alpine variants
- Add `--no-distroless` CI flag and fix package selector to use `.deb` for distroless
- Add structural smoke-test harness under `docker/tests/distroless/`
The distroless images use `gcr.io/distroless/cc-debian12:nonroot` as base,
expose the same ports as ubuntu, run as uid/gid 101, and include a debug
variant (`distroless-debug`) with a busybox shell for troubleshooting.