Skip to content
xraphPublic

Latest commit

 

History

125 Commits

Folders and files

Repository files navigation

Vault

Composable secrets, feature flags, and runtime config for Go.

Vault is a Go library that unifies three capabilities behind a single API surface: encrypted secrets, rule-based feature flags, and hot-reloadable runtime configuration. It is a library, not a service: you import it, bring your own database and encryption key, and control the process lifecycle. Vault provides the plumbing: encryption, versioning, tenant-scoped evaluation, rotation, audit, and a plugin system for extending every subsystem.

Vault is part of the Forge ecosystem and integrates cleanly with Forge extensions, Grove ORM stores, and Confy config sources, but none of them are required to use it standalone.

Features

Secrets

  • AES-256-GCM encryption at rest, transparent decryption on read
  • Auto-versioning: every Set archives the previous value; fetch any historical version by number
  • Environment-variable key provider with hex/base64 auto-detection
  • Optional metadata (expiration, custom fields)

Feature flags

  • Five value types: bool, string, int, float, json
  • Six targeting rule types: WhenTenant, WhenTenantTag, WhenUser, Rollout (deterministic %), Schedule (time window), Custom (plugin-evaluated)
  • Priority-ordered evaluation with per-tenant overrides
  • Type-safe accessors (Bool, String, Int, Float, JSON) that return a default on error
  • LRU evaluation cache with configurable TTL (default 30s)

Runtime configuration

  • Typed entries (string, bool, int, float, json) with Duration parsing
  • Per-tenant overrides resolved ahead of the app-level value
  • Version tracking and Watch callbacks fired on mutation
  • Composable sources: memory, env, database, priority chain

Cross-cutting

  • Tenant isolation by design: scope.WithTenantID(ctx, ...) propagates to every service via context.Context; cross-tenant reads are structurally impossible
  • Secret rotation: background manager with per-key Rotator callbacks, automatic versioning, and record-keeping
  • Audit logging: append-only trail of action/resource/outcome with full scope context; optional hook for forwarding to external systems
  • Plugin system: register plugins that implement any subset of eight capability interfaces (OnInit, OnShutdown, SourceProvider, EncryptionProvider, FlagEvaluator, OnSecretAccess, OnConfigChange, RotationStrategy)
  • TypeID identifiers: every entity uses type-prefixed, K-sortable UUIDv7 IDs (sec_, flag_, cfg_, …); passing the wrong prefix fails at parse time

Install

go get github.com/xraph/vault

Quick start

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/xraph/vault/config"
    "github.com/xraph/vault/crypto"
    "github.com/xraph/vault/flag"
    "github.com/xraph/vault/scope"
    "github.com/xraph/vault/secret"
    "github.com/xraph/vault/store/memory"
)

func main() {
    ctx := scope.WithScope(context.Background(), "myapp", "tenant-1", "user-42", "10.0.0.1")

    store := memory.New()

    enc, err := crypto.NewEncryptor([]byte("my-32-byte-secret-key-for-vault!"))
    if err != nil {
        log.Fatal(err)
    }

    // Secrets: encrypted, auto-versioned
    secrets := secret.NewService(store, enc, secret.WithAppID("myapp"))
    meta, _ := secrets.Set(ctx, "openai-api-key", []byte("sk-abc123"), "myapp")
    sec, _ := secrets.Get(ctx, "openai-api-key", "myapp")
    fmt.Printf("secret v%d = %s\n", meta.Version, sec.Value)

    // Feature flags: evaluated against context scope
    flags := flag.NewService(flag.NewEngine(store), flag.WithAppID("myapp"))
    if flags.Bool(ctx, "new-dashboard", false) {
        fmt.Println("new dashboard enabled")
    }

    // Runtime config: typed accessors with defaults
    cfg := config.NewService(store, config.WithAppID("myapp"))
    _ = cfg.Set(ctx, "rate-limit", 100, "myapp")
    fmt.Printf("rate limit = %d\n", cfg.Int(ctx, "rate-limit", 50))
}

See docs/content/docs/getting-started.mdx for a step-by-step walkthrough covering rule-based flags, tenant overrides, rotation, and swapping in a production store.

Storage backends

Every backend satisfies the same composite store.Store interface (secrets, flags, config, overrides, rotation and audit), so switching stores is a single type change. All expose Migrate, Ping, and Close.

Backend Import Use case
Memory github.com/xraph/vault/store/memory Tests, development, single-process demos
PostgreSQL github.com/xraph/vault/store/postgres Production, direct pgx connection pool
SQLite github.com/xraph/vault/store/sqlite Embedded deployments, local-first apps (via Grove)
MongoDB github.com/xraph/vault/store/mongo Document-oriented workloads (mongo-driver/v2)
Grove github.com/xraph/vault/store/grovestore Apps already using the Grove ORM

Architecture at a glance

Vault is organised as a root package with shared types, six service packages implementing domain logic, supporting packages for encryption/scoping/sources, and a set of store backends implementing one composite interface.

Every operation follows the same three-phase flow: scope the context → resolve the value (tenant override → rule match → default) → respond with a coerced type or the caller's default on error. See docs/content/docs/architecture.mdx for the full package diagram and request-flow breakdown.

Ecosystem integration

Forge extension. Mount Vault as a Forge extension to auto-wire the store, encryption and the dashboard contract into your Forge app (audit is always on). The React dashboard plugin, @forge-go/dashboard-plugin-vault, reads that contract (see MIGRATION.md for what moved from the old templ pages). See extension/ and docs/content/docs/guides/forge-extension.mdx.

Confy source. Adapt Vault as a Confy ConfigSource and SecretProvider so a single confy.Load call pulls typed config and encrypted secrets through Vault alongside your other sources. See confy/ and docs/content/docs/guides/confy-integration.mdx.

Configuration

The root Config struct controls instance-wide behaviour. All fields have sensible defaults via DefaultConfig().

Field Purpose Default
AppID Application identifier used to scope secrets, flags, and config none
EncryptionKey 32-byte AES-256-GCM master key none
EncryptionKeyEnv Fallback environment variable holding the key (hex or base64) none
FlagCacheTTL TTL for the flag evaluation cache 30s
SourcePollInterval Interval for polling database-backed config sources 30s

Matching functional options live in options.go: WithAppID, WithEncryptionKey, WithEncryptionKeyEnv, WithLogger, WithConfig.

Development

The Makefile exposes short aliases for the common workflows:

make test         # go test ./...
make test-race    # go test -race ./...
make coverage     # coverage.out + function-level summary
make coverage-html
make lint         # golangci-lint run ./...
make fmt          # gofmt + goimports
make check        # fmt + vet + lint
make docs         # serve the Next.js docs site at http://localhost:3000
make deps         # install goimports, air, golangci-lint

Requires Go 1.25+. See go.mod for the full dependency set.

Documentation

A full documentation site lives under docs/ and can be served locally with make docs. Key pages:

Status

Actively developed. Core service APIs (secret, flag, config) are stable; storage backends and the Forge/Confy integrations continue to evolve. See recent commits on main.

License

See the repository root for licensing.

Releases

Packages

Used by

Contributors

Languages