Skip to content

Commit 31c7151

Browse files
committed
Normalize API key display formatting
1 parent f157df3 commit 31c7151

2 files changed

Lines changed: 87 additions & 26 deletions

File tree

cmd/api_keys.go

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,15 @@ func (c APIKeysCmd) List(ctx context.Context, in APIKeysListInput) error {
126126

127127
table := pterm.TableData{{"ID", "Name", "Scope", "Project", "Masked Key", "Expires At", "Created At"}}
128128
for _, key := range keys {
129+
display := newAPIKeyDisplay(key)
129130
table = append(table, []string{
130-
key.ID,
131-
key.Name,
132-
formatAPIKeyScope(key),
133-
formatAPIKeyProject(key),
134-
key.MaskedKey,
135-
formatAPIKeyExpiresAt(key),
136-
util.FormatLocal(key.CreatedAt),
131+
display.ID,
132+
display.Name,
133+
display.Scope,
134+
display.Project,
135+
display.MaskedKey,
136+
display.ExpiresAt,
137+
display.CreatedAt,
137138
})
138139
}
139140
PrintTableNoPad(table, true)
@@ -201,36 +202,69 @@ func (c APIKeysCmd) Delete(ctx context.Context, in APIKeysDeleteInput) error {
201202
return nil
202203
}
203204

205+
type apiKeyDisplay struct {
206+
ID string
207+
Name string
208+
PlaintextKey string
209+
Scope string
210+
Project string
211+
MaskedKey string
212+
CreatedBy string
213+
ExpiresAt string
214+
CreatedAt string
215+
}
216+
204217
func renderCreatedAPIKey(key *kernel.CreatedAPIKey) {
218+
display := newCreatedAPIKeyDisplay(key)
205219
rows := pterm.TableData{
206220
{"Field", "Value"},
207-
{"ID", key.ID},
208-
{"Name", key.Name},
209-
{"Key", key.Key},
210-
{"Scope", formatAPIKeyScope(key.APIKey)},
211-
{"Project", formatAPIKeyProject(key.APIKey)},
212-
{"Masked Key", key.MaskedKey},
213-
{"Expires At", formatAPIKeyExpiresAt(key.APIKey)},
221+
{"ID", display.ID},
222+
{"Name", display.Name},
223+
{"Key", display.PlaintextKey},
224+
{"Scope", display.Scope},
225+
{"Project", display.Project},
226+
{"Masked Key", display.MaskedKey},
227+
{"Expires At", display.ExpiresAt},
214228
}
215229
PrintTableNoPad(rows, true)
216230
}
217231

218232
func renderAPIKeyDetails(key *kernel.APIKey) {
233+
display := newAPIKeyDisplay(*key)
219234
rows := pterm.TableData{
220235
{"Field", "Value"},
221-
{"ID", key.ID},
222-
{"Name", key.Name},
223-
{"Scope", formatAPIKeyScope(*key)},
224-
{"Project", formatAPIKeyProject(*key)},
225-
{"Masked Key", key.MaskedKey},
226-
{"Created By", formatAPIKeyCreator(*key)},
227-
{"Expires At", formatAPIKeyExpiresAt(*key)},
228-
{"Created At", util.FormatLocal(key.CreatedAt)},
236+
{"ID", display.ID},
237+
{"Name", display.Name},
238+
{"Scope", display.Scope},
239+
{"Project", display.Project},
240+
{"Masked Key", display.MaskedKey},
241+
{"Created By", display.CreatedBy},
242+
{"Expires At", display.ExpiresAt},
243+
{"Created At", display.CreatedAt},
229244
}
230245
PrintTableNoPad(rows, true)
231246
}
232247

233-
func formatAPIKeyProject(key kernel.APIKey) string {
248+
func newCreatedAPIKeyDisplay(key *kernel.CreatedAPIKey) apiKeyDisplay {
249+
display := newAPIKeyDisplay(key.APIKey)
250+
display.PlaintextKey = key.Key
251+
return display
252+
}
253+
254+
func newAPIKeyDisplay(key kernel.APIKey) apiKeyDisplay {
255+
return apiKeyDisplay{
256+
ID: key.ID,
257+
Name: key.Name,
258+
Scope: apiKeyScope(key),
259+
Project: apiKeyProject(key),
260+
MaskedKey: key.MaskedKey,
261+
CreatedBy: apiKeyCreator(key),
262+
ExpiresAt: apiKeyExpiresAt(key),
263+
CreatedAt: util.FormatLocal(key.CreatedAt),
264+
}
265+
}
266+
267+
func apiKeyProject(key kernel.APIKey) string {
234268
if key.JSON.ProjectName.Valid() && key.ProjectName != "" {
235269
return key.ProjectName
236270
}
@@ -240,14 +274,14 @@ func formatAPIKeyProject(key kernel.APIKey) string {
240274
return "-"
241275
}
242276

243-
func formatAPIKeyScope(key kernel.APIKey) string {
277+
func apiKeyScope(key kernel.APIKey) string {
244278
if key.JSON.ProjectID.Valid() && key.ProjectID != "" {
245279
return "Project"
246280
}
247281
return "Org"
248282
}
249283

250-
func formatAPIKeyCreator(key kernel.APIKey) string {
284+
func apiKeyCreator(key kernel.APIKey) string {
251285
if key.CreatedBy.JSON.Name.Valid() && key.CreatedBy.Name != "" {
252286
return key.CreatedBy.Name
253287
}
@@ -257,7 +291,7 @@ func formatAPIKeyCreator(key kernel.APIKey) string {
257291
return "-"
258292
}
259293

260-
func formatAPIKeyExpiresAt(key kernel.APIKey) string {
294+
func apiKeyExpiresAt(key kernel.APIKey) string {
261295
if !key.JSON.ExpiresAt.Valid() {
262296
return "Never"
263297
}

cmd/api_keys_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"testing"
99

10+
"github.com/kernel/cli/pkg/util"
1011
"github.com/kernel/kernel-go-sdk"
1112
"github.com/kernel/kernel-go-sdk/option"
1213
"github.com/kernel/kernel-go-sdk/packages/pagination"
@@ -196,6 +197,32 @@ func TestAPIKeysListPassesPaginationAndRendersRows(t *testing.T) {
196197
assert.Contains(t, out, "Never")
197198
}
198199

200+
func TestAPIKeyDisplayNormalizesSDKFields(t *testing.T) {
201+
key := apiKeyFromJSON(`{"id":"key_123","name":"ci","masked_key":"sk_...123","created_at":"2026-05-27T12:00:00Z","created_by":{"id":"user_123","email":"dev@example.com","name":"Dev"},"expires_at":"2026-06-27T12:00:00Z","project_id":"proj_123","project_name":"Prod"}`)
202+
203+
display := newAPIKeyDisplay(*key)
204+
205+
assert.Equal(t, "key_123", display.ID)
206+
assert.Equal(t, "ci", display.Name)
207+
assert.Equal(t, "Project", display.Scope)
208+
assert.Equal(t, "Prod", display.Project)
209+
assert.Equal(t, "sk_...123", display.MaskedKey)
210+
assert.Equal(t, "Dev", display.CreatedBy)
211+
assert.Equal(t, util.FormatLocal(key.ExpiresAt), display.ExpiresAt)
212+
assert.Equal(t, util.FormatLocal(key.CreatedAt), display.CreatedAt)
213+
}
214+
215+
func TestAPIKeyDisplayFallsBackForAbsentOptionalFields(t *testing.T) {
216+
key := apiKeyFromJSON(`{"id":"key_123","name":"ci","masked_key":"sk_...123","created_at":"2026-05-27T12:00:00Z","created_by":{"id":"user_123","email":"dev@example.com","name":null},"expires_at":null,"project_id":null,"project_name":null}`)
217+
218+
display := newAPIKeyDisplay(*key)
219+
220+
assert.Equal(t, "Org", display.Scope)
221+
assert.Equal(t, "-", display.Project)
222+
assert.Equal(t, "dev@example.com", display.CreatedBy)
223+
assert.Equal(t, "Never", display.ExpiresAt)
224+
}
225+
199226
func TestAPIKeysUpdateRequiresName(t *testing.T) {
200227
c := APIKeysCmd{apiKeys: &FakeAPIKeysService{}}
201228
err := c.Update(context.Background(), APIKeysUpdateInput{ID: "key_123"})

0 commit comments

Comments
 (0)