Repository navigation
Added
-
The agent now says whether it is verifying OTA update signatures. At startup it logs its update-signature mode and the trust bundle path —
OTA update signature mode: off(no bundle, so update binaries are not signature-checked),bundle, orbundle+require. When auto-update is enabled, the OTA update checker also warns, once, when it first starts (after the agent first connects) if the bundle is set but cannot be loaded. Every heartbeat carries the same mode as the status tagyuzu.ota_signature_mode; the tag is stored by the server, not yet surfaced in any view — the startup log line is the per-endpoint source of truth. The agent also warns at startup about any environment variable starting withYUZU_UPDATE_that it does not read, so a misspelling AFTER theYUZU_UPDATE_prefix (for exampleYUZU_UPDATE_TRUST_BUNDEL) no longer leaves signing silently off. The WindowsEnvironment-value check script in the server administration guide now also rejects non-ASCII characters in the signing entries and the binary path, and requires$stageto be 1 or 2. (#5249) -
--postgres-dsn-fileand--oidc-client-secret-fileread the server's database connection string and OIDC client secret from a file, so they need not appear on the command line, where other local users can read them. On Windows, the service's environment is readable by local users too. The whole file is the value; trailing whitespace and a UTF-8 byte-order mark are ignored. The server refuses to start if the file is missing, empty or larger than 64 KiB, or if the matching direct option (--postgres-dsn/YUZU_POSTGRES_DSN,--oidc-client-secret/YUZU_OIDC_CLIENT_SECRET) is also set. This works with the usual Docker and Kubernetes secret files. Env:YUZU_POSTGRES_DSN_FILE,YUZU_OIDC_CLIENT_SECRET_FILE. (#5272)
Changed
-
Breaking for alert rules — an OTA update refused because the agent's own trust bundle cannot be loaded is now counted as
yuzu_agent_ota_signature_refused_total{reason="bundle_unreadable"}and logged asOTA update <version> REFUSED: the update trust bundle could not be loaded, no longerreason="untrusted"/signature verification FAILED (untrusted chain)(the grep string the 0.14.0 notes gave for #5196). Rules, dashboards or saved searches keyed on the old reason or text for this fault need updating; for those faults (missing, permission-denied, not PEM) the refusal itself is unchanged, and the heartbeat totalyuzu.ota_signature_refused(soyuzu_fleet_ota_signature_refusing_agents) still includes it. New refusal: both--update-trust-bundleand--plugin-trust-bundleare now read bounded — a bundle over 1 MiB, one that is not a regular file, or (Windows) one held open by another process that does not allow shared reading is refused, where 0.14.0 loaded it; with--update-require-signatureor--plugin-require-signaturethat blocks every signed update or plugin, so check the bundle size before upgrading (see the upgrade notes). Agent-only; no server change. (#5249) -
The release workflow now refuses to publish over a tag that already has a published release (#5282). A new first job in
release.yml,release-guard, refuses any run that is not on avX.Y.Z[-{alpha,beta,rc}N]tag, and fails the run before any build or push whenGET /releases/tags/<tag>answers 200; it proceeds only on HTTP 404 and fails closed on any other answer. Every image push and the release creation additionally re-check that the tag still points at the run's commit (scripts/ci/check-release-tag-sha.sh). Every image-publishing job, the release job and the build jobs wait for it. Before this, a run started against an already-released tag (by mistake, or a superseded run) pushed new image digests over:X.Y.Z(and:X.Y/:latest) that no longer matched the release's signedSHA256SUMSand SBOMs, andCreate GitHub Releasethen skipped with a notice and went green; that step now fails instead. Recovery for a failed job is "Re-run failed jobs" on the newest run for the tag (digests kept); there is no override, and redoing a published release means cutting a new version. Residual paths are listed indocs/ci-architecture.md, Release re-publish guard.
Fixed
-
The Windows agent installer no longer leaves a running agent stopped when an upgrade fails. If an upgrade fails after the installer has stopped the
YuzuAgentservice (for example, a file in the program directory cannot be replaced, which an unattended/SUPPRESSMSGBOXESinstall answers with Abort, exit code 5), the installer now starts the service again before it exits if it was running or still starting, even when/NOSTARTwas given. It waits for a slow stop to finish and then records in the Setup log (/LOG=) the state it actually saw: RUNNING, or that the service could NOT be started, withsc.exe's exit code. Files the failed upgrade had already replaced are not put back, so run the installer again. Earlier installers left the agent offline until someone ransc.exe start YuzuAgentor rebooted. A trust-anchor refusal (exit code 7) still happens before the service is stopped. Its message now also says what the attempt left at%ProgramData%\Yuzu\agent-certs: when the lock on a new directory is blocked, nothing is created there, and an existing directory's own permissions are never changed. The agent and server installers' messages now saysc.exe, never plainsc, which PowerShell reads as Set-Content. (#5250) -
A docs- or changelog-only push to
main/devnow gets the required CI checks (#5320).ci.yml's push trigger dropped itspathsfilter, so every push runs; preflight'scode_changedgate skips the build matrix for a docs-only push, as it already did for a docs-only PR, and the required contexts appear on the commit as success or skipped instead of being absent. The v0.14.0 release commit was tagged without them because its only change wasCHANGELOG.md. The build legs are skipped only when the previous commit's push run succeeded, the push is a fast-forward, and every changed path (and every rename's previous path) is in the docs set — so the skip never follows an unbuilt or red code commit; any API error, control character in a path, or other answer builds. A push touchingdocs/os-capability-matrix.mdstill builds and runs its drift gate. The release skill's tag gate now says that skipped required checks count as passing and absent, failed or cancelled ones do not. -
Action required before upgrading from 0.14.0 on Docker Compose: copy
/etc/yuzu/certsout of the running server container first (Upgrading → "Docker Compose: copy/etc/yuzu/certsout of the server container before you recreate it"). Affected: a 0.14.0 Docker Compose stack whose server has no named volume on/etc/yuzu/certswhile Postgres has one —deploy/docker/docker-compose.yml(the 0.14.0 README quickstart),docker-compose.uat.yml,docker-compose.full-uat.yml,docker-compose.viz-uat.yml,docker-compose.demo.ymlused with--keep, any compose copied from them, and Compose Wizard output from before 0.14.1 in Plaintext mode, with 'Persist generated certs' unticked, or with named volumes off and an external Postgres. Not affected:docker-compose.reference.yml(which the README quickstart saves asdocker-compose.ymlsince #5419) anddocker-compose.reference-gateway.yml(theircertsvolume). The server keeps its internal CA, default certificates and secrets key-encryption key (KEK) in/etc/yuzu/certs, and since 0.14.0 the KEK is also registered in Postgres. In those stacks an image upgrade,docker compose downthenup, or--force-recreatedeleted the key files, and the server then refused to start withkek_unresolvable. Those composes and the/testupgrade-test compose now mount aserver-certsvolume on/etc/yuzu/certs. The Compose Wizard's Default and Plaintext output always mount a volume there too (its "Persist generated certs" option is now always on): the namedserver-certsvolume when named volumes are on or Postgres is external, otherwise an anonymous volume that is discarded together with the database's anonymous volume. The wizard's Operator-certs mode still mounts./certsread-only, so the server cannot write its KEK and stops at first boot withprovider_failure(#5420). The path does not move, so CA key paths recorded in Postgres stay valid. The chiselled server image now creates/etc/yuzu/certsowned by the server user, and the demo stack adds a one-shotserver-certs-initservice so it also works on older chiselled images. The upgrade guide gives a checked copy-out recipe, the diagnostics to run before anything destructive (a lost volume line, the wrong file owner, or keys left on a dangling anonymous volume give the same error), a rollback that keeps the keys, and what can still be saved if the files are already gone. The/testupgrade gate also recreates the upgraded server and checks that it comes back on the same keys. (#5370) -
The README's Docker Compose quickstart now works with the released images. In 0.14.0 it downloaded
deploy/docker/docker-compose.ymland ranYUZU_VERSION=0.14.0 docker compose up -d. That compose builds from a checkout of the repository (build: context: ../..), so a downloaded copy has nothing to build,YUZU_VERSIONwas ignored, and the stack never started. The quickstart now downloadsdeploy/docker/docker-compose.reference.ymlfrom the release tag, which pullsghcr.io/devnullltd/yuzu-serverandyuzu-postgresat${YUZU_VERSION}, serves HTTPS on 8443 and keeps/etc/yuzu/certson a named volume. It is three short steps that paste safely into bash or zsh: create the directory and a.envwith the version and two different Postgres passwords, write the first admin account toyuzu-server.cfg(the server's interactive first-run setup exits when there is no terminal), then start the stack and check/readyzagainst the server's own CA. Pasting a step twice cannot replace the database passwords or a live admin account: step 1 stops if the directory or any of the project's volumes already exists, and step 2 never overwrites either copy ofyuzu-server.cfg. The README says to setYUZU_CERT_SANbefore the first start, never to clear/etc/yuzu/certs(it holds the secrets key, #5370), and that on 0.14.xyuzu-server.cfgis the admin password's live source (the server reads it at every start and its entry wins over the database) until 0.15.0 (#5274); the upgrade guide and the AuthDB agent notes that called the file a one-time seed are corrected. The server's warning when--cert-sannames are missing from the existing certificates, and the--cert-sanand certificate-rotation advice in the server administration guide, the PKI architecture notes and the certificate-expiry alert, no longer say to clear the certificate directory: to add names, renamedefault-marker.jsonaside (moving it back undoes this) and restart, which re-issues the certificates under the same CA. The README describesdeploy/docker/docker-compose.ymlas a development stack for a clone. A docs-suite test,tests/test_readme_quickstart.py, checks the downloaded compose (nobuild:,${YUZU_VERSION}image tags, 8443, a persisted/etc/yuzu/certs), that the compose URL's tag, the.envversion and the compose default agree, that the steps are paste-safe and never overwrite, and that the admin seed matches the image's--configpath and the server's PBKDF2 parameters. (#5419)
Security
-
Docs site and demo app dependencies patched (25 advisories; OpenSSF Scorecard Vulnerabilities check). Lockfile-only bumps, with no
package.jsonchange, of transitive npm dependencies that Dependabot does not propose. The server, agent, gateway and installers are not affected: neither project ships in a product artifact. Insite/(the docs site):undici8.10.0 → 8.11.2 (GHSA-2gqq-gqf2-x968, GHSA-2jfj-6hjv-fm6j, GHSA-3wwx-pv8p-q78v, GHSA-3xpg-4rpp-hhhm, GHSA-8436-99hf-9mmv, GHSA-pmjh-fq2x-6v4x, GHSA-r53p-7pc4-xj5r, GHSA-rfgv-xxqx-mfg5, GHSA-rx4f-c7p8-82vq, GHSA-vp8m-p9jh-q5pm, GHSA-w293-vg96-wgc3),devalue5.8.1 → 5.9.4 (GHSA-4q55-j62x-fr9h, GHSA-9rgm-9g3h-6x36, GHSA-hx4r-w6wj-j8fg, GHSA-j22f-vq7h-c4qm, GHSA-mcm9-63f2-9j32, GHSA-r9w8-h9r3-54w4, GHSA-wf3x-273g-mvxv, GHSA-x5rw-q4pp-hg5g),svgo4.0.2 → 4.1.0 (GHSA-4vpr-x523-8j87, GHSA-w27v-7q3p-w38r),smol-toml1.7.0 → 1.9.0 (GHSA-7w5x-hrqm-74c2) andhttp-cache-semantics4.2.0 → 4.3.0 (GHSA-ch52-4w7c-c8xp). In the Cedar & Vale demo app:qs6.15.3 → 6.16.0 (GHSA-4mjr-xmp4-gh2g, GHSA-x5fp-wj9c-mxmx). An OSV scan of every npm lockfile on the branch reports 0 advisories, down from 25. -
The Windows server installer now keeps the secrets it handles in a directory only Administrators and SYSTEM can open, and off the service's command line. In every earlier version,
%ProgramData%\Yuzu Serverkept ProgramData's inherited permissions. Local users could readyuzu-server.cfg(the dashboard password hashes) and the TLS private keys incerts\, and could create files in its subfolders. The OIDC client secret was meant to be passed on the service's command line, which every local user can read. In practice ansc.exequoting fault dropped every argument, so the service ran with none. The installer now:- locks that directory to exactly Administrators and SYSTEM, by SID so non-English Windows works;
- verifies every entry it writes or resets before the install proceeds (the server's own subfolders in
data\are not walked); - stores the PostgreSQL connection string (
postgres.dsn) and the OIDC client secret (oidc-client-secret) there, passing only their paths to the server (--postgres-dsn-file,--oidc-client-secret-file); - writes the service's command line with its arguments and a quoted executable path, confirms it, and disables the service (exit code 10) if it cannot.
An upgrade over an earlier, unsecured install builds a new locked directory. It copies across only plain files that Administrators or SYSTEM own and no other account can change, from folders no other account can delete or rename in. It renames the old directory to
Yuzu Server.insecure-<date>-<time>rather than changing or deleting it. After upgrading, rotate the passwords, TLS keys and OIDC secret it held. Movedata\agent-updates\anddata\upload-blobs\across if you ran the server, then delete the renamed directory. (#5196, #5210, #5272)Behaviour changes for unattended installs:
- A connection string is now required on a fresh install and on an upgrade from any earlier version:
/POSTGRES_DSN_FILE=<file>, which keeps the password out of logs, or/POSTGRES_DSN=. AYUZU_POSTGRES_DSNenvironment variable is honoured instead, with a warning. Before, the registered service could never start, because no connection string was ever passed. - An OIDC client secret is not carried from an earlier version; give it again. If one had been added to the service's command line by hand and OIDC is enabled on the upgrade, the upgrade refuses until it is.
- An upgrade without
/ADMIN_PASSkeeps the existing accounts. - Upgrade in place rather than uninstalling first.
- Any input, directory, file or certificate that cannot be secured stops the install before any file is installed, with exit code 7 and the reason in the setup log on a
PrepareToInstall:line. A service already stopped by then stays stopped unless the abort came before the old directory was moved. - An unsecured data directory that no Yuzu Server installation is registered for is refused.
The setup log (
/LOG=) and deployment tools record the full command line, including any password given on it. Prefer the_FILEparameters. Windows server remains unsupported (ADR-0035). Separately, it cannot yet run under the Service Control Manager at all (#5325). The server's own CA and key-encryption keys stay inC:\ProgramData\Yuzu\certsfor now (#5273).
Enterprise installers
| Component | Windows | macOS | Debian/Ubuntu | RHEL/Fedora |
|---|---|---|---|---|
| Agent | .exe (InnoSetup) |
.pkg (launchd) |
.deb (systemd) |
.rpm (systemd) |
| Server | .exe (InnoSetup) |
— | .deb (systemd) |
.rpm (systemd) |
| Gateway | — | — | .deb (systemd) |
.rpm (systemd) |
Windows silent install (GPO / SCCM / Intune)
# Agent
YuzuAgentSetup-*.exe /VERYSILENT /SUPPRESSMSGBOXES /SERVER=yuzu-server:50051 /TOKEN=<enrollment-token>
# Server
YuzuServerSetup-*.exe /VERYSILENT /SUPPRESSMSGBOXES /ADMIN_USER=admin /ADMIN_PASS=<password> `
/HTTPS_CERT=cert.pem /HTTPS_KEY=key.pemSilent uninstall — agent: "C:\Program Files\Yuzu\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES; server: "C:\Program Files\Yuzu Server\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES (or the path in the product's UninstallString registry value, if it was installed to another directory). Each removes the program but keeps its data directory: %ProgramData%\Yuzu (the agent's identity and mTLS private key) or %ProgramData%\Yuzu Server (databases, configuration, TLS keys). To decommission a device, revoke its certificate on the server and delete that directory (see docs/agent-bundle.md). Uninstallers from earlier releases (up to 0.14.0-rc2) hang on a silent uninstall; upgrade first.
macOS silent install (Jamf / MDM)
sudo installer -pkg YuzuAgent-*.pkg -target /Linux install
# Debian/Ubuntu
sudo dpkg -i yuzu-agent_*.deb
sudo systemctl edit yuzu-agent # set --server address
# RHEL/Fedora
sudo rpm -i yuzu-agent-*.rpmPlatform archives
| Archive | Platform | Arch |
|---|---|---|
yuzu-linux-x64.tar.gz |
Linux (server + agent) | x86_64 |
yuzu-linux-arm64.tar.gz |
Linux (server + agent) | ARM64 (coming soon) |
yuzu-gateway-linux-x64.tar.gz |
Linux (gateway) | x86_64 |
yuzu-windows-x64.zip |
Windows (server + agent) | x86_64 |
yuzu-macos-arm64.tar.gz |
macOS (server + agent) | ARM64 (Apple Silicon) |
Compose Wizard
yuzu-compose-wizard-*.zip — browser-based step-by-step
generator for a customised docker-compose.yml + .env.
Zero dependencies — extract the zip and open index.html in
a browser. Contributed by
@fjarvis in
#405.
unzip yuzu-compose-wizard-*.zip
cd yuzu-compose-wizard-*
# Open index.html in your browser, or:
python3 -m http.server 8000Docker images
docker pull ghcr.io/DevNullLtd/yuzu-server:v0.14.1
docker pull ghcr.io/DevNullLtd/yuzu-gateway:v0.14.1Architecture: linux/amd64. Images are published to GHCR by this workflow as part of the release.
Verify checksums
sha256sum -c SHA256SUMSVerify signature (cosign)
cosign verify-blob --bundle SHA256SUMS.sigstore \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
SHA256SUMSSupply chain: SBOM, SLSA provenance, signed images
Every release ships CycloneDX + SPDX SBOMs per platform
(yuzu-*-{linux-x64,windows-x64,macos-arm64}.{cdx,spdx}.json,
yuzu-{server,gateway,postgres}-image.{cdx,spdx}.json and
yuzu-{server,gateway,agent}-chisel-image.{cdx,spdx}.json), GitHub-native
SLSA build provenance attestations for every binary archive
and Docker image, and cosign keyless signatures on both the
Docker images and the SHA256SUMS manifest. See
docs/user-manual/release-verification.md
for the full verification workflow (gh attestation verify,
cosign verify, CycloneDX / SPDX validation).
See the user manual for full setup instructions.
Known issues
- The second first-run account cannot log in on Postgres (#5343). First-run setup, and the Windows server installer's optional
/OPERATOR_USER+/OPERATOR_PASSpair, write a second, non-admin account toyuzu-server.cfg, but first boot copies only the admin account into the Postgres auth store, so every login with the second account fails. Workaround: sign in as the admin and create further accounts in Settings → User Management. - Linux native packages need a recent distribution (#5143). The
.deb,.rpmand tarball binaries are built with GCC 15 and need glibc 2.38; the server also needs GCC 15's libstdc++ (GLIBCXX_3.4.34). The server runs on Ubuntu 26.04 and Fedora 42, the agent also on Ubuntu 24.04; neither runs on Ubuntu 22.04, Debian 12 or RHEL/Rocky 9. 0.14.1 does not change this. Workaround: use the container images, which carry their own runtime libraries. The full matrix is under Supported Platforms indocs/user-manual/README.md. - The gateway RPM does not start on RHEL, Rocky or Fedora (#5171). The bundled Erlang/OTP
cryptolibrary needs SM4 symbols that Red Hat–family OpenSSL is built without, so the node fails withundefined symbol: EVP_sm4_cbcduring boot. The gateway.debdoes not declare its OpenSSL 3 dependency either. Workaround: run the gateway container image on those distributions. - Compose Wizard composes can lose, or cannot write, the secrets key in
/etc/yuzu/certs(#5420). This is the same class of problem as #5370, which 0.14.1 fixes in the tracked composes and the README quickstart, but not in the wizard. In Plaintext mode, or with "Persist generated certs" unticked, the directory is in the container layer and the key is lost when the container is recreated; the server then refuses to boot (kek_unresolvable). In Operator mode the directory is mounted read-only (./certs:/etc/yuzu/certs:ro), so the server cannot write the key at all; this case has not been tested in Docker. Workaround: before the first start, change the generated compose so/etc/yuzu/certsis a named, writable volume, and mount any operator-supplied TLS files separately.
Release gate waiver
The nightly ASan+UBSan and TSan legs were red at tag time on timing flakes seen only under the sanitizers: #4270 (the subprocess-runner K1 natural-exit check loses its race when the runner is starved), #5538 (MFA enroll-race test gets 401 instead of 409) and #5539 (Guardian journal_maintenance_tick gate test sees policy_generation() == 1). #5538 and #5539 each failed on only one of the nightly's two attempts. The maintainer waived these legs for 0.14.1.