Skip to content

Upgrading

OpaqueVault is pre-1.0. Breaking changes land on minor versions and are always called out in the CHANGELOG. This page condenses each one into what breaks and what to do about it.

To upgrade the binary itself: brew upgrade ov on macOS, or re-run the installer on Linux (curl -fsSL https://get.opaquevault.com | sh). See Updating.


v0.11.2 — ov auth derive-machine-key --app removed

Section titled “v0.11.2 — ov auth derive-machine-key --app removed”

What breaks: any script or runbook that calls ov auth derive-machine-key --app <slug>. The flag returns a deprecation error in v0.11.2 and is hard-removed in v0.12.0.

Why: the --app-scoped derivation never worked correctly — it re-keyed the vault session onto a divergent HMAC namespace, so cross-namespace reads and writes 404’d. The machine key was always master-KEK-equivalent on the only path that worked. --app on ov run and ov agent start is unchanged — those are routing flags, not key-scoping.

Fix — regenerate without the flag:

Terminal window
ov auth derive-machine-key --out /path/to/machine.kek

Recovering orphaned secrets. If you ever wrote secrets using an --app-scoped machine key, those rows landed under a divergent key and are invisible to your normal master-password session (cross-key operations never completed, so only same-key writes left rows behind). To recover the plaintext:

  1. Do this on a quiescent host — no untrusted co-tenant workloads while secrets are in a subprocess environment.
  2. Use the old --app-scoped key one last time to read each value out:
    Terminal window
    ov run --machine-key /path/to/old-scoped.kek --app X --secrets FOO -- printenv FOO
  3. Re-store each value normally (interactive ov secret set, under your regular session).
  4. Delete the old key file.

The orphaned rows themselves can’t be deleted client-side in this release — they’re unreachable from both the machine-key path (ov secret delete doesn’t accept --machine-key) and the master-password path (different HMAC namespace). They’re encrypted under a key you’ve now discarded, so they’re inert — but if you want them purged from storage, file a support ticket referencing OV-273.


v0.11.0 — OV_STRICT_CONTEXT defaults to ON

Section titled “v0.11.0 — OV_STRICT_CONTEXT defaults to ON”

What breaks: non-Claude MCP clients (or custom agents) that call vault_run in “ambient” mode — without declaring which app/env they expect to be operating on. With strict context on, vault_run requires expected_app and expected_env parameters and refuses the call when they don’t match the bridge’s resolved context.

Fix, in order of preference:

  1. Declare intent. Have the agent pass expected_app / expected_env on every vault_run, and use the vault_check_context tool as a preflight after any directory change (side-effect-free except a context_forged audit event on mismatch). This is the designed flow — it’s what stops a cd into the wrong repo from injecting production secrets.
  2. Opt out (not recommended): set OV_STRICT_CONTEXT=false in the environment of ov mcp serve to restore permissive ambient mode. Unset, empty, and unparseable values all resolve to ON.

Also in this release:

  • Sessions now expire after OV_SESSION_TTL (default 1 hour) — stricter than the previous effective 8-hour max lifetime. If your agent sessions start locking mid-day (SESSION_LOCKED), set OV_SESSION_TTL (max 24h) in the agent’s environment. See Troubleshooting.
  • Self-hosted operators: migration 000020_audit_event_id is mandatory — run make migrate-up after upgrading the API server.
  • v0.10.2 was documented but never tagged; upgrading from v0.10.1 delivers both the v0.10.2 changes (including the strict-context flip and vault_check_context) and the v0.11.0 additions at once.

What changed: the v2 schema pins your project to the app’s immutable UUID via an app_id field (and optionally env_id), instead of relying on the mutable slug alone. v1 files (slug-only, no app_id) have been deprecated since v0.9.6.

What breaks: the MCP bridge refuses legacy v1 files — MCP tool calls in that project won’t resolve your app. The CLI still accepts v1 for now, printing a warning on every invocation.

Fix — one command in the project directory:

Terminal window
ov app pin

ov app pin takes no arguments — it reads the slug from the .ov.yaml’s existing app: field, resolves it to its UUID on the server, and writes the file to v2 in place. It’s fail-closed: if the file already has an app_id that disagrees with the slug lookup, it refuses to overwrite rather than silently repoint your project.

Don’t confuse it with ov app use — that sets your global config default app in ~/.config/ov/config.toml and never touches .ov.yaml.

Verify the result:

Terminal window
ov status --explain

A clean trace shows .ov.yaml matching with an app_id, and no legacy-ovyaml warning.