Changelog
Every change to galata-vault that a user would notice, newest first. The
format is Keep a Changelog; the
project follows Semantic Versioning,
with the pre-1.0 rule that a 0.y release may break the API and a 0.y.z
release does not (README.md).
The wire and file formats are versioned separately from the crates, by their own markers; docs/spec/stability.md says what a marker guarantees.
Unreleased
Fixed
- A store refuses, at open, a database whose tables are not its version’s
shape. A 0.4
gv-serverstarted on a data directory written by a pre-release build at the same schema version, listened, and failed at the first write withtable vaults has no column named owner_bundle_sig, which the client saw as an internal error. It now compares every table with what this build’s migrations produce and exits at startup, naming the table, the column and the remedy.
0.4.0 - 2026-09-22
Changed
- Ten published crates became one.
galata-vaultis now the only crate on crates.io;galata_vault::proto,::keys,::seal,::client,::backend(wasgalata-vault-store),::server_core,::server,::cliand::mcpare its modules, each behind the feature that needs it. Code that depended ongalata-vaultand used its re-exports is unaffected. Code that depended on one of the nine directly moves to the matching module:galata_vault_proto::api::Scopebecomesgalata_vault::proto::api::Scope, and so on. The nine names stay on crates.io at 0.2.0 and are not updated again. - The separation the crates enforced is now enforced by features, and
checked.
serverdoes not enablesdk, so a server build compiles no value- or name-crypto code and links none of those crates; the SDK’s default build links no database, HTTP server or async runtime. The four linkage guards are replaced by one,scripts/check-linkage.sh, which reads the dependency graph per feature set and reads the source for a serving module that namescrate::keys,crate::sealorcrate::client– the half the compiler used to do for free. - The binaries moved to unpublished crates (
crates/gv,crates/gv-server,crates/gv-mcp), thin wrappers that exist so each keeps its own release target list.gvis therefore no longer installable withcargo install galata-vault-cli: use the installer from a release, the Python package, orcargo install --git. - Match arms that existed only because an enum was
#[non_exhaustive]in another crate are gone; inside one crate the compiler proves them unreachable, and a new variant now fails the build at each site instead of falling into a fallback.
0.3.0 - 2026-09-21
Changed
- A release is now a tag, and nothing else.
scripts/release.sh <version>sets the version everywhere it is written down, dates the changelog entry, runs the gate, commits and tags; pushing that tag publishes the crates (.github/workflows/crates.yml, onecargo publish --workspace), the wheels and the binaries, in parallel, with nothing left to approve. Both uploads authenticate as their workflow through OIDC, so no publishing token is stored. release-plz and its release pull request are gone, along with the by-hand dependency order the ten crates used to be published in – cargo works that out itself.RELEASING.mdis the whole procedure.
Added
scripts/check-version.sh, which fails the build when the workspace version, the versions its path dependencies carry and the newest changelog entry disagree – or, in a release workflow, when they disagree with the tag that started it. The tree is no longer bumped ahead of a release: it carries the released version, and notes wait under## [Unreleased].scripts/trusted-publishers.sh, which registers this repository as the trusted publisher of every published crate on crates.io in one pass, reading the crate list from the workspace.
0.2.0 - 2026-09-21
The gv ui screenshots in the README and docs/local-ui.md, a logo, and
package badges. Version bumped as a minor release at the maintainer’s
request: the changes below are additive, so a 0.1.x would also have been
accurate.
Added
- The audit chain records a token receiving the vault’s token list, as
token_list(code 13). The owner’s own status reads are not recorded – an environment opens with one, and the chain would fill with them – and a lesser scope reading status is not an attempt to list, so it is not a refusal either.
Changed
scripts/check-packaging.sh verifybuilds every published crate from its own.crateagain. It was skipped for 0.1.0 because verification resolves each crate’s siblings from a registry, and they were not published yet. It no longer passes--offline: a machine that has only built this workspace has never downloaded these crates, because the workspace uses path dependencies.
0.1.0 - 2026-09-21
The first release. Ten crates on crates.io, the galata-vault package on
PyPI, and gv, gv-server and gv-mcp binaries with installers and build
attestations on the GitHub release.
Fixed
- Rotation now reports a lost race as stale, not as a missing secret.
Two owners rotating at once: the loser could fail with
not_found(secret NAME has no version N) instead ofstale_generation. A rotation that lands re-indexes every record under the new generation’s name key, so the loser’s index — computed with the generation it opened — stops resolving partway through gathering. The retry loop could not recover, because it absorbed only a revision conflict. Gathering a record that vanishes now rebuilds, and the generation guard then reports it as stale. No data was at risk: the winner’s chain was always intact and no acknowledged write was lost. The error was the bug. scripts/conformance.shwaited about 10 seconds forgv-server localand reported “the server did not start” when it was merely slow to first-exec after being relinked. The budget is now 60 seconds; a server that really fails still reports immediately, because the wait ends as soon as the process does.- An absent token list no longer reads as an empty one.
VaultStatus.tokensis optional to distinguish “you may not see this” from “there are none”, and two callers flattened that away. One of them was the guard that refuses to mint while a token of a scope this client does not know exists — so it waved everything through in exactly the case it was written for. galata_vault::mcp’s stdio test gavegv-mcp20 seconds to answer whilegv-mcpitself allows 60 for the vault opens it does first, so a slow open failed the test rather than the code. It now waits for the readiness line before speaking the protocol.
Added
- An
admintoken can list and revoke tokens throughgvand the SDK, as the specification has always said it may (docs/spec/http-api.md#2). The server allowed it; only the command line refused, telling the holder that “a token cannot do it, whatever its scope”.gv token lsandgv token revokenow accept one,Vault::tokens()andVault::revoke()give the SDK the same view an owner gets, and revoking through a token raises the same forward-only warning, since a token cannot rotate.gv token revoke --rotatestill needs the owner key, and says why. - Continuous integration:
.github/workflows/ci.ymlrunsscripts/check-all.shon every pull request and push,dco.ymlenforces the sign-offCONTRIBUTING.mdrequires, anddeny.ymlrunscargo deny checkon pull requests and on a daily schedule. deploy/README.md: running a server for machines other than your own, and what this build deliberately does not implement.- This changelog, and
CODE_OF_CONDUCT.md.