/ common / utils / runtime_paths.go
runtime_paths.go
  1  package utils
  2  
  3  import (
  4  	"fmt"
  5  	"os"
  6  	"os/exec"
  7  	"path/filepath"
  8  	"strings"
  9  )
 10  
 11  const (
 12  	AgentScanDirEnv      = "AIG_AGENT_SCAN_DIR"
 13  	McpScanDirEnv        = "AIG_MCP_SCAN_DIR"
 14  	PromptSecurityDirEnv = "AIG_PROMPT_SECURITY_DIR"
 15  	UvBinEnv             = "AIG_UV_BIN"
 16  )
 17  
 18  func ResolveAgentScanDir() (string, error) {
 19  	return resolveRuntimeDir(AgentScanDirEnv, "/app/agent-scan", "agent-scan")
 20  }
 21  
 22  func ResolveMcpScanDir() (string, error) {
 23  	return resolveRuntimeDir(McpScanDirEnv, "/app/mcp-scan", "mcp-scan")
 24  }
 25  
 26  func ResolvePromptSecurityDir() (string, error) {
 27  	return resolveRuntimeDir(PromptSecurityDirEnv, "/app/AIG-PromptSecurity", "AIG-PromptSecurity")
 28  }
 29  
 30  func ResolveUvBin() (string, error) {
 31  	if override := strings.TrimSpace(os.Getenv(UvBinEnv)); override != "" {
 32  		return override, nil
 33  	}
 34  	if uvPath, err := exec.LookPath("uv"); err == nil {
 35  		return uvPath, nil
 36  	}
 37  	const containerUvPath = "/usr/local/bin/uv"
 38  	if info, err := os.Stat(containerUvPath); err == nil && !info.IsDir() {
 39  		return containerUvPath, nil
 40  	}
 41  	return "", fmt.Errorf("unable to locate uv; set %s to override the path", UvBinEnv)
 42  }
 43  
 44  func resolveRuntimeDir(envName, containerPath, relativePath string) (string, error) {
 45  	candidates := collectRuntimeDirCandidates(envName, containerPath, relativePath, runtimeSearchBases()...)
 46  	for _, candidate := range candidates {
 47  		info, err := os.Stat(candidate)
 48  		if err == nil && info.IsDir() {
 49  			return candidate, nil
 50  		}
 51  	}
 52  	return "", fmt.Errorf("unable to locate %s; set %s to override the path", relativePath, envName)
 53  }
 54  
 55  func runtimeSearchBases() []string {
 56  	var bases []string
 57  	if wd, err := os.Getwd(); err == nil {
 58  		bases = append(bases, wd)
 59  	}
 60  	if execPath, err := os.Executable(); err == nil {
 61  		bases = append(bases, filepath.Dir(execPath))
 62  	}
 63  	return bases
 64  }
 65  
 66  func collectRuntimeDirCandidates(envName, containerPath, relativePath string, bases ...string) []string {
 67  	var candidates []string
 68  	seen := make(map[string]struct{})
 69  	addCandidate := func(path string) {
 70  		path = strings.TrimSpace(path)
 71  		if path == "" {
 72  			return
 73  		}
 74  		path = filepath.Clean(path)
 75  		if !filepath.IsAbs(path) {
 76  			if absPath, err := filepath.Abs(path); err == nil {
 77  				path = absPath
 78  			}
 79  		}
 80  		if _, ok := seen[path]; ok {
 81  			return
 82  		}
 83  		seen[path] = struct{}{}
 84  		candidates = append(candidates, path)
 85  	}
 86  
 87  	addCandidate(os.Getenv(envName))
 88  	addCandidate(containerPath)
 89  
 90  	for _, base := range bases {
 91  		base = strings.TrimSpace(base)
 92  		if base == "" {
 93  			continue
 94  		}
 95  		current := filepath.Clean(base)
 96  		for i := 0; i < 8; i++ {
 97  			addCandidate(filepath.Join(current, relativePath))
 98  			parent := filepath.Dir(current)
 99  			if parent == current {
100  				break
101  			}
102  			current = parent
103  		}
104  	}
105  
106  	return candidates
107  }