Repository: kurtosis-tech/kurtosis
Pull request #1216 (2023-09-01 08:10:07)

feat: Update bucket user folder to also suffix it with enclave UUID
## Description:
Enclave name is now accessible in Starlark via the `kurtosis` global module: `kurtosis.enclave_name`

## Is this change user facing?
YES
<!-- If yes, please add the "user facing" label to the PR -->
<!-- If yes, don't forget to include docs changes where relevant -->

## References (if applicable):
<!-- Add relevant Github Issues, Discord threads, or other helpful information. -->



Patch:
diff --git a/core/server/api_container/server/service_network/default_service_network.go b/core/server/api_container/server/service_network/default_service_network.go
index b4b627203..af2db3f6a 100644
--- a/core/server/api_container/server/service_network/default_service_network.go
+++ b/core/server/api_container/server/service_network/default_service_network.go
@@ -841,6 +841,10 @@ func (network *DefaultServiceNetwork) GetApiContainerInfo() *ApiContainerInfo {
 	return network.apiContainerInfo
 }
 
+func (network *DefaultServiceNetwork) GetEnclaveUuid() enclave.EnclaveUUID {
+	return network.enclaveUuid
+}
+
 // ====================================================================================================
 //
 //	Private helper methods
diff --git a/core/server/api_container/server/service_network/mock_service_network.go b/core/server/api_container/server/service_network/mock_service_network.go
index 925b4e66a..72022a913 100644
--- a/core/server/api_container/server/service_network/mock_service_network.go
+++ b/core/server/api_container/server/service_network/mock_service_network.go
@@ -5,9 +5,11 @@ package service_network
 import (
 	context "context"
 
-	exec_result "github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/exec_result"
+	enclave "github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
 	enclave_data_directory "github.com/kurtosis-tech/kurtosis/core/server/commons/enclave_data_directory"
 
+	exec_result "github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/exec_result"
+
 	http "net/http"
 
 	io "io"
@@ -305,6 +307,47 @@ func (_c *MockServiceNetwork_GetApiContainerInfo_Call) RunAndReturn(run func() *
 	return _c
 }
 
+// GetEnclaveUuid provides a mock function with given fields:
+func (_m *MockServiceNetwork) GetEnclaveUuid() enclave.EnclaveUUID {
+	ret := _m.Called()
+
+	var r0 enclave.EnclaveUUID
+	if rf, ok := ret.Get(0).(func() enclave.EnclaveUUID); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(enclave.EnclaveUUID)
+	}
+
+	return r0
+}
+
+// MockServiceNetwork_GetEnclaveUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEnclaveUuid'
+type MockServiceNetwork_GetEnclaveUuid_Call struct {
+	*mock.Call
+}
+
+// GetEnclaveUuid is a helper method to define mock.On call
+func (_e *MockServiceNetwork_Expecter) GetEnclaveUuid() *MockServiceNetwork_GetEnclaveUuid_Call {
+	return &MockServiceNetwork_GetEnclaveUuid_Call{Call: _e.mock.On("GetEnclaveUuid")}
+}
+
+func (_c *MockServiceNetwork_GetEnclaveUuid_Call) Run(run func()) *MockServiceNetwork_GetEnclaveUuid_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run()
+	})
+	return _c
+}
+
+func (_c *MockServiceNetwork_GetEnclaveUuid_Call) Return(_a0 enclave.EnclaveUUID) *MockServiceNetwork_GetEnclaveUuid_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockServiceNetwork_GetEnclaveUuid_Call) RunAndReturn(run func() enclave.EnclaveUUID) *MockServiceNetwork_GetEnclaveUuid_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // GetExistingAndHistoricalServiceIdentifiers provides a mock function with given fields:
 func (_m *MockServiceNetwork) GetExistingAndHistoricalServiceIdentifiers() (service_identifiers.ServiceIdentifiers, error) {
 	ret := _m.Called()
diff --git a/core/server/api_container/server/service_network/service_network.go b/core/server/api_container/server/service_network/service_network.go
index 123b06b1c..a8c113bf0 100644
--- a/core/server/api_container/server/service_network/service_network.go
+++ b/core/server/api_container/server/service_network/service_network.go
@@ -2,6 +2,7 @@ package service_network
 
 import (
 	"context"
+	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
 	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/exec_result"
 	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network/render_templates"
@@ -114,4 +115,6 @@ type ServiceNetwork interface {
 	GetUniqueNameForFileArtifact() (string, error)
 
 	GetApiContainerInfo() *ApiContainerInfo
+
+	GetEnclaveUuid() enclave.EnclaveUUID
 }
diff --git a/core/server/api_container/server/startosis_engine/builtins/kurtosis_module.go b/core/server/api_container/server/startosis_engine/builtins/kurtosis_module.go
index 933d68719..be25a0ca6 100644
--- a/core/server/api_container/server/startosis_engine/builtins/kurtosis_module.go
+++ b/core/server/api_container/server/startosis_engine/builtins/kurtosis_module.go
@@ -1,6 +1,8 @@
 package builtins
 
 import (
+	"fmt"
+	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_errors"
 	starlarkjson "go.starlark.net/lib/json"
 	"go.starlark.net/starlark"
@@ -18,8 +20,8 @@ var (
 	noKwargs []starlark.Tuple
 )
 
-func KurtosisModule(thread *starlark.Thread, enclaveEnvVars string) (*starlarkstruct.Module, *startosis_errors.InterpretationError) {
-	enclaveEnvVarsStringDict, interpretationErr := convertEnvVarsToDict(thread, enclaveEnvVars)
+func KurtosisModule(thread *starlark.Thread, enclaveUuid enclave.EnclaveUUID, enclaveEnvVars string) (*starlarkstruct.Module, *startosis_errors.InterpretationError) {
+	enclaveEnvVarsStringDict, interpretationErr := convertEnvVarsToDict(thread, enclaveUuid, enclaveEnvVars)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}
@@ -30,7 +32,7 @@ func KurtosisModule(thread *starlark.Thread, enclaveEnvVars string) (*starlarkst
 	}, nil
 }
 
-func convertEnvVarsToDict(thread *starlark.Thread, enclaveEnvVars string) (*starlark.StringDict, *startosis_errors.InterpretationError) {
+func convertEnvVarsToDict(thread *starlark.Thread, enclaveUuid enclave.EnclaveUUID, enclaveEnvVars string) (*starlark.StringDict, *startosis_errors.InterpretationError) {
 	envVarsDict := starlark.StringDict{}
 	if enclaveEnvVars == "" {
 		return &envVarsDict, nil
@@ -68,7 +70,25 @@ func convertEnvVarsToDict(thread *starlark.Thread, enclaveEnvVars string) (*star
 			return nil, startosis_errors.NewInterpretationError("No value found for key '%s' converting the environment variables dictionary", envVarName)
 		}
 		lowercaseEnvVarName := strings.ToLower(envVarName.GoString())
-		envVarsDict[lowercaseEnvVarName] = envVarValue
+
+		// TODO: This is a hack to "inject" the enclave ID in the bucket user folder variable such that each enclave can
+		// write to its own folder, rather than all enclaves writing to at the root of the user folder and potentially
+		// experiencing file name collisions.
+		// Once each AWS bucket is created inside the Starlark script (under the user own AWS account), we can remove
+		// this and let the user own and manage their bucket
+		if lowercaseEnvVarName == "aws_bucket_user_folder" {
+			envVarValueStr, ok := envVarValue.(starlark.String)
+			if !ok {
+				return nil, startosis_errors.NewInterpretationError("Environment variable value for "+
+					"'AWS_BUCKET_USER_FOLDER' was expected to be a string, but was not: '%v'. This is unexpected",
+					envVarValue)
+			}
+			trimmedEnvVarValueStr := strings.Trim(envVarValueStr.GoString(), "/")
+			envVarValueWithEnclaveUuid := fmt.Sprintf("%s/%s", trimmedEnvVarValueStr, string(enclaveUuid))
+			envVarsDict[lowercaseEnvVarName] = starlark.String(envVarValueWithEnclaveUuid)
+		} else {
+			envVarsDict[lowercaseEnvVarName] = envVarValue
+		}
 	}
 	return &envVarsDict, nil
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter.go b/core/server/api_container/server/startosis_engine/startosis_interpreter.go
index 3cc3b5fee..a975d923f 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter.go
@@ -342,7 +342,7 @@ func (interpreter *StartosisInterpreter) buildBindings(thread *starlark.Thread,
 		return result, nil
 	}
 
-	kurtosisModule, interpretationErr := builtins.KurtosisModule(thread, interpreter.enclaveEnvVars)
+	kurtosisModule, interpretationErr := builtins.KurtosisModule(thread, interpreter.serviceNetwork.GetEnclaveUuid(), interpreter.enclaveEnvVars)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}


Test patch:
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
index 25e27c289..d6bf14391 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
@@ -150,7 +150,7 @@ func testKurtosisTypeConstructor(t *testing.T, builtin KurtosisTypeConstructorBa
 }
 
 func getBasePredeclaredDict(t *testing.T, thread *starlark.Thread) starlark.StringDict {
-	kurtosisModule, err := builtins.KurtosisModule(thread, "")
+	kurtosisModule, err := builtins.KurtosisModule(thread, "", "")
 	require.Nil(t, err)
 	// TODO: refactor this with the one we have in the interpreter
 	predeclared := starlark.StringDict{
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go b/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
index 9cc41ac87..5b4e02f1c 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
@@ -2,6 +2,7 @@ package startosis_engine
 
 import (
 	"context"
+	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/enclave_structure"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/instructions_plan/resolver"
@@ -15,6 +16,8 @@ import (
 )
 
 const (
+	enclaveUuid = enclave.EnclaveUUID("enclave-uuid")
+
 	noInputParams = "{}"
 )
 
@@ -34,6 +37,7 @@ func (suite *StartosisInterpreterIdempotentTestSuite) SetupTest() {
 	serviceNetwork.EXPECT().GetApiContainerInfo().Maybe().Return(
 		service_network.NewApiContainerInfo(net.IPv4(0, 0, 0, 0), uint16(1234), "0.0.0"),
 	)
+	serviceNetwork.EXPECT().GetEnclaveUuid().Maybe().Return(enclaveUuid)
 	suite.interpreter = NewStartosisInterpreter(serviceNetwork, suite.packageContentProvider, runtimeValueStore, "")
 }
 
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go b/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
index 4086fd449..a1a939781 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/binding_constructors"
+	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
 	"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/builtins/print_builtin"
@@ -75,6 +76,7 @@ func (suite *StartosisInterpreterTestSuite) SetupTest() {
 		string(testServiceName),
 	)
 	suite.serviceNetwork.EXPECT().GetUniqueNameForFileArtifact().Maybe().Return(mockFileArtifactName, nil)
+	suite.serviceNetwork.EXPECT().GetEnclaveUuid().Maybe().Return(enclave.EnclaveUUID(mockEnclaveUuid))
 	suite.serviceNetwork.EXPECT().ExistServiceRegistration(testServiceName).Maybe().Return(true, nil)
 }