env.go
1 // Copyright 2026 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "fmt" 19 "os" 20 "strings" 21 22 "github.com/alibaba/opensandbox/execd/pkg/log" 23 "github.com/alibaba/opensandbox/execd/pkg/util/pathutil" 24 ) 25 26 // loadExtraEnvFromFile reads key=value lines from EXECD_ENVS (if set). 27 // Empty lines and lines starting with '#' are ignored. 28 func loadExtraEnvFromFile() map[string]string { 29 path := os.Getenv("EXECD_ENVS") 30 if path == "" { 31 return nil 32 } 33 resolvedPath, err := pathutil.ExpandPath(path) 34 if err != nil { 35 log.Warn("EXECD_ENVS: failed to resolve file path %s: %v", path, err) 36 return nil 37 } 38 39 data, err := os.ReadFile(resolvedPath) 40 if err != nil { 41 log.Warn("EXECD_ENVS: failed to read file %s: %v", resolvedPath, err) 42 return nil 43 } 44 45 envs := make(map[string]string) 46 lines := strings.Split(string(data), "\n") 47 for _, line := range lines { 48 line = strings.TrimSpace(line) 49 if line == "" || strings.HasPrefix(line, "#") { 50 continue 51 } 52 kv := strings.SplitN(line, "=", 2) 53 if len(kv) != 2 { 54 log.Warn("EXECD_ENVS: skip malformed line: %s", line) 55 continue 56 } 57 envs[kv[0]] = os.ExpandEnv(kv[1]) 58 } 59 60 return envs 61 } 62 63 // mergeEnvs overlays extra into base and returns a merged slice. 64 func mergeEnvs(base []string, extra map[string]string) []string { 65 if len(extra) == 0 { 66 return base 67 } 68 69 merged := make(map[string]string, len(base)+len(extra)) 70 for _, kv := range base { 71 pair := strings.SplitN(kv, "=", 2) 72 if len(pair) == 2 { 73 merged[pair[0]] = pair[1] 74 } 75 } 76 77 for k, v := range extra { 78 merged[k] = v 79 } 80 81 out := make([]string, 0, len(merged)) 82 for k, v := range merged { 83 out = append(out, fmt.Sprintf("%s=%s", k, v)) 84 } 85 86 return out 87 } 88 89 // mergeExtraEnvs merges environment maps from file and request-level overrides. 90 func mergeExtraEnvs(fromFile, fromRequest map[string]string) map[string]string { 91 if len(fromRequest) == 0 { 92 return fromFile 93 } 94 95 merged := make(map[string]string, len(fromFile)+len(fromRequest)) 96 for k, v := range fromFile { 97 merged[k] = v 98 } 99 for k, v := range fromRequest { 100 merged[k] = v 101 } 102 103 return merged 104 }