diff --git a/cli/cmd_vault.go b/cli/cmd_vault.go new file mode 100644 index 00000000..fab86f52 --- /dev/null +++ b/cli/cmd_vault.go @@ -0,0 +1,35 @@ +package main + +import "fmt" + +// vault verbs give each unix user no-HITL access to THEIR OWN Vaultwarden vault. +// Identity is the kernel UID; per-user creds live in that user's isolated Vault +// path (secret/workstation/claude-users/) read via their scoped token, and +// decryption is done by the official `bw` CLI. See +// docs/superpowers/specs/2026-06-24-homelab-vault-design.md. +func vaultCommands() []Command { + return []Command{ + {Path: []string{"vault", "setup"}, Tier: TierWrite, + Summary: "one-time: store your Vaultwarden master password + API key in your Vault path", Run: vaultSetup}, + {Path: []string{"vault", "status"}, Tier: TierRead, + Summary: "show whether your vault is configured/reachable (no secrets)", Run: vaultStatus}, + {Path: []string{"vault", "list"}, Tier: TierRead, + Summary: "list your item names: vault list [--search Q]", Run: vaultList}, + {Path: []string{"vault", "get"}, Tier: TierRead, + Summary: "fetch one item: vault get [--field password|username|uri|notes] [--json]", Run: vaultGet}, + {Path: []string{"vault", "search"}, Tier: TierRead, + Summary: "search your item names: vault search ", Run: vaultSearch}, + {Path: []string{"vault", "code"}, Tier: TierRead, + 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}, + } +} + +func vaultSetup(args []string) error { return fmt.Errorf("not implemented") } +func vaultStatus(args []string) error { return fmt.Errorf("not implemented") } +func vaultList(args []string) error { return fmt.Errorf("not implemented") } +func vaultGet(args []string) error { return fmt.Errorf("not implemented") } +func vaultSearch(args []string) error { return fmt.Errorf("not implemented") } +func vaultCode(args []string) error { return fmt.Errorf("not implemented") } +func vaultLock(args []string) error { return fmt.Errorf("not implemented") } diff --git a/cli/cmd_vault_test.go b/cli/cmd_vault_test.go new file mode 100644 index 00000000..42a4f21e --- /dev/null +++ b/cli/cmd_vault_test.go @@ -0,0 +1,30 @@ +package main + +import "testing" + +func TestVaultCommandsRegistered(t *testing.T) { + want := map[string]Tier{ + "vault setup": TierWrite, + "vault status": TierRead, + "vault list": TierRead, + "vault get": TierRead, + "vault search": TierRead, + "vault code": TierRead, + "vault lock": TierWrite, + } + got := map[string]Tier{} + for _, c := range vaultCommands() { + got[c.name()] = c.Tier + } + for name, tier := range want { + if got[name] != tier { + t.Errorf("command %q: tier=%q, want %q (registered=%v)", name, got[name], tier, got[name] != "") + } + } +} + +func TestVaultGroupInRegistry(t *testing.T) { + if !isCommandGroup(buildRegistry(), "vault") { + t.Fatal("`vault` group not wired into buildRegistry()") + } +} diff --git a/cli/homelab.go b/cli/homelab.go index 5f781791..62c0c8aa 100644 --- a/cli/homelab.go +++ b/cli/homelab.go @@ -23,6 +23,7 @@ func buildRegistry() []Command { reg = append(reg, usageCommands()...) reg = append(reg, haCommands()...) reg = append(reg, browserCommands()...) + reg = append(reg, vaultCommands()...) return reg }