Repository navigation
v0.9.0
Release v0.9.0
📦 NPM packages
🐳 Docker image
docker pull ms2data/malloy-publisher:0.9.0
docker pull ms2data/malloy-publisher:latest
ℹ️ Details
- Release branch:
release/sdk-0.9.0 - Triggered by: @housejester
The Docker image no longer ships Node or Python, and refreshes Debian packages daily
ms2data/malloy-publisher no longer installs Node.js from the NodeSource repository, which also removes the Debian python3.13 packages that NodeSource's nodejs package depends on. The server runs under Bun and does not use either. Removing Python also drops netbase and media-types, which only Python pulled in, so /etc/services, /etc/protocols and /etc/mime.types are no longer in the image and getent services https fails; the server reads none of them.
A node command inside the image now resolves to the Bun-backed fallback that the oven/bun base provides, rather than /usr/bin/node (Node 20). That wrapper runs node file.js and node -e, but it rejects node --version and node -v ("does not support a repl"), so a healthcheck or script that calls those needs to change. python3 is no longer present either. A FROM ms2data/malloy-publisher image or a docker exec script that calls /usr/bin/node or python3 by path needs to install it; /usr/bin/env node still finds the fallback.
Image builds also pick up Debian security updates the day they are published, instead of waiting for the ISO week to roll over.
Malloy 0.0.434: two security fixes, and changes that can break a model
Publisher now builds on @malloydata/* 0.0.434, up from 0.0.432. Two of the changes are security fixes:
- An unsafe
timezone:name is now a compile error (malloydata/malloy#3089). On 0.0.432 any ad-hoc query could put raw SQL intimezone:, and it ran past givens and#(authorize). It now fails withInvalid timezone. - The tag parser no longer writes onto
Object.prototype(malloydata/malloy#3078). A model annotation such as# __proto__ { a=b }or##! __proto__ { a=b }used to write onto shared objects in the server process, after which every later tag parse failed, for every package on that worker. Publisher had a guard on the#annotations it reads itself. The parser fix makes it unnecessary, so it is removed. One effect: while anything had added an accessor toObject.prototype, the guard refused every given's filter control. That no longer happens.
These can stop an existing model compiling, or change what a query returns:
select: *leaves out private fields (malloydata/malloy#3051). A query that does-> { select: * }and then names a private field in a later stage stops compiling with'<field>' is not defined. A data-app page that read that column from the result now getsundefined, with no error.- MySQL
TINYINT(1)andBOOLEANcolumns are integers, not booleans (malloydata/malloy#3058). A MySQL model withwhere: is_activestops compiling on reload; writewhere: is_active = 1. DECIMAL values are also cast differently. - Generated SQL changes for filtered joins, including how BigQuery packs them (malloydata/malloy#3075), and for the ordering of multi-stage nests (malloydata/malloy#3083). Results should not change; SQL you compare or cache will.
- The Trino driver moves to
@trinodb/trino-js-client(malloydata/malloy#3066).
The Docker image runs the server as a non-root user
ms2data/malloy-publisher now runs the server as bun, uid 1000 and gid 1000, instead of root. Its USER is the numeric 1000:1000, so a Kubernetes pod with runAsNonRoot: true starts without also setting runAsUser. The DuckDB CLI and the baked extensions move from /root/.duckdb/ to /home/bun/.duckdb/, and the image sets HOME=/home/bun.
If you persist /publisher/publisher_data in a named volume that an earlier image wrote to, chown it before you upgrade. That volume holds root-owned files the new server cannot write to. The server still reports serving, but each environment it cannot write is missing, and GET /api/v0/status lists it under loadErrors with EACCES: permission denied. The fix:
# docker run: name the volume you mount
docker run --rm --user 0 --entrypoint chown \
-v publisher_data:/publisher/publisher_data \
ms2data/malloy-publisher -R 1000:1000 /publisher/publisher_data
# Compose: run it through the service, from the directory holding docker-compose.yml
docker compose run --rm --no-deps --user 0 --entrypoint chown \
publisher -R 1000:1000 /publisher/publisher_dataUse the Compose form under Compose. Compose names the volume <project>_publisher_data, so the docker run form would chown a new, empty publisher_data volume, exit 0, and leave the real one root-owned.
A new named volume on /publisher/publisher_data needs nothing: Docker seeds it from the image, ownership included. It is the only writable mount point the image prepares. A new named volume anywhere else, such as a local DuckLake bucketUrl, starts root-owned and must be chowned to uid 1000 first; DuckDB reports that case as No such file or directory, not EACCES. A bind mount the server writes to must be writable by uid 1000. A read-only mount, such as the config file, only has to be readable. Until you can change the ownership, --user 0 runs the server as root, as before. packages/server/README.docker.md has the details.
What's Changed
- chore(release): stamp 0.8.5 on main by @Sha-Bang in #1270
- feat(eval): run an eval set one command per step, and refuse the setups that broke it by @jswir in #1221
- feat(docker): run the server as a non-root user by @housejester in #1273
- chore(deps): upgrade @malloydata/* to 0.0.434, so select: * leaves out private fields and the tag parser stops writing to Object.prototype by @jswir in #1274
- refactor(server): drop the tag-parser prototype guard now that Malloy 0.0.434 fixes it, and note what 0.0.434 changes by @jswir in #1279
- fix(docker): clear the fixable HIGH image findings and accept the unfixed ones with expiry by @sagarswamirao in #1276
- fix(server): redact URI passwords in linear time in pg_helpers by @sagarswamirao in #1280
Full Changelog: v0.8.5...v0.9.0