Releases

SparkLabX follows semantic versioning. Pre-1.0 means minor versions may introduce breaking changes; patches are always backwards-compatible.

0.3.1

Latest2026-06-19

Backend hardening — same connectors & SSO from v0.3.0, on a sturdier foundation.

Backend hardening — same connectors & SSO from v0.3.0, on a sturdier foundation.

Backend

  • Native pgx driver replaces lib/pq, with versioned, embedded schema migrations (golang-migrate) that adopt an existing database or provision a fresh one with no manual step.
  • Routes split by concern (auth / admin / notebooks / kernel / connectors) — a leaner entrypoint and a route map that’s easy to scan.

Fixes & polish

  • Connector labels in the sidebar now line up regardless of each source’s icon shape (fixed-width icon box).

Security & CI

  • Cleared the high-severity frontend advisories (npm audit clean at high), CodeQL upgraded to v4 and run on the default branch, and golangci-lint gates only newly-introduced issues.
View on GitHub →

0.3.0

Stable2026-06-17

UI-managed data connectors + SSO — query Trino / Postgres / MySQL as your own identity.

UI-managed data connectors + SSO — query Trino / Postgres / MySQL as your own identity.

Data connectors

  • Add a source from the UI — structured Host / Port / Database / SSL, no JDBC string to memorize, for Trino, PostgreSQL and MySQL. Browse its catalog → schema → table → columns, and query from any notebook with one helper in both languages: query("<id>", "SELECT ...").
  • Personal & per-user identity — each connector is owned by you and authenticates as your SSO identity. The app mints a short-lived RS256 JWT that the source validates via the app’s JWKS (app-as-issuer), so Trino’s own access control keys off the real user. Optional broker-mapped username/password (AES-GCM at rest) for sources without SSO.

SSO

  • Google / Microsoft / generic OIDC (Keycloak, Okta, Auth0) alongside username/password, gated by the email allowlist.

Spark & kernel

  • Per-notebook Spark UI — each notebook’s Spark UI binds its own port, so the in-app Spark UI proxy always shows the right kernel.
  • DataFlint on by default for PySpark and Scala — a performance tab in the Spark UI that flags slow stages, skew, and oversized scans.

Security

  • SSRF guard on connector requests (blocks cloud-metadata endpoints), hardened Spark-UI cookie, and repo-wide scanning (CodeQL / Dependabot / npm audit / golangci-lint).
View on GitHub →

0.2.0

Stable2026-06-12

Pick your kernel's CPU & RAM per session — admin-curated presets plus capped custom sizing.

Pick your kernel’s CPU & RAM per session — admin-curated presets plus capped custom sizing.

Resource presets

  • Resources picker in the Connect Kernel dialog — a vertical radio list of admin-defined sizes (e.g. Medium 1 vCPU · 2 GB, Large 2 · 4, XLarge 4 · 8) with the default badged, plus an optional Custom row taking plain numbers (cores / GB) under admin-set ceilings. Fixes #41.
  • Kubernetes: the picked size is applied as request and limit — Guaranteed QoS, the user gets exactly what they picked. Docker: applied as the container’s CPU/memory limits.
  • Resize on connect — picking a size different from the running kernel restarts it at the new size. The dialog shows the running kernel’s size with an explicit warning (the kernel is per-user, so other notebooks on it reconnect with cleared variables).
  • Server-side validation — unknown preset ids, malformed quantities, sizes over the admin caps, and sub-floor values (<0.1 core, <128Mi) are rejected with clear 400s.
  • Opt-in via kernel.resources.presets in values.yaml — with no presets defined the picker is hidden and upgrading changes nothing.

Library feedback

  • Failed library installs are no longer silent (#33). A bad Maven coordinate now raises a toast naming the coordinate(s) that failed to resolve — on connect and on Manage Libraries → Apply & Restart — instead of a later cryptic ClassNotFoundException. Detected from the kernel log (PySpark) and the init-cell error (Scala/Almond), so neither kernel slips through.
  • Honest failure state: a resolution failure shows a red Spark not ready badge (not a misleading green Connected), blocks Run / Run All, and offers a Fix libraries action. The kernel stays alive for a fast in-pod fix — no teardown, and no more Booting Spark… / starting badge stuck until a page reload.

Fixes

  • Resources picker shows the running kernel’s size immediately after a connect/resize — previously it stayed hidden on k8s until metrics-server scraped (~15s).
  • Resource-usage widget (docker) read the CPU quota from static config — now reads the live per-container limit, so per-session sizes report correctly.
  • “Disconnecting…” badge could spin forever when the backend was unreachable — the disconnect request now has a timeout and the local state always lands.
  • Kernel pod termination grace cut 30s → 5s — kernels hold no durable state, so resize/restart now completes in ~12s instead of ~40s.
  • Spawn no longer re-reads pod sizes from the DB row mid-spawn — a concurrent destroy could race the read and silently revert the pod to default sizes.
View on GitHub →

0.1.5

Stable2026-06-11

Persistent kernel recorder — tab close no longer loses cell output.

Persistent kernel recorder — tab close no longer loses cell output.

Recorder

  • Per-kernel singleton WebSocket to JKG, independent of any client. Captures every iopub message, attributes it to a cell via metadata.sparklabx_cell_id registered on execute_request, and persists output to notebook_cells.last_output with a 500 ms debounce. Closing the tab no longer drops in-flight output — the next page load shows it.
  • State restore on reload via GET /kernel/active-executions fired before the WebSocket opens. Running cells come back with their original startedAt, queued cells stay queued. No envelope ordering races because the restore is HTTP, not WS.
  • Completion detected via iopub status:idle (broadcast) instead of execute_reply (shell channel, session-scoped). A reloaded tab can now clean up cell state when the original execution finishes or gets interrupted.

Run All

  • Queues every cell upfront instead of chaining via onComplete. The kernel’s native FIFO + stop_on_error takes over, so closing the tab mid-batch no longer halts the rest of the cells. iopub status:busy promotes a queued cell into running when the kernel picks it up; KernelStartedAt on the backend record measures runtime from real start, excluding queue wait.

UX polish

  • Spark re-init skipped on tab reload when the kernel pod is unchanged (kernel_id persisted in localStorage). Eliminates the spurious “Booting Spark…” badge and fake “Stop All” button after Cmd+R during a running cell.
  • “Disconnecting…” badge during the kernel disconnect / shutdown round-trip, with a 500 ms floor so the state stays visible on fast backends. flushSync + status guard so the badge transition isn’t clobbered by ws.onclose.
  • Toolbar stability: fixed-width language badge, connection-status badge, Connect/Disconnect button, and notebook name input — switching notebooks or connection states no longer reflows the toolbar.
  • Sidebar files panel: stable row + breadcrumb heights, scope prefix stripped from the path (My Space / Public is already shown in the tabs), back arrow always renders (disabled at root).
  • Admin Storage page: renamed “Buckets” → “Spaces” for consistency with the sidebar, friendly bucket names (My Space / Public), correct s3a:// path on Copy (resolves via getUserDataPath() instead of emitting the logical name), table-fixed rows so long filenames don’t bump row heights.
  • Drop interrupt-on-leave — the warning prompt + auto-interrupt are gone, the recorder makes them unnecessary.
View on GitHub →

0.1.4

Stable2026-06-10

Notebook UX overhaul + idle-reaper safety net.

Notebook UX overhaul + idle-reaper safety net.

Notebook UX

  • Interrupt running cell without restarting the kernel. Per-cell Run morphs into Stop while executing; toolbar ‘Run All’ morphs into ‘Stop All’. SIGINT cancels the active Spark job — SparkSession, imports, variables, and cached DataFrames all survive. Fixes #45.
  • Live elapsed-time timer ticks every 100 ms while a cell runs (N.NNs format, matches the final badge).
  • Final execution time shows immediately on execute_reply (previously relied on a DB write that never happened automatically).
  • Refuses Run on a second cell while another is executing — toast ‘Kernel is busy’ instead of two cells sharing one SIGINT.

Reliability

  • Idle reaper no longer kills pods mid-execution when the browser tab is closed during a long Spark job. Checks Jupyter execution_state before deleting. Applies to both k8s_per_user and docker_per_user modes. Fixes #44.
View on GitHub →

0.1.3

Stable2026-06-08

Backend reliability + security release.

Backend reliability + security release.

Reliability

  • Backend DB retry — wrap startup db.Ping() in a 30-attempt loop (~2 min budget). Fresh helm install no longer crashloops while postgres warms up. Same loop also absorbs network blips and postgres failovers during runtime. Fixes #37.

Security

  • 17 Go stdlib CVEs cleared via toolchain bump (go 1.26.0 → 1.26.4) and golang.org/x/net v0.54.0 → v0.55.0. Includes crypto/x509 (×6), crypto/tls KeyUpdate DoS, net/http2 infinite loop, html/template XSS, net/mail quadratic parsing. govulncheck ./... reports clean.

CI

  • Bump actions/setup-go@v5 → @v6 and actions/checkout@v5 → @v6 for Node 24 compatibility.
View on GitHub →

0.1.2

Stable2026-06-07

Frontend lint + UX cleanup.

Frontend lint + UX cleanup.

UX

  • Login UI: drop Student/Admin button label dichotomy; placeholder uses admin@sparklabx.com
  • README: embed login screenshot after the quickstart block

Code quality

  • ESLint: 119 warnings cleared to 0 errors / 0 warnings
  • Removed CRA leftovers (nginx-kubernetes.conf, docker-entrypoint.sh, reportWebVitals) — net -440 lines
  • Squash-merge workflow for dev → test → main promotion chain
View on GitHub →

0.1.1

Stable2026-06-07

CORS, kernel pre-pull, CI pipeline.

CORS, kernel pre-pull, CI pipeline.

  • CORS wildcard handling + WebSocket bypass for dev/staging custom domains
  • Kernel image pre-pull: docker-compose kernel-cache + Helm kernel-prepuller DaemonSet. Fixes #26.
  • Frontend Service type configurable — ClusterIP / NodePort / LoadBalancer
  • CI pipeline — build/lint/test on PR + push to dev/test
View on GitHub →

0.1.0

Stable2026-06-04

First public release.

First public release.

  • PySpark + Scala (Almond) kernels bundled and configured
  • Per-user kernel pod isolation (Kubernetes) or per-user container (Docker)
  • OAuth login (Google + Microsoft) with email allow-list
  • MinIO IAM per-user prefix enforcement
  • Single Helm install or docker compose up
View on GitHub →