Clients

Go

go.valt0.com/valt0 connects to the Valt0 service and opens the vaults that have been imported into it with valt0 import.

Install it

Requires Go 1.26 or later.

go get go.valt0.com/valt0

Open a vault

A vault is opened by its id and its name.

valt0.OpenVault loads a vault from the local service. The service can only open a vault that has been imported into it, so run valt0 import on the vault first.

It returns an error if the service cannot be reached, or if the vault cannot be loaded.

Go
import "go.valt0.com/valt0"

vault, err := valt0.OpenVault(valt0.VaultOptions{
    Id:   "your-vault-id",
    Name: "your-vault-name",
})
if err != nil {
    log.Fatal(err)
}

Read a secret

Ask for a secret by name, use it, then destroy it.

vault.Secret(name) fetches one secret and returns a *Secret. Take the value out as bytes where you can: Bytes() hands back the secret’s own buffer, and Destroy() zeroes it, so defer Destroy() as soon as you have the secret.

If you need the secret as a string use Reveal().

Go
secret, err := vault.Secret("DATABASE_PASSWORD")
if err != nil {
    log.Fatal(err)
}
// Zero the underlying buffer as soon as you are finished
defer secret.Destroy()

// Preferred: raw bytes, wiped by Destroy()
pw := secret.Bytes()

// Or, when a string is unavoidable
db.Connect(secret.Reveal())

Anywhere else, a Secret prints as [REDACTED] rather than its value. It implements fmt.Stringer, fmt.GoStringer, json.Marshaler, encoding.TextMarshaler and slog.LogValuer, so a fmt call, a JSON or text payload and a log line all get the redacted form. The value comes out only where you ask for it, with Reveal() or Bytes().

Go
fmt.Println(secret)                         // [REDACTED]
fmt.Printf("%#v\n", secret)                 // [REDACTED]
json.Marshal(map[string]any{"pw": secret})  // {"pw":"[REDACTED]"}
slog.Info("connecting", "pw", secret)       // ... pw=[REDACTED]

secret.Reveal()                             // the actual value

Handle errors

The two ways a connection fails have errors of their own.

OpenVault returns valt0.ErrCantConnectToService when the service’s socket or session file does not exist, which usually means the service is not running: valt0 status tells you whether it is. It returns valt0.ErrNoServiceResponse when the service did not answer within the one second the client waits.

Check for either with errors.Is. Any other error, such as a vault that could not be loaded, comes back as it is.

Go
vault, err := valt0.OpenVault(opts)
switch {
case errors.Is(err, valt0.ErrCantConnectToService):
    // socket or session file not found: is the valt0 service running?
case errors.Is(err, valt0.ErrNoServiceResponse):
    // the service did not answer within the transport timeout (1s)
case err != nil:
    // any other error, e.g. the vault could not be loaded
}

API

OpenVault(opts): (Vault, error)

Loads the local session and opens the vault named in opts, a valt0.VaultOptions. Returns an error if the session file is missing, the service cannot be reached or the vault cannot be loaded; the two connection failures are ErrCantConnectToService and ErrNoServiceResponse.

Options

Idstring
The vault’s id, the one valt0 info prints.
Namestring
The vault’s name. .valt0 is added to it when it is missing.

Vault

The opened vault.

Methods

Id()
The vault’s id.
Name()
The vault’s name.
Secret(name)(*Secret, error)
Fetches one secret by name.

Secret

One secret, fetched from a vault.

Methods

Bytes()
The raw bytes: the secret’s own buffer, not a copy. Preferable to use where you can, because Destroy() wipes it.
Reveal()string
The value as a string. A string cannot be wiped, so use it sparingly.
Destroy()
Zeroes the buffer.