AnnZarro v0.5.0
This release adds an admin web interface to AnnZarro. On a shared server, an administrator can now add data directories, manage users, give an external collaborator only some of the datasets, switch panels and external hosts off, and read the server's health and an audit log, all in the browser. It also protects every state-changing request against forged requests, hardens the server against requests that hold a worker, and makes very large datasets cheaper to open and read.
Admin interface
/admin(login on) has six sections: Users, Data directories, Server health, Panel sets, Settings and Audit log. A change needs the admin's password entered within the last 30 minutes, and every change is written to the audit log. Behind a reverse proxy that terminates TLS, setserver.proxy_count, or the page refuses changes.- Users: add and remove users, reset passwords (a generated password is shown once), grant or revoke admin, and clear a lockout. The last admin cannot be removed or demoted, on the web or on the command line. Everyone can change their own password at Change password in the header.
- Data directories: with
server.admin_data_rootsset, an admin adds directories in the browser, below the parents the operator allows. They appear in the dataset picker at once. - Dataset access for external collaborators: restrict a user to the folders, stores and remote prefixes you grant. Everyone else keeps seeing everything. A restricted user gets the same "not found" for a dataset they may not read as for one that does not exist. Manage it in the Users section (Access), or with
annzarro user access. - Settings: switch panel types off for everyone or one user, and control what Gene Set Analysis may send out (all external hosts, individual services, the species lookup, the Links). The server tells the browser which hosts it may contact and the browser refuses any other. Enrichr and Reactome are off by default on a shared server.
- Server health: each worker's read budget in use, cache size, requests and refusals by reason, and who was seen recently. Panel sets: list by owner, reassign or delete.
GET /statusandGET /cache/infoare now admin-only on a shared server. - Audit log: each record carries the hash of the one before it, so an edit in the middle is found (
annzarro admin audit verify). The log is also written to theannzarro.auditlogger. - A change by an admin, or with
annzarro user ..., reaches every gunicorn worker on its next request, with no restart.
Security
- Every request that changes something now needs the session's token plus a same-origin
Origin(andSec-Fetch-Site). Sign-in has its own one-time token, and signing out is aPOST. - Pages carry a
Content-Security-Policythat lists the external hosts the user's settings allow. - A request body over
server.max_request_mb(64) is refused with413: one with a length before it is read, a chunked one as soon as it passes the limit.
Performance and limits
- Cell and gene names (
/data/cells,/data/genes) are streamed a chunk at a time. For a 95.6 million cell store that is 0.42 GiB and 0.14 s to the first byte, where it was 15.2 GiB and 14.4 s.server.names_stream_max_concurrent(2) bounds the threads slow readers hold. Behind nginx, useproxy_http_version 1.1. - Sharded stores: a subset read takes a shard's rows in bounded batches instead of the whole shard. A 1,000-row read of a 5M x 50 store in one 850 MB shard peaks at 47 MiB instead of 757.
- Colouring by a gene on a cell subset of a CSR
Xreads each chunk once: 10,000 cells of a 175,000-cell store took 70 to 118 s before. - Subsets share the cache and the compute fairly between users. The cell subsets a worker computes at once are charged by their cells against
server.subset_budget_mb(15% of RAM by default); while others wait, one user holds at mostserver.read_user_share_percent(50) of it and of the pairwise read budget. A subset that cannot start withinserver.subset_wait_s(30) is answered503 read_busy, and one larger than the whole budget runs alone. - Numeric subset filters compare the column as the array it is stored as. Six at once on a 95.6 million cell store take 1.8 s and 10.8 GB, where they took 18.8 s and 30.5 GB.
- Regular-expression name search: a pattern that could hold a worker is refused (
400 regex_too_complex, orregex_too_longoverserver.name_search_max_regex_chars), and every match runs underserver.name_search_timeout_s(10 s) with theregexpackage, which stops inside a match. The picker says when a search ran out of time. - Remote stores: one request may spend at most
server.remote_request_timeout_son remote reads (120 s on a shared server, 600 s for one user). Past it the reply is504 remote_deadline. - Other limits: panel-set quotas (
max_sessions_per_user500,max_sessions5,000,max_sessions_mb256),dataset_scan_max_entries(200,000) for the directory listings and/status, aunsmember is sized againstserver.max_read_mbbefore it is read whole (strings by their real length), and gunicorn replaces a worker aftermax_requests(20,000) requests. annzarro store checkreports, from metadata only, what in a store's layout makes AnnZarro slow, with the cost in clicks and a fix for each (--json,--fail-on).- In large-plot mode, hovering finds the nearest point in 1 ms instead of 43 at 95.6 million points, skips categories hidden with the legend, and the large plot's graphics memory is freed when a subset makes the plot regular.
Fixes
- Switching a plot axis between a text field and a number field draws the axis as what the new field is, and refits it. In large-plot mode the x and y pickers grey out the categorical columns, with the reason, until a subset is made.
- A table column named like
orig.identorx.y.zshows its values (they showed N/A). - A wheel zoom of a 3D plot is kept when the focused cell changes or the plot is redrawn.
- The open dataset list follows the window height, up to 70% of it or 640 px, with one scrollbar.
- Center at 0 with Lock Range centres the colour scale on the locked range (±the larger of the two limits) and brings the typed limits back when it is turned off; a locked range of 0 to 0 disables it. Log with Lock Range keeps the typed limits too, so turning Log off restores a typed Min at or below 0. Unlocking a centred panel recentres it at once.
- A panel opened from the welcome page before the first dataset had started loading no longer keeps its "No dataset loaded" screen and hidden controls.
- Splitting a panel, choosing a panel type in a new section and closing a section ease to the new sizes instead of jumping (no animation with the system's reduced-motion setting).
- A missing store is the same
404 not_foundon every data route (five answered 404 or 500 in their own words).
Docs
- New Python API reference (
annzarro.__all__: readers, store check, the server factories, the figure recipe), with types linked to anndata, zarr and numpy. - Desktop app or server: the landing page, the README and a new getting-started page compare the two ways to run AnnZarro and say which to choose.
- New pages: The admin interface and the Admin API; the policy registry; Resource limits; and a section on restricting a user in the authentication guide.
CONTRIBUTING.mdand a code of conduct.- The README and
CITATION.cffcite the bioRxiv preprint.
Desktop
- The macOS app is signed with a Developer ID and notarized by Apple. Install it by opening the
.dmgand dragging AnnZarro to Applications. - The desktop app bundles the
regexpackage; its licence is in the app's third-party notices.
Upgrade notes
- Forged-request checks. Scripts that sign in with a cookie and send
POST,PUTorDELETEmust now send the session's token inX-AnnZarro-CSRF(the page has it in<meta name="annzarro-csrf">).curlandannzarro exporton a server with login off are not affected. Behind a proxy that terminates TLS or rewritesHost, setserver.proxy_count, or every change is refused with403 csrf_failed. - Sign-in and sign-out. The login form carries a one-time
login_csrffield; a script that posts to/loginmust fetch the form first./logoutisPOSTonly;GET /logoutshows a button. - Content-Security-Policy. Every page now has a
connect-srcthat lists only the external hosts the policy allows. A customised page or an embedding that contacts other hosts is refused by the browser. - External hosts. Enrichr and Reactome are off by default on a shared server; switch them on in Settings or with
integrations.gene_set.services.integrations.external_requestsaccepts a new value,none.ANNZARRO_EXTERNAL_REQUESTSbeats the YAML in both directions. /statusand/cache/infoanswer admins only on a shared server.- Remote deadline. A remote read that took longer than
server.remote_request_timeout_sin total now fails with504 remote_deadline. Keep the proxy'sproxy_read_timeoutat or above it (120 s).0turns it off. - Subset budget. Cell subsets now wait for, and are refused past,
server.subset_budget_mbandserver.subset_wait_s; raise them if users see503 read_busyon subsets. - New limits and defaults: the keys under Performance and limits above, all in
server.*; see Resource limits in the docs. The admin state lives inannzarro_admin/beside the users file; back it up with the users file. - Command line.
annzarro usercommands must run as the account that owns the users file's directory.
Downloads
Desktop apps for macOS (Apple silicon and Intel), Windows and Linux are attached below. macOS: open the dmg, drag AnnZarro to Applications and open it. Windows: SmartScreen asks for More info > Run anyway. Details: https://annzarro.readthedocs.io/en/latest/getting-started/desktop-app.html. Verify downloads against SHA256SUMS.txt. The Python package: pip install annzarro.