diff --git a/cmd/auth_connections.go b/cmd/auth_connections.go index 72d5c5d..f0b041b 100644 --- a/cmd/auth_connections.go +++ b/cmd/auth_connections.go @@ -46,6 +46,9 @@ type AuthConnectionCreateInput struct { SaveCredentials bool NoSaveCredentials bool HealthCheckInterval int + NoHealthChecks bool + NoAutoReauth bool + RecordSession bool Output string } @@ -74,6 +77,9 @@ type AuthConnectionUpdateInput struct { SaveCredentials BoolFlag HealthCheckInterval int HealthCheckIntervalSet bool + HealthChecks BoolFlag + AutoReauth BoolFlag + RecordSession BoolFlag Output string } @@ -179,6 +185,18 @@ func (c AuthConnectionCmd) Create(ctx context.Context, in AuthConnectionCreateIn params.ManagedAuthCreateRequest.SaveCredentials = kernel.Opt(false) } + if in.NoHealthChecks { + params.ManagedAuthCreateRequest.HealthChecks = kernel.Opt(false) + } + + if in.NoAutoReauth { + params.ManagedAuthCreateRequest.AutoReauth = kernel.Opt(false) + } + + if in.RecordSession { + params.ManagedAuthCreateRequest.RecordSession = kernel.Opt(true) + } + if in.Output != "json" { pterm.Info.Printf("Creating managed auth for %s...\n", in.Domain) } @@ -218,6 +236,9 @@ func printManagedAuthSummary(auth *kernel.ManagedAuth) { if auth.ProxyID != "" { tableData = append(tableData, []string{"Proxy ID", auth.ProxyID}) } + tableData = append(tableData, []string{"Health Checks", fmt.Sprintf("%t", auth.HealthChecks)}) + tableData = append(tableData, []string{"Auto Reauth", fmt.Sprintf("%t", auth.AutoReauth)}) + tableData = append(tableData, []string{"Record Session", fmt.Sprintf("%t", auth.RecordSession)}) PrintTableNoPad(tableData, true) } @@ -243,6 +264,18 @@ func (c AuthConnectionCmd) Update(ctx context.Context, in AuthConnectionUpdateIn params.ManagedAuthUpdateRequest.SaveCredentials = kernel.Opt(in.SaveCredentials.Value) hasChanges = true } + if in.HealthChecks.Set { + params.ManagedAuthUpdateRequest.HealthChecks = kernel.Opt(in.HealthChecks.Value) + hasChanges = true + } + if in.AutoReauth.Set { + params.ManagedAuthUpdateRequest.AutoReauth = kernel.Opt(in.AutoReauth.Value) + hasChanges = true + } + if in.RecordSession.Set { + params.ManagedAuthUpdateRequest.RecordSession = kernel.Opt(in.RecordSession.Value) + hasChanges = true + } if in.AllowedDomainsSet { params.ManagedAuthUpdateRequest.AllowedDomains = in.AllowedDomains hasChanges = true @@ -810,6 +843,9 @@ func init() { authConnectionsCreateCmd.Flags().String("proxy-name", "", "Proxy name to use") authConnectionsCreateCmd.Flags().Bool("no-save-credentials", false, "Disable saving credentials after successful login") authConnectionsCreateCmd.Flags().Int("health-check-interval", 0, "Interval in seconds between health checks (300-86400)") + authConnectionsCreateCmd.Flags().Bool("no-health-checks", false, "Disable periodic health checks (also prevents automatic re-auth)") + authConnectionsCreateCmd.Flags().Bool("no-auto-reauth", false, "Disable automatic re-authentication when a health check detects an expired session") + authConnectionsCreateCmd.Flags().Bool("record-session", false, "Record browser sessions for this connection by default") _ = authConnectionsCreateCmd.MarkFlagRequired("domain") _ = authConnectionsCreateCmd.MarkFlagRequired("profile-name") authConnectionsCreateCmd.MarkFlagsMutuallyExclusive("credential-name", "credential-provider") @@ -830,8 +866,17 @@ func init() { authConnectionsUpdateCmd.Flags().Bool("save-credentials", false, "Enable saving credentials after successful login") authConnectionsUpdateCmd.Flags().Bool("no-save-credentials", false, "Disable saving credentials after successful login") authConnectionsUpdateCmd.Flags().Int("health-check-interval", 0, "Interval in seconds between health checks") + authConnectionsUpdateCmd.Flags().Bool("health-checks", false, "Enable periodic health checks") + authConnectionsUpdateCmd.Flags().Bool("no-health-checks", false, "Disable periodic health checks (also prevents automatic re-auth)") + authConnectionsUpdateCmd.Flags().Bool("auto-reauth", false, "Enable automatic re-authentication on health check failure") + authConnectionsUpdateCmd.Flags().Bool("no-auto-reauth", false, "Disable automatic re-authentication") + authConnectionsUpdateCmd.Flags().Bool("record-session", false, "Record browser sessions for this connection by default") + authConnectionsUpdateCmd.Flags().Bool("no-record-session", false, "Do not record browser sessions by default") authConnectionsUpdateCmd.MarkFlagsMutuallyExclusive("credential-name", "credential-provider") authConnectionsUpdateCmd.MarkFlagsMutuallyExclusive("save-credentials", "no-save-credentials") + authConnectionsUpdateCmd.MarkFlagsMutuallyExclusive("health-checks", "no-health-checks") + authConnectionsUpdateCmd.MarkFlagsMutuallyExclusive("auto-reauth", "no-auto-reauth") + authConnectionsUpdateCmd.MarkFlagsMutuallyExclusive("record-session", "no-record-session") // List flags authConnectionsListCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response") @@ -887,6 +932,9 @@ func runAuthConnectionsCreate(cmd *cobra.Command, args []string) error { proxyName, _ := cmd.Flags().GetString("proxy-name") noSaveCredentials, _ := cmd.Flags().GetBool("no-save-credentials") healthCheckInterval, _ := cmd.Flags().GetInt("health-check-interval") + noHealthChecks, _ := cmd.Flags().GetBool("no-health-checks") + noAutoReauth, _ := cmd.Flags().GetBool("no-auto-reauth") + recordSession, _ := cmd.Flags().GetBool("record-session") svc := client.Auth.Connections c := AuthConnectionCmd{svc: &svc} @@ -903,6 +951,9 @@ func runAuthConnectionsCreate(cmd *cobra.Command, args []string) error { ProxyName: proxyName, NoSaveCredentials: noSaveCredentials, HealthCheckInterval: healthCheckInterval, + NoHealthChecks: noHealthChecks, + NoAutoReauth: noAutoReauth, + RecordSession: recordSession, Output: output, }) } @@ -942,6 +993,36 @@ func runAuthConnectionsUpdate(cmd *cobra.Command, args []string) error { saveCredentialsFlag = BoolFlag{Set: true, Value: !noSaveCredentials} } + healthChecksFlag := BoolFlag{} + if cmd.Flags().Changed("health-checks") { + v, _ := cmd.Flags().GetBool("health-checks") + healthChecksFlag = BoolFlag{Set: true, Value: v} + } + if cmd.Flags().Changed("no-health-checks") { + v, _ := cmd.Flags().GetBool("no-health-checks") + healthChecksFlag = BoolFlag{Set: true, Value: !v} + } + + autoReauthFlag := BoolFlag{} + if cmd.Flags().Changed("auto-reauth") { + v, _ := cmd.Flags().GetBool("auto-reauth") + autoReauthFlag = BoolFlag{Set: true, Value: v} + } + if cmd.Flags().Changed("no-auto-reauth") { + v, _ := cmd.Flags().GetBool("no-auto-reauth") + autoReauthFlag = BoolFlag{Set: true, Value: !v} + } + + recordSessionFlag := BoolFlag{} + if cmd.Flags().Changed("record-session") { + v, _ := cmd.Flags().GetBool("record-session") + recordSessionFlag = BoolFlag{Set: true, Value: v} + } + if cmd.Flags().Changed("no-record-session") { + v, _ := cmd.Flags().GetBool("no-record-session") + recordSessionFlag = BoolFlag{Set: true, Value: !v} + } + svc := client.Auth.Connections c := AuthConnectionCmd{svc: &svc} return c.Update(cmd.Context(), AuthConnectionUpdateInput{ @@ -964,6 +1045,9 @@ func runAuthConnectionsUpdate(cmd *cobra.Command, args []string) error { SaveCredentials: saveCredentialsFlag, HealthCheckInterval: healthCheckInterval, HealthCheckIntervalSet: cmd.Flags().Changed("health-check-interval"), + HealthChecks: healthChecksFlag, + AutoReauth: autoReauthFlag, + RecordSession: recordSessionFlag, Output: output, }) } diff --git a/cmd/auth_connections_test.go b/cmd/auth_connections_test.go index 96bb131..7fff1e1 100644 --- a/cmd/auth_connections_test.go +++ b/cmd/auth_connections_test.go @@ -293,6 +293,34 @@ func TestAuthConnectionsCreate_ProviderWithExplicitAuto_SetsAuto(t *testing.T) { assert.True(t, cred.Auto.Value) } +func TestAuthConnectionsCreate_HealthMonitoringFlags(t *testing.T) { + var captured kernel.AuthConnectionNewParams + fake := &FakeAuthConnectionService{ + NewFunc: func(ctx context.Context, body kernel.AuthConnectionNewParams, opts ...option.RequestOption) (*kernel.ManagedAuth, error) { + captured = body + return &kernel.ManagedAuth{ID: "conn-new"}, nil + }, + } + + c := AuthConnectionCmd{svc: fake} + err := c.Create(context.Background(), AuthConnectionCreateInput{ + Domain: "example.com", + ProfileName: "p", + NoHealthChecks: true, + NoAutoReauth: true, + RecordSession: true, + Output: "json", + }) + require.NoError(t, err) + + require.True(t, captured.ManagedAuthCreateRequest.HealthChecks.Valid()) + assert.False(t, captured.ManagedAuthCreateRequest.HealthChecks.Value) + require.True(t, captured.ManagedAuthCreateRequest.AutoReauth.Valid()) + assert.False(t, captured.ManagedAuthCreateRequest.AutoReauth.Value) + require.True(t, captured.ManagedAuthCreateRequest.RecordSession.Valid()) + assert.True(t, captured.ManagedAuthCreateRequest.RecordSession.Value) +} + // --credential-name references a Kernel-managed credential and should never // carry a provider/auto/path — the default-auto logic must not kick in here. func TestAuthConnectionsCreate_CredentialName_UnaffectedByAutoDefault(t *testing.T) { @@ -352,6 +380,9 @@ func TestAuthConnectionsUpdate_MapsParams(t *testing.T) { SaveCredentials: BoolFlag{Set: true, Value: false}, HealthCheckInterval: 900, HealthCheckIntervalSet: true, + HealthChecks: BoolFlag{Set: true, Value: false}, + AutoReauth: BoolFlag{Set: true, Value: false}, + RecordSession: BoolFlag{Set: true, Value: true}, }) require.NoError(t, err) require.True(t, captured.ManagedAuthUpdateRequest.LoginURL.Valid()) @@ -369,6 +400,12 @@ func TestAuthConnectionsUpdate_MapsParams(t *testing.T) { assert.False(t, captured.ManagedAuthUpdateRequest.SaveCredentials.Value) require.True(t, captured.ManagedAuthUpdateRequest.HealthCheckInterval.Valid()) assert.Equal(t, int64(900), captured.ManagedAuthUpdateRequest.HealthCheckInterval.Value) + require.True(t, captured.ManagedAuthUpdateRequest.HealthChecks.Valid()) + assert.False(t, captured.ManagedAuthUpdateRequest.HealthChecks.Value) + require.True(t, captured.ManagedAuthUpdateRequest.AutoReauth.Valid()) + assert.False(t, captured.ManagedAuthUpdateRequest.AutoReauth.Value) + require.True(t, captured.ManagedAuthUpdateRequest.RecordSession.Valid()) + assert.True(t, captured.ManagedAuthUpdateRequest.RecordSession.Value) } func newFakeWithMfaOptions(options []kernel.ManagedAuthMfaOption) *FakeAuthConnectionService { diff --git a/go.mod b/go.mod index 62cf135..f83ae1c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1 github.com/golang-jwt/jwt/v5 v5.2.2 github.com/joho/godotenv v1.5.1 - github.com/kernel/kernel-go-sdk v0.53.0 + github.com/kernel/kernel-go-sdk v0.55.0 github.com/klauspost/compress v1.18.5 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pterm/pterm v0.12.80 diff --git a/go.sum b/go.sum index b29cf9b..d07fdd8 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/kernel/kernel-go-sdk v0.53.0 h1:XgcuJv3G4a6nr9LYBZ21gLUWvsIDLSG4YhZAngNrqE0= -github.com/kernel/kernel-go-sdk v0.53.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ= +github.com/kernel/kernel-go-sdk v0.55.0 h1:JjLqrh+58oX8l4N/+MfVGVh+L6G/UHnCRdeXFUpXPWo= +github.com/kernel/kernel-go-sdk v0.55.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ= github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=