Skip to content

Releases: valkyrianlabs/vaulthalla-server

v1.19.0 — Clients and servers negotiate a protocol version

Choose a tag to compare

@github-actions github-actions released this 30 Oct 22:28

The server, the web console and Vaulthalla Desktop release on their own schedules, so a client now starts its
WebSocket session with meta.hello (on the web socket, once signed in: the server still tells no one its version
before login). It says which protocol versions it speaks; the server answers its product version,
the protocol version the session will use, the features it has (capabilities such as fs.entry.metadata_version or
device.mcp) and every command it offers. A client that has no version in common with the server gets a clear
protocol_unsupported answer naming the server's range instead of failing on a changed shape later. A paired device's
reported app version now stays current in the device list instead of keeping the version it paired with.

An unknown command now carries the error code unknown_command (the message is unchanged). The rules for what may
change within a protocol version are in WebSocket Protocol.

v1.18.0 — Vaulthalla moves to the Valkyrian Labs organization

Choose a tag to compare

@github-actions github-actions released this 30 Oct 19:18

Vaulthalla's source, issues and roadmap now live under Valkyrian Labs LLC on GitHub:
valkyrianlabs/vaulthalla-server and
valkyrianlabs/vaulthalla-desktop. Old vaulthalla/server links
redirect. Nothing changes for installs: the APT repository, apt.vaulthalla.sh and brew install --cask vaulthalla/tap/vaulthalla keep working.

S3 gateway behind Cloudflare

The S3 gateway now works through a proxied Cloudflare record with the AWS CLI's CRT transfer client. Cloudflare drops
Content-Length: 0 from GET, HEAD and DELETE requests that the client signed with it, which failed with
SignatureDoesNotMatch; the gateway now treats the missing header as 0 when the request had no body. Every gateway
response also carries Cache-Control: private, no-store, so a CDN never caches an object or a presigned GET. See
Behind Cloudflare Or Another CDN.

Parallel uploads no longer exhaust the TPM

Under parallel S3 multipart uploads the daemon could log Esys_Load failed ... out of memory for object contexts:
several secrets were unsealed at once, and a TPM without a resource manager in front (the managed swtpm) holds only three
transient objects.
TPM operations now run one at a time, each flushing its objects before the next starts, and a TPM that another process
has momentarily filled is retried a few times instead of failing the request.

Stats history no longer fills the database

The 5-minute trend rollups behind the health dashboard were kept for 365 days whatever stats_snapshots.retention_days
said, and on a busy install they grew to gigabytes. Each rollup tier now has its own setting:
stats_snapshots.rollup_5m_retention_days (default 30 days; the dashboard reads this tier only for windows up to 7
days) and stats_snapshots.rollup_1h_retention_days (default 365 days). Both are also under Settings → Health
history
. The first daily purge after upgrading deletes the backlog; PostgreSQL keeps the freed space in the table file,
so reclaim it once with VACUUM (FULL) or
pg_repack during a maintenance window.

v1.17.0 — macOS crash durability

Choose a tag to compare

@github-actions github-actions released this 27 Oct 16:11

On macOS, every write Vaulthalla needs to survive a power loss now reaches the disk itself, not just the drive's
volatile cache. Covered: file saves and seals, key rotation, recovery snapshots and versions, cloud hydration, vh fs put, durable preview artifacts and the bootstrap secret. Plain fsync on macOS does not guarantee this, so an
interrupted write could previously leave a file that didn't match its database row. Linux behaviour is unchanged.

No server mount on macOS

The macOS server never mounts vaults, and no longer carries the unused macFUSE build path. Finder access belongs to
Vaulthalla Desktop, which is building it on Apple's File Provider. vh status and the console's Runtime page now say
so on the mount line. If an older config.yaml on a Mac sets mount.mode to multiuser or service_private, the
daemon runs with the mount disabled and logs a warning instead of reporting degraded health. vh fs, the web console
and the S3 gateway remain the ways to reach vault files on a Mac. Linux is unchanged.

Item versions for sync clients

Every file and folder the console, Desktop and other ws clients list or look up now carries a metadata_version, and
every file a content_version. The content version is exactly the strong ETag /download/content serves for the
file's current bytes, so a client can tell from a listing which files changed without asking for each one, and send it
back as a precondition. It changes on every write and stays the same across rename and move. The metadata version
changes on rename, move, mode change and any change of the modification time. An entry's id stays the same across
rename and move, so it can serve as a stable item identifier. Renaming or touching an empty file no longer changes its
ETag. Nothing else changes for existing clients: the fields are additive.

Saving over a file from a client

A new upload lane, PUT /upload/content, lets Desktop and other clients of the HTTP and device lanes save a file of
any size, up to the 8 GiB upload limit, safely:

  • Replace a file with If-Match: <content_version>. It succeeds only if nobody changed the file since that
    version. Otherwise it answers 412 with the current version, and nothing is lost. A file open through the mounted
    filesystem is never replaced underneath the program editing it.
  • Create a file with If-None-Match: *. It succeeds only if nothing is there yet.

The body is streamed to disk, so memory use doesn't depend on the file size. The answer carries the file's new entry
and versions.

Uploads through /upload/session (the web console's uploads) no longer hold each file in memory while it is stored.
Their results are the same. A file whose upload request failed partway, for example on a dropped connection, can now
be sent again within the same upload session instead of restarting the whole session.

Security

  • Folder listings hide what you may not see. The web console and Desktop (fs.dir.list) and vh fs ls now leave
    out files and folders you aren't allowed to look up, as the mounted filesystem already did, and a folder's size and
    item counts no longer include them. The Linux mount hides two more cases it used to list: entries matched by a deny
    override whose pattern starts above the folder (such as /**/secret.txt), and every file for a role that can list
    folders but neither preview nor download files. Anyone who could see the names of entries they couldn't open no
    longer sees them.
  • Moving something into a folder now needs permission to create it there. Moving or renaming a file or folder into
    another folder, in the web console, Desktop or the mounted filesystem, used to check only that you could move or
    rename the source. It now also needs what creating it in the destination needs: upload for a file, create-folder
    for a folder, and for a folder, the same for everything inside it. Refused moves change nothing; in the Linux mount
    they fail with "permission denied" (or "no such file or directory" for a folder you can't see). Renaming within the
    same folder works as before.

A Valkyrian Labs product

Vaulthalla is now owned and published by Valkyrian Labs LLC, the company its creator founded to build it. The
license does not change: Vaulthalla stays free software under the AGPL, version 3 or later. The package's copyright
file, NOTICE and TRADEMARKS.md name Valkyrian Labs LLC as copyright holder and owner of the Vaulthalla name and
logo, and the copyright file now credits the third-party code bundled with the server.

One package repository, one signing key

Vaulthalla now ships from the Valkyrian Labs APT repository, apt.valkyrianlabs.com, together with PDFium, the
libpqxx SDK and the other Valkyrian Labs tools, all signed by the Valkyrian Labs LLC key
(494D 71A1 EEDD F87B D48E 5048 6D64 CB7B DFC3 0EC6). apt.vaulthalla.sh keeps working: it now serves that same
index, so existing sources need no edits.

  • Existing installs: run sudo apt update && sudo apt upgrade (or apt-get dist-upgrade; a plain apt-get upgrade holds vaulthalla back). vaulthalla-archive-keyring 2026.10.27-1 adds the Valkyrian Labs LLC key to
    /usr/share/keyrings/vaulthalla.gpg, which your apt.vaulthalla.sh source already trusts. If apt update reports
    NO_PUBKEY 6D64CB7BDFC30EC6, rerun curl -fsSL https://apt.vaulthalla.sh/install.sh | bash.
  • New installs (install.sh, bin/setup/install_deps.sh, the manual steps in the docs) configure
    apt.valkyrianlabs.com with /usr/share/keyrings/valkyrianlabs.gpg. A source line written by an earlier
    install.sh is retired, so the host ends up with one entry for the one index; a hand-edited one is left alone.
  • vaulthalla now recommends valkyrianlabs-archive-keyring, which keeps that key current through upgrades.

v1.16.0 — Pair Vaulthalla Desktop, and let AI agents operate Vaulthalla

Choose a tag to compare

@github-actions github-actions released this 22 Oct 19:56

Paired devices

The daemon now serves Vaulthalla Desktop through its own device listener on port 36972: TLS 1.3 with a
certificate on both sides, each side pinning the other's key. No browser cookie, nginx or certificate authority is
involved. The listener answers on loopback only until a super admin runs vh device remote enable, which opens
it to the network at once (no restart) and keeps it that way across restarts and upgrades; vh device remote disable closes it again.

Any signed-in user can pair a Mac with their own account: vh device pair opens a 10-minute pairing window, lists
the Mac when it asks, and offers three codes. Pick the one the Mac shows; a wrong pick denies the request. A paired
device acts as its account with that account's permissions, and follows it: role changes apply at once,
deactivation refuses it, and a password reset or role change closes its open connections. Manage devices with
vh device list | rename | revoke (super admins: vh device list --all). Revoking is final: the device's
connections close immediately and its key is never accepted again.

A paired Mac also downloads, previews and uploads files over the same connection, with the same permission checks
as the web console (share links aren't offered there), and its AI agents can use remote MCP at /mcp: the same
tools, limits and confirmations as vh mcp. Agents can never approve pairing requests, turn remote connections on or
off, or export keys or secrets.

In the web console

Devices (in the main navigation and the account menu) lists your paired Macs with their platform, app version,
when they were paired and last seen, the last address and the device id, and lets you rename or revoke them. Pair a
device
is one click: the dialog opens a pairing window, shows the Mac's request with three codes as large buttons,
and you click the one the Mac shows. A wrong click declines the request; if another user is pairing on the node at
the same time, the dialog says so and leaves their window alone. The dialog shows the address and port to enter
in Desktop and counts down by the server's clock. Closing the dialog closes your window.

Super admins also get Devices → All devices: every user's devices with their owners, and a Remote connections
card with the listener's live status (address, port, connections, any bind error, the server key fingerprint) and an
on/off switch. Settings → Device listener links there.

Vault key backup, status and restore

vh vault keys status shows each vault's key backup state without printing key material: the current key version
and its key check (a public fingerprint that identifies a key without revealing it), the last exported version,
whether a rotation is under way, and every key version the vault still needs. Deleted vaults whose key is still
retained are included. A paired Vaulthalla Desktop uses the same information to back keys up to 1Password: it exports
over its paired connection and confirms each backup by its key check, and the server records the backup only if the
key is still current.

Key exports are now complete during a rotation: an export taken before the rotation finished re-encrypting the vault
used to omit the previous key, which still decrypts the files not yet re-encrypted. Every export now carries all
versions the vault needs (the current key, an unfinished rotation's previous key, and retired keys recovery data
uses), each with its key check, and a deleted vault's export carries them too. Keys still leave the server only
through the local vh CLI or a paired device, never the web console or an AI agent.

Restoring keys. vh vault keys import <vault> --file <export> is a recovery mechanism: it puts back key
versions a vault already had when this host can no longer use them, after the master key was lost or replaced (for
example a database restored onto a new host), after a database restore that predates a key rotation, or for a
deleted vault that can still be restored. It can't be used to set your own key: every export now carries the
server's attestation of each key version (a signature by a signing key sealed on the host, never exported), and
a version is restored only when its attestation verifies and the vault's records show it had that version. A key
the host can still use is never replaced, and a version the vault has no record of is refused. vh reads the export
on your side (--file - reads standard input, so a GPG export can be decrypted into a pipe). Writing asks you to type
the vault's name (--confirm-name without a terminal); the vault starts again right away. A paired Vaulthalla
Desktop restores from 1Password the same way. Export your vault keys again after upgrading: older exports carry
no attestations.

Salvage. A key version that can't be proven (an older export, another server's key) is reported as needing
salvage, and nothing is written for it. --salvage then makes a best effort: the server creates a fresh key of its
own, re-encrypts every file the supplied key decrypts under it (crash-safe, resumable), reports the files it couldn't
decrypt as unrecoverable, and never stores the supplied key. Files that exist only in an S3 bucket go through the
vault's price budget, and are reported as skipped with the estimate when it refuses.

No new key over encrypted data (behavior change). Vaulthalla used to create a fresh key at startup for a vault whose
key record was missing, even when the vault held encrypted files that key could never decrypt. Now such a vault (or one
whose key doesn't unseal, or whose files need a key version that is gone) does not start: vh status reports degraded and
names it, the console's health turns degraded, vh vault keys status says why, and the log names the import
command. New and empty vaults still get their first key automatically.

See Secrets And Key Export.

See every vault you can reach

vh vault list --accessible lists every vault you can reach and how: as its owner, through a vault role assigned to
you or to one of your groups, through your admin role, or as a super admin. Each vault says whether you can browse its
files and whether you can manage it, decided by the same permission checks that apply when you open it. vh vault list is unchanged and still shows only the vaults your admin role lets you view, so an account whose access comes
from a vault role or from owning a vault finds those vaults with --accessible. Vaulthalla Desktop's file browser
uses the same list (ws storage.vault.accessible.list), and AI agents get it as the read-only tool
vaults_accessible_list.

More than 100 vaults. At startup the daemon brought up only the first 100 vaults (by id): after a restart, any
vault beyond those was unreachable on every surface until it was changed. vh vault keys status all, vh vault keys export all and resolving an S3 gateway vault by name also stopped at 100. They all cover every vault now.

Let Claude Code or Codex operate Vaulthalla

vh mcp is a Model Context Protocol server built into the vh CLI, and vh skill install --agent claude|codex
sets an agent up in one step: it writes a vaulthalla skill (safety guidance plus a reference of every command
agents may run) and registers the server with the agent's CLI, or prints the command when that CLI isn't installed.

  • The agent acts as you. Every tool call is an ordinary, non-interactive vh command, so your Vaulthalla roles
    and permissions decide what works.
  • Destructive commands need your OK every time. Deleting, revoking, purging, rotating keys or restoring over files
    is refused by the MCP server until the agent passes an explicit destructive acknowledgement, which it is told to
    give only after you approve, even where the command itself wouldn't ask without a terminal.
  • Confirmations stay with you. A command that would ask you to confirm (deleting a user or vault, an encryption
    waiver, a restore over files, a bucket cleanup) refuses first; the agent has to show you the message and may only
    pass the confirmation after you approve. The server never adds --yes or --accept-* itself.
  • Keys and secrets stay out of reach. Vault key export, secret export, secrets update, setup, teardown
    and fs get|put are never available to agents.
  • Tools: vh_help to browse commands, vh_read for read-only commands, vh_run for the rest, and typed tools such
    as users_create, vaults_delete and recovery_restore. Each is marked read, write or destructive, so clients
    can run read-only tools freely and ask before destructive ones.

Calls run side by side, can be cancelled by the agent, and are abandoned after 10 minutes without a result
(VAULTHALLA_MCP_TIMEOUT).

See AI Agents And MCP.

Every command now says what it does

Each vh command declares whether it reads, writes or is destructive. The machine-readable contract
(vh_usage --json) carries it as effect.

Every ws command is in the published contract

The ws contract the daemon publishes (vh_usage --json, identified by meta.contract.get) now describes every
command it answers on /ws: 223 commands, up from 76. File management, vaults and API keys, roles and permissions,
shares and share sessions, stats and dashboards, sync conflicts, pricing budgets, the S3 gateway, settings,
operator email, paired devices and vault key backup are covered, each with its payload, response, session
requirement, refusals and client timeout. Native clients can be generated from it, and the web console now takes
every command's timeout from the server.

The contract also publishes the shape of every object those commands send: 170 named models (users and roles,
vaults, devices, vault key status and exports, files and folders, share links, stats, recovery plans, upstream
...

Read more

v1.15.0 — File recovery: snapshots, local versioning and provider versioning

Choose a tag to compare

@github-actions github-actions released this 17 Oct 17:51

Vaulthalla can now bring back earlier versions of files and folders. Each vault chooses a recovery preference in
Vault settings → Recovery or with vh vault recovery set <vault> --mode …:

  • Local snapshots. Explicit, named recovery points of a file or a whole folder, taken with Recovery history →
    Create snapshot
    or vh snapshot create <vault> <path> --name …. Snapshots are stored encrypted, deduplicated (an
    unchanged file costs nothing twice), count against an optional snapshot quota and the vault quota, and survive the
    deletion of the files they captured. Nothing is ever snapshotted automatically.
  • Provider versioning (AWS S3). For S3 vaults, the bucket itself keeps every version. Vaulthalla turns versioning
    on only after showing an estimate of what it will cost — Provider Versioning — Estimated Monthly Cost — and
    after you acknowledge it (and, when costs can't be estimated, a separate acknowledgement of unpriced recurring
    charges). AWS versioning can't be undone, only suspended; Vaulthalla says so before you enable it, never suspends it
    on its own, and never deletes old versions when you remove a vault. You choose how long old versions are kept
    (30, 90 or 365 days, or indefinitely). Cloudflare R2 doesn't support object versioning and is refused.
  • Local versioning (optional, any vault). Every change to a file keeps its previous version on this server, with
    limits you set (keep the last N, a maximum age, a size quota). For S3 vaults these versions also queue up while the
    provider is unreachable and are sent in order once it is back, so a versioned bucket ends up with the full history.

Recovery history. Right-click a file or folder in the web console (or vh recovery list <vault> <path>) to see
its snapshots, local versions and provider versions. Restoring always shows a preview first — what will be created,
overwritten or skipped, and what it costs — and asks you to type RESTORE before anything is overwritten. A folder can
be restored to a point in time from provider versions; that is a reconstruction from each file's version timestamps,
not an atomic snapshot, and the preview says so. Restoring from the provider in a smart-cache vault copies the old
version inside the bucket: nothing is downloaded to list versions and nothing is uploaded twice.

Costs you can see. The cost panel in Sync & cost and vh recovery costs <vault> show the estimated monthly
versioning surcharge, month to date, the 30-day forecast, how much history is retained, and what drives its growth.
Estimates are computed on this server from its own measurements and the signed price catalog — no usage is sent
anywhere — and they are labelled as estimates, not invoices. You can set a monthly threshold; going over it raises a
notification and never blocks writes.

Fixes. Editors can save over files on the mount again (renaming a temporary file over the original failed with an I/O error); with local versioning on, the version the save replaces is kept. Vault keys load again after a restart in the middle of a key rotation. S3 bucket listings past 1,000
objects no longer fail their signature. Deleting a folder no longer leaves its subfolders cached. A sync pass whose
bucket listing fails part-way now stops instead of working from a partial view, and S3 vaults with more than 1,000
objects index all of them. Unsent versions of a deleted file no longer stay pending in vh vault recovery status:
maintenance sends them to a versioned bucket (the file stays deleted) or drops them where there is no history to keep.

v1.14.1 — APT signing key kept current through upgrades

Choose a tag to compare

@github-actions github-actions released this 17 Oct 00:18

vaulthalla now depends on vaulthalla-archive-keyring, which owns /usr/share/keyrings/vaulthalla.gpg: the
signed-by= key that install.sh and the documented manual setup have always configured. When the repository's
signing key is renewed (for example a new expiry date), the keyring package updates it on the next upgrade, so
existing installs keep verifying apt.vaulthalla.sh without downloading the key again or editing their APT sources.

Upgrading. sudo apt upgrade (or apt-get dist-upgrade) installs the new dependency. A plain apt-get upgrade
never installs new packages and holds vaulthalla back until you run one of those, or
sudo apt install vaulthalla-archive-keyring first. The signing key fingerprint is
0657 4F63 2342 3EBC 99A1 DF7B E906 C69B 29C0 E706.

No daemon, database or configuration changes.

v1.14.0 — Managed S3 and R2 buckets, and event-driven sync

Choose a tag to compare

@github-actions github-actions released this 16 Oct 13:50

AWS S3 and Cloudflare R2 credentials can now administer their account. Turn it on for an existing credential with
vh upstream admin enable <key> (or the credential's Provider administration panel), and Vaulthalla can list the
account's buckets, create a new bucket when you create a vault, adopt an existing bucket after a read-only admission
check, keep its own lifecycle rule on the buckets it manages, and delete buckets it created when you explicitly ask.
One access-key pair per account does everything; who may do what is decided by the new admin.upstream permissions
(view, configure, provision, protect, unprotect, destroy), granted to the built-in roles as documented.

Protection locks. vh upstream protect <key> <bucket> --reason … excludes a bucket from everything Vaulthalla
does: no probes, adoption, vault binding, lifecycle or event rules, sync reads or writes, emptying or deletion,
including scheduled jobs, retries and work already running. The lock belongs to the bucket (provider, account and
name), not the credential, survives restarts and credential re-creation, and is loaded before the server makes any
upstream request. Removing it needs its own permission and an explicit, audited confirmation.

Event-driven sync. vh upstream events enable <vault> subscribes a vault's bucket to a Vaulthalla-owned queue
(AWS S3 → SQS, Cloudflare R2 → Queues with HTTP pull), and files written to the bucket by other tools reach the vault
within seconds: each event is stored before its queue message is acknowledged, deduplicated and ordered, applied to
the remote index, and only the changed keys are synced (about one HEAD and one GET per new object, one HEAD per
removal), under the vault's request and price budgets. Other applications' notification rules are preserved; only
Vaulthalla's own rules and queues are ever removed. Removals upstream now delete the vault's copy when it hasn't
changed since the last sync and the provider confirms the object is gone. If events may have been lost (dead-lettered
messages, or a delivery gap longer than the queue keeps messages), the next sync lists the bucket again instead of
trusting events. vh upstream events status shows queue health, backlog and errors; repair fixes
failed provisioning. R2 event delivery needs one Cloudflare API token (Queues: Edit, Workers R2 Storage: Edit), stored
sealed on the same credential; the R2 S3 key pair can't sign Cloudflare's account API.

Safety. Creating a bucket never takes over an existing one: name collisions are refused without changing
anything, and an existing bucket must be adopted explicitly. Deleting or detaching a vault leaves its bucket and
objects in place. Deleting a bucket is a separate operation, only for buckets Vaulthalla created and no vault uses,
after a preflight with object and version counts and a typed confirmation, and it reports partial results honestly.
Every control-plane change is in the upstream audit log (vh upstream audit), which shows each reader only the
credentials they may view. Bucket names and regions are validated before any request, and a bucket's identity (and so
its lock) follows the credential's endpoint, whatever provider label the credential was saved under.

Existing credentials and vaults are unchanged until you turn administration on: plain credentials make no
administrative calls. Also fixed: an object overwritten upstream by another tool could fail to sync on vaults that
don't encrypt upstream. On vaults that do, an object without Vaulthalla metadata over an encrypted file is still
treated as tampering unless the vault's event subscription imports foreign objects (the default for adopted buckets;
other vaults that encrypt upstream ignore foreign objects unless you choose --foreign-objects import).

v1.13.0 — Vaulthalla on macOS

Choose a tag to compare

@github-actions github-actions released this 13 Oct 19:06

Vaulthalla now installs on Apple Silicon Macs (macOS 14 or later) as a system service, from an installer package or
Homebrew (brew install --cask vaulthalla/tap/vaulthalla). Both run the same package: it creates a hidden
_vaulthalla service account, keeps vault data, sealed secrets and a private PostgreSQL database in
/Library/Application Support/Vaulthalla where only that account can read them, and starts the server, the web
console and the database at boot through launchd, before anyone logs in. The person installing it is enrolled for
vh and becomes the CLI admin (change it later with vh). Upgrading reinstalls over the top and keeps every vault;
/Library/Application Support/Vaulthalla/uninstall.sh removes it and keeps the data unless given --purge.
On macOS the vault isn't mounted in Finder yet: use the web console, the S3 gateway or vh fs.

HTTPS on macOS is one command: sudo vh setup caddy --domain vault.home.arpa serves the console, WebSockets,
uploads and downloads (and, with --s3-domain, the S3 gateway) through Caddy, running as the service account.
Internal names (.home.arpa, .internal, .lan, .local, .test) get certificates from Vaulthalla's own CA, which is
name-constrained to your hostnames so trusting it on a device can't let it vouch for any other site; --trust trusts
it on the Mac, and the command prints how to trust it on phones and other computers. Public names get Let's Encrypt
certificates, through Cloudflare DNS with --dns-cloudflare (the same credentials file vh setup nginx uses on
Linux) when the Mac isn't reachable from the internet, or use your own certificate with --cert/--key. Caddy renews
certificates by itself; vh setup caddy --status shows what is served, and vh teardown caddy removes it.

The package isn't signed by Apple yet. Opened from Finder, macOS blocks it the first time: choose Open Anyway in
System Settings → Privacy & Security, then run it again. sudo installer -pkg vaulthalla-<version>-arm64.pkg -target /
and the Homebrew cask install it without that prompt.

Existing behavior on Ubuntu installs is unchanged. Internals that touched Linux-only system calls now sit behind small
platform interfaces, so one code base builds and passes its tests on both systems.

New: vh fs ls, vh fs get and vh fs put read and write vault files over the control socket, without a mount, with
the same permissions as the web console. Downloads to a file are written atomically and only when complete; uploads
are stored only when every byte arrives, and --overwrite refuses to replace a file that changed meanwhile. This is
an interim path for macOS until its FUSE mount can map local users to their own Vaulthalla identities.

Fixes found along the way:

  • vh … --help no longer reads an uninitialized color theme while rendering help text.
  • The vh client and daemon compute the control-socket address length portably and refuse socket paths that are
    too long instead of truncating them.
  • On the FUSE mount, an exchange-rename (renameat2(RENAME_EXCHANGE)) is now refused instead of silently
    overwriting the second file.
  • Binding the first CLI user to the admin account no longer attempts a group change the unprivileged daemon could
    never make (membership is already checked when vh connects).

v1.12.3 — Trustworthy integration testing, an admin-role fix and typed console errors

Choose a tag to compare

@github-actions github-actions released this 12 Oct 17:31

Fixed

  • Admin roles: deleting an admin role that accounts still hold is refused again. The check counted the wrong
    table, so a held role could be deleted, which silently removed the admin role from every account that had it; an
    unused role could also be refused for no reason.
  • Web console: moving, renaming or copying into a folder that doesn't exist (or from a missing source) now says
    "not found" instead of a generic error.

Web console follows the server's command definitions

  • The console's command types are generated from the daemon's own command definitions, so the two can't drift
    apart unnoticed.
  • After a daemon upgrade, an open console page notices that the server's commands changed and suggests reloading
    (once, without interrupting anything). This uses a new read-only command, meta.contract.get, which needs a
    signed-in session and returns no secrets.

For contributors: an integration engine for the real daemon

  • vaulthalla-server can run as a fully private test instance (VH_TEST_MODE=1): its own database, paths, ports,
    CLI socket and FUSE mount. It refuses to start if anything would point at a real install. vh honours
    VAULTHALLA_CLI_SOCKET to talk to such an instance.
  • Tests are isolated from the development install. make test (DB-backed unit tests) and make itest (integration
    proofs) each run against a database created for that run and dropped afterwards, with private paths and nothing
    installed. The old make run_test, which installed a test build over the system binaries, rotated a shared test
    password into the daemon's environment file and could reach the development database, is gone (run_test now
    runs make itest). One-time setup: sudo tools/harness/bootstrap.sh.
  • Test mode can no longer fall back to the configured database: it needs its connection settings in the environment,
    and the test-only wipe helpers refuse any database that isn't a test database.
  • tools/harness drives many independent CLI, web-console (ws), HTTP and FUSE sessions against a private instance,
    checks every result against an authorization model, canaries and cross-surface parity, records a replayable trace,
    shrinks failures and keeps them as regressions. See .claude/context/testing.md.

v1.12.2 — Identity checks from memory and cheaper previews

Choose a tag to compare

@github-actions github-actions released this 11 Oct 21:18

Every FUSE operation, preview, download, S3 request and permission check used to reload the caller's account (and,
for most permission checks, the vault owner's) from the database, together with the full member list of every group
the account belonged to. Accounts and groups now live in memory as one shared object each, kept current as they
change, so those checks no longer wait on the database.

Faster

  • FUSE operations (stat, ls, open, reads and writes) no longer query the database to identify the caller or to
    check vault permissions.
  • Thumbnail grids, previews, downloads and S3 gateway requests no longer reload accounts per request.
  • Requests signed in by the session cookie (thumbnails, previews, downloads) check the session with one database read
    instead of three; the session signing key stays in memory instead of being read and unsealed for every request.
    Revoked sessions are still refused at the next request.
  • Listing a folder in the FUSE mount (ls) checks the database with one query instead of reloading the folder and
    each of its subfolders, and no longer scans every cached entry to find the folder's contents.
  • Adding, overwriting or deleting a file updates the totals of every folder above it in one statement instead of
    two per level.

Changes take effect at once

  • A rename, a role change, a vault role or permission override, a group membership or a group's vault role, made
    from the CLI or the web console, applies to the very next request everywhere: open web sessions, the S3 gateway
    and the FUSE mount included, without waiting for a session to refresh.
  • Changes made directly in the database (for example with psql) are picked up within about a second.
  • Security: a deactivated account could still use the FUSE mount through its Linux UID; it is now refused at the
    next operation, like everywhere else. Deleted and deactivated accounts are refused at the next request even on
    connections that were already open.
  • Password hashes are no longer kept in memory with the account; logins and password changes read them from the
    database each time.

Previews and thumbnails

  • The file grid's readiness check (/preview/batch) answers from the cache index in one query instead of reading
    and decrypting every cached thumbnail just to say it exists.
  • A file that can't be previewed (corrupt or over a limit) is reported as such once; the grid used to keep asking
    for it.
  • Opening an image also leaves its grid thumbnails behind, and concurrent requests for the same file share one
    decode instead of each decoding it. The image or PDF page you opened is sent as soon as it is ready; its grid
    thumbnails are finished right after, from the same decode.
  • Background thumbnail generation (uploads, cloud sync, grid fills) has its own render budget and can no longer
    make the image viewer wait or answer "busy".
  • Serving a cached preview costs one database round trip instead of six, and PDF page previews no longer read a
    second cache entry for the page count.
  • The grid asks for thumbnails sized for its tiles (256 px, 512 px on high-density screens) instead of stretching
    128 px images. Thumbnails are smaller to store and send (4:2:0 chroma), and transparent PNGs render on white
    instead of black. Existing thumbnails are regenerated on first view.
  • Cached previews are no longer flushed to disk one by one (they are verified on every read and regenerated if a
    crash damaged one), which makes generating thumbnails much lighter on slow disks.

Fixes

  • Overwriting a file from the web console or the API now updates the folder sizes the file browser shows right away;
    they could stay stale.
  • Vault roles now grant their sync permissions. A member whose vault role (their own, or a group's) allows triggering
    a sync, editing sync settings or signing the encryption waiver can now do so on that vault; before, only admin
    vault globals counted, so built-in roles such as contributor, editor and manager could not trigger a sync on
    someone else's vault.
  • S3/R2 vaults using the keep_remote or keep_newest conflict policy no longer download a file again on every sync
    after downloading it once. A file neither side changed since its last sync is left alone under every policy.