Skip to content

Commit e882e48

Browse files
committed
add show-keys command to CLI for displaying authorized_keys content
1 parent 526a5cc commit e882e48

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

ui/cli/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ Running without a subcommand will launch the interactive TUI.`,
278278
// Register debug command
279279
cmd.AddCommand(debugCmd)
280280

281+
// Register show-keys command
282+
cmd.AddCommand(showKeysCmd)
283+
281284
// Define flags
282285
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output (sets -v for DB logs)")
283286
cmd.PersistentFlags().BoolVarP(&showVersionFlag, "version", "V", false, "Print version and exit")

ui/cli/show_keys.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2026 Keymaster Team
2+
// Keymaster - SSH key management system
3+
// This source code is licensed under the MIT license found in the LICENSE file.
4+
5+
package cli
6+
7+
import (
8+
"fmt"
9+
"os"
10+
11+
"github.com/spf13/cobra"
12+
"github.com/toeirei/keymaster/internal/core"
13+
"github.com/toeirei/keymaster/internal/core/db"
14+
"github.com/toeirei/keymaster/internal/model"
15+
)
16+
17+
var showKeysCmd = &cobra.Command{
18+
Use: "show-keys [user@hostname]",
19+
Short: "Show what authorized_keys content would be deployed to an account",
20+
Long: `Displays the authorized_keys content that would be deployed to the specified account without actually deploying it. Useful for debugging key deployment issues.`,
21+
Args: cobra.ExactArgs(1),
22+
Run: func(cmd *cobra.Command, args []string) {
23+
identifier := args[0]
24+
25+
// Parse username@hostname using same logic as deploy command
26+
parts := splitUsernameHostname(identifier)
27+
if len(parts) != 2 {
28+
fmt.Fprintf(os.Stderr, "Invalid format '%s'. Use: user@hostname\n", identifier)
29+
os.Exit(1)
30+
}
31+
username := parts[0]
32+
hostname := parts[1]
33+
34+
// Find the account in database
35+
accounts, err := db.GetAllAccounts()
36+
if err != nil {
37+
fmt.Fprintf(os.Stderr, "Error getting accounts: %v\n", err)
38+
os.Exit(1)
39+
}
40+
41+
var dbAccount *model.Account
42+
for _, acc := range accounts {
43+
if acc.Hostname == hostname && acc.Username == username {
44+
dbAccount = &acc
45+
break
46+
}
47+
}
48+
49+
if dbAccount == nil {
50+
fmt.Fprintf(os.Stderr, "Account '%s' not found in database\n", identifier)
51+
os.Exit(1)
52+
}
53+
54+
// Generate the authorized_keys content
55+
content, err := core.GenerateKeysContent(dbAccount.ID)
56+
if err != nil {
57+
fmt.Fprintf(os.Stderr, "Error generating keys content: %v\n", err)
58+
os.Exit(1)
59+
}
60+
61+
fmt.Println(content)
62+
},
63+
}
64+
65+
// Helper function to split user@hostname
66+
func splitUsernameHostname(identifier string) []string {
67+
parts := make([]string, 0, 2)
68+
idx := -1
69+
for i := len(identifier) - 1; i >= 0; i-- {
70+
if identifier[i] == '@' {
71+
idx = i
72+
break
73+
}
74+
}
75+
if idx == -1 {
76+
return parts
77+
}
78+
parts = append(parts, identifier[:idx], identifier[idx+1:])
79+
return parts
80+
}

0 commit comments

Comments
 (0)