Repository: kurtosis-tech/kurtosis
Pull request #2044 (2024-01-12 20:55:57)

feat: allow any GitHub path on the `upload_files` instruction
## Description:
allow any GitHub path on the `upload_files` instruction

## Is this change user facing?
YES

## References (if applicable):
Fix https://github.com/kurtosis-tech/kurtosis/issues/1700


cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>98fb880</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://7769ba04.kurtosis-docs.pages.dev'>https://7769ba04.kurtosis-docs.pages.dev</a>
</td></tr>
<tr><td><strong>Branch Preview URL:</strong></td><td>
<a href='https://lporoli-ticket-1700.kurtosis-docs.pages.dev'>https://lporoli-ticket-1700.kurtosis-docs.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/kurtosis/7769ba04-e8e3-423a-b523-5314a107766e)


Patch:
diff --git a/api/golang/core/lib/shared_utils/parsed_git_url.go b/api/golang/core/lib/shared_utils/parsed_git_url.go
index b2944f20f..215398b65 100644
--- a/api/golang/core/lib/shared_utils/parsed_git_url.go
+++ b/api/golang/core/lib/shared_utils/parsed_git_url.go
@@ -12,7 +12,7 @@ const (
 	GithubDomainPrefix = "github.com"
 	httpsSchema        = "https"
 	UrlPathSeparator   = "/"
-	//MinimumSubPathsForValidGitURL for a valid GitURl we need it to look like github.com/author/moduleName
+	//MinimumSubPathsForValidGitURL for a valid GitURl we need it to look like github.com/author/repositoryName
 	// the last two are the minimum requirements for a valid Startosis URL
 	MinimumSubPathsForValidGitURL = 2
 
@@ -26,13 +26,13 @@ const (
 
 // ParsedGitURL an object representing a parsed moduleURL
 type ParsedGitURL struct {
-	// moduleAuthor the git of the module (GitHub user or org)
-	moduleAuthor string
-	// moduleName the name of the module
-	moduleName string
+	// repositoryAuthor the git of the module (GitHub user or org)
+	repositoryAuthor string
+	// repositoryName the name of the module
+	repositoryName string
 	// gitURL the url ending with `.git` where the module lives
 	gitURL string
-	// relativeRepoPath the relative path to the repo this would be moduleAuthor/moduleName/
+	// relativeRepoPath the relative path to the repo this would be repositoryAuthor/repositoryName/
 	relativeRepoPath string
 	// relativeFilePath the full path of the file relative to the module store relativeRepoPath/path/to/file.star
 	// empty if there is no file
@@ -45,8 +45,8 @@ type ParsedGitURL struct {
 
 func newParsedGitURL(moduleAuthor, moduleName, gitURL, relativeRepoPath, relativeFilePath string, tagBranchOrCommit string) *ParsedGitURL {
 	return &ParsedGitURL{
-		moduleAuthor:      moduleAuthor,
-		moduleName:        moduleName,
+		repositoryAuthor:  moduleAuthor,
+		repositoryName:    moduleName,
 		gitURL:            gitURL,
 		relativeRepoPath:  relativeRepoPath,
 		relativeFilePath:  relativeFilePath,
@@ -54,12 +54,12 @@ func newParsedGitURL(moduleAuthor, moduleName, gitURL, relativeRepoPath, relativ
 	}
 }
 
-func (parsedUrl *ParsedGitURL) GetModuleAuthor() string {
-	return parsedUrl.moduleAuthor
+func (parsedUrl *ParsedGitURL) GetRepositoryAuthor() string {
+	return parsedUrl.repositoryAuthor
 }
 
-func (parsedUrl *ParsedGitURL) GetModuleName() string {
-	return parsedUrl.moduleName
+func (parsedUrl *ParsedGitURL) GetRepositoryName() string {
+	return parsedUrl.repositoryName
 }
 
 func (parsedUrl *ParsedGitURL) GetGitURL() string {
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_instruction/upload_files/upload_files.go b/core/server/api_container/server/startosis_engine/kurtosis_instruction/upload_files/upload_files.go
index f23923762..cf2135e22 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_instruction/upload_files/upload_files.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_instruction/upload_files/upload_files.go
@@ -116,7 +116,7 @@ func (builtin *UploadFilesCapabilities) Interpret(locatorOfModuleInWhichThisBuil
 		return nil, startosis_errors.WrapWithInterpretationError(interpretationErr, "Tried to convert locator '%v' into absolute locator but failed", src.GoString())
 	}
 
-	pathOnDisk, interpretationErr := builtin.packageContentProvider.GetOnDiskAbsoluteFilePath(absoluteLocator)
+	pathOnDisk, interpretationErr := builtin.packageContentProvider.GetOnDiskAbsolutePath(absoluteLocator)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_types/service_config/image_build_spec.go b/core/server/api_container/server/startosis_engine/kurtosis_types/service_config/image_build_spec.go
index 37205897e..b7107d6ad 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_types/service_config/image_build_spec.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_types/service_config/image_build_spec.go
@@ -175,7 +175,8 @@ func getOnDiskImageBuildSpecPaths(
 
 	// get on disk directory path of Dockerfile
 	containerImageAbsoluteLocator := path.Join(contextDirAbsoluteLocator, defaultContainerImageFileName)
-	containerImagePathOnDisk, interpretationErr := packageContentProvider.GetOnDiskAbsoluteFilePath(containerImageAbsoluteLocator)
+
+	containerImagePathOnDisk, interpretationErr := packageContentProvider.GetOnDiskAbsolutePackageFilePath(containerImageAbsoluteLocator)
 	if interpretationErr != nil {
 		return "", "", interpretationErr
 	}
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
index 9dc8c7e58..1580f8c93 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
@@ -44,16 +44,16 @@ const (
 )
 
 type GitPackageContentProvider struct {
-	// Where to temporarily store packages while
-	packagesTmpDir                  string
-	packagesDir                     string
+	// Where to temporarily store repositories while
+	repositoriesTmpDir              string
+	repositoriesDir                 string
 	packageReplaceOptionsRepository *packageReplaceOptionsRepository
 }
 
-func NewGitPackageContentProvider(moduleDir string, tmpDir string, enclaveDb *enclave_db.EnclaveDB) *GitPackageContentProvider {
+func NewGitPackageContentProvider(repositoriesDir string, tmpDir string, enclaveDb *enclave_db.EnclaveDB) *GitPackageContentProvider {
 	return &GitPackageContentProvider{
-		packagesDir:                     moduleDir,
-		packagesTmpDir:                  tmpDir,
+		repositoriesDir:                 repositoriesDir,
+		repositoriesTmpDir:              tmpDir,
 		packageReplaceOptionsRepository: newPackageReplaceOptionsRepository(enclaveDb),
 	}
 }
@@ -64,13 +64,12 @@ func (provider *GitPackageContentProvider) ClonePackage(packageId string) (strin
 		return "", startosis_errors.WrapWithInterpretationError(err, "An error occurred parsing Git URL for package ID '%s'", packageId)
 	}
 
-	interpretationError := provider.atomicClone(parsedURL)
-	if interpretationError != nil {
+	if interpretationError := provider.atomicClone(parsedURL); interpretationError != nil {
 		return "", interpretationError
 	}
 
 	relPackagePathToPackagesDir := getPathToPackageRoot(parsedURL)
-	packageAbsolutePathOnDisk := path.Join(provider.packagesDir, relPackagePathToPackagesDir)
+	packageAbsolutePathOnDisk := path.Join(provider.repositoriesDir, relPackagePathToPackagesDir)
 
 	return packageAbsolutePathOnDisk, nil
 }
@@ -82,7 +81,7 @@ func (provider *GitPackageContentProvider) GetKurtosisYaml(packageAbsolutePathOn
 			startosis_constants.KurtosisYamlName, packageAbsolutePathOnDisk, startosis_constants.KurtosisYamlName, user_support_constants.StarlarkPackagesReferenceURL)
 	}
 
-	kurtosisYaml, interpretationError := validateAndGetKurtosisYaml(pathToKurtosisYaml, provider.packagesDir)
+	kurtosisYaml, interpretationError := validateAndGetKurtosisYaml(pathToKurtosisYaml, provider.repositoriesDir)
 	if interpretationError != nil {
 		return nil, interpretationError
 	}
@@ -90,16 +89,26 @@ func (provider *GitPackageContentProvider) GetKurtosisYaml(packageAbsolutePathOn
 	return kurtosisYaml, nil
 }
 
-func (provider *GitPackageContentProvider) GetOnDiskAbsoluteFilePath(absoluteFileLocator string) (string, *startosis_errors.InterpretationError) {
-	parsedURL, err := shared_utils.ParseGitURL(absoluteFileLocator)
+func (provider *GitPackageContentProvider) GetOnDiskAbsolutePath(repositoryPathURL string) (string, *startosis_errors.InterpretationError) {
+	shouldOnlyAcceptsPackagePath := false
+	return provider.getOnDiskAbsolutePath(repositoryPathURL, shouldOnlyAcceptsPackagePath)
+}
+
+func (provider *GitPackageContentProvider) GetOnDiskAbsolutePackageFilePath(repositoryPathURL string) (string, *startosis_errors.InterpretationError) {
+	shouldOnlyAcceptsPackagePath := true
+	return provider.getOnDiskAbsolutePath(repositoryPathURL, shouldOnlyAcceptsPackagePath)
+}
+
+func (provider *GitPackageContentProvider) getOnDiskAbsolutePath(repositoryPathURL string, shouldOnlyAcceptsPackageFilePath bool) (string, *startosis_errors.InterpretationError) {
+	parsedURL, err := shared_utils.ParseGitURL(repositoryPathURL)
 	if err != nil {
-		return "", startosis_errors.WrapWithInterpretationError(err, "An error occurred parsing Git URL for absolute file locator '%s'", absoluteFileLocator)
+		return "", startosis_errors.WrapWithInterpretationError(err, "An error occurred parsing Git URL for absolute file locator '%s'", repositoryPathURL)
 	}
-	if parsedURL.GetRelativeFilePath() == "" {
-		return "", startosis_errors.NewInterpretationError("The path '%v' needs to point to a specific file but it didn't. Users can only read or import specific files and not entire packages.", absoluteFileLocator)
+	if shouldOnlyAcceptsPackageFilePath && parsedURL.GetRelativeFilePath() == "" {
+		return "", startosis_errors.NewInterpretationError("The path '%v' needs to point to a specific file but it didn't. Users can only read or import specific files and not entire packages.", repositoryPathURL)
 	}
-	pathToFileOnDisk := path.Join(provider.packagesDir, parsedURL.GetRelativeFilePath())
-	packagePath := path.Join(provider.packagesDir, parsedURL.GetRelativeRepoPath())
+	pathToFileOnDisk := path.Join(provider.repositoriesDir, parsedURL.GetRelativeFilePath())
+	packagePath := path.Join(provider.repositoriesDir, parsedURL.GetRelativeRepoPath())
 
 	// Return the file path straight if it exists
 	if _, err := os.Stat(pathToFileOnDisk); err == nil {
@@ -114,22 +123,25 @@ func (provider *GitPackageContentProvider) GetOnDiskAbsoluteFilePath(absoluteFil
 	}
 
 	// Otherwise clone the repo and return the absolute path of the requested file
-	interpretationError := provider.atomicClone(parsedURL)
-	if interpretationError != nil {
+	if interpretationError := provider.atomicClone(parsedURL); interpretationError != nil {
 		return "", interpretationError
 	}
 
+	if !shouldOnlyAcceptsPackageFilePath {
+		return pathToFileOnDisk, nil
+	}
+
 	// check whether kurtosis yaml exists in the path
-	maybeKurtosisYamlPath, interpretationError := getKurtosisYamlPathForFileUrl(pathToFileOnDisk, provider.packagesDir)
+	maybeKurtosisYamlPath, interpretationError := getKurtosisYamlPathForFileUrl(pathToFileOnDisk, provider.repositoriesDir)
 	if interpretationError != nil {
-		return "", startosis_errors.WrapWithInterpretationError(err, "Error occurred while verifying whether '%v' belongs to a Kurtosis package.", absoluteFileLocator)
+		return "", startosis_errors.WrapWithInterpretationError(err, "Error occurred while verifying whether '%v' belongs to a Kurtosis package.", repositoryPathURL)
 	}
 
 	if maybeKurtosisYamlPath == filePathToKurtosisYamlNotFound {
-		return "", startosis_errors.NewInterpretationError("%v is not found in the path of '%v'; files can only be accessed from Kurtosis packages. For more information, go to: %v", startosis_constants.KurtosisYamlName, absoluteFileLocator, user_support_constants.HowImportWorksLink)
+		return "", startosis_errors.NewInterpretationError("%v is not found in the path of '%v'; files can only be accessed from Kurtosis packages. For more information, go to: %v", startosis_constants.KurtosisYamlName, repositoryPathURL, user_support_constants.HowImportWorksLink)
 	}
 
-	if _, interpretationError = validateAndGetKurtosisYaml(maybeKurtosisYamlPath, provider.packagesDir); interpretationError != nil {
+	if _, interpretationError = validateAndGetKurtosisYaml(maybeKurtosisYamlPath, provider.repositoriesDir); interpretationError != nil {
 		return "", interpretationError
 	}
 
@@ -137,7 +149,7 @@ func (provider *GitPackageContentProvider) GetOnDiskAbsoluteFilePath(absoluteFil
 }
 
 func (provider *GitPackageContentProvider) GetModuleContents(fileInsideModuleUrl string) (string, *startosis_errors.InterpretationError) {
-	pathToFile, interpretationError := provider.GetOnDiskAbsoluteFilePath(fileInsideModuleUrl)
+	pathToFile, interpretationError := provider.GetOnDiskAbsolutePackageFilePath(fileInsideModuleUrl)
 	if interpretationError != nil {
 		return "", interpretationError
 	}
@@ -158,7 +170,7 @@ func (provider *GitPackageContentProvider) GetOnDiskAbsolutePackagePath(packageI
 	}
 
 	relPackagePathToPackagesDir := getPathToPackageRoot(parsedPackageId)
-	packageAbsolutePathOnDisk := path.Join(provider.packagesDir, relPackagePathToPackagesDir)
+	packageAbsolutePathOnDisk := path.Join(provider.repositoriesDir, relPackagePathToPackagesDir)
 
 	_, err = os.Stat(packageAbsolutePathOnDisk)
 	if err != nil {
@@ -174,7 +186,7 @@ func (provider *GitPackageContentProvider) StorePackageContents(packageId string
 	}
 
 	relPackagePathToPackagesDir := getPathToPackageRoot(parsedPackageId)
-	packageAbsolutePathOnDisk := path.Join(provider.packagesDir, relPackagePathToPackagesDir)
+	packageAbsolutePathOnDisk := path.Join(provider.repositoriesDir, relPackagePathToPackagesDir)
 
 	if overwriteExisting {
 		err := os.RemoveAll(packageAbsolutePathOnDisk)
@@ -285,13 +297,13 @@ func (provider *GitPackageContentProvider) CloneReplacedPackagesIfNeeded(current
 	return nil
 }
 
-// atomicClone This first clones to a temporary directory and then moves it
+// atomicClone This first clones to a temporary directory and then moves it into the package file system
 // TODO make this support versioning via tags, commit hashes or branches
 func (provider *GitPackageContentProvider) atomicClone(parsedURL *shared_utils.ParsedGitURL) *startosis_errors.InterpretationError {
 	// First we clone into a temporary directory
-	tempRepoDirPath, err := os.MkdirTemp(provider.packagesTmpDir, temporaryRepoDirPattern)
+	tempRepoDirPath, err := os.MkdirTemp(provider.repositoriesTmpDir, temporaryRepoDirPattern)
 	if err != nil {
-		return startosis_errors.WrapWithInterpretationError(err, "Cloning the module '%s' failed. Error creating temporary directory for the repository to be cloned into", parsedURL.GetGitURL())
+		return startosis_errors.WrapWithInterpretationError(err, "Cloning the repository '%s' failed. Error creating temporary directory for the repository to be cloned into", parsedURL.GetGitURL())
 	}
 	defer os.RemoveAll(tempRepoDirPath)
 	gitClonePath := path.Join(tempRepoDirPath, parsedURL.GetRelativeRepoPath())
@@ -301,6 +313,9 @@ func (provider *GitPackageContentProvider) atomicClone(parsedURL *shared_utils.P
 		depth = depthAssumingBranchTagsCommitsAreSpecified
 	}
 
+	//TODO evaluate to use the GitHub client GetContents call instead, because we are cloning the entire repository's workspace with this approach
+	//TODO and the startosis package could be just a small sub-folder inside a giant mono-repository
+	//TODO and even now, in the upload_files instruction, we are allowing to upload files or a folder for any repository, but we are cloning the entire repository for this
 	repo, err := git.PlainClone(gitClonePath, isNotBareClone, &git.CloneOptions{
 		URL:               parsedURL.GetGitURL(),
 		Auth:              nil,
@@ -360,25 +375,25 @@ func (provider *GitPackageContentProvider) atomicClone(parsedURL *shared_utils.P
 	}
 
 	// Then we move it into the target directory
-	packageAuthorPath := path.Join(provider.packagesDir, parsedURL.GetModuleAuthor())
-	packagePath := path.Join(provider.packagesDir, parsedURL.GetRelativeRepoPath())
+	packageAuthorPath := path.Join(provider.repositoriesDir, parsedURL.GetRepositoryAuthor())
+	packagePath := path.Join(provider.repositoriesDir, parsedURL.GetRelativeRepoPath())
 	fileMode, err := os.Stat(packageAuthorPath)
 	if err == nil && !fileMode.IsDir() {
 		return startosis_errors.WrapWithInterpretationError(err, "Expected '%s' to be a directory but it is something else", packageAuthorPath)
 	}
 	if err != nil {
 		if err = os.Mkdir(packageAuthorPath, moduleDirPermission); err != nil {
-			return startosis_errors.WrapWithInterpretationError(err, "Cloning the package '%s' failed. An error occurred while creating the directory '%s'.", parsedURL.GetGitURL(), packageAuthorPath)
+			return startosis_errors.WrapWithInterpretationError(err, "Cloning the repository '%s' failed. An error occurred while creating the directory '%s'.", parsedURL.GetGitURL(), packageAuthorPath)
 		}
 	}
 	if _, err = os.Stat(packagePath); !os.IsNotExist(err) {
 		logrus.Debugf("Package '%s' already exists in enclave at path '%s'. Going to remove previous version.", parsedURL.GetGitURL(), packagePath)
 		if err = os.RemoveAll(packagePath); err != nil {
-			return startosis_errors.NewInterpretationError("Unable to remove a previous version of package '%s' existing inside Kurtosis enclave at '%s'.", parsedURL.GetGitURL(), packagePath)
+			return startosis_errors.NewInterpretationError("Unable to remove a previous version of repository '%s' existing inside Kurtosis enclave at '%s'.", parsedURL.GetGitURL(), packagePath)
 		}
 	}
 	if err = os.Rename(gitClonePath, packagePath); err != nil {
-		return startosis_errors.NewInterpretationError("Cloning the package '%s' failed. An error occurred while moving package at temporary destination '%s' to final destination '%s'", parsedURL.GetGitURL(), gitClonePath, packagePath)
+		return startosis_errors.NewInterpretationError("Cloning the repository '%s' failed. An error occurred while moving repository at temporary destination '%s' to final destination '%s'", parsedURL.GetGitURL(), gitClonePath, packagePath)
 	}
 	return nil
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
index f5ca1273b..cab172daa 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.23.1. DO NOT EDIT.
+// Code generated by mockery v2.29.0. DO NOT EDIT.
 
 package startosis_packages
 
@@ -288,8 +288,8 @@ func (_c *MockPackageContentProvider_GetModuleContents_Call) RunAndReturn(run fu
 	return _c
 }
 
-// GetOnDiskAbsoluteFilePath provides a mock function with given fields: fileInsidePackageUrl
-func (_m *MockPackageContentProvider) GetOnDiskAbsoluteFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError) {
+// GetOnDiskAbsolutePackageFilePath provides a mock function with given fields: fileInsidePackageUrl
+func (_m *MockPackageContentProvider) GetOnDiskAbsolutePackageFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(fileInsidePackageUrl)
 
 	var r0 string
@@ -314,30 +314,30 @@ func (_m *MockPackageContentProvider) GetOnDiskAbsoluteFilePath(fileInsidePackag
 	return r0, r1
 }
 
-// MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOnDiskAbsoluteFilePath'
-type MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call struct {
+// MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOnDiskAbsolutePackageFilePath'
+type MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call struct {
 	*mock.Call
 }
 
-// GetOnDiskAbsoluteFilePath is a helper method to define mock.On call
+// GetOnDiskAbsolutePackageFilePath is a helper method to define mock.On call
 //   - fileInsidePackageUrl string
-func (_e *MockPackageContentProvider_Expecter) GetOnDiskAbsoluteFilePath(fileInsidePackageUrl interface{}) *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call {
-	return &MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call{Call: _e.mock.On("GetOnDiskAbsoluteFilePath", fileInsidePackageUrl)}
+func (_e *MockPackageContentProvider_Expecter) GetOnDiskAbsolutePackageFilePath(fileInsidePackageUrl interface{}) *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call {
+	return &MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call{Call: _e.mock.On("GetOnDiskAbsolutePackageFilePath", fileInsidePackageUrl)}
 }
 
-func (_c *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call) Run(run func(fileInsidePackageUrl string)) *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call {
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call) Run(run func(fileInsidePackageUrl string)) *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(string))
 	})
 	return _c
 }
 
-func (_c *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call {
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
-func (_c *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call {
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetOnDiskAbsolutePackageFilePath_Call {
 	_c.Call.Return(run)
 	return _c
 }
@@ -396,6 +396,60 @@ func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call) RunAndRe
 	return _c
 }
 
+// GetOnDiskAbsolutePath provides a mock function with given fields: repositoryPathURL
+func (_m *MockPackageContentProvider) GetOnDiskAbsolutePath(repositoryPathURL string) (string, *startosis_errors.InterpretationError) {
+	ret := _m.Called(repositoryPathURL)
+
+	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(repositoryPathURL)
+	}
+	if rf, ok := ret.Get(0).(func(string) string); ok {
+		r0 = rf(repositoryPathURL)
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	if rf, ok := ret.Get(1).(func(string) *startosis_errors.InterpretationError); ok {
+		r1 = rf(repositoryPathURL)
+	} else {
+		if ret.Get(1) != nil {
+			r1 = ret.Get(1).(*startosis_errors.InterpretationError)
+		}
+	}
+
+	return r0, r1
+}
+
+// MockPackageContentProvider_GetOnDiskAbsolutePath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOnDiskAbsolutePath'
+type MockPackageContentProvider_GetOnDiskAbsolutePath_Call struct {
+	*mock.Call
+}
+
+// GetOnDiskAbsolutePath is a helper method to define mock.On call
+//   - repositoryPathURL string
+func (_e *MockPackageContentProvider_Expecter) GetOnDiskAbsolutePath(repositoryPathURL interface{}) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+	return &MockPackageContentProvider_GetOnDiskAbsolutePath_Call{Call: _e.mock.On("GetOnDiskAbsolutePath", repositoryPathURL)}
+}
+
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePath_Call) Run(run func(repositoryPathURL string)) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(string))
+	})
+	return _c
+}
+
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePath_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePath_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // StorePackageContents provides a mock function with given fields: packageId, packageContent, overwriteExisting
 func (_m *MockPackageContentProvider) StorePackageContents(packageId string, packageContent io.Reader, overwriteExisting bool) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(packageId, packageContent, overwriteExisting)
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
index 9e4ac411c..acd1e7c18 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
@@ -32,13 +32,24 @@ func NewMockPackageContentProvider() *MockPackageContentProvider {
 	}
 }
 
-func (provider *MockPackageContentProvider) GetOnDiskAbsoluteFilePath(packageId string) (string, *startosis_errors.InterpretationError) {
-	absFilePath, found := provider.starlarkPackages[packageId]
+func (provider *MockPackageContentProvider) GetOnDiskAbsolutePackageFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError) {
+	absFilePath, found := provider.starlarkPackages[fileInsidePackageUrl]
+	if !found {
+		return "", startosis_errors.NewInterpretationError("Module '%v' not found", fileInsidePackageUrl)
+	}
+	if _, err := os.Stat(absFilePath); err != nil {
+		return "", startosis_errors.NewInterpretationError("Unable to read content of package '%v'", fileInsidePackageUrl)
+	}
+	return absFilePath, nil
+}
+
+func (provider *MockPackageContentProvider) GetOnDiskAbsolutePath(repositoryPathURL string) (string, *startosis_errors.InterpretationError) {
+	absFilePath, found := provider.starlarkPackages[repositoryPathURL]
 	if !found {
-		return "", startosis_errors.NewInterpretationError("Module '%v' not found", packageId)
+		return "", startosis_errors.NewInterpretationError("Module '%v' not found", repositoryPathURL)
 	}
 	if _, err := os.Stat(absFilePath); err != nil {
-		return "", startosis_errors.NewInterpretationError("Unable to read content of package '%v'", packageId)
+		return "", startosis_errors.NewInterpretationError("Unable to read content of package '%v'", repositoryPathURL)
 	}
 	return absFilePath, nil
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
index 8744e0325..d7a0003f7 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
@@ -12,11 +12,15 @@ import (
 // Regenerate mock with the following command from core/server directory:
 // mockery -r --name=PackageContentProvider --filename=mock_package_content_provider.go --structname=MockPackageContentProvider --with-expecter --inpackage
 type PackageContentProvider interface {
-	// GetOnDiskAbsoluteFilePath returns the absolute file path of a file inside a module.
+	// GetOnDiskAbsolutePackageFilePath returns the absolute file path of a file inside a module.
 	// The corresponding GitHub repo will be cloned if necessary
-	GetOnDiskAbsoluteFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError)
+	GetOnDiskAbsolutePackageFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError)
 
-	// GetModuleContents returns the stringified content of a file inside a module
+	// GetOnDiskAbsolutePath returns the absolute path (it can be a filer or a folder and, it can be from a package or not) on APIC's disk.
+	// The corresponding GitHub repo will be cloned if necessary
+	GetOnDiskAbsolutePath(repositoryPathURL string) (string, *startosis_errors.InterpretationError)
+
+	// GetModuleContents returns the stringifies content of a file inside a module
 	GetModuleContents(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError)
 
 	// GetOnDiskAbsolutePackagePath returns the absolute folder path containing this package
@@ -30,7 +34,7 @@ type PackageContentProvider interface {
 	ClonePackage(packageId string) (string, *startosis_errors.InterpretationError)
 
 	// GetAbsoluteLocator does:
-	// 1. if the given locator is relative, translates it to absolute using sourceModuleLocator (if it's already absolute, does nothing)
+	// 1. if the given locator is relative, translates it to absolute locator using sourceModuleLocator (if it's already absolute, does nothing)
 	// 2. applies any replace rules, if they match the now-absolute locator
 	GetAbsoluteLocator(packageId string, locatorOfModuleInWhichThisBuiltInIsBeingCalled string, relativeOrAbsoluteLocator string, packageReplaceOptions map[string]string) (string, *startosis_errors.InterpretationError)
 
diff --git a/core/server/commons/enclave_data_directory/enclave_data_directory.go b/core/server/commons/enclave_data_directory/enclave_data_directory.go
index e3134ede2..e9506b336 100644
--- a/core/server/commons/enclave_data_directory/enclave_data_directory.go
+++ b/core/server/commons/enclave_data_directory/enclave_data_directory.go
@@ -20,12 +20,12 @@ const (
 	artifactStoreDirname = "artifact-store"
 
 	// The name of the directory INSIDE THE ENCLAVE DATA DIR where Starlark packages will be stored
-	startosisPackageStoreDirname = "startosis-packages"
+	repositoriesStoreDirname = "repositories"
 
-	// The name of the directory INSIDE THE ENCLAVE DATA DIR where temporary packages will be stored
+	// The name of the directory INSIDE THE ENCLAVE DATA DIR where temporary repositories will be stored
 	// We place the temp folder here so that the move to the final destination is atomic
-	// Move from places outside of the enclave data dir are not atomic as they're over the network
-	tmpPackageStoreDirname = "tmp-startosis-packages"
+	// Move from places outside the enclave data dir are not atomic as they're over the network
+	tmpRepositoriesStoreDirname = "tmp-repositories"
 )
 
 // A directory containing all the data associated with a certain enclave (i.e. a Docker subnetwork where services are spun up)
@@ -67,15 +67,15 @@ func (dir EnclaveDataDirectory) GetFilesArtifactStore() (*FilesArtifactStore, er
 }
 
 func (dir EnclaveDataDirectory) GetGitPackageContentProvider(enclaveDb *enclave_db.EnclaveDB) (*git_package_content_provider.GitPackageContentProvider, error) {
-	packageStoreDirpath := path.Join(dir.absMountDirpath, startosisPackageStoreDirname)
-	if err := ensureDirpathExists(packageStoreDirpath); err != nil {
-		return nil, stacktrace.Propagate(err, "An error occurred ensuring the Starlark package store dirpath '%v' exists.", packageStoreDirpath)
+	repositoriesStoreDirpath := path.Join(dir.absMountDirpath, repositoriesStoreDirname)
+	if err := ensureDirpathExists(repositoriesStoreDirpath); err != nil {
+		return nil, stacktrace.Propagate(err, "An error occurred ensuring the repositories store dirpath '%v' exists.", repositoriesStoreDirpath)
 	}
 
-	tempPackageStoreDirpath := path.Join(dir.absMountDirpath, tmpPackageStoreDirname)
-	if err := ensureDirpathExists(tempPackageStoreDirpath); err != nil {
-		return nil, stacktrace.Propagate(err, "An error occurred ensuring the Starlark temporary package store dirpath '%v' exists.", tempPackageStoreDirpath)
+	tempRepositoriesStoreDirpath := path.Join(dir.absMountDirpath, tmpRepositoriesStoreDirname)
+	if err := ensureDirpathExists(tempRepositoriesStoreDirpath); err != nil {
+		return nil, stacktrace.Propagate(err, "An error occurred ensuring the temporary repositories store dirpath '%v' exists.", tempRepositoriesStoreDirpath)
 	}
 
-	return git_package_content_provider.NewGitPackageContentProvider(packageStoreDirpath, tempPackageStoreDirpath, enclaveDb), nil
+	return git_package_content_provider.NewGitPackageContentProvider(repositoriesStoreDirpath, tempRepositoriesStoreDirpath, enclaveDb), nil
 }
diff --git a/docs/docs/api-reference/starlark-reference/plan.md b/docs/docs/api-reference/starlark-reference/plan.md
index 2544afb6f..ee8ec2f62 100644
--- a/docs/docs/api-reference/starlark-reference/plan.md
+++ b/docs/docs/api-reference/starlark-reference/plan.md
@@ -622,7 +622,7 @@ The `upload_files` instruction packages the files specified by the [locator][loc
 ```python
 artifact_name = plan.upload_files(
     # The file to upload into a files artifact
-    # Must be a Kurtosis locator.
+    # Must be any GitHub URL without the '/blob/main' part.
     # MANDATORY
     src = "github.com/foo/bar/static/example.txt",
 


Test patch:
diff --git a/api/golang/core/lib/shared_utils/parsed_git_url_test.go b/api/golang/core/lib/shared_utils/parsed_git_url_test.go
index aa52f9e08..c4f024a69 100644
--- a/api/golang/core/lib/shared_utils/parsed_git_url_test.go
+++ b/api/golang/core/lib/shared_utils/parsed_git_url_test.go
@@ -70,8 +70,8 @@ func TestParsedGitURL_ParsingGetsRidOfAnyPathEscapes(t *testing.T) {
 	escapedURLWithStartosisFile := "github.com/../../etc/passwd/startosis.star"
 	parsedURL, err = ParseGitURL(escapedURLWithStartosisFile)
 	require.Nil(t, err)
-	require.Equal(t, parsedURL.moduleAuthor, "etc")
-	require.Equal(t, parsedURL.moduleName, "passwd")
+	require.Equal(t, parsedURL.repositoryAuthor, "etc")
+	require.Equal(t, parsedURL.repositoryName, "passwd")
 	require.Equal(t, parsedURL.gitURL, "https://github.com/etc/passwd.git")
 	require.Equal(t, parsedURL.relativeFilePath, "etc/passwd/startosis.star")
 	require.Equal(t, parsedURL.relativeRepoPath, "etc/passwd")
@@ -79,8 +79,8 @@ func TestParsedGitURL_ParsingGetsRidOfAnyPathEscapes(t *testing.T) {
 	escapedURLWithStartosisFile = "github.com/foo/../etc/passwd/startosis.star"
 	parsedURL, err = ParseGitURL(escapedURLWithStartosisFile)
 	require.Nil(t, err)
-	require.Equal(t, parsedURL.moduleAuthor, "etc")
-	require.Equal(t, parsedURL.moduleName, "passwd")
+	require.Equal(t, parsedURL.repositoryAuthor, "etc")
+	require.Equal(t, parsedURL.repositoryName, "passwd")
 	require.Equal(t, parsedURL.gitURL, "https://github.com/etc/passwd.git")
 	require.Equal(t, parsedURL.relativeFilePath, "etc/passwd/startosis.star")
 	require.Equal(t, parsedURL.relativeRepoPath, "etc/passwd")
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/image_build_spec_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/image_build_spec_framework_test.go
index a47dafed1..f2f5ab548 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/image_build_spec_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/image_build_spec_framework_test.go
@@ -22,7 +22,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestImageBuildSpecTest() {
 		Return(testBuildContextLocator, nil)
 
 	suite.packageContentProvider.EXPECT().
-		GetOnDiskAbsoluteFilePath(testContainerImageLocator).
+		GetOnDiskAbsolutePackageFilePath(testContainerImageLocator).
 		Times(1).
 		Return(testOnDiskContainerImagePath, nil)
 
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/service_config_image_build_spec_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/service_config_image_build_spec_test.go
index 3a7932369..ade8edebe 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/service_config_image_build_spec_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/service_config_image_build_spec_test.go
@@ -26,7 +26,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestServiceConfigWithImageBuildSp
 		Return(testBuildContextLocator, nil)
 
 	suite.packageContentProvider.EXPECT().
-		GetOnDiskAbsoluteFilePath(testContainerImageLocator).
+		GetOnDiskAbsolutePackageFilePath(testContainerImageLocator).
 		Times(1).
 		Return(testOnDiskContainerImagePath, nil)
 
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider_test.go b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider_test.go
index 047c0e2e1..33d221124 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider_test.go
@@ -17,7 +17,8 @@ import (
 
 const (
 	packagesDirRelPath                = "startosis-packages"
-	packagesTmpDirRelPath             = "tmp-startosis-packages"
+	repositoriesTmpDirRelPath         = "tmp-repositories"
+	genericRepositoriesDirRelPath     = "generic-repositories"
 	packageDescriptionForTest         = "package description test"
 	localAbsoluteLocatorNotAllowedMsg = "is referencing a file within the same package using absolute import syntax"
 )
@@ -28,7 +29,7 @@ func TestGitPackageProvider_SucceedsForValidPackage(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -44,7 +45,7 @@ func TestGitPackageProvider_SucceedsForValidPackageWithExplicitMasterSet(t *test
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -60,7 +61,7 @@ func TestGitPackageProvider_SucceedsForValidPackageWithBranch(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -76,7 +77,7 @@ func TestGitPackageProvider_FailsForInvalidBranch(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -91,7 +92,7 @@ func TestGitPackageProvider_SucceedsForValidPackageWithTag(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -107,7 +108,7 @@ func TestGitPackageProvider_SucceedsForValidPackageWithCommit(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -123,7 +124,7 @@ func TestGitPackageProvider_SucceedsForValidPackageWithCommitOnABranch(t *testin
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -139,7 +140,7 @@ func TestGitPackageProvider_SucceedsForNonStarlarkFile(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -156,7 +157,7 @@ func TestGitPackageProvider_FailsForNonExistentPackage(t *testing.T) {
 	oackageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(oackageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
@@ -171,14 +172,14 @@ func TestGetAbsolutePathOnDisk_WorksForPureDirectories(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
 	provider := NewGitPackageContentProvider(packageDir, packageTmpDir, nil)
 
 	packagePath := "github.com/kurtosis-tech/datastore-army-package/src/helpers.star"
-	pathOnDisk, err := provider.GetOnDiskAbsoluteFilePath(packagePath)
+	pathOnDisk, err := provider.getOnDiskAbsolutePath(packagePath, true)
 
 	require.Nil(t, err, "This test depends on your internet working and the kurtosis-tech/datastore-army-package existing")
 	require.Equal(t, path.Join(packageDir, "kurtosis-tech", "datastore-army-package", "src/helpers.star"), pathOnDisk)
@@ -188,19 +189,55 @@ func TestGetAbsolutePathOnDisk_WorksForNonInMainBranchLocators(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
 	provider := NewGitPackageContentProvider(packageDir, packageTmpDir, nil)
 
 	absoluteFileLocator := "github.com/kurtosis-tech/sample-dependency-package@test-branch/main.star"
-	pathOnDisk, err := provider.GetOnDiskAbsoluteFilePath(absoluteFileLocator)
+	pathOnDisk, err := provider.getOnDiskAbsolutePath(absoluteFileLocator, true)
 
 	require.Nil(t, err, "This test depends on your internet working and the kurtosis-tech/datastore-army-package existing")
 	require.Equal(t, path.Join(packageDir, "kurtosis-tech", "sample-dependency-package", "main.star"), pathOnDisk)
 }
 
+func TestGetAbsolutePathOnDisk_GenericRepositoryDir(t *testing.T) {
+	repositoriesDir, err := os.MkdirTemp("", packagesDirRelPath)
+	require.Nil(t, err)
+	defer os.RemoveAll(repositoriesDir)
+
+	repositoriesTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
+	require.Nil(t, err)
+	defer os.RemoveAll(repositoriesTmpDir)
+
+	provider := NewGitPackageContentProvider(repositoriesDir, repositoriesTmpDir, nil)
+
+	repositoryPathURL := "github.com/kurtosis-tech/minimal-grpc-server/golang/scripts"
+	pathOnDisk, err := provider.GetOnDiskAbsolutePath(repositoryPathURL)
+
+	require.Nil(t, err, "This test depends on your internet working and the kurtosis-tech/minimal-grpc-server existing")
+	require.Equal(t, path.Join(repositoriesDir, "kurtosis-tech", "minimal-grpc-server", "golang", "scripts"), pathOnDisk)
+}
+
+func TestGetAbsolutePathOnDisk_GenericRepositoryFile(t *testing.T) {
+	repositoriesDir, err := os.MkdirTemp("", packagesDirRelPath)
+	require.Nil(t, err)
+	defer os.RemoveAll(repositoriesDir)
+
+	repositoriesTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
+	require.Nil(t, err)
+	defer os.RemoveAll(repositoriesTmpDir)
+
+	provider := NewGitPackageContentProvider(repositoriesDir, repositoriesTmpDir, nil)
+
+	repositoryPathURL := "github.com/kurtosis-tech/minimal-grpc-server/golang/scripts/build.sh"
+	pathOnDisk, err := provider.GetOnDiskAbsolutePath(repositoryPathURL)
+
+	require.Nil(t, err, "This test depends on your internet working and the kurtosis-tech/minimal-grpc-server existing")
+	require.Equal(t, path.Join(repositoriesDir, "kurtosis-tech", "minimal-grpc-server", "golang", "scripts", "build.sh"), pathOnDisk)
+}
+
 func TestGetAbsoluteLocator_SucceedsForRelativeFile(t *testing.T) {
 	provider := NewGitPackageContentProvider("", "", nil)
 
@@ -557,7 +594,7 @@ func TestCloneReplacedPackagesIfNeeded_Succeeds(t *testing.T) {
 	packageDir, err := os.MkdirTemp("", packagesDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageDir)
-	packageTmpDir, err := os.MkdirTemp("", packagesTmpDirRelPath)
+	packageTmpDir, err := os.MkdirTemp("", repositoriesTmpDirRelPath)
 	require.Nil(t, err)
 	defer os.RemoveAll(packageTmpDir)
 
diff --git a/internal_testsuites/golang/testsuite/startosis_package_test/startosis_no_main_file_test.go b/internal_testsuites/golang/testsuite/startosis_package_test/startosis_no_main_file_test.go
index 7474fe13e..5b291048e 100644
--- a/internal_testsuites/golang/testsuite/startosis_package_test/startosis_no_main_file_test.go
+++ b/internal_testsuites/golang/testsuite/startosis_package_test/startosis_no_main_file_test.go
@@ -18,8 +18,8 @@ func (suite *StartosisPackageTestSuite) TestStartosisPackage_NoMainFile() {
 	require.Error(t, err)
 	require.NotNil(t, runResult)
 
-	expectedErrorContents := `An error occurred while verifying that 'main.star' exists in the package 'github.com/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star' at '/kurtosis-data/startosis-packages/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star/main.star'
-	Caused by: stat /kurtosis-data/startosis-packages/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star/main.star: no such file or directory`
+	expectedErrorContents := `An error occurred while verifying that 'main.star' exists in the package 'github.com/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star' at '/kurtosis-data/repositories/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star/main.star'
+	Caused by: stat /kurtosis-data/repositories/kurtosis-tech/kurtosis/internal_testsuites/starlark/no-main-star/main.star: no such file or directory`
 	require.NotNil(t, runResult.InterpretationError)
 	require.Equal(t, expectedErrorContents, runResult.InterpretationError.GetErrorMessage())
 	require.Empty(t, runResult.ValidationErrors)
diff --git a/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_generic_package_test.go b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_generic_package_test.go
new file mode 100644
index 000000000..917bda418
--- /dev/null
+++ b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_generic_package_test.go
@@ -0,0 +1,44 @@
+package startosis_upload_file_test
+
+import (
+	"context"
+	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/require"
+	"os"
+	"path"
+)
+
+const (
+	packageWithUploadFileGenericRelPath = "../../../starlark/upload-file/upload-file-generic-package"
+)
+
+func (suite *StartosisUploadFileTestSuite) TestStartosisPackage_UploadFileGenericPackage() {
+	ctx := context.Background()
+	t := suite.T()
+	// ------------------------------------- ENGINE SETUP ----------------------------------------------
+
+	// ------------------------------------- TEST RUN ----------------------------------------------
+	currentWorkingDirectory, err := os.Getwd()
+	require.Nil(t, err)
+	packageDirpath := path.Join(currentWorkingDirectory, packageWithUploadFileGenericRelPath)
+
+	// ------------------------------------- TEST RUN ----------------------------------------------
+	logrus.Info("Executing Startosis Package...")
+
+	// Note: the result extracted from the recipe inside Starlark contains a newline char at the end.
+	// We need to add it here manually to have matching hashes
+	isRemotePackage := false
+	runResult, err := suite.RunPackage(ctx, packageDirpath, nil, isRemotePackage)
+	require.NoError(t, err, "Unexpected error executing Starlark package")
+
+	// the package itself runs the assertion here. If the file hash computed withing the enclave with md5sum differs
+	// from the one passed as parameter to the package (computed in Go above), an Execution Error will be returned
+	require.Nil(t, runResult.InterpretationError, "Unexpected interpretation error")
+	require.Empty(t, runResult.ValidationErrors, "Unexpected validation error")
+	require.Nil(t, runResult.ExecutionError, "Unexpected execution error")
+
+	expectedScriptOutputSubstring := `uploaded with artifact UUID`
+	require.Contains(t, string(runResult.RunOutput), expectedScriptOutputSubstring)
+
+	logrus.Info("Successfully ran Startosis module")
+}
diff --git a/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_test.go b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_test.go
index ce0110e68..b75a5d075 100644
--- a/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_test.go
+++ b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_test.go
@@ -1,4 +1,4 @@
-package startosis_upload_files_test
+package startosis_upload_file_test
 
 import (
 	"context"
@@ -11,33 +11,27 @@ import (
 	"github.com/stretchr/testify/require"
 	"os"
 	"path"
-	"testing"
 )
 
 const (
-	validPackageWithInputTestName = "upload-file-package"
-	validPackageWithInputRelPath  = "../../../starlark/upload-file-package"
+	packageWithUploadFileRelPath = "../../../starlark/upload-file/upload-file-package"
 
 	fileName = "large-file.bin"
 	fileSize = 25 * 1024 * 1024 // 25MB
 )
 
-func TestStartosisPackage_UploadFileAndCheckFileHash(t *testing.T) {
-	t.Parallel()
+func (suite *StartosisUploadFileTestSuite) TestStartosisPackage_UploadFileAndCheckFileHash() {
 	ctx := context.Background()
-
+	t := suite.T()
 	// ------------------------------------- ENGINE SETUP ----------------------------------------------
-	enclaveCtx, _, destroyEnclaveFunc, err := test_helpers.CreateEnclave(t, ctx, validPackageWithInputTestName)
-	require.NoError(t, err, "An error occurred creating an enclave")
-	defer func() { _ = destroyEnclaveFunc() }()
 
+	// ------------------------------------- TEST RUN ----------------------------------------------
 	currentWorkingDirectory, err := os.Getwd()
 	require.Nil(t, err)
-	packageDirpath := path.Join(currentWorkingDirectory, validPackageWithInputRelPath)
+	packageDirpath := path.Join(currentWorkingDirectory, packageWithUploadFileRelPath)
 
-	// ------------------------------------- TEST RUN ----------------------------------------------
 	// we generate a file and place it into the package - as it is a big file, we don't want to check it in GitHub
-	fileRelPath := path.Join(validPackageWithInputRelPath, fileName)
+	fileRelPath := path.Join(packageWithUploadFileRelPath, fileName)
 	randomFilePath, deleteFile, err := test_helpers.GenerateRandomTempFile(fileSize, fileRelPath)
 	require.NoError(t, err)
 	defer deleteFile()
@@ -57,7 +51,9 @@ func TestStartosisPackage_UploadFileAndCheckFileHash(t *testing.T) {
 	// Note: the result extracted from the recipe inside Starlark contains a newline char at the end.
 	// We need to add it here manually to have matching hashes
 	params := fmt.Sprintf(`{"file_hash": "%s\n"}`, randomFileHexHash)
-	runResult, err := enclaveCtx.RunStarlarkPackageBlocking(ctx, packageDirpath, starlark_run_config.NewRunStarlarkConfig(starlark_run_config.WithSerializedParams(params)))
+	runConfig := starlark_run_config.NewRunStarlarkConfig(starlark_run_config.WithSerializedParams(params))
+	isRemotePackage := false
+	runResult, err := suite.RunPackage(ctx, packageDirpath, runConfig, isRemotePackage)
 	require.NoError(t, err, "Unexpected error executing Starlark package")
 
 	// the package itself runs the assertion here. If the file hash computed withing the enclave with md5sum differs
diff --git a/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_testsuite_test.go b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_testsuite_test.go
new file mode 100644
index 000000000..8b67ac552
--- /dev/null
+++ b/internal_testsuites/golang/testsuite/startosis_upload_file_test/startosis_upload_file_testsuite_test.go
@@ -0,0 +1,69 @@
+package startosis_upload_file_test
+
+import (
+	"context"
+	"github.com/kurtosis-tech/kurtosis-cli/golang_internal_testsuite/test_helpers"
+	"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/enclaves"
+	"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/starlark_run_config"
+	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/require"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+const (
+	name = "startosis-upload-file"
+)
+
+type StartosisUploadFileTestSuite struct {
+	suite.Suite
+	enclaveCtx         *enclaves.EnclaveContext
+	destroyEnclaveFunc func() error
+}
+
+func TestStartosisUploadFileTestSuite(t *testing.T) {
+	suite.Run(t, new(StartosisUploadFileTestSuite))
+}
+
+func (suite *StartosisUploadFileTestSuite) SetupTest() {
+	ctx := context.Background()
+	t := suite.T()
+	enclaveCtx, _, destroyEnclaveFunc, err := test_helpers.CreateEnclave(t, ctx, name)
+	require.NoError(t, err, "An error occurred creating an enclave")
+	suite.enclaveCtx = enclaveCtx
+	suite.destroyEnclaveFunc = destroyEnclaveFunc
+}
+
+func (suite *StartosisUploadFileTestSuite) TearDownTest() {
+	err := suite.destroyEnclaveFunc()
+	require.NoError(suite.T(), err, "Destroying the test suite's enclave process has failed, you will have to remove it manually")
+}
+
+func (suite *StartosisUploadFileTestSuite) RunPackage(
+	ctx context.Context,
+	packageLocation string,
+	runConfig *starlark_run_config.StarlarkRunConfig,
+	remote bool,
+) (*enclaves.StarlarkRunResult, error) {
+	logrus.Infof("Executing Startosis package...")
+
+	logrus.Debugf("Startosis package location: %v", packageLocation)
+
+	if runConfig == nil {
+		runConfig = starlark_run_config.NewRunStarlarkConfig()
+	}
+
+	if remote {
+		return suite.enclaveCtx.RunStarlarkRemotePackageBlocking(
+			ctx,
+			packageLocation,
+			runConfig,
+		)
+	}
+
+	return suite.enclaveCtx.RunStarlarkPackageBlocking(
+		ctx,
+		packageLocation,
+		runConfig,
+	)
+}
diff --git a/internal_testsuites/starlark/upload-file/upload-file-generic-package/kurtosis.yml b/internal_testsuites/starlark/upload-file/upload-file-generic-package/kurtosis.yml
new file mode 100644
index 000000000..923e558c1
--- /dev/null
+++ b/internal_testsuites/starlark/upload-file/upload-file-generic-package/kurtosis.yml
@@ -0,0 +1,1 @@
+name: "github.com/kurtosis-tech/kurtosis/internal_testsuites/starlark/upload-file/upload-file-generic-package"
diff --git a/internal_testsuites/starlark/upload-file/upload-file-generic-package/main.star b/internal_testsuites/starlark/upload-file/upload-file-generic-package/main.star
new file mode 100644
index 000000000..03550f152
--- /dev/null
+++ b/internal_testsuites/starlark/upload-file/upload-file-generic-package/main.star
@@ -0,0 +1,21 @@
+SERVICE_NAME = "service-example"
+
+def run(plan, args={}):
+    url = "github.com/kurtosis-tech/minimal-grpc-server/golang/scripts/build.sh"
+    artifact_name_1 = plan.upload_files(url)
+
+    service = plan.add_service(
+        SERVICE_NAME,
+        config=ServiceConfig(
+            image="alpine:latest",
+            cmd=["/bin/sh",
+                 "-c","ls /files && sleep 9999"],
+            files={
+                "/files": Directory(
+                    artifact_names=[artifact_name_1]
+                )
+            },
+        ),
+    )
+
+
diff --git a/internal_testsuites/starlark/upload-file-package/.gitignore b/internal_testsuites/starlark/upload-file/upload-file-package/.gitignore
similarity index 100%
rename from internal_testsuites/starlark/upload-file-package/.gitignore
rename to internal_testsuites/starlark/upload-file/upload-file-package/.gitignore
diff --git a/internal_testsuites/starlark/upload-file-package/kurtosis.yml b/internal_testsuites/starlark/upload-file/upload-file-package/kurtosis.yml
similarity index 62%
rename from internal_testsuites/starlark/upload-file-package/kurtosis.yml
rename to internal_testsuites/starlark/upload-file/upload-file-package/kurtosis.yml
index 957dc7ab4..97a23143f 100644
--- a/internal_testsuites/starlark/upload-file-package/kurtosis.yml
+++ b/internal_testsuites/starlark/upload-file/upload-file-package/kurtosis.yml
@@ -1,1 +1,1 @@
-name: "github.com/kurtosis-tech/kurtosis/internal_testsuites/starlark/upload-file-package"
+name: "github.com/kurtosis-tech/kurtosis/internal_testsuites/starlark/upload-file/upload-file-package"