From 0fb61bd887e619b51547ec9ef02e5b42d1d22d17 Mon Sep 17 00:00:00 2001 From: Ilyaas Kapadia <86218345+IlyaasK@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:30:00 -0400 Subject: [PATCH] Show extension checksums in CLI output Expose the API-provided SHA-256 checksum in list, get, and upload tables so operators can verify extension artifacts without switching to JSON output. --- README.md | 2 +- cmd/extensions.go | 23 +++++++---------------- cmd/extensions_test.go | 12 +++++++++--- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c54f458c..1a35d1f2 100644 --- a/README.md +++ b/README.md @@ -481,7 +481,7 @@ Per-category updates are partial — only categories you name are changed; other - `kernel extensions list` - List all uploaded extensions - `--output json`, `-o json` - Output raw JSON array -- `kernel extensions get ` - Show extension metadata (id, name, created, size, last used) +- `kernel extensions get ` - Show extension metadata (id, name, checksum, created, size, last used) - `--output json`, `-o json` - Output raw JSON object - `kernel extensions upload ` - Upload an unpacked browser extension directory - `--name ` - Optional unique extension name diff --git a/cmd/extensions.go b/cmd/extensions.go index 80f15d74..69aa33fa 100644 --- a/cmd/extensions.go +++ b/cmd/extensions.go @@ -129,15 +129,12 @@ func (e ExtensionsCmd) List(ctx context.Context, in ExtensionsListInput) error { pterm.Info.Println("No extensions found") return nil } - rows := pterm.TableData{{"Extension ID", "Name", "Created At", "Size (bytes)", "Last Used At"}} + rows := pterm.TableData{{"Extension ID", "Name", "Checksum", "Created At", "Size (bytes)", "Last Used At"}} for _, it := range items { - name := it.Name - if name == "" { - name = "-" - } rows = append(rows, []string{ it.ID, - name, + util.FirstOrDash(it.Name), + util.FirstOrDash(it.Checksum), util.FormatLocal(it.CreatedAt), fmt.Sprintf("%d", it.SizeBytes), util.FormatLocal(it.LastUsedAt), @@ -165,17 +162,14 @@ func (e ExtensionsCmd) Get(ctx context.Context, in ExtensionsGetInput) error { return util.PrintPrettyJSON(item) } - name := item.Name - if name == "" { - name = "-" - } rows := pterm.TableData{{"Property", "Value"}} rows = append(rows, []string{"ID", item.ID}) - rows = append(rows, []string{"Name", name}) + rows = append(rows, []string{"Name", util.FirstOrDash(item.Name)}) rows = append(rows, []string{"Created At", util.FormatLocal(item.CreatedAt)}) rows = append(rows, []string{"Size (bytes)", fmt.Sprintf("%d", item.SizeBytes)}) rows = append(rows, []string{"Last Used At", util.FormatLocal(item.LastUsedAt)}) PrintTableNoPad(rows, true) + pterm.Printf("Checksum: %s\n", util.FirstOrDash(item.Checksum)) return nil } @@ -432,16 +426,13 @@ func (e ExtensionsCmd) Upload(ctx context.Context, in ExtensionsUploadInput) err return util.PrintPrettyJSON(item) } - name := item.Name - if name == "" { - name = "-" - } rows := pterm.TableData{{"Property", "Value"}} rows = append(rows, []string{"ID", item.ID}) - rows = append(rows, []string{"Name", name}) + rows = append(rows, []string{"Name", util.FirstOrDash(item.Name)}) rows = append(rows, []string{"Created At", util.FormatLocal(item.CreatedAt)}) rows = append(rows, []string{"Size (bytes)", fmt.Sprintf("%d", item.SizeBytes)}) PrintTableNoPad(rows, true) + pterm.Printf("Checksum: %s\n", util.FirstOrDash(item.Checksum)) return nil } diff --git a/cmd/extensions_test.go b/cmd/extensions_test.go index 83626810..b9fc0f97 100644 --- a/cmd/extensions_test.go +++ b/cmd/extensions_test.go @@ -67,10 +67,11 @@ func (f *FakeExtensionsService) Upload(ctx context.Context, body kernel.Extensio func TestExtensionsGet_Table(t *testing.T) { buf := capturePtermOutput(t) + const checksum = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" fake := &FakeExtensionsService{ GetFunc: func(ctx context.Context, idOrName string, opts ...option.RequestOption) (*kernel.ExtensionGetResponse, error) { assert.Equal(t, "my-ext", idOrName) - return &kernel.ExtensionGetResponse{ID: "e-123", Name: "my-ext", CreatedAt: time.Unix(0, 0), SizeBytes: 42}, nil + return &kernel.ExtensionGetResponse{ID: "e-123", Name: "my-ext", Checksum: checksum, CreatedAt: time.Unix(0, 0), SizeBytes: 42}, nil }, } e := ExtensionsCmd{extensions: fake} @@ -79,6 +80,7 @@ func TestExtensionsGet_Table(t *testing.T) { out := buf.String() assert.Contains(t, out, "e-123") assert.Contains(t, out, "my-ext") + assert.Contains(t, out, "Checksum: "+checksum) assert.Contains(t, out, "42") } @@ -93,15 +95,17 @@ func TestExtensionsList_Empty(t *testing.T) { func TestExtensionsList_WithRows(t *testing.T) { buf := capturePtermOutput(t) created := time.Unix(0, 0) - rows := []kernel.ExtensionListResponse{{ID: "e1", Name: "alpha", CreatedAt: created, SizeBytes: 10}, {ID: "e2", Name: "", CreatedAt: created, SizeBytes: 20}} + rows := []kernel.ExtensionListResponse{{ID: "e1", Name: "alpha", Checksum: "abc123", CreatedAt: created, SizeBytes: 10}, {ID: "e2", Name: "", CreatedAt: created, SizeBytes: 20}} fake := &FakeExtensionsService{ListFunc: func(ctx context.Context, query kernel.ExtensionListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.ExtensionListResponse], error) { return &pagination.OffsetPagination[kernel.ExtensionListResponse]{Items: rows}, nil }} e := ExtensionsCmd{extensions: fake} _ = e.List(context.Background(), ExtensionsListInput{}) out := buf.String() + assert.Contains(t, out, "Checksum") assert.Contains(t, out, "e1") assert.Contains(t, out, "alpha") + assert.Contains(t, out, "abc123") assert.Contains(t, out, "e2") } @@ -205,13 +209,14 @@ func TestExtensionsDownloadWebStore_InvalidOS(t *testing.T) { func TestExtensionsUpload_Success(t *testing.T) { buf := capturePtermOutput(t) + const checksum = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" dir := t.TempDir() // create a sample file inside dir err := os.WriteFile(filepath.Join(dir, "manifest.json"), []byte("{}"), 0644) assert.NoError(t, err) fake := &FakeExtensionsService{UploadFunc: func(ctx context.Context, body kernel.ExtensionUploadParams, opts ...option.RequestOption) (*kernel.ExtensionUploadResponse, error) { - return &kernel.ExtensionUploadResponse{ID: "e1", Name: "myext", CreatedAt: time.Unix(0, 0), SizeBytes: 10}, nil + return &kernel.ExtensionUploadResponse{ID: "e1", Name: "myext", Checksum: checksum, CreatedAt: time.Unix(0, 0), SizeBytes: 10}, nil }} e := ExtensionsCmd{extensions: fake} _ = e.Upload(context.Background(), ExtensionsUploadInput{Dir: dir, Name: "myext"}) @@ -220,6 +225,7 @@ func TestExtensionsUpload_Success(t *testing.T) { assert.Contains(t, out, "e1") assert.Contains(t, out, "Name") assert.Contains(t, out, "myext") + assert.Contains(t, out, "Checksum: "+checksum) } func TestExtensionsUpload_InvalidDir(t *testing.T) {