feat(dist): curl|sh install for the local runner + CI releases#54
Merged
Conversation
Distribute the Python local runner as a downloadable bundle so users can run it with just python3 — no clone, no Node. - install.sh (root): POSIX `curl | sh` installer. Resolves the latest release, downloads altinity-sql-browser.tar.gz, verifies the sha256, extracts to ~/.altinity-sql-browser, installs a launcher in ~/.local/bin. (Distinct from deploy/install.sh, which deploys onto a ClickHouse cluster.) - build/bundle.sh: assemble the release tarball (prebuilt sql.html + local.py + config.example.xml + self-resolving run.sh + VERSION/README) with a sha256. - build/local.py: discover sql.html across layouts — $SQL_BROWSER_SPA, then next-to-the-script (bundle), then ../dist (dev) — so the same runner works in the bundle and in a checkout. - deploy/clickhouse-client-config.example.xml: a sample connections file shipped in the bundle as config.example.xml; it never replaces the user's real ~/.clickhouse-client/config.xml. - .github/workflows/release.yml: on a v* tag → gate + bundle + gh release. - .github/workflows/ci.yml: new `bundle` job smoke-tests the artifact on every PR (extract → boot the runner → fetch /sql + /config.json) and shellchecks the installer. - README: curl|sh quick-install + a Releasing section. Verified locally: bundle builds, extracts, boots under the sample config (SPA found via bundle layout, config.json hosts parsed), and the dev layout still serves from ../dist. Coverage gate unchanged (952 passing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
…demos Refines the bundle from real, verified connections and adds a second connection source so a fresh install has something to connect to. - build/local.py: read connections from MULTIPLE files and merge, de-duped by name (first wins): ~/.clickhouse-client/config.xml (the user's own, wins on a clash), then ~/.clickhouse-client/sql-browser.xml (installed demos), then a sql-browser.xml next to the runner (run-from-bundle). LOCAL_CH_CONFIG still overrides to a single explicit file. Document that the HTTP port comes from <http_port> or the 8443/8123 default — the native <port> (9440/9000) is never used to derive it. - deploy/sql-browser.xml: replaces the placeholder example with PUBLIC demo clusters verified reachable over the HTTP interface (antalya, altinity-demo, clickhouse-sql) + a commented OAuth template (no real secret). Dropped play.clickhouse.com: it exposes no HTTP query interface (native-only), so the browser can't reach it. - install.sh: write the sample to ~/.clickhouse-client/sql-browser.xml (backing up any existing one); never touches config.xml. - build/bundle.sh + ci.yml: ship/smoke-test sql-browser.xml; the CI boot test now relies on the runner discovering it next to local.py (no LOCAL_CH_CONFIG). - README: document the merge + the http-port rule. Verified: merge keeps config.xml on a name clash (5 real → 5, demos deduped); fresh machine (bundled file only) → 3 demos; gate 952 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
…int table The picker only offers connections the browser can actually POST to. At startup the runner resolves each connection's HTTP URL, probes /ping concurrently, prints a status table to stdout, and serves only the reachable hosts — so a native-only endpoint (e.g. play.clickhouse.com, no HTTP interface) is shown as skipped with a reason instead of being a dead pick in the picker. - build/local.py: split build_config into pure collect()/serialize(); add probe() (GET /ping, unverified TLS for accept-invalid hosts; "reachable" = any HTTP response, "unreachable" = connection-level failure) + concurrent probe_all(); main() probes, prints the table, and serializes only kept hosts (dropping an unreachable OAuth host also drops its now-dangling IdP). Flushed so the table shows immediately. SQL_BROWSER_PROBE=0 / SQL_BROWSER_PROBE_TIMEOUT to control it. - ci.yml: smoke test sets SQL_BROWSER_PROBE=0 (don't depend on external hosts). - README + docstring: document the probe + skip behavior. Verified against the real config: 4/5 reachable, clickhouse-play skipped (timed out — native-only); served config.json excludes it. Gate 952 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
Port discovery is core to the runner: a cluster may serve the HTTP interface on 8443 (direct) or 443 (TLS-terminating proxy), and the config only carries the native <port>. So when no <http_port> is given, try both standard ports and pin whichever answers Ok. on /ping; only skip a host when NO port has an HTTP interface. - collect(): build a per-host candidate list (_alts) — [8443,443] secure / [8123,80] plain, or the single explicit/embedded port; default url = first. - probe(): try candidates in order, first /ping == "Ok." wins; returns the chosen URL (port pinned) or None. serialize() strips the internal _alts field. - main(): table shows the winning port per host, or the per-port failure reasons for a skip. Effect: clickhouse-play, which times out on :8443, now resolves on :443 (its /ping returns Ok.) → 5/5 reachable instead of being skipped. Gate 952 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
The Connect button required BOTH a username and a non-empty password, so a passwordless user (e.g. ClickHouse `play` on the public playground / our bundled demos) could never connect — the button stayed disabled. Require only a username; an empty password sends HTTP Basic `user:`, which ClickHouse accepts. - src/ui/login.js: hasCreds() now checks the username only. - tests: a username alone enables Connect (primary, "as <user>"); Enter submits with a username and no password; selecting a passwordless saved connection enables Connect. Updated the prior "needs both fields" Enter test. Verified in-browser against the public playground: selecting the passwordless demo enables Connect, login succeeds, and the schema loads. Gate 954 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
Two fixes for cross-origin picker connections: - src/ui/app.js: app.host() returned the serving host (loc.host) in OAuth mode, so signing in via a picker connection that targets another cluster showed "localhost:8900" instead of the cluster. Use chCtx.origin's host for both auth modes — it already resolves to the basic target / oauth_origin / serving origin. (URL.host drops a default :443, so a 443 cluster shows a bare hostname.) - build/local.py: probe 443 before 8443 for secure connections (8123 then 80 for plain). 443 is the canonical public endpoint for managed clusters and avoids the 8443 timeout when only 443 is open; the /ping=='Ok.' check still rejects a 443 auth-gateway and falls through to 8443 (e.g. the support tenant). Verified: header shows antalya.demo.altinity.cloud (cross-origin), all demo clusters resolve on :443 (5/5, no 8443 stall). Gate 955 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #53 (base =
feat/local-accept-invalid-cert). Review/merge #53 first; GitHub will retarget this tomainonce #53 lands. The diff below is distribution-only.What
Distribute the (Python) local runner so users can run it with just
python3— no clone, no Node:Changes
install.sh(repo root) — POSIXcurl | shinstaller: resolves the latest release, downloadsaltinity-sql-browser.tar.gz, verifies the sha256, extracts to~/.altinity-sql-browser, installs a launcher in~/.local/bin. Env overridesASB_VERSION/ASB_HOME/ASB_BIN. Distinct fromdeploy/install.sh(which deploys onto a ClickHouse cluster).build/bundle.sh— assembles the release tarball: prebuiltsql.html+local.py+config.example.xml+ a self-resolvingrun.sh+VERSION/README.txt, with a.sha256. Runnable locally; used by CI.build/local.py— discoverssql.htmlacross layouts ($SQL_BROWSER_SPA→ next-to-script bundle →../distdev), so one runner works both bundled and in a checkout.deploy/clickhouse-client-config.example.xml— a sample clickhouse-client connections file shipped in the bundle asconfig.example.xml. It never replaces the user's real~/.clickhouse-client/config.xml; use it viaLOCAL_CH_CONFIG..github/workflows/release.yml— on av*tag: coverage gate → build bundle →gh release createwith the tarball, checksum, and rawsql.html..github/workflows/ci.yml— newbundlejob smoke-tests the artifact on every PR (extract → boot the runner → fetch/sql+/config.json) and shellchecks the installer.curl | shquick-install + a Releasing section.Testing
run.shunder the sample config:/sql200 (SPA found via bundle layout),/config.jsonhosts parsed (dev-tenant→insecure=true, secure hosts →:8443). Dev layout (build/local.py→../dist) still serves. Coverage gate unchanged (952 passing).bundlejob reproduces the extract-and-boot path on every PR.Cut a release
git tag v0.1.0 && git push origin v0.1.0🤖 Generated with Claude Code
https://claude.ai/code/session_01MUc6UU9qs5J3u7qoy5YoNN