Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func isAuthExempt(cmd *cobra.Command) bool {

// Check if the top-level command is in the exempt list
switch topLevel.Name() {
case "login", "logout", "help", "completion", "create", "mcp", "upgrade":
case "login", "logout", "help", "completion", "create", "mcp", "upgrade", "status":
return true
case "auth":
// Only exempt the auth command itself (status display), not its subcommands
Expand Down Expand Up @@ -147,6 +147,7 @@ func init() {
rootCmd.AddCommand(createCmd)
rootCmd.AddCommand(mcp.MCPCmd)
rootCmd.AddCommand(upgradeCmd)
rootCmd.AddCommand(statusCmd)

rootCmd.PersistentPostRunE = func(cmd *cobra.Command, args []string) error {
// running synchronously so we never slow the command
Expand Down
125 changes: 125 additions & 0 deletions cmd/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package cmd

import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"time"

"github.com/pterm/pterm"
"github.com/spf13/cobra"
)

type statusComponent struct {
Name string `json:"name"`
Status string `json:"status"`
}

type statusGroup struct {
Name string `json:"name"`
Status string `json:"status"`
Components []statusComponent `json:"components"`
}

type statusResponse struct {
Status string `json:"status"`
Groups []statusGroup `json:"groups"`
}

const defaultBaseURL = "https://api.onkernel.com"

var statusCmd = &cobra.Command{
Use: "status",
Short: "Check the operational status of Kernel services",
RunE: runStatus,
}

func init() {
statusCmd.Flags().StringP("output", "o", "", "Output format (json)")
}

func getBaseURL() string {
if u := os.Getenv("KERNEL_BASE_URL"); strings.TrimSpace(u) != "" {
return strings.TrimRight(u, "/")
}
return defaultBaseURL
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated base URL resolution logic across files

Low Severity

The getBaseURL() function and defaultBaseURL constant duplicate the base URL resolution logic already present inline in cmd/deploy.go (lines 150–153), which also reads KERNEL_BASE_URL and falls back to "https://api.onkernel.com". The two implementations also differ subtly — getBaseURL trims trailing slashes while deploy.go does not — creating a risk of inconsistent behavior and requiring updates in multiple places if the default URL changes.

Additional Locations (1)

Fix in Cursor Fix in Web


func runStatus(cmd *cobra.Command, args []string) error {
output, _ := cmd.Flags().GetString("output")

client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(getBaseURL() + "/status")
if err != nil {
pterm.Error.Println("Could not reach Kernel API. Check https://status.kernel.sh for updates.")
return fmt.Errorf("request failed: %w", err)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double error output from printing then returning error

Medium Severity

runStatus calls pterm.Error.Println to display a friendly error, then returns a fmt.Errorf wrapping the same failure. The returned error triggers fang's WithErrorHandler in root.go, which also calls pterm.Error.Println, producing duplicate error output for the user. The rest of the codebase (e.g. cmd/browser_pools.go) follows the pattern of printing via pterm and returning nil to avoid this double-printing.

Additional Locations (1)

Fix in Cursor Fix in Web

defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
pterm.Error.Println("Could not reach Kernel API. Check https://status.kernel.sh for updates.")
return fmt.Errorf("status request failed: %s", resp.Status)
}

var status statusResponse
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
return fmt.Errorf("invalid response: %w", err)
}

if output == "json" {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(status)
}

printStatus(status)
return nil
}

// Colors match the dashboard's api-status-indicator.tsx
var statusDisplay = map[string]struct {
label string
rgb pterm.RGB
}{
"operational": {label: "Operational", rgb: pterm.NewRGB(31, 163, 130)},
"degraded_performance": {label: "Degraded Performance", rgb: pterm.NewRGB(245, 158, 11)},
"partial_outage": {label: "Partial Outage", rgb: pterm.NewRGB(242, 85, 51)},
"full_outage": {label: "Major Outage", rgb: pterm.NewRGB(239, 68, 68)},
"maintenance": {label: "Maintenance", rgb: pterm.NewRGB(36, 99, 235)},
"unknown": {label: "Unknown", rgb: pterm.NewRGB(128, 128, 128)},
}

func getStatusDisplay(status string) (string, pterm.RGB) {
if d, ok := statusDisplay[status]; ok {
return d.label, d.rgb
}
return "Unknown", pterm.NewRGB(128, 128, 128)
}

func coloredDot(rgb pterm.RGB) string {
return rgb.Sprint("●")
}

func printStatus(resp statusResponse) {
label, rgb := getStatusDisplay(resp.Status)
header := fmt.Sprintf("Kernel Status: %s", rgb.Sprint(label))
pterm.Println()
pterm.Println(" " + header)

for _, group := range resp.Groups {
pterm.Println()
if len(group.Components) == 0 {
groupLabel, groupColor := getStatusDisplay(group.Status)
pterm.Printf(" %s %s %s\n", coloredDot(groupColor), pterm.Bold.Sprint(group.Name), groupLabel)
} else {
pterm.Println(" " + pterm.Bold.Sprint(group.Name))
for _, comp := range group.Components {
compLabel, compColor := getStatusDisplay(comp.Status)
pterm.Printf(" %s %-20s %s\n", coloredDot(compColor), comp.Name, compLabel)
}
}
}
pterm.Println()
}