Go Client Library¶
MaestroVault ships a Go client library at pkg/client for programmatic access to the REST API. It communicates over the Unix domain socket using standard net/http.
Prerequisites
The API server must be running: mav serve. For automation or CI where biometric prompts are not possible, start the server with mav serve --no-touchid. API token authentication still applies to all requests.
Installation¶
Quick Start¶
package main
import (
"fmt"
"log"
"github.com/rmkohlman/MaestroVault/pkg/client"
)
func main() {
c, err := client.New("mvt_your_token_here")
if err != nil {
log.Fatal(err)
}
// Store a secret in the "dev" environment
err = c.Set("api-key", "dev", "sk-abc123", map[string]any{"service": "api"})
if err != nil {
log.Fatal(err)
}
// Retrieve it
secret, err := c.Get("api-key", "dev")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Value: %s\n", secret.Value)
}
Creating a Client¶
// Default socket path (~/.maestrovault/maestrovault.sock)
c, err := client.New("mvt_token")
// Custom socket path
c, err := client.New("mvt_token", client.WithSocketPath("/tmp/mv.sock"))
// Custom timeout
c, err := client.New("mvt_token", client.WithTimeout(10 * time.Second))
Secrets¶
Get¶
secret, err := c.Get("db-password", "prod")
// secret.Name, secret.Environment, secret.Value, secret.Metadata, secret.CreatedAt, secret.UpdatedAt
List¶
secrets, err := c.List("prod") // pass "" for all environments
for _, s := range secrets {
fmt.Println(s.Name, s.Environment)
}
List by Metadata¶
Set¶
Edit¶
newVal := "updated-value"
err := c.Edit("name", "prod", &newVal, nil) // nil metadata = keep existing
Delete¶
Fields¶
Secrets can have individually encrypted key-value fields in addition to (or instead of) the main value.
SetField¶
Set a single field on a secret. Creates the parent secret if it doesn't exist.
GetField¶
Retrieve a single decrypted field.
GetFields¶
Retrieve all fields for a secret.
fields, err := c.GetFields("db-creds", "prod")
for key, value := range fields {
fmt.Printf("%s = %s\n", key, value)
}
SetFields¶
Set multiple fields at once. Creates the parent secret if it doesn't exist.
err := c.SetFields("db-creds", "prod", map[string]string{
"host": "db.example.com",
"port": "5432",
"username": "admin",
})
DeleteField¶
Delete a single field from a secret.
Search¶
Generate Password¶
result, err := c.Generate(client.GenerateOpts{
Name: "wifi-password",
Length: 24,
})
fmt.Println(result.Password)
fmt.Println(result.Stored) // true if Name was provided
Vault Info¶
info, err := c.Info()
fmt.Printf("Secrets: %d\n", info.SecretCount)
fmt.Printf("DB size: %d bytes\n", info.DBSize)
Health Check¶
Token Management¶
Requires a token with admin scope.
List Tokens¶
tokens, err := c.ListTokens()
for _, t := range tokens {
fmt.Printf("%s: %s (%v)\n", t.ID, t.Name, t.Scopes)
}
Create Token¶
result, err := c.CreateToken("ci-reader", []string{"read"}, "720h")
fmt.Println(result.Token) // Save this -- shown only once
Revoke Token¶
Error Handling¶
All methods return errors for HTTP 4xx/5xx responses. The error message includes the status code and server error message:
secret, err := c.Get("nonexistent", "")
if err != nil {
// err: "API error (404): secret \"nonexistent\" not found"
fmt.Println(err)
}
Types¶
SecretEntry¶
type SecretEntry struct {
Name string `json:"name"`
Environment string `json:"environment"`
Value string `json:"value,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
Fields map[string]string `json:"fields,omitempty"`
FieldCount int `json:"field_count,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
FieldResponse¶
type FieldResponse struct {
Name string `json:"name"`
Field string `json:"field"`
Value string `json:"value"`
}
VaultInfo¶
type VaultInfo struct {
Dir string `json:"dir"`
DBPath string `json:"db_path"`
DBSize int64 `json:"db_size_bytes"`
SecretCount int `json:"secret_count"`
}
GenerateOpts¶
type GenerateOpts struct {
Name string `json:"name,omitempty"`
Environment string `json:"environment,omitempty"`
Length int `json:"length,omitempty"`
Uppercase *bool `json:"uppercase,omitempty"`
Lowercase *bool `json:"lowercase,omitempty"`
Digits *bool `json:"digits,omitempty"`
Symbols *bool `json:"symbols,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}