Skip to content

Commit 55a2524

Browse files
rgarciaCursor AgentmasnwilliamsCursor Agent
authored
CLI: Update SDK to 8dc9875576ae and add credentials + proxy check commands (#79)
This PR updates the Go SDK to 8dc9875576aea5daa08fa44faeee0bd0e99888a8 and adds CLI commands for new SDK methods. ## SDK Update - Updated kernel-go-sdk to 8dc9875576aea5daa08fa44faeee0bd0e99888a8 ## Coverage Analysis This PR was generated by performing a full enumeration of SDK methods and CLI commands. ## New Commands ### Credentials - `kernel credentials list` - List stored credentials for automatic re-authentication - `kernel credentials get <id-or-name>` - Get credential details - `kernel credentials create` - Create a new credential with name, domain, and values (username/password) - `kernel credentials update <id-or-name>` - Update credential properties - `kernel credentials delete <id-or-name>` - Delete a credential - `kernel credentials totp-code <id-or-name>` - Get current TOTP code for 2FA credentials ### Proxies - `kernel proxies check <id>` - Check proxy health status and get current IP address ## New Flags - Credentials create: `--name`, `--domain`, `--value` (repeatable), `--sso-provider`, `--totp-secret` - Credentials update: `--name`, `--sso-provider`, `--totp-secret`, `--value` (repeatable) - Credentials list: `--domain`, `--limit`, `--offset` - Proxies check: `--output` (json) Triggered by: kernel/kernel-go-sdk@8dc9875 Reviewer: @masnwilliams <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces credential management and proxy health-check capabilities in the CLI. > > - **New commands**: `kernel credentials` with `list`, `get`, `create`, `update`, `delete`, `totp-code`; `kernel proxies check` to run a health check and display status/IP/config > - **Core wiring**: Registers `credentials` under root; adds flags for filtering, output, and parameters (e.g., `--domain`, `--value`, `--totp-secret`, `--sso-provider`) > - **SDK and interfaces**: Extends proxy service with `Check`; adds credential service methods usage; updates `go.mod` to `github.com/kernel/kernel-go-sdk v0.26.0` > - **UX/output**: Human-readable tables and optional `--output json` across new commands > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 057e59a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor Agent <cursor-agent@kernel.sh> Co-authored-by: Mason Williams <43387599+masnwilliams@users.noreply.github.com> Co-authored-by: Cursor Agent <cursor-agent@onkernel.com>
1 parent 9e5c941 commit 55a2524

File tree

8 files changed

+734
-3
lines changed

8 files changed

+734
-3
lines changed

cmd/credentials.go

Lines changed: 545 additions & 0 deletions
Large diffs are not rendered by default.

cmd/proxies/check.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package proxies
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/kernel/cli/pkg/table"
8+
"github.com/kernel/cli/pkg/util"
9+
"github.com/kernel/kernel-go-sdk"
10+
"github.com/pterm/pterm"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
func (p ProxyCmd) Check(ctx context.Context, in ProxyCheckInput) error {
15+
if in.Output != "" && in.Output != "json" {
16+
return fmt.Errorf("unsupported --output value: use 'json'")
17+
}
18+
19+
if in.Output != "json" {
20+
pterm.Info.Printf("Running health check on proxy %s...\n", in.ID)
21+
}
22+
23+
proxy, err := p.proxies.Check(ctx, in.ID)
24+
if err != nil {
25+
return util.CleanedUpSdkError{Err: err}
26+
}
27+
28+
if in.Output == "json" {
29+
return util.PrintPrettyJSON(proxy)
30+
}
31+
32+
// Display proxy details after check
33+
rows := pterm.TableData{{"Property", "Value"}}
34+
35+
rows = append(rows, []string{"ID", proxy.ID})
36+
37+
name := proxy.Name
38+
if name == "" {
39+
name = "-"
40+
}
41+
rows = append(rows, []string{"Name", name})
42+
rows = append(rows, []string{"Type", string(proxy.Type)})
43+
44+
// Display protocol (default to https if not set)
45+
protocol := string(proxy.Protocol)
46+
if protocol == "" {
47+
protocol = "https"
48+
}
49+
rows = append(rows, []string{"Protocol", protocol})
50+
51+
// Display IP address if available
52+
if proxy.IPAddress != "" {
53+
rows = append(rows, []string{"IP Address", proxy.IPAddress})
54+
}
55+
56+
// Display type-specific config details
57+
rows = append(rows, getProxyCheckConfigRows(proxy)...)
58+
59+
// Display status with color
60+
status := string(proxy.Status)
61+
if status == "" {
62+
status = "-"
63+
} else if proxy.Status == kernel.ProxyCheckResponseStatusAvailable {
64+
status = pterm.Green(status)
65+
} else if proxy.Status == kernel.ProxyCheckResponseStatusUnavailable {
66+
status = pterm.Red(status)
67+
}
68+
rows = append(rows, []string{"Status", status})
69+
70+
// Display last checked timestamp
71+
lastChecked := util.FormatLocal(proxy.LastChecked)
72+
rows = append(rows, []string{"Last Checked", lastChecked})
73+
74+
table.PrintTableNoPad(rows, true)
75+
76+
// Print a summary message
77+
if proxy.Status == kernel.ProxyCheckResponseStatusAvailable {
78+
pterm.Success.Println("Proxy health check passed")
79+
} else {
80+
pterm.Warning.Println("Proxy health check failed - proxy is unavailable")
81+
}
82+
83+
return nil
84+
}
85+
86+
func getProxyCheckConfigRows(proxy *kernel.ProxyCheckResponse) [][]string {
87+
var rows [][]string
88+
config := &proxy.Config
89+
90+
switch proxy.Type {
91+
case kernel.ProxyCheckResponseTypeDatacenter, kernel.ProxyCheckResponseTypeIsp:
92+
if config.Country != "" {
93+
rows = append(rows, []string{"Country", config.Country})
94+
}
95+
case kernel.ProxyCheckResponseTypeResidential:
96+
if config.Country != "" {
97+
rows = append(rows, []string{"Country", config.Country})
98+
}
99+
if config.City != "" {
100+
rows = append(rows, []string{"City", config.City})
101+
}
102+
if config.State != "" {
103+
rows = append(rows, []string{"State", config.State})
104+
}
105+
if config.Zip != "" {
106+
rows = append(rows, []string{"ZIP", config.Zip})
107+
}
108+
if config.Asn != "" {
109+
rows = append(rows, []string{"ASN", config.Asn})
110+
}
111+
if config.Os != "" {
112+
rows = append(rows, []string{"OS", config.Os})
113+
}
114+
case kernel.ProxyCheckResponseTypeMobile:
115+
if config.Country != "" {
116+
rows = append(rows, []string{"Country", config.Country})
117+
}
118+
if config.City != "" {
119+
rows = append(rows, []string{"City", config.City})
120+
}
121+
if config.State != "" {
122+
rows = append(rows, []string{"State", config.State})
123+
}
124+
if config.Zip != "" {
125+
rows = append(rows, []string{"ZIP", config.Zip})
126+
}
127+
if config.Asn != "" {
128+
rows = append(rows, []string{"ASN", config.Asn})
129+
}
130+
if config.Carrier != "" {
131+
rows = append(rows, []string{"Carrier", config.Carrier})
132+
}
133+
case kernel.ProxyCheckResponseTypeCustom:
134+
if config.Host != "" {
135+
rows = append(rows, []string{"Host", config.Host})
136+
}
137+
if config.Port != 0 {
138+
rows = append(rows, []string{"Port", fmt.Sprintf("%d", config.Port)})
139+
}
140+
if config.Username != "" {
141+
rows = append(rows, []string{"Username", config.Username})
142+
}
143+
hasPassword := "No"
144+
if config.HasPassword {
145+
hasPassword = "Yes"
146+
}
147+
rows = append(rows, []string{"Has Password", hasPassword})
148+
}
149+
150+
return rows
151+
}
152+
153+
func runProxiesCheck(cmd *cobra.Command, args []string) error {
154+
client := util.GetKernelClient(cmd)
155+
output, _ := cmd.Flags().GetString("output")
156+
svc := client.Proxies
157+
p := ProxyCmd{proxies: &svc}
158+
return p.Check(cmd.Context(), ProxyCheckInput{ID: args[0], Output: output})
159+
}

cmd/proxies/common_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type FakeProxyService struct {
4141
GetFunc func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ProxyGetResponse, error)
4242
NewFunc func(ctx context.Context, body kernel.ProxyNewParams, opts ...option.RequestOption) (*kernel.ProxyNewResponse, error)
4343
DeleteFunc func(ctx context.Context, id string, opts ...option.RequestOption) error
44+
CheckFunc func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ProxyCheckResponse, error)
4445
}
4546

4647
func (f *FakeProxyService) List(ctx context.Context, opts ...option.RequestOption) (*[]kernel.ProxyListResponse, error) {
@@ -72,6 +73,13 @@ func (f *FakeProxyService) Delete(ctx context.Context, id string, opts ...option
7273
return nil
7374
}
7475

76+
func (f *FakeProxyService) Check(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ProxyCheckResponse, error) {
77+
if f.CheckFunc != nil {
78+
return f.CheckFunc(ctx, id, opts...)
79+
}
80+
return &kernel.ProxyCheckResponse{ID: id, Type: kernel.ProxyCheckResponseTypeDatacenter}, nil
81+
}
82+
7583
// Helper function to create test proxy responses
7684
func createDatacenterProxy(id, name, country string) kernel.ProxyListResponse {
7785
return kernel.ProxyListResponse{

cmd/proxies/proxies.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,21 @@ var proxiesDeleteCmd = &cobra.Command{
6060
RunE: runProxiesDelete,
6161
}
6262

63+
var proxiesCheckCmd = &cobra.Command{
64+
Use: "check <id>",
65+
Short: "Run a health check on a proxy",
66+
Long: "Run a health check on a proxy to verify it's working and update its status.",
67+
Args: cobra.ExactArgs(1),
68+
RunE: runProxiesCheck,
69+
}
70+
6371
func init() {
6472
// Add subcommands
6573
ProxiesCmd.AddCommand(proxiesListCmd)
6674
ProxiesCmd.AddCommand(proxiesGetCmd)
6775
ProxiesCmd.AddCommand(proxiesCreateCmd)
6876
ProxiesCmd.AddCommand(proxiesDeleteCmd)
77+
ProxiesCmd.AddCommand(proxiesCheckCmd)
6978

7079
// Add output flags
7180
proxiesListCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
@@ -99,4 +108,7 @@ func init() {
99108

100109
// Delete flags
101110
proxiesDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
111+
112+
// Check flags
113+
proxiesCheckCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
102114
}

cmd/proxies/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type ProxyService interface {
1313
Get(ctx context.Context, id string, opts ...option.RequestOption) (res *kernel.ProxyGetResponse, err error)
1414
New(ctx context.Context, body kernel.ProxyNewParams, opts ...option.RequestOption) (res *kernel.ProxyNewResponse, err error)
1515
Delete(ctx context.Context, id string, opts ...option.RequestOption) (err error)
16+
Check(ctx context.Context, id string, opts ...option.RequestOption) (res *kernel.ProxyCheckResponse, err error)
1617
}
1718

1819
// ProxyCmd handles proxy operations independent of cobra.
@@ -56,3 +57,8 @@ type ProxyDeleteInput struct {
5657
ID string
5758
SkipConfirm bool
5859
}
60+
61+
type ProxyCheckInput struct {
62+
ID string
63+
Output string
64+
}

cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func init() {
139139
rootCmd.AddCommand(profilesCmd)
140140
rootCmd.AddCommand(proxies.ProxiesCmd)
141141
rootCmd.AddCommand(extensionsCmd)
142+
rootCmd.AddCommand(credentialsCmd)
142143
rootCmd.AddCommand(createCmd)
143144
rootCmd.AddCommand(mcp.MCPCmd)
144145
rootCmd.AddCommand(upgradeCmd)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1
1010
github.com/golang-jwt/jwt/v5 v5.2.2
1111
github.com/joho/godotenv v1.5.1
12-
github.com/kernel/kernel-go-sdk v0.26.1-0.20260117115631-ebae1efd3449
12+
github.com/kernel/kernel-go-sdk v0.26.0
1313
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1414
github.com/pterm/pterm v0.12.80
1515
github.com/samber/lo v1.51.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
6464
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6565
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
6666
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
67-
github.com/kernel/kernel-go-sdk v0.26.1-0.20260117115631-ebae1efd3449 h1:NDrHon1ahRBI1xlatalhEUxjRk03EX5MtZ7Q1sapsLs=
68-
github.com/kernel/kernel-go-sdk v0.26.1-0.20260117115631-ebae1efd3449/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
67+
github.com/kernel/kernel-go-sdk v0.26.0 h1:IBiEohSSZN5MEZjmnfqseT3tEip6+xg7Zxr79vJYMBA=
68+
github.com/kernel/kernel-go-sdk v0.26.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
6969
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
7070
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
7171
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=

0 commit comments

Comments
 (0)