Multi-AutoML Interface v5.0.1
Multi-AutoML Interface 5.0.1
5.0.1 - 2026-09-28
Second release, published after an audit of the codebase and of the packaged app. It
fixes the local-first MLflow default, closes the multi-session exposures, repairs
several runtime defects and leaves the end-of-life Electron 28 shell.
Fixed
- The app recorded no MLflow runs.
safe_set_experimentfailed on every startup
because MLflow 3 refuses a file-based tracking store unless
MLFLOW_ALLOW_FILE_STOREis set; the test suite set it, so the breakage was
invisible in CI. The desktop app now logs the experiment setup successfully, and a
configuredMLFLOW_TRACKING_URIis honoured instead of being overwritten with the
local path (a shared server or database store was silently ignored before). python run.pylistened on every interface. Streamlit binds0.0.0.0when no
address is given, so the local launcher exposed the app, and the code execution of
the Python behind it, to the whole network. It now binds127.0.0.1unless
--server.addressorSTREAMLIT_SERVER_ADDRESSis supplied, and the DagsHub
credential gate treats an unset address as shared.- Cross-session credential leak. The DagsHub panel wrote a visitor's username and
token into process-globalos.environand never cleared them; in multi-session mode
another user's run would authenticate with them. Per-user tokens are accepted only
when the server is bound to loopback. - Untrusted model loading (CWE-502). All six MLflow flavors are restored with
pickle/joblib, and the run id came from a free-text field against a tracking URI that
the sidebar can repoint. Loading now requires an explicit confirmation in the UI and
rejects run ids containing path characters. - CORS was disabled everywhere. Both containers and the Electron launcher passed
--server.enableCORS=false; with the app reachable from other origins, any page that
could reach the port could read and post to it. Streamlit's defaults now stand, and
Compose publishes 8501/5000 on loopback only. - Leaked host repository into containers. Compose bind-mounted
.:./app, which
also exposed.gitand let the container overwrite source; it now mountsdata_lake/
andmlruns/only. Its MLflow server image (v2.11.1) was also two majors behind the
pinned client and is now version-matched. - Threads that never stopped. The H2O cancellation watcher and telemetry loop only
exited when training returned, so a failed run left them polling inside the shared
process; they are released from afinally. Two concurrent FLAML runs wrote the same
flaml.log, now named per run. - Requests that could hang forever.
dvc initanddvc addran without timeouts and
so could block a session indefinitely; they now bound at 120 and 900 seconds, and the
interpreter probe inrun.pyat 10. - Run history destroyed by the auto-healer.
heal_mlrunsdeleted any numeric
mlruns/directory lackingmeta.yaml, which under multi-session is an experiment
being written right now. It quarantines tomlruns/.trashinstead and skips anything
touched within the last hour. shutil.rmtreeon a path built from user input, ZIP extraction without member
checks, and 14 bareexcept:clauses that swallowedKeyboardInterrupt.queue_experiment()crashed when called without a manager, because it fell back
toget_or_create_manager()without the session state that function requires; the
manager is now an explicit argument, so the orchestrator cannot silently share one
across sessions.run.pyaccepted any interpreter newer than 3.11 while the frameworks need 3.11.
It now re-launches on 3.11 whenever available, warns and continues on a newer
interpreter, and hard-fails only on older ones.- Generated notebooks could not be written in the installed app: the exporter wrote
into the working directory, which is inside Program Files there. They now land under
the system temp directory. - Progress bars disappeared in a terminal. The stdout/stderr router used to capture
per-run logs inheritedio.TextIOBase, whoseisatty()always answers False and whose
fileno()raises - so H2O, FLAML and tqdm disabled their bars even in a real terminal,
and anything probing the descriptor failed. Both now delegate to the underlying stream
and degrade cleanly when there is none. - A cancelled run dropped its result.
refresh_allonly polled entries that were
running or queued, so the payload a cancelled worker still delivered was never read:
entry.resultstayed empty and the UI reported "Unknown" instead of the real outcome.
Cancelled runs are polled too, and a late result no longer relabels the row as
completed or failed. - Desktop shell: external links (
file://, custom schemes) were passed straight to
shell.openExternalwith no navigation guard; Electron moves from the unsupported
28.3.3 to 44.4.5 withelectron-builder26.15.3; the preload assigned
window.electronin its own isolated world where no page could read it, now exposed
throughcontextBridge;npm cireplacesnpm installso the lockfile is respected. - Dependency advisories: mlflow and mlflow-tracing to 3.16.1 and cryptography to
50.0.1, which closes the two advisories 5.0.0 had to leave open (CVE-2026-69247,
CVE-2026-71211). OSV reports no applicable vulnerability for any pin in
requirements.txtandnpm auditreports none for the desktop toolchain.
The unusedskopspin was dropped.
Added
- CI gates that mean something: the nightly full suite is now authoritative when the
dependency stack installs (it wascontinue-on-error),pip-audit --strictruns over
requirements.txt,npm audit --audit-level=highruns before packaging, and both
Python and JS installers now build from lockfiles.pytestinvocations pass
-o addopts=""so the pass/skip summary is not swallowed by a double-q. - Multi-session deployment notes in
docs/DOCUMENTATION.md, plus troubleshooting
entries for the loopback default and the artifact-trust confirmation. - A missing DVC remote is now reported after an upload, because the
.dvcpointer will
not resolve on another machine.
Changed
build-electron.ymlno longer runs the 3-OS matrix on every push tomain; it builds
on packaging changes in pull requests and on manual dispatch, sincerelease.yml
already builds and publishes on tags.
Known limitations
- The app still has no authentication or per-user quota of its own: an internet-facing
deployment must terminate TLS and authentication in a reverse proxy, and sessions
continue to sharemlruns/,models/and the data lake in one working directory. electron/renderer.jsis still not wired into the window; enabling it would overlay a
custom header on the Streamlit UI, which is a design decision rather than a bug fix.- 23
use_container_widthcalls inapp.pyemit Streamlit deprecation warnings past
their announced removal date. They cannot be replaced mechanically:st.pyplothas no
widthargument, so each widget needs its own judgement. - Installers remain unsigned and unnotarized, and still require Python plus
requirements.txton the target machine.
Prerequisites
The desktop installers bundle the Electron shell and the Streamlit UI, not the Python
runtime. Install Python 3.11/3.12 and the app dependencies first:
pip install -r requirements.txtAutoML backends (AutoGluon, PyCaret, TPOT, Lale, H2O, AutoKeras, HuggingFace) are optional
and lazy-imported; see the README for what each one needs.
Installers are not code-signed or notarized, so SmartScreen and Gatekeeper will warn
on first launch.