Skip to content
Closed
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
88 changes: 84 additions & 4 deletions src/cmdBuilder/createRunFunc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,30 @@ import (
"context"
"fmt"
"os"
"time"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/zeropsio/zcli/src/cliStorage"
"github.com/zeropsio/zcli/src/constants"
"github.com/zeropsio/zcli/src/entity"
"github.com/zeropsio/zcli/src/flagParams"
"github.com/zeropsio/zcli/src/httpClient"
"github.com/zeropsio/zcli/src/i18n"
"github.com/zeropsio/zcli/src/optional"
"github.com/zeropsio/zcli/src/printer"
"github.com/zeropsio/zcli/src/region"
"github.com/zeropsio/zcli/src/uxBlock"
"github.com/zeropsio/zcli/src/uxHelpers"
getVersion "github.com/zeropsio/zcli/src/version"
"github.com/zeropsio/zcli/src/zeropsRestApiClient"
"github.com/zeropsio/zerops-go/types/uuid"
)

const (
EnvTokenKey = "ZEROPS_TOKEN" //nolint:gosec // Environment variable name, not a credential
)

type GuestCmdData struct {
CliStorage *cliStorage.Handler
UxBlocks *uxBlock.Blocks
Expand All @@ -44,6 +52,78 @@ type LoggedUserCmdData struct {
VpnKeys map[uuid.ProjectId]entity.VpnKey
}

// resolveRegion finds a region by name or returns the default region.
// This is a simplified, non-interactive version of the login region logic.
func resolveRegion(regions []region.Item, selectedRegion string) (region.Item, error) {
if selectedRegion == "" {
for _, reg := range regions {
if reg.IsDefault {
return reg, nil
}
}
return region.Item{}, errors.New("no default region available")
}

for _, reg := range regions {
if reg.Name == selectedRegion {
return reg, nil
}
}

return region.Item{}, errors.Errorf("region '%s' not found", selectedRegion)
}

func resolveAuthenticationData(ctx context.Context, storedData cliStorage.Data, storage *cliStorage.Handler) (string, region.Item, error) {
token := storedData.Token
regionData := storedData.RegionData

envToken := os.Getenv(EnvTokenKey)
usingEnvToken := false

if token == "" && envToken != "" {
token = envToken
usingEnvToken = true
}

if token == "" {
return "", region.Item{}, errors.New(i18n.T(i18n.UnauthenticatedUser))
}

// Use default region for env tokens OR when region data is missing
if usingEnvToken || regionData.Address == "" {
// Use the same region fetching logic as login command
regionRetriever := region.New(httpClient.New(ctx, httpClient.Config{HttpTimeout: time.Minute * 5}))
regions, err := regionRetriever.RetrieveAllFromURL(ctx, constants.DefaultRegionUrl)
if err != nil {
return "", region.Item{}, errors.Wrap(err, "failed to retrieve regions")
}

// Use our simplified region resolution (no interactive mode)
resolvedRegion, err := resolveRegion(regions, "")
if err != nil {
if usingEnvToken {
return "", region.Item{}, errors.Wrap(err, "environment token requires default region")
}
return "", region.Item{}, errors.Wrap(err, "failed to resolve region data")
}
regionData = resolvedRegion

// Auto-login: Save env token and region like login command does
if usingEnvToken {
_, err = storage.Update(func(data cliStorage.Data) cliStorage.Data {
data.Token = token
data.RegionData = regionData
return data
})
if err != nil {
return "", region.Item{}, errors.Wrap(err, "failed to save authentication data")
}
}
}

return token, regionData, nil
}

func createCmdRunFunc(
cmd *Cmd,
flagParams *flagParams.Handler,
Expand Down Expand Up @@ -85,12 +165,12 @@ func createCmdRunFunc(

storedData := cliStorage.Data()

token := storedData.Token
if token == "" {
token, regionData, err := resolveAuthenticationData(ctx, storedData, cliStorage)
if err != nil {
if cmd.guestRunFunc != nil {
return cmd.guestRunFunc(ctx, guestCmdData)
}
return errors.New(i18n.T(i18n.UnauthenticatedUser))
return err
}

// user is logged in but there is only the guest run func
Expand All @@ -103,7 +183,7 @@ func createCmdRunFunc(
VpnKeys: storedData.VpnKeys,
}

cmdData.RestApiClient = zeropsRestApiClient.NewAuthorizedClient(token, "https://"+storedData.RegionData.Address)
cmdData.RestApiClient = zeropsRestApiClient.NewAuthorizedClient(token, "https://"+regionData.Address)

if cmd.scopeLevel != nil {
if err := cmd.scopeLevel.LoadSelectedScope(ctx, cmd, cmdData); err != nil {
Expand Down
Loading