Thanks to visit codestin.com
Credit goes to github.com

Skip to content

riptideslabs/keyledger

Repository files navigation

KeyLedger

KeyLedger is an interactive terminal dashboard that gives you a unified view of every API key issued across your AI providers — with health scoring, snapshot diffs, and encrypted credential storage.

Demo

Features

  • Interactive TUI — full-screen terminal dashboard built with Bubble Tea
  • Unified inventory — query all your AI providers simultaneously with a configurable timeout
  • Health scoring — flag stale, idle, or never-used keys with configurable age thresholds; dedicated Risk column sortable in the keys view
  • WorkSpaces view — hierarchical workspace/project tree per provider with per-scope key counts and risk breakdown, accessible as a tab inside the Keys view
  • Live filtering — search keys by name, scope, status, age, owner, risk score, and more
  • Snapshots manager — list, export, delete, and diff snapshots from a dedicated Snapshots view; trigger snapshots from the Keys or Health views
  • Periodic watch mode — collect keys on a schedule, persist to database, and dump JSON files automatically
  • Encrypted credential storage — credentials stored in AES-256-GCM encrypted SQLite; never plaintext on disk
  • Provider management UI — enable/disable providers and configure credentials interactively; credential status shown as "set" or "missing"

Documentation

Provider setup guides, configuration reference, and examples are at keyledger.riptides.io.

Provider Coverage

Provider Key listing Owner info Last used
OpenAI
Anthropic ✓ (30-day window)
AWS IAM access keys
AWS service-specific credentials
Google Cloud IAM
Mistral

Installation

go install

go install github.com/riptideslabs/keyledger@latest

Build from source

git clone https://github.com/riptideslabs/keyledger
cd keyledger
make build
./build/keyledger

Install to GOPATH/bin

make install

Requires Go 1.25 or later. No CGO required.

Configuration

Credentials

Launch the TUI and press p to open the Providers screen. Select a provider, enable it, and enter your API credentials — they are stored in an AES-256-GCM encrypted SQLite database and never written to disk in plaintext. You will be prompted to set a master password on first use.

OpenAI

Credential field Description
admin_key An Admin API key (sk-admin-…) from platform.openai.com → API keys

The admin key must have permission to list keys across the organisation. By default all projects are enumerated; use Exclude projects in the Providers screen to skip specific ones.

Anthropic

Credential field Description
admin_key An Admin API key (sk-ant-admin01-…) from console.anthropic.com → API Keys

The admin key must belong to an account with the Admin role. Optional settings (resolve user/workspace names, exclude workspaces) are configurable from the Providers screen.

AWS

Three credential modes are supported, tried in this order:

Mode Credential field Description
SSO profile sso_creds Profile name from ~/.aws/config after aws sso login
Static keys access_key_id + secret_access_key Long-lived IAM access keys

Either sso_creds alone, or both access_key_id and secret_access_key, must be set — the Providers screen shows set when the minimum required fields are present.

Google Cloud

Credential field Description
service_account_json Full JSON content of a GCP service account key file

Paste the entire contents of the downloaded .json key file into the service_account_json field. The service account needs the following roles (or equivalent custom permissions):

  • roles/resourcemanager.projectViewer — to enumerate projects
  • roles/apikeys.viewer — to list API keys
  • roles/iam.serviceAccountViewer — to list service account keys

By default all accessible projects are auto-discovered. Use Projects (override) to pin a list of project IDs, or Exclude projects to skip specific ones.

Mistral

Mistral uses an interactive login flow rather than a static API key. In the Providers screen press Login and enter your Mistral email and password — keyledger authenticates via Mistral's Kratos endpoint and stores the session token automatically. The session token is refreshed on each login.

Usage

Interactive TUI

keyledger

Launches the full-screen dashboard. All state (enabled providers, settings, snapshots) is persisted to ~/.keyledger/keyledger.db.

Keyboard shortcuts

Key Action
1 Keys view
2 Health view
3 Diff view
4 Snapshots view
p Provider management
g Settings
r Refresh all providers
s Save snapshot to database (Keys / Health views)
tab Toggle sidebar focus
o Cycle sort order (Keys view)
← → Switch between Keys and WorkSpaces tabs (Keys view)
/ Filter keys (Keys view)
? Toggle help overlay
esc Go back / close dialog
q Quit

Keys view columns

The keys table includes a dedicated Risk column (ok / WARN / CRIT) alongside the status column, so you can see health at a glance without opening the Health view. The active sort column is highlighted in purple with an underline. Sort cycles through: Created → Last Used → Name → Risk.

Keys view filter syntax

Expression Matches
foo Substring in ID, name, scope, or status
name:prod Keys whose name contains "prod"
scope:staging Keys in a scope containing "staging"
status:active Keys with exact status "active"
risk:critical Keys with risk score "critical"
age:>90 Keys older than 90 days
idle:never Keys that have never been used
owner:alice Keys created by a user matching "alice"

Watch mode

keyledger watch [--interval <duration>] [--output <dir>] [--unseal-addr <addr>]
keyledger --data-dir /mnt/data watch --interval 1h

Runs continuously: collects keys, saves to the database, and dumps a JSON file on every tick. Stops cleanly on Ctrl+C or SIGTERM.

keyledger watch --interval 1h --output /var/log/keyledger

Each run prints a one-line summary:

[2026-05-11 03:00:00] snapshot #12 — 47 keys (0 critical, 2 warnings) → /var/log/keyledger/snapshot-20260511T030000.json

The --interval flag accepts any Go duration string: 30m, 1h, 6h, 24h, etc. Default is 1h.

--output sets where snapshot JSON files are written. The database lives separately — use --data-dir (or $KEYLEDGER_HOME) to point it elsewhere; the startup line watch: store: … always shows which database is active.

Unseal API (headless / Docker)

In headless environments (e.g. a Linux container without a terminal), watch automatically starts a local HTTPS API so credentials can be supplied at runtime.

watch: credential store locked — POST password to https://127.0.0.1:9876/v1/unseal
watch: TLS cert fingerprint (SHA-256): AB:CD:EF:…

The server uses an ephemeral self-signed TLS certificate (ECDSA P-256, valid 24 h). Use --unseal-addr to change the bind address (default 127.0.0.1:9876).

Endpoint Method Body Description
/v1/status GET {"sealed":bool,"setup":bool}
/v1/providers GET List registered providers and their expected field names
/v1/init POST {"password":"…"} Initialise encryption on first run, then unseal
/v1/unseal POST {"password":"…"} Unseal an already-initialised store
/v1/credentials POST {"provider":"…","field":"…","value":"…"} Store a credential and enable the provider (requires unsealed)
/v1/credentials DELETE {"provider":"…","field":"…"} Remove a credential (requires unsealed)

Use GET /v1/providers to discover the exact field names before posting credentials:

curl -sk https://localhost:9876/v1/providers
# [
#   {"provider":"anthropic","fields":["admin_key"]},
#   {"provider":"aws","fields":["access_key_id","secret_access_key","sso_creds"]},
#   {"provider":"google","fields":["service_account_json"]},
#   {"provider":"openai","fields":["admin_key"]}
# ]

Docker

Pre-built multi-arch images (linux/amd64, linux/arm64) are published to the GitHub Container Registry on every release:

docker pull ghcr.io/riptideslabs/keyledger:latest
docker run -p 9876:9876 -v keyledger-data:/data ghcr.io/riptideslabs/keyledger:latest

Or build locally from source:

docker build -t keyledger .
docker run -p 9876:9876 -v keyledger-data:/data keyledger

The container runs keyledger watch --unseal-addr 0.0.0.0:9876 --interval 5m by default. Use the unseal API to supply credentials:

# 1. Check whether encryption has been initialised yet
curl -sk https://localhost:9876/v1/status
# {"sealed":true,"setup":false}

# 2a. First run — initialise encryption and unseal in one step
curl -sk -X POST https://localhost:9876/v1/init \
  -H 'Content-Type: application/json' \
  -d '{"password":"my-secret"}'
# {"sealed":false}

# 2b. Subsequent restarts — store is already initialised, just unseal
curl -sk -X POST https://localhost:9876/v1/unseal \
  -H 'Content-Type: application/json' \
  -d '{"password":"my-secret"}'

# 3. Push provider credentials
curl -sk -X POST https://localhost:9876/v1/credentials \
  -H 'Content-Type: application/json' \
  -d '{"provider":"openai","field":"admin_key","value":"sk-..."}'

curl -sk -X POST https://localhost:9876/v1/credentials \
  -H 'Content-Type: application/json' \
  -d '{"provider":"anthropic","field":"admin_key","value":"sk-ant-..."}'

# Remove a credential
curl -sk -X DELETE https://localhost:9876/v1/credentials \
  -H 'Content-Type: application/json' \
  -d '{"provider":"openai","field":"admin_key"}'

Note: -sk skips certificate verification for the self-signed cert. For stricter usage, extract the SHA-256 fingerprint printed at startup and pass it to curl --pinnedpubkey sha256//<base64> or verify with openssl s_client -connect localhost:9876.

Development

make help        # list all targets
make build       # build for current platform
make build-all   # cross-compile for all platforms
make run         # build and launch the TUI
make test        # run tests with coverage
make lint        # run golangci-lint (downloads on first run)
make lint-fix    # run golangci-lint with auto-fix
make check       # fmt + vet + lint
make clean       # remove build artifacts

License

MIT — see LICENSE. Copyright © 2026 Riptides Labs, Inc.

About

Unified TUI for inventory, health-check, and track every API key issued across your AI providers.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages