diff --git a/handlers_test.go b/handlers_test.go index 1ef62338..8915ebee 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -19,6 +19,7 @@ package main import ( + "context" "crypto/tls" "fmt" "io/ioutil" @@ -27,6 +28,7 @@ import ( "strings" "sync" "testing" + "time" "github.com/stretchr/testify/assert" @@ -132,9 +134,12 @@ func TestSketchProcessIsRunning(t *testing.T) { sketchTopic := "upload" fs := http.FileServer(http.Dir("test/sketch_devops_integ_test")) + http.DefaultServeMux = new(http.ServeMux) http.Handle("/", fs) - go func() { http.ListenAndServe(":3000", nil) }() + srv := &http.Server{Addr: ":3000"} + + go func() { srv.ListenAndServe() }() sketchDownloadCommand := fmt.Sprintf(`{"token": "","url": "%s","name": "sketch_devops_integ_test.elf","id": "0774e17e-f60e-4562-b87d-18017b6ef3d2"}`, "http://10.0.2.2:3000/sketch_devops_integ_test.elf") responseSketchRun := mqtt.MqttSendAndReceiveSync(t, sketchTopic, sketchDownloadCommand) @@ -149,6 +154,10 @@ func TestSketchProcessIsRunning(t *testing.T) { t.Error(err) } assert.Equal(t, 1, len(strings.Split(strings.TrimSuffix(outputMessage, "\n"), "\n"))) + ctx, _ := context.WithTimeout(context.Background(), 1*time.Second) + if err := srv.Shutdown(ctx); err != nil { + t.Error(err) + } } // tests @@ -158,13 +167,67 @@ func TestMaliciousSketchProcessIsNotRunning(t *testing.T) { sketchTopic := "upload" fs := http.FileServer(http.Dir("test/sketch_devops_integ_test/sketch_devops_integ_test_malicious")) + http.DefaultServeMux = new(http.ServeMux) http.Handle("/", fs) + srv := &http.Server{Addr: ":3000"} - go func() { http.ListenAndServe(":3000", nil) }() + go func() { srv.ListenAndServe() }() sketchDownloadCommand := fmt.Sprintf(`{"token": "","url": "%s","name": "sketch_devops_integ_test.elf","id": "0774e17e-f60e-4562-b87d-18017b6ef3d2"}`, "http://10.0.2.2:3000/sketch_devops_integ_test.elf") responseSketchRun := mqtt.MqttSendAndReceiveSync(t, sketchTopic, sketchDownloadCommand) t.Log(responseSketchRun) assert.Equal(t, true, strings.Contains(responseSketchRun, "ERROR: signature do not match")) + ctx, _ := context.WithTimeout(context.Background(), 1*time.Second) + if err := srv.Shutdown(ctx); err != nil { + t.Error(err) + } +} + +func TestSketchProcessHasConfigWhitelistedEnvVars(t *testing.T) { + // see upload_dev_artifacts_on_s3.sh to see where env vars are passed to the config + mqtt := NewMqttTestClient() + defer mqtt.Close() + + //test connector config + outputMessage, err := ExecAsVagrantSshCmd("sudo cat /root/arduino-connector.cfg") + if err != nil { + t.Error(err) + } + envString := outputMessage + t.Log(envString) + assert.Equal(t, true, strings.Contains(envString, "env_vars_to_load=HDDL_INSTALL_DIR=/opt/intel/computer_vision_sdk/inference_engine/external/hddl/,ENV_TEST_PATH=/tmp")) + + //test environment + sketchTopic := "upload" + + fs := http.FileServer(http.Dir("test/sketch_env_integ_test")) + http.DefaultServeMux = new(http.ServeMux) + http.Handle("/", fs) + + srv := &http.Server{Addr: ":3000"} + + go func() { srv.ListenAndServe() }() + + sketchDownloadCommand := fmt.Sprintf(`{"token": "","url": "%s","name": "connector_env_var_test.bin","id": "0774e17e-f60e-4562-b87d-18017b6ef3d2"}`, "http://10.0.2.2:3000/connector_env_var_test.bin") + responseSketchRun := mqtt.MqttSendAndReceiveSync(t, sketchTopic, sketchDownloadCommand) + t.Log(responseSketchRun) + + assert.Equal(t, true, strings.Contains(responseSketchRun, "INFO: Sketch started with PID ")) + + outputMessage, err = ExecAsVagrantSshCmd("cat /tmp/printenv.out") + if err != nil { + t.Error(err) + } + + envString = outputMessage + t.Log(envString) + + assert.Equal(t, true, strings.Contains(envString, "HDDL_INSTALL_DIR=/opt/intel/computer_vision_sdk/inference_engine/external/hddl/")) + assert.Equal(t, true, strings.Contains(envString, "ENV_TEST_PATH=/tmp")) + ctx, _ := context.WithTimeout(context.Background(), 1*time.Second) + if err := srv.Shutdown(ctx); err != nil { + t.Error(err) + } + } diff --git a/main.go b/main.go index b3d73dea..8e2721dc 100644 --- a/main.go +++ b/main.go @@ -53,19 +53,20 @@ var ( // Config holds the configuration needed by the application type Config struct { - ID string - URL string - HTTPProxy string - HTTPSProxy string - ALLProxy string - AuthURL string - APIURL string - updateURL string - appName string - CertPath string - SketchesPath string - CheckRoFs bool - SignatureKey string + ID string + URL string + HTTPProxy string + HTTPSProxy string + ALLProxy string + AuthURL string + APIURL string + updateURL string + appName string + CertPath string + SketchesPath string + CheckRoFs bool + SignatureKey string + EnvVarsToLoad string } func (c Config) String() string { @@ -79,6 +80,7 @@ func (c Config) String() string { out += "cert_path=" + c.CertPath + "\r\n" out += "sketches_path=" + c.SketchesPath + "\r\n" out += "check_ro_fs=" + strconv.FormatBool(c.CheckRoFs) + "\r\n" + out += "env_vars_to_load=" + c.EnvVarsToLoad + "\r\n" return out } @@ -111,6 +113,7 @@ func main() { flag.BoolVar(&config.CheckRoFs, "check_ro_fs", false, "Check for Read Only file system and remount if necessary") flag.BoolVar(&debugMqtt, "debug-mqtt", false, "Output all received/sent messages") flag.StringVar(&config.SignatureKey, "signature_key", "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvc0yZr1yUSen7qmE3cxF\nIE12rCksDnqR+Hp7o0nGi9123eCSFcJ7CkIRC8F+8JMhgI3zNqn4cUEn47I3RKD1\nZChPUCMiJCvbLbloxfdJrUi7gcSgUXrlKQStOKF5Iz7xv1M4XOP3JtjXLGo3EnJ1\npFgdWTOyoSrA8/w1rck4c/ISXZSinVAggPxmLwVEAAln6Itj6giIZHKvA2fL2o8z\nCeK057Lu8X6u2CG8tRWSQzVoKIQw/PKK6CNXCAy8vo4EkXudRutnEYHEJlPkVgPn\n2qP06GI+I+9zKE37iqj0k1/wFaCVXHXIvn06YrmjQw6I0dDj/60Wvi500FuRVpn9\ntwIDAQAB\n-----END PUBLIC KEY-----", "key for verifying sketch binary signature") + flag.StringVar(&config.EnvVarsToLoad, "env_vars_to_load", "", "List of comma-separated Environment variables to load from system before launching sketches binaries") flag.Parse() @@ -184,6 +187,7 @@ func (p program) run() { // - any spawned sketch process'es also have access to them // Note, all_proxy will not be used by any HTTP/HTTPS connections. p.exportProxyEnvVars() + p.exportConfigWhitelistedEnvVars() // Start nats-server on localhost:4222 opts := server.Options{} @@ -478,6 +482,15 @@ func (p program) exportProxyEnvVars() { } } +func (p program) exportConfigWhitelistedEnvVars() { + for _, envVar := range strings.Split(p.Config.EnvVarsToLoad, ",") { + if strings.Contains(envVar, "=") { + envTuple := strings.Split(envVar, "=") + os.Setenv(envTuple[0], envTuple[1]) + } + } +} + func check(err error, context string) { if err != nil { log.Fatal(context, " - ", err) diff --git a/test/sketch_env_integ_test/connector_env_var_test.bin b/test/sketch_env_integ_test/connector_env_var_test.bin new file mode 100644 index 00000000..a4eee44e Binary files /dev/null and b/test/sketch_env_integ_test/connector_env_var_test.bin differ diff --git a/test/sketch_env_integ_test/connector_env_var_test.bin.sig b/test/sketch_env_integ_test/connector_env_var_test.bin.sig new file mode 100644 index 00000000..2f1b9b88 Binary files /dev/null and b/test/sketch_env_integ_test/connector_env_var_test.bin.sig differ diff --git a/test/sketch_env_integ_test/connector_env_var_test.ino b/test/sketch_env_integ_test/connector_env_var_test.ino new file mode 100644 index 00000000..7cf540da --- /dev/null +++ b/test/sketch_env_integ_test/connector_env_var_test.ino @@ -0,0 +1,12 @@ +/* + +*/ + +void setup() { + System.runShellCommand("printenv > /tmp/printenv.out"); + exit(0); +} + +void loop() { + +} \ No newline at end of file diff --git a/test/upload_dev_artifacts_on_s3.sh b/test/upload_dev_artifacts_on_s3.sh index 63784b48..fd56557b 100755 --- a/test/upload_dev_artifacts_on_s3.sh +++ b/test/upload_dev_artifacts_on_s3.sh @@ -16,6 +16,7 @@ cat >ui_gen_install.sh <