From 15643d1f441a9f1eb8e3df5efd1cad25884f7e65 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Wed, 24 Jun 2026 10:29:32 +0000 Subject: [PATCH] feat(cli): bare `homelab vault` help command --- cli/cmd_vault.go | 21 +++++++++++++++++++++ cli/cmd_vault_test.go | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/cli/cmd_vault.go b/cli/cmd_vault.go index 21d0313b..bf270886 100644 --- a/cli/cmd_vault.go +++ b/cli/cmd_vault.go @@ -32,9 +32,30 @@ func vaultCommands() []Command { Summary: "current TOTP code for an item: vault code ", Run: vaultCode}, {Path: []string{"vault", "lock"}, Tier: TierWrite, Summary: "lock/log out the local bw session", Run: vaultLock}, + {Path: []string{"vault"}, Tier: TierRead, + Summary: "Vaultwarden access for your own vault (run `homelab vault` for help)", + Run: func([]string) error { fmt.Print(vaultHelp()); return nil }}, } } +// vaultHelp is shown for bare `homelab vault`. +func vaultHelp() string { + return `homelab vault — read YOUR OWN Vaultwarden logins (no-HITL after one-time setup) + + homelab vault setup one-time: store your master password + API key in your Vault path + homelab vault status configured / unlocked / reachable (no secrets) + homelab vault list [--search Q] list your item names (no secrets) + homelab vault get [--field password|username|uri|notes|totp] [--json] + TTY → clipboard (auto-clears); piped → stdout + homelab vault code current TOTP code + homelab vault lock lock / log out the local bw session + +Creds live only in your own Vault path; the admin never sees them. Identity is +your unix UID. Security model: docs/superpowers/specs/2026-06-24-homelab-vault-design.md +(note: anything running as your user can decrypt your vault — the accepted no-HITL trade). +` +} + const vwUserPathPrefix = "secret/workstation/claude-users/" // vwCreds is one user's Vaultwarden auth material, read from their Vault path. diff --git a/cli/cmd_vault_test.go b/cli/cmd_vault_test.go index 55f01508..36aab1f4 100644 --- a/cli/cmd_vault_test.go +++ b/cli/cmd_vault_test.go @@ -331,6 +331,24 @@ func TestBwNeedsLogin(t *testing.T) { } } +func TestVaultHelpMentionsSecurity(t *testing.T) { + h := vaultHelp() + for _, want := range []string{"homelab vault get", "no-HITL", "your own", "setup"} { + if !strings.Contains(h, want) { + t.Errorf("vault help missing %q", want) + } + } +} + +func TestVaultBareGroupRegistered(t *testing.T) { + for _, c := range vaultCommands() { + if len(c.Path) == 1 && c.Path[0] == "vault" { + return + } + } + t.Fatal("bare `vault` help command not registered") +} + // getValue is the testable core: given a runner + opts, returns the secret value. func TestGetValueFlow(t *testing.T) { f := &fakeRunner{out: map[string]string{