Repository: ovh/cds
Pull request #6137 (2022-04-06 09:57:02)

fix(api,ui): download worker route + user profile form
Signed-off-by: francois  samin <francois.samin@corp.ovh.com>


ovh-cds: 
CDS Report build-all-cds#17296.0 ✘  
* Build
  * Build and Package All ✔ 
  * Build Debpacker ✔ 
  * Build OS-Ansible-Inventory ✔ 
  * Build SMTPMock ✔ 
  * Lint UI Translate ✔ 
  * Test CLI ✔ 
  * Test Engine ✘  
  * Test SDK ✔ 
  * Test SDK Rust ✔ 
  * Test UI ✔ 

ovh-cds: 
CDS Report build-all-cds#17298.0 ✘  
* Build
  * Build and Package All ✔ 
  * Build Debpacker ✔ 
  * Build OS-Ansible-Inventory ✔ 
  * Build SMTPMock ✔ 
  * Lint UI Translate ✔ 
  * Test CLI ✔ 
  * Test Engine ✘  
  * Test SDK ✔ 
  * Test SDK Rust ✔ 
  * Test UI ✔ 

ovh-cds: 
CDS Report build-all-cds#17299.0 ✘  
* Build
  * Build and Package All ✔ 
  * Build Debpacker ✔ 
  * Build OS-Ansible-Inventory ✔ 
  * Build SMTPMock ✔ 
  * Lint UI Translate ✔ 
  * Test CLI ✔ 
  * Test Engine ✔ 
  * Test SDK ✔ 
  * Test SDK Rust ✔ 
  * Test UI ✔ 
* Package
  * Docker ✔ 
* Integration
  * Docker Compose Tests ✘  
  * Standalone Tests ✘  


Patch:
diff --git a/engine/api/application/dao.go b/engine/api/application/dao.go
index 5c7adc32d..e82d5a0a2 100644
--- a/engine/api/application/dao.go
+++ b/engine/api/application/dao.go
@@ -27,7 +27,7 @@ func (e dbApplication) Canonical() gorpmapper.CanonicalForms {
 }
 
 // LoadOptionFunc is a type for all options in LoadOptions
-type LoadOptionFunc *func(gorp.SqlExecutor, *sdk.Application) error
+type LoadOptionFunc *func(context.Context, gorp.SqlExecutor, *sdk.Application) error
 
 // LoadOptions provides all options on project loads functions
 var LoadOptions = struct {
@@ -137,14 +137,14 @@ func getWithClearVCSStrategyPassword(ctx context.Context, db gorp.SqlExecutor, k
 		return nil, err
 	}
 	if !isValid {
-		log.Error(context.Background(), "application.get> application %d data corrupted", dbApp.ID)
+		log.Error(ctx, "application.get> application %d data corrupted", dbApp.ID)
 		return nil, sdk.WithStack(sdk.ErrNotFound)
 	}
 	dbApp.ProjectKey = key
-	return unwrap(db, opts, &dbApp)
+	return unwrap(ctx, db, opts, &dbApp)
 }
 
-func unwrap(db gorp.SqlExecutor, opts []LoadOptionFunc, dbApp *dbApplication) (*sdk.Application, error) {
+func unwrap(ctx context.Context, db gorp.SqlExecutor, opts []LoadOptionFunc, dbApp *dbApplication) (*sdk.Application, error) {
 	app := &dbApp.Application
 	if app.ProjectKey == "" {
 		pkey, errP := db.SelectStr("SELECT projectkey FROM project WHERE id = $1", app.ProjectID)
@@ -155,7 +155,7 @@ func unwrap(db gorp.SqlExecutor, opts []LoadOptionFunc, dbApp *dbApplication) (*
 	}
 
 	for _, f := range opts {
-		if err := (*f)(db, app); err != nil && sdk.Cause(err) != sql.ErrNoRows {
+		if err := (*f)(ctx, db, app); err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return nil, sdk.WrapError(err, "application.unwrap")
 		}
 	}
@@ -283,7 +283,7 @@ func getAllWithClearVCS(ctx context.Context, db gorp.SqlExecutor, opts []LoadOpt
 			continue
 		}
 		a := &res[i]
-		app, err := unwrap(db, opts, a)
+		app, err := unwrap(ctx, db, opts, a)
 		if err != nil {
 			return nil, sdk.WrapError(err, "application.getAllWithClearVCS")
 		}
@@ -310,7 +310,7 @@ func getAll(ctx context.Context, db gorp.SqlExecutor, opts []LoadOptionFunc, que
 		}
 
 		a := &res[i]
-		app, err := unwrap(db, opts, a)
+		app, err := unwrap(ctx, db, opts, a)
 		if err != nil {
 			return nil, sdk.WrapError(err, "application.getAll")
 		}
diff --git a/engine/api/application/dao_application_integration.go b/engine/api/application/dao_application_integration.go
index cad4b3ca5..e4c2f163d 100644
--- a/engine/api/application/dao_application_integration.go
+++ b/engine/api/application/dao_application_integration.go
@@ -8,6 +8,7 @@ import (
 	"github.com/rockbears/log"
 
 	"github.com/ovh/cds/engine/api/database/gorpmapping"
+	"github.com/ovh/cds/engine/api/integration"
 	"github.com/ovh/cds/engine/gorpmapper"
 	"github.com/ovh/cds/sdk"
 )
@@ -46,7 +47,7 @@ func (e *dbApplicationDeploymentStrategy) IntegrationConfig() sdk.IntegrationCon
 }
 
 // LoadDeploymentStrategies loads the deployment strategies for an application
-func LoadDeploymentStrategies(db gorp.SqlExecutor, appID int64, withClearPassword bool) (map[string]sdk.IntegrationConfig, error) {
+func LoadDeploymentStrategies(ctx context.Context, db gorp.SqlExecutor, appID int64, withClearPassword bool) (map[string]sdk.IntegrationConfig, error) {
 	query := gorpmapping.NewQuery(`
     SELECT *
 	  FROM application_deployment_strategy
@@ -54,7 +55,7 @@ func LoadDeploymentStrategies(db gorp.SqlExecutor, appID int64, withClearPasswor
   `).Args(appID)
 
 	var res []dbApplicationDeploymentStrategy
-	if err := gorpmapping.GetAll(context.Background(), db, query, &res, gorpmapping.GetOptions.WithDecryption); err != nil {
+	if err := gorpmapping.GetAll(ctx, db, query, &res, gorpmapping.GetOptions.WithDecryption); err != nil {
 		return nil, sdk.WrapError(err, "unable to load deployment strategies")
 	}
 
@@ -65,7 +66,7 @@ func LoadDeploymentStrategies(db gorp.SqlExecutor, appID int64, withClearPasswor
 			return nil, err
 		}
 		if !isValid {
-			log.Error(context.Background(), "application.LoadDeploymentStrategies> application_deployment_strategy %d data corrupted", appID)
+			log.Error(ctx, "application.LoadDeploymentStrategies> application_deployment_strategy %d data corrupted", appID)
 			continue
 		}
 
@@ -85,12 +86,16 @@ func LoadDeploymentStrategies(db gorp.SqlExecutor, appID int64, withClearPasswor
 				newCfg[k] = v
 			}
 		}
-		// Sorry about that :(
-		projectIntegrationName, err := db.SelectStr("SELECT name FROM project_integration WHERE id = $1 ", r.ProjectIntegrationID)
+		projectIntegration, err := integration.LoadProjectIntegrationByID(ctx, db, r.ProjectIntegrationID)
 		if err != nil {
 			return nil, sdk.WrapError(err, "unable to find project integration name for ID=%d", r.ProjectIntegrationID)
 		}
-		deps[projectIntegrationName] = newCfg
+		for name, val := range projectIntegration.Model.AdditionalDefaultConfig {
+			if _, ok := newCfg[name]; !ok {
+				newCfg[name] = val
+			}
+		}
+		deps[projectIntegration.Name] = newCfg
 	}
 
 	return deps, nil
diff --git a/engine/api/application/dao_dependencies.go b/engine/api/application/dao_dependencies.go
index b2e436aa4..9a3dab8fe 100644
--- a/engine/api/application/dao_dependencies.go
+++ b/engine/api/application/dao_dependencies.go
@@ -1,6 +1,7 @@
 package application
 
 import (
+	"context"
 	"database/sql"
 
 	"github.com/go-gorp/gorp"
@@ -9,14 +10,14 @@ import (
 )
 
 var (
-	loadDefaultDependencies = func(db gorp.SqlExecutor, app *sdk.Application) error {
-		if err := loadVariables(db, app); err != nil && sdk.Cause(err) != sql.ErrNoRows {
+	loadDefaultDependencies = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
+		if err := loadVariables(ctx, db, app); err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return sdk.WrapError(err, "application.loadDefaultDependencies %s", app.Name)
 		}
 		return nil
 	}
 
-	loadVariables = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadVariables = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		variables, err := LoadAllVariables(db, app.ID)
 		if err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return sdk.WrapError(err, "Unable to load variables for application %d", app.ID)
@@ -25,7 +26,7 @@ var (
 		return nil
 	}
 
-	loadVariablesWithClearPassword = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadVariablesWithClearPassword = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		variables, err := LoadAllVariablesWithDecrytion(db, app.ID)
 		if err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return sdk.WrapError(err, "Unable to load variables for application %d", app.ID)
@@ -34,7 +35,7 @@ var (
 		return nil
 	}
 
-	loadKeys = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadKeys = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		keys, err := LoadAllKeys(db, app.ID)
 		if err != nil {
 			return err
@@ -43,7 +44,7 @@ var (
 		return nil
 	}
 
-	loadClearKeys = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadClearKeys = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		keys, err := LoadAllKeysWithPrivateContent(db, app.ID)
 		if err != nil {
 			return err
@@ -52,16 +53,16 @@ var (
 		return nil
 	}
 
-	loadDeploymentStrategies = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadDeploymentStrategies = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		var err error
-		app.DeploymentStrategies, err = LoadDeploymentStrategies(db, app.ID, false)
+		app.DeploymentStrategies, err = LoadDeploymentStrategies(ctx, db, app.ID, false)
 		if err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return sdk.WrapError(err, "Unable to load deployment strategies for application %d", app.ID)
 		}
 		return nil
 	}
 
-	loadIcon = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadIcon = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		var err error
 		app.Icon, err = LoadIcon(db, app.ID)
 		if err != nil && sdk.Cause(err) != sql.ErrNoRows {
@@ -70,7 +71,7 @@ var (
 		return nil
 	}
 
-	loadVulnerabilities = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadVulnerabilities = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		var err error
 		app.Vulnerabilities, err = LoadVulnerabilities(db, app.ID)
 		if err != nil {
@@ -79,9 +80,9 @@ var (
 		return nil
 	}
 
-	loadDeploymentStrategiesWithClearPassword = func(db gorp.SqlExecutor, app *sdk.Application) error {
+	loadDeploymentStrategiesWithClearPassword = func(ctx context.Context, db gorp.SqlExecutor, app *sdk.Application) error {
 		var err error
-		app.DeploymentStrategies, err = LoadDeploymentStrategies(db, app.ID, true)
+		app.DeploymentStrategies, err = LoadDeploymentStrategies(ctx, db, app.ID, true)
 		if err != nil && sdk.Cause(err) != sql.ErrNoRows {
 			return sdk.WrapError(err, "Unable to load deployment strategies for application %d", app.ID)
 		}
diff --git a/engine/api/download.go b/engine/api/download.go
index 641bdd84f..33a5997df 100644
--- a/engine/api/download.go
+++ b/engine/api/download.go
@@ -24,11 +24,15 @@ func (api *API) downloadsHandler() service.Handler {
 func (api *API) downloadHandler() service.Handler {
 	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
 		vars := mux.Vars(r)
-		name := vars["name"]
-		os := vars["os"]
-		arch := vars["arch"]
+		name := sdk.NoPath(vars["name"])
+		os := sdk.NoPath(vars["os"])
+		arch := sdk.NoPath(vars["arch"])
 		r.ParseForm() // nolint
-		variant := r.Form.Get("variant")
+		variant := sdk.NoPath(r.Form.Get("variant"))
+
+		if !sdk.IsInArray(variant, []string{"", "nokeychain", "keychain"}) {
+			return sdk.NewErrorFrom(sdk.ErrWrongRequest, "invalid variant: %s", variant)
+		}
 
 		if err := download.CheckBinary(ctx, api.getDownloadConf(), name, os, arch, variant); err != nil {
 			return err
diff --git a/engine/api/project/loader.go b/engine/api/project/loader.go
index 134a1f375..f12f79b54 100644
--- a/engine/api/project/loader.go
+++ b/engine/api/project/loader.go
@@ -101,7 +101,7 @@ func loadApplicationWithDeploymentStrategies(ctx context.Context, db gorp.SqlExe
 	}
 	for i := range proj.Applications {
 		a := &proj.Applications[i]
-		if err := (*application.LoadOptions.WithDeploymentStrategies)(db, a); err != nil {
+		if err := (*application.LoadOptions.WithDeploymentStrategies)(ctx, db, a); err != nil {
 			return sdk.WithStack(err)
 		}
 	}
@@ -134,7 +134,7 @@ func loadApplicationVariables(ctx context.Context, db gorp.SqlExecutor, proj *sd
 	}
 
 	for _, a := range proj.Applications {
-		if err := (*application.LoadOptions.WithVariables)(db, &a); err != nil {
+		if err := (*application.LoadOptions.WithVariables)(ctx, db, &a); err != nil {
 			return sdk.WithStack(err)
 		}
 	}
@@ -150,7 +150,7 @@ func loadApplicationKeys(ctx context.Context, db gorp.SqlExecutor, proj *sdk.Pro
 	}
 
 	for _, a := range proj.Applications {
-		if err := (*application.LoadOptions.WithKeys)(db, &a); err != nil {
+		if err := (*application.LoadOptions.WithKeys)(ctx, db, &a); err != nil {
 			return sdk.WithStack(err)
 		}
 	}
diff --git a/engine/api/user.go b/engine/api/user.go
index 5e9319374..88a218c56 100644
--- a/engine/api/user.go
+++ b/engine/api/user.go
@@ -83,7 +83,6 @@ func (api *API) putUserHandler() service.Handler {
 		}
 
 		newUser := *oldUser
-		newUser.Username = data.Username
 		newUser.Fullname = data.Fullname
 
 		// Only an admin can change the ring of a user
diff --git a/sdk/common.go b/sdk/common.go
index 588cfa5c4..0b3485c18 100644
--- a/sdk/common.go
+++ b/sdk/common.go
@@ -13,6 +13,7 @@ import (
 	"io"
 	"os"
 	"path"
+	"path/filepath"
 	"reflect"
 	"regexp"
 	"runtime"
@@ -338,3 +339,33 @@ type KeyValues struct {
 	Key    string
 	Values []string
 }
+
+func CleanPath(path string) string {
+	// Deal with empty strings nicely.
+	if path == "" {
+		return ""
+	}
+
+	// Ensure that all paths are cleaned (especially problematic ones like
+	// "/../../../../../" which can cause lots of issues).
+	path = filepath.Clean(path)
+
+	// If the path isn't absolute, we need to do more processing to fix paths
+	// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
+	// paths to relative ones.
+	if !filepath.IsAbs(path) {
+		path = filepath.Clean(string(os.PathSeparator) + path)
+		// This can't fail, as (by definition) all paths are relative to root.
+		path, _ = filepath.Rel(string(os.PathSeparator), path)
+	}
+
+	// Clean the path again for good measure.
+	return filepath.Clean(path)
+}
+
+func NoPath(path string) string {
+	if path == "" {
+		return ""
+	}
+	return filepath.Base(CleanPath(path))
+}
diff --git a/sdk/download.go b/sdk/download.go
index aa976035c..58bf183fc 100644
--- a/sdk/download.go
+++ b/sdk/download.go
@@ -124,12 +124,12 @@ func BinaryFilename(name, os, arch, variant string) string {
 	if os == "windows" {
 		suffix = ".exe"
 	}
-	return fmt.Sprintf("%s%s-%s-%s%s%s", prefix, name, os, getArchName(arch), variant, suffix)
+	return NoPath(fmt.Sprintf("%s%s-%s-%s%s%s", prefix, name, os, getArchName(arch), variant, suffix))
 }
 
 // IsDownloadedBinary returns true if the binary is already downloaded, false otherwise
 func IsDownloadedBinary(directoriesDownload, filename string) bool {
-	if _, err := os.Stat(path.Join(directoriesDownload, filename)); err == nil {
+	if _, err := os.Stat(CleanPath(path.Join(directoriesDownload, filename))); err == nil {
 		return true
 	}
 	return false
diff --git a/sdk/luascript/luascript.go b/sdk/luascript/luascript.go
index 043f0df35..a51d91c4d 100644
--- a/sdk/luascript/luascript.go
+++ b/sdk/luascript/luascript.go
@@ -56,7 +56,7 @@ func NewCheck() (*Check, error) {
 	state.PreloadModule("json", luajson.Loader)
 
 	// Sandboxing lua engine
-	if err := state.DoString("coroutine=nil;debug=nil;io=nil;open=nil;os.rename=nil;os.remove=nil;os.exit=nil;os.clock=nil;os.execute=nil;os.getenv=nil;os.setlocale=nil;os.tmpname=nil"); err != nil {
+	if err := state.DoString("coroutine=nil;debug=nil;io=nil;open=nil;dofile=nil;loadfile=nil;getfenv=nil;print=nil;pcall=nil;os.rename=nil;os.remove=nil;os.exit=nil;os.clock=nil;os.execute=nil;os.getenv=nil;os.setlocale=nil;os.tmpname=nil"); err != nil {
 		return nil, err
 	}
 
diff --git a/ui/src/app/views/settings/user/edit/user.edit.html b/ui/src/app/views/settings/user/edit/user.edit.html
index a9a51d77f..03d2af1c3 100644
--- a/ui/src/app/views/settings/user/edit/user.edit.html
+++ b/ui/src/app/views/settings/user/edit/user.edit.html
@@ -15,7 +15,7 @@
                                     <div class="field">
                                         <label>{{'user_label_username' | translate}}</label>
                                         <input class="ui input" type="text" name="username" [(ngModel)]="user.username"
-                                            [disabled]="loading" [readonly]="!editable">
+                                            [disabled]="loading" readonly>
                                     </div>
                                     <div class="field">
                                         <label>{{'user_label_fullname' | translate}}</label>


Test patch:
diff --git a/engine/api/application/dao_application_integration_test.go b/engine/api/application/dao_application_integration_test.go
index f90bf770e..bcd7fd7b7 100644
--- a/engine/api/application/dao_application_integration_test.go
+++ b/engine/api/application/dao_application_integration_test.go
@@ -75,4 +75,23 @@ func Test_LoadAllDeploymentAllApps(t *testing.T) {
 	require.Len(t, deps[app2.ID], 1)
 	require.Equal(t, "secret1", deps[app1.ID][pp.ID]["token"].Value)
 	require.Equal(t, "secret2", deps[app2.ID][pp.ID]["token"].Value)
+
+	pf.AdditionalDefaultConfig = sdk.IntegrationConfig{
+		"token": sdk.IntegrationConfigValue{
+			Type:  sdk.IntegrationConfigTypePassword,
+			Value: "my-secret-token",
+		},
+		"bar": sdk.IntegrationConfigValue{
+			Type:  sdk.IntegrationConfigTypeString,
+			Value: "foo",
+		},
+	}
+
+	test.NoError(t, integration.UpdateModel(context.TODO(), db, &pf))
+
+	st, err := application.LoadDeploymentStrategies(context.TODO(), db, app1.ID, false)
+	require.NoError(t, err)
+	require.Len(t, st, 1)
+	require.Equal(t, st[pf.Name]["token"].Value, "**********")
+	require.Equal(t, st[pf.Name]["bar"].Value, "foo")
 }
diff --git a/engine/api/application_deployment_test.go b/engine/api/application_deployment_test.go
index 5fb5de93d..739139866 100644
--- a/engine/api/application_deployment_test.go
+++ b/engine/api/application_deployment_test.go
@@ -353,7 +353,7 @@ func Test_postApplicationDeploymentStrategyConfigHandlerAsProvider(t *testing.T)
 	})
 	test.NoError(t, err)
 
-	cfg, err := application.LoadDeploymentStrategies(api.mustDB(), app.ID, true)
+	cfg, err := application.LoadDeploymentStrategies(context.TODO(), api.mustDB(), app.ID, true)
 	test.NoError(t, err)
 
 	var assertCfg = func(key string, cfg sdk.IntegrationConfig, expected sdk.IntegrationConfigValue) {
diff --git a/engine/api/user_test.go b/engine/api/user_test.go
index bf2a7e049..b38b09051 100644
--- a/engine/api/user_test.go
+++ b/engine/api/user_test.go
@@ -65,7 +65,6 @@ func Test_putUserHandler(t *testing.T) {
 	assets.DeleteAdmins(t, db)
 
 	initial, jwtInitialRaw := assets.InsertLambdaUser(t, db)
-	initialNewUsername := sdk.RandomString(10)
 	initialNewFullname := sdk.RandomString(10)
 	admin1, jwtAdmin1Raw := assets.InsertAdminUser(t, db)
 	admin2, jwtAdmin2Raw := assets.InsertAdminUser(t, db)
@@ -79,43 +78,32 @@ func Test_putUserHandler(t *testing.T) {
 		ExpectedStatus int
 	}{
 		{
-			Name:           "A lambda user can change its username or fullname",
+			Name:           "A lambda user can't change username but can change fullname",
 			JWT:            jwtInitialRaw,
 			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: sdk.RandomString(10),
 				Fullname: initialNewFullname,
 				Ring:     initial.Ring,
 			},
 			Expected: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: initial.Username,
 				Fullname: initialNewFullname,
 				Ring:     initial.Ring,
 			},
 			ExpectedStatus: http.StatusOK,
 		},
-		{
-			Name:           "A lambda user can rename to an existing username",
-			JWT:            jwtInitialRaw,
-			TargetUsername: initialNewUsername,
-			Data: sdk.AuthentifiedUser{
-				Username: admin1.Username,
-				Fullname: initialNewFullname,
-				Ring:     initial.Ring,
-			},
-			ExpectedStatus: http.StatusBadRequest,
-		},
 		{
 			Name:           "A lambda user can't change its ring",
 			JWT:            jwtInitialRaw,
-			TargetUsername: initialNewUsername,
+			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: initial.Username,
 				Fullname: initialNewFullname,
 				Ring:     sdk.UserRingAdmin,
 			},
 			Expected: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: initial.Username,
 				Fullname: initialNewFullname,
 				Ring:     initial.Ring,
 			},
@@ -124,14 +112,14 @@ func Test_putUserHandler(t *testing.T) {
 		{
 			Name:           "A admin user can change the ring of a user",
 			JWT:            jwtAdmin1Raw,
-			TargetUsername: initialNewUsername,
+			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: initial.Username,
 				Fullname: initialNewFullname,
 				Ring:     sdk.UserRingMaintainer,
 			},
 			Expected: sdk.AuthentifiedUser{
-				Username: initialNewUsername,
+				Username: initial.Username,
 				Fullname: initialNewFullname,
 				Ring:     sdk.UserRingMaintainer,
 			},
@@ -167,15 +155,15 @@ func Test_putUserHandler(t *testing.T) {
 		{
 			Name:           "A lambda user can't change its organization",
 			JWT:            jwtInitialRaw,
-			TargetUsername: initialNewUsername,
+			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username:     initialNewUsername,
+				Username:     initial.Username,
 				Fullname:     initialNewFullname,
 				Ring:         sdk.UserRingMaintainer,
 				Organization: "my-org",
 			},
 			Expected: sdk.AuthentifiedUser{
-				Username:     initialNewUsername,
+				Username:     initial.Username,
 				Fullname:     initialNewFullname,
 				Ring:         sdk.UserRingMaintainer,
 				Organization: "",
@@ -185,15 +173,15 @@ func Test_putUserHandler(t *testing.T) {
 		{
 			Name:           "A admin user can set user organization",
 			JWT:            jwtAdmin2Raw,
-			TargetUsername: initialNewUsername,
+			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username:     initialNewUsername,
+				Username:     initial.Username,
 				Fullname:     initialNewFullname,
 				Ring:         sdk.UserRingMaintainer,
 				Organization: "my-org",
 			},
 			Expected: sdk.AuthentifiedUser{
-				Username:     initialNewUsername,
+				Username:     initial.Username,
 				Fullname:     initialNewFullname,
 				Ring:         sdk.UserRingMaintainer,
 				Organization: "my-org",
@@ -203,9 +191,9 @@ func Test_putUserHandler(t *testing.T) {
 		{
 			Name:           "A admin user can't change user organization",
 			JWT:            jwtAdmin2Raw,
-			TargetUsername: initialNewUsername,
+			TargetUsername: initial.Username,
 			Data: sdk.AuthentifiedUser{
-				Username:     initialNewUsername,
+				Username:     initial.Username,
 				Fullname:     initialNewFullname,
 				Ring:         sdk.UserRingMaintainer,
 				Organization: "my-other-org",
diff --git a/sdk/common_test.go b/sdk/common_test.go
index 55d672c74..1fbe69b51 100644
--- a/sdk/common_test.go
+++ b/sdk/common_test.go
@@ -46,3 +46,83 @@ func TestPathIsAbs(t *testing.T) {
 	assert.True(t, PathIsAbs(`/tmp`))
 	assert.False(t, PathIsAbs(`tmp`))
 }
+
+func TestCleanPath(t *testing.T) {
+	type args struct {
+		path string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "test1",
+			args: args{
+				path: "../../foobar",
+			},
+			want: "foobar",
+		},
+		{
+			name: "test1",
+			args: args{
+				path: "./foobar",
+			},
+			want: "foobar",
+		},
+		{
+			name: "test2",
+			args: args{
+				path: "/foo/bar/biz",
+			},
+			want: "/foo/bar/biz",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := CleanPath(tt.args.path); got != tt.want {
+				t.Errorf("CleanPath() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestNoPath(t *testing.T) {
+	type args struct {
+		path string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "test1",
+			args: args{
+				path: "/foo/bar/biz",
+			},
+			want: "biz",
+		},
+		{
+			name: "test2",
+			args: args{
+				path: "",
+			},
+			want: "",
+		},
+		{
+			name: "test3",
+			args: args{
+				path: ".",
+			},
+			want: ".",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := NoPath(tt.args.path); got != tt.want {
+				t.Errorf("NoPath() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}