Execute the managed interpreter through its real path
ci / vet-and-test (pull_request) Successful in 1m3s

Why: the sandbox hides /home and only remounts the resolved Python prefix, so executing python/current/bin/python3 failed before the base layer could be imported.
Evidence: go test ./internal/tools/ -run TestResolveInterpreterFollowsManagedSymlink passed, and env doctor against the built base layer printed doctor ok (SELF).
Impact: run_python and env doctor follow the symlink into the mounted prefix or /usr/bin/python3. The layer and the prefix mount stay the same.
Refs: Agent-System-Backend PR 207
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-15 14:43:13 +00:00
co-authored by Cursor
parent c5a4c6306b
commit 28544cfe5d
3 changed files with 33 additions and 1 deletions
+4
View File
@@ -6,6 +6,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"path/filepath"
"time" "time"
"agent-system-backend/internal/execenv" "agent-system-backend/internal/execenv"
@@ -137,6 +138,9 @@ func runDoctor(ctx context.Context, root *execenv.Root, py string, sandbox bool)
if prefix := root.PythonPrefix(); prefix != "" { if prefix := root.PythonPrefix(); prefix != "" {
mounts = append(mounts, prefix) mounts = append(mounts, prefix)
} }
if resolved, err := filepath.EvalSymlinks(py); err == nil {
py = resolved
}
if err := execenv.Doctor(ctx, py, pyPath, nil, sandbox, mounts); err != nil { if err := execenv.Doctor(ctx, py, pyPath, nil, sandbox, mounts); err != nil {
fmt.Fprintln(os.Stderr, "env doctor:", err) fmt.Fprintln(os.Stderr, "env doctor:", err)
return 1 return 1
+7 -1
View File
@@ -203,7 +203,13 @@ func resolveInterpreter(name string) (string, error) {
case "python3": case "python3":
if execPythonBin != "" { if execPythonBin != "" {
if st, err := os.Stat(execPythonBin); err == nil && !st.IsDir() { if st, err := os.Stat(execPythonBin); err == nil && !st.IsDir() {
return execPythonBin, nil // current/bin/python3 是符号链接。沙箱用 tmpfs 盖住 /home 后只挂真实前缀,
// 执行未解析的 current 路径会找不到文件。
resolved, err := filepath.EvalSymlinks(execPythonBin)
if err != nil {
return "", err
}
return resolved, nil
} }
return "", fmt.Errorf("python3: configured interpreter missing: %s", execPythonBin) return "", fmt.Errorf("python3: configured interpreter missing: %s", execPythonBin)
} }
+22
View File
@@ -213,6 +213,28 @@ func TestExecEnvIncludesSkillsRoot(t *testing.T) {
} }
} }
func TestResolveInterpreterFollowsManagedSymlink(t *testing.T) {
prev := execPythonBin
t.Cleanup(func() { execPythonBin = prev })
dir := t.TempDir()
link := filepath.Join(dir, "python3")
if err := os.Symlink("/usr/bin/python3", link); err != nil {
t.Fatal(err)
}
execPythonBin = link
got, err := resolveInterpreter("python3")
if err != nil {
t.Fatal(err)
}
want, err := filepath.EvalSymlinks("/usr/bin/python3")
if err != nil {
t.Fatal(err)
}
if got != want {
t.Fatalf("resolved %q, want %q", got, want)
}
}
func TestInterpreterExecConfigForKernel(t *testing.T) { func TestInterpreterExecConfigForKernel(t *testing.T) {
cfg := InterpreterExecConfig() cfg := InterpreterExecConfig()
if cfg == nil { if cfg == nil {