mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 01:16:45 +08:00
`multica runtime profile set-path` was accepted on Windows but the daemon never used the override: the gate required a Unix executable bit, which Go never sets on Windows files (0666/0444 for regular files; 0111 only on directories). Every override — including a plain .exe — read as not executable, so the daemon fell back to PATH: either failing registration with a message that blamed the user's filesystem, or silently registering a different install than the pinned one. appendProfileRuntimes now resolves the override through resolveAgentExecutablePath (exec.LookPath) — the same contract agent launches use — and records the resolved path rather than the raw override, so Windows PATHEXT completion picks up .cmd shims and extension-less pins. Unix exec-bit checks are unchanged, and a stale or mistyped override still falls back to PATH with the existing warning. Regression coverage runs on the real Windows runner via the existing windows-execenv job. Fixes #7613
89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
package daemon
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
// TestResolveAgentExecutablePath_ProfileOverride is the set-path gate
|
|
// regression for MUL-3284 / #7613. appendProfileRuntimes must reuse
|
|
// resolveAgentExecutablePath (exec.LookPath) so Windows PATHEXT completion
|
|
// and unix exec-bit checks match what agent launch already does — including
|
|
// assigning LookPath's return value, not the raw override.
|
|
func TestResolveAgentExecutablePath_ProfileOverride(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
if runtime.GOOS == "windows" {
|
|
t.Setenv("PATHEXT", ".COM;.EXE;.BAT;.CMD")
|
|
|
|
exe := filepath.Join(dir, "tool.exe")
|
|
if err := os.WriteFile(exe, []byte("MZ"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := resolveAgentExecutablePath(exe)
|
|
if err != nil {
|
|
t.Fatalf("resolveAgentExecutablePath(%q): %v", exe, err)
|
|
}
|
|
if got != exe {
|
|
t.Fatalf("resolved .exe = %q, want %q", got, exe)
|
|
}
|
|
|
|
cmd := filepath.Join(dir, "tool.cmd")
|
|
if err := os.WriteFile(cmd, []byte("@echo off\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err = resolveAgentExecutablePath(cmd)
|
|
if err != nil {
|
|
t.Fatalf("resolveAgentExecutablePath(%q): %v", cmd, err)
|
|
}
|
|
if got != cmd {
|
|
t.Fatalf("resolved .cmd = %q, want %q", got, cmd)
|
|
}
|
|
|
|
// npm-style shim: operator pins C:\tools\openclaw while only
|
|
// openclaw.cmd exists. LookPath must complete the extension.
|
|
shimDir := t.TempDir()
|
|
shimCmd := filepath.Join(shimDir, "openclaw.cmd")
|
|
if err := os.WriteFile(shimCmd, []byte("@echo off\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
extensionless := filepath.Join(shimDir, "openclaw")
|
|
got, err = resolveAgentExecutablePath(extensionless)
|
|
if err != nil {
|
|
t.Fatalf("resolveAgentExecutablePath(%q): %v", extensionless, err)
|
|
}
|
|
if got != shimCmd {
|
|
t.Fatalf("extension-less override resolved to %q, want %q", got, shimCmd)
|
|
}
|
|
// Non-PATHEXT absolute files are not asserted: on Windows,
|
|
// exec.LookPath accepts an absolute path to any existing file.
|
|
} else {
|
|
tool := filepath.Join(dir, "tool")
|
|
if err := os.WriteFile(tool, []byte("#!/bin/sh\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := resolveAgentExecutablePath(tool); err == nil {
|
|
t.Fatalf("0644 file should not resolve on unix")
|
|
}
|
|
if err := os.Chmod(tool, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := resolveAgentExecutablePath(tool)
|
|
if err != nil {
|
|
t.Fatalf("resolveAgentExecutablePath(%q): %v", tool, err)
|
|
}
|
|
if got != tool {
|
|
t.Fatalf("resolved unix tool = %q, want %q", got, tool)
|
|
}
|
|
}
|
|
|
|
if _, err := resolveAgentExecutablePath(dir); err == nil {
|
|
t.Fatalf("directory should not resolve")
|
|
}
|
|
if _, err := resolveAgentExecutablePath(filepath.Join(dir, "missing")); err == nil {
|
|
t.Fatalf("missing path should not resolve")
|
|
}
|
|
}
|