github.com/kubeshop/testkube@v1.17.23/pkg/executor/env/manager.go (about)

     1  package env
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	corev1 "k8s.io/api/core/v1"
    10  
    11  	"github.com/kubeshop/testkube/pkg/api/v1/testkube"
    12  )
    13  
    14  const (
    15  	// SecretEnvVarPrefix is a prefix for secret env vars
    16  	SecretEnvVarPrefix = "RUNNER_SECRET_ENV"
    17  	// SecretVarPrefix is a prefix for secret vars
    18  	SecretVarPrefix = "RUNNER_SECRET_VAR_"
    19  	// ConfigMapVarPrefix is a prefix for config map vars
    20  	ConfigMapVarPrefix = "RUNNER_CONFIGMAP_VAR_"
    21  	// GitUsernameEnvVarName is git username environment var name
    22  	GitUsernameEnvVarName = "RUNNER_GITUSERNAME"
    23  	// GitTokenEnvVarName is git token environment var name
    24  	GitTokenEnvVarName = "RUNNER_GITTOKEN"
    25  )
    26  
    27  // Interface is responsible for exchanging envs and vars with executor pod
    28  type Interface interface {
    29  	// PrepareSecrets prepares secret env vars based on secret envs and variables
    30  	PrepareSecrets(secretEnvs map[string]string, variables map[string]testkube.Variable) (secretEnvVars []corev1.EnvVar)
    31  	// PrepareEnvs prepares env vars based on envs and variables
    32  	PrepareEnvs(envs map[string]string, variables map[string]testkube.Variable) []corev1.EnvVar
    33  	// PrepareGitCredentials prepares git credentials
    34  	PrepareGitCredentials(usernameSecret, tokenSecret *testkube.SecretRef) (envVars []corev1.EnvVar)
    35  	// GetSecretEnvs get secret envs
    36  	GetSecretEnvs() (secretEnvs map[string]string)
    37  	// GetReferenceVars gets reference vars
    38  	GetReferenceVars(variables map[string]testkube.Variable)
    39  	// ObfuscateSecrets obfuscates secret values
    40  	ObfuscateSecrets(p []byte) []byte
    41  	// ObfuscateStringSlice obfuscates string slice values
    42  	ObfuscateStringSlice(values []string) []string
    43  }
    44  
    45  // NewManager returns an implementation of the Manager
    46  func NewManager() *Manager {
    47  	return &Manager{}
    48  }
    49  
    50  // NewManagerWithVars returns an implementation of the Manager with variables
    51  func NewManagerWithVars(variables map[string]testkube.Variable) *Manager {
    52  	return &Manager{
    53  		Variables: variables,
    54  	}
    55  }
    56  
    57  // Manager manages secret and config map exchange from job pods using env
    58  type Manager struct {
    59  	Variables map[string]testkube.Variable
    60  }
    61  
    62  // PrepareSecrets prepares secret env vars based on secret envs and variables
    63  func (m Manager) PrepareSecrets(secretEnvs map[string]string, variables map[string]testkube.Variable) (secretEnvVars []corev1.EnvVar) {
    64  	// preparet secret envs
    65  	i := 1
    66  	// Deprecated: use Secret Variables instead
    67  	for secretVar, secretName := range secretEnvs {
    68  		// TODO: these are duplicated because Postman executor is expecting it as json string
    69  		// and gets unmarshalled and the name and the value are taken from there, for other executors it will be like a normal env var.
    70  		secretEnvVars = append(secretEnvVars, corev1.EnvVar{
    71  			Name: secretVar,
    72  			ValueFrom: &corev1.EnvVarSource{
    73  				SecretKeyRef: &corev1.SecretKeySelector{
    74  					LocalObjectReference: corev1.LocalObjectReference{
    75  						Name: secretName,
    76  					},
    77  					Key: secretVar,
    78  				},
    79  			},
    80  		})
    81  
    82  		secretEnvVars = append(secretEnvVars, corev1.EnvVar{
    83  			Name: fmt.Sprintf("%s%d", SecretEnvVarPrefix, i),
    84  			ValueFrom: &corev1.EnvVarSource{
    85  				SecretKeyRef: &corev1.SecretKeySelector{
    86  					LocalObjectReference: corev1.LocalObjectReference{
    87  						Name: secretName,
    88  					},
    89  					Key: secretVar,
    90  				},
    91  			},
    92  		})
    93  		i++
    94  	}
    95  
    96  	i = 1
    97  	// prepare secret vars
    98  	for name, variable := range variables {
    99  		if !variable.IsSecret() || variable.SecretRef == nil {
   100  			continue
   101  		}
   102  
   103  		// TODO: these are duplicated because Postman executor is expecting it as json string
   104  		// and gets unmarshalled and the name and the value are taken from there, for other executors it will be like a normal env var.
   105  		secretEnvVars = append(secretEnvVars, corev1.EnvVar{
   106  			Name: name,
   107  			ValueFrom: &corev1.EnvVarSource{
   108  				SecretKeyRef: &corev1.SecretKeySelector{
   109  					LocalObjectReference: corev1.LocalObjectReference{
   110  						Name: variable.SecretRef.Name,
   111  					},
   112  					Key: variable.SecretRef.Key,
   113  				},
   114  			},
   115  		})
   116  
   117  		secretEnvVars = append(secretEnvVars, corev1.EnvVar{
   118  			Name: fmt.Sprintf("%s%d", SecretEnvVarPrefix, i),
   119  			ValueFrom: &corev1.EnvVarSource{
   120  				SecretKeyRef: &corev1.SecretKeySelector{
   121  					LocalObjectReference: corev1.LocalObjectReference{
   122  						Name: variable.SecretRef.Name,
   123  					},
   124  					Key: variable.SecretRef.Key,
   125  				},
   126  			},
   127  		})
   128  		i++
   129  
   130  		secretEnvVars = append(secretEnvVars, corev1.EnvVar{
   131  			Name: fmt.Sprintf("%s%s", SecretVarPrefix, name),
   132  			ValueFrom: &corev1.EnvVarSource{
   133  				SecretKeyRef: &corev1.SecretKeySelector{
   134  					LocalObjectReference: corev1.LocalObjectReference{
   135  						Name: variable.SecretRef.Name,
   136  					},
   137  					Key: variable.SecretRef.Key,
   138  				},
   139  			},
   140  		})
   141  	}
   142  
   143  	return secretEnvVars
   144  }
   145  
   146  // PrepareEnvs prepares env vars based on envs and variables
   147  func (m Manager) PrepareEnvs(envs map[string]string, variables map[string]testkube.Variable) []corev1.EnvVar {
   148  	var env []corev1.EnvVar
   149  	for k, v := range envs {
   150  		env = append(env, corev1.EnvVar{
   151  			Name:  k,
   152  			Value: v,
   153  		})
   154  	}
   155  	// prepare vars
   156  	for name, variable := range variables {
   157  		if variable.IsSecret() {
   158  			continue
   159  		}
   160  
   161  		if variable.ConfigMapRef == nil {
   162  			env = append(env, corev1.EnvVar{
   163  				Name:  name,
   164  				Value: variable.Value,
   165  			})
   166  		} else {
   167  			env = append(env, corev1.EnvVar{
   168  				Name: name,
   169  				ValueFrom: &corev1.EnvVarSource{
   170  					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
   171  						LocalObjectReference: corev1.LocalObjectReference{
   172  							Name: variable.ConfigMapRef.Name,
   173  						},
   174  						Key: variable.ConfigMapRef.Key,
   175  					},
   176  				},
   177  			})
   178  
   179  			env = append(env, corev1.EnvVar{
   180  				Name: fmt.Sprintf("%s%s", ConfigMapVarPrefix, name),
   181  				ValueFrom: &corev1.EnvVarSource{
   182  					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
   183  						LocalObjectReference: corev1.LocalObjectReference{
   184  							Name: variable.ConfigMapRef.Name,
   185  						},
   186  						Key: variable.ConfigMapRef.Key,
   187  					},
   188  				},
   189  			})
   190  		}
   191  	}
   192  
   193  	return env
   194  }
   195  
   196  // PrepareGitCredentials prepares git credentials
   197  func (m Manager) PrepareGitCredentials(usernameSecret, tokenSecret *testkube.SecretRef) (envVars []corev1.EnvVar) {
   198  	var data = []struct {
   199  		envVar    string
   200  		secretRef *testkube.SecretRef
   201  	}{
   202  		{
   203  			GitUsernameEnvVarName,
   204  			usernameSecret,
   205  		},
   206  		{
   207  			GitTokenEnvVarName,
   208  			tokenSecret,
   209  		},
   210  	}
   211  
   212  	for _, value := range data {
   213  		if value.secretRef != nil {
   214  			envVars = append(envVars, corev1.EnvVar{
   215  				Name: value.envVar,
   216  				ValueFrom: &corev1.EnvVarSource{
   217  					SecretKeyRef: &corev1.SecretKeySelector{
   218  						LocalObjectReference: corev1.LocalObjectReference{
   219  							Name: value.secretRef.Name,
   220  						},
   221  						Key: value.secretRef.Key,
   222  					},
   223  				},
   224  			})
   225  		}
   226  	}
   227  
   228  	return envVars
   229  }
   230  
   231  // GetSecretEnvs gets secret envs
   232  func (m Manager) GetSecretEnvs() (secretEnvs map[string]string) {
   233  	secretEnvs = make(map[string]string, 0)
   234  	i := 1
   235  	for {
   236  		envName := fmt.Sprintf("%s%d", SecretEnvVarPrefix, i)
   237  		secretEnv, ok := os.LookupEnv(envName)
   238  		if !ok {
   239  			break
   240  		}
   241  
   242  		secretEnvs[envName] = secretEnv
   243  		i++
   244  	}
   245  
   246  	return secretEnvs
   247  }
   248  
   249  // GetReferenceVars gets reference vars
   250  func (m Manager) GetReferenceVars(variables map[string]testkube.Variable) {
   251  	for name, variable := range variables {
   252  		if variable.IsSecret() {
   253  			value, ok := os.LookupEnv(fmt.Sprintf("%s%s", SecretVarPrefix, name))
   254  			if !ok {
   255  				continue
   256  			}
   257  
   258  			variable.Value = value
   259  			variables[name] = variable
   260  		} else {
   261  			value, ok := os.LookupEnv(fmt.Sprintf("%s%s", ConfigMapVarPrefix, name))
   262  			if !ok {
   263  				continue
   264  			}
   265  
   266  			variable.Value = value
   267  			variables[name] = variable
   268  		}
   269  	}
   270  
   271  	return
   272  }
   273  
   274  // ObfuscateSecrets obfuscates secret values
   275  func (m Manager) ObfuscateSecrets(p []byte) []byte {
   276  	if m.Variables == nil {
   277  		return p
   278  	}
   279  
   280  	for _, variable := range m.Variables {
   281  		if !variable.IsSecret() {
   282  			continue
   283  		}
   284  
   285  		p = bytes.ReplaceAll(p, []byte(variable.Value), []byte(strings.Repeat("*", len(variable.Value))))
   286  	}
   287  
   288  	return p
   289  }
   290  
   291  // ObfuscateStringSlice obfuscates string slice values
   292  func (m Manager) ObfuscateStringSlice(values []string) []string {
   293  	if m.Variables == nil {
   294  		return values
   295  	}
   296  
   297  	var results []string
   298  	for _, value := range values {
   299  		for _, variable := range m.Variables {
   300  			if !variable.IsSecret() {
   301  				continue
   302  			}
   303  
   304  			value = strings.ReplaceAll(value, variable.Value, strings.Repeat("*", len(variable.Value)))
   305  		}
   306  
   307  		results = append(results, value)
   308  	}
   309  
   310  	return results
   311  }