Only allow .scl files to load other .scl files

.scl files are starlark configuraiont language files, which is starlark
without any of the bazel buildin symbols.

This is to match bazel's behavior, and it doesn't make sense for
scl files to load bzl files.

We should change all the release config bzl files to scl, and then
also make it so that when using executionModeScl you can only load
scl files.

Test: go test
Change-Id: I196bcf3a4548118791ed1d47c2d37e46a1ef86c4
diff --git a/tools/rbcrun/host.go b/tools/rbcrun/host.go
index 1d68d43..7f5e332 100644
--- a/tools/rbcrun/host.go
+++ b/tools/rbcrun/host.go
@@ -31,11 +31,11 @@
 type ExecutionMode int
 const (
 	ExecutionModeRbc ExecutionMode = iota
-	ExecutionModeMake ExecutionMode = iota
+	ExecutionModeScl ExecutionMode = iota
 )
 
 const allowExternalEntrypointKey = "allowExternalEntrypoint"
-const callerDirKey = "callerDir"
+const callingFileKey = "callingFile"
 const executionModeKey = "executionMode"
 const shellKey = "shell"
 
@@ -58,7 +58,7 @@
 	"rblf_wildcard": starlark.NewBuiltin("rblf_wildcard", wildcard),
 }
 
-var makeBuiltins starlark.StringDict = starlark.StringDict{
+var sclBuiltins starlark.StringDict = starlark.StringDict{
 	"struct":   starlark.NewBuiltin("struct", starlarkstruct.Make),
 	"json": starlarkjson.Module,
 }
@@ -128,7 +128,8 @@
 			module = module[:pipePos]
 		}
 	}
-	modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string), allowExternalEntrypoint)
+	callingFile := thread.Local(callingFileKey).(string)
+	modulePath, err := cleanModuleName(module, filepath.Dir(callingFile), allowExternalEntrypoint)
 	if err != nil {
 		return nil, err
 	}
@@ -150,6 +151,13 @@
 
 		// Load or return default
 		if mustLoad {
+			if strings.HasSuffix(callingFile, ".scl") && !strings.HasSuffix(modulePath, ".scl") {
+				return nil, fmt.Errorf(".scl files can only load other .scl files: %q loads %q", callingFile, modulePath)
+			}
+			// Switch into scl mode from here on
+			if strings.HasSuffix(modulePath, ".scl") {
+				mode = ExecutionModeScl
+			}
 			childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
 			// Cheating for the sake of testing:
 			// propagate starlarktest's Reporter key, otherwise testing
@@ -161,14 +169,14 @@
 
 			// Only the entrypoint starlark file allows external loads.
 			childThread.SetLocal(allowExternalEntrypointKey, false)
-			childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
+			childThread.SetLocal(callingFileKey, modulePath)
 			childThread.SetLocal(executionModeKey, mode)
 			childThread.SetLocal(shellKey, thread.Local(shellKey))
 			if mode == ExecutionModeRbc {
 				globals, err := starlark.ExecFile(childThread, modulePath, nil, rbcBuiltins)
 				e = &modentry{globals, err}
-			} else if mode == ExecutionModeMake {
-				globals, err := starlark.ExecFile(childThread, modulePath, nil, makeBuiltins)
+			} else if mode == ExecutionModeScl {
+				globals, err := starlark.ExecFile(childThread, modulePath, nil, sclBuiltins)
 				e = &modentry{globals, err}
 			} else {
 				return nil, fmt.Errorf("unknown executionMode %d", mode)
@@ -338,7 +346,7 @@
 			if mode == ExecutionModeRbc {
 				// In rbc mode, rblf_log is used to print to stderr
 				fmt.Println(msg)
-			} else if mode == ExecutionModeMake {
+			} else if mode == ExecutionModeScl {
 				fmt.Fprintln(os.Stderr, msg)
 			}
 		},
@@ -365,13 +373,13 @@
 
 	var results starlark.StringDict
 	mainThread.SetLocal(allowExternalEntrypointKey, allowExternalEntrypoint)
-	mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
+	mainThread.SetLocal(callingFileKey, filename)
 	mainThread.SetLocal(executionModeKey, mode)
 	mainThread.SetLocal(shellKey, shellPath)
 	if mode == ExecutionModeRbc {
 		results, err = starlark.ExecFile(mainThread, filename, src, rbcBuiltins)
-	} else if mode == ExecutionModeMake {
-		results, err = starlark.ExecFile(mainThread, filename, src, makeBuiltins)
+	} else if mode == ExecutionModeScl {
+		results, err = starlark.ExecFile(mainThread, filename, src, sclBuiltins)
 	} else {
 		return results, nil, fmt.Errorf("unknown executionMode %d", mode)
 	}