源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package runtimeprep
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCursorBackgroundTaskGuardAllowsForegroundAndDeniesBackground(t *testing.T) {
|
||||
nodePath, err := exec.LookPath("node")
|
||||
if err != nil {
|
||||
t.Skip("node is required to execute the generated Cursor hook")
|
||||
}
|
||||
|
||||
pluginDir := t.TempDir()
|
||||
if err := installCursorBackgroundTaskGuard(filepath.Join(pluginDir, "hooks")); err != nil {
|
||||
t.Fatalf("installCursorBackgroundTaskGuard() error = %v", err)
|
||||
}
|
||||
hookPath := filepath.Join(pluginDir, "hooks", "guard-background-task.mjs")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantDenied bool
|
||||
}{
|
||||
{
|
||||
name: "foreground omitted",
|
||||
input: `{"tool_name":"Task","tool_input":{"prompt":"run_in_background=true is mentioned only as text"}}`,
|
||||
wantDenied: false,
|
||||
},
|
||||
{
|
||||
name: "foreground false",
|
||||
input: `{"tool_name":"Task","tool_input":{"run_in_background":false}}`,
|
||||
wantDenied: false,
|
||||
},
|
||||
{
|
||||
name: "background snake case",
|
||||
input: `{"tool_name":"Task","tool_input":{"run_in_background":true}}`,
|
||||
wantDenied: true,
|
||||
},
|
||||
{
|
||||
name: "background camel case",
|
||||
input: `{"toolName":"Task","toolInput":{"runInBackground":true}}`,
|
||||
wantDenied: true,
|
||||
},
|
||||
{
|
||||
name: "invalid payload fails closed",
|
||||
input: `{`,
|
||||
wantDenied: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
command := exec.Command(nodePath, hookPath)
|
||||
command.Stdin = strings.NewReader(tt.input)
|
||||
output, err := command.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("generated hook error = %v", err)
|
||||
}
|
||||
var response struct {
|
||||
Permission string `json:"permission"`
|
||||
UserMessage string `json:"user_message"`
|
||||
}
|
||||
if err := json.Unmarshal(output, &response); err != nil {
|
||||
t.Fatalf("generated hook output = %q: %v", output, err)
|
||||
}
|
||||
if tt.wantDenied {
|
||||
if response.Permission != "deny" || response.UserMessage != cursorBackgroundTaskGuardDeniedMessage {
|
||||
t.Fatalf("generated hook response = %#v, want background denial", response)
|
||||
}
|
||||
} else if response.Permission != "" || response.UserMessage != "" {
|
||||
t.Fatalf("generated hook response = %#v, want empty allow response", response)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCursorPromptPolicyUsesRelativeSearchRootsOnWindows(t *testing.T) {
|
||||
base := "base runtime policy"
|
||||
windowsPolicy := cursorPromptPolicyForGOOS(base, "windows")
|
||||
for _, expected := range []string{
|
||||
"## Windows file-search boundary",
|
||||
"drive-qualified absolute Windows paths",
|
||||
"workspace-relative path",
|
||||
"native terminal",
|
||||
"retry through the relative-path or native-terminal route",
|
||||
} {
|
||||
if !strings.Contains(windowsPolicy, expected) {
|
||||
t.Fatalf("Windows Cursor policy missing %q: %s", expected, windowsPolicy)
|
||||
}
|
||||
}
|
||||
if got := cursorPromptPolicyForGOOS(base, "linux"); got != base {
|
||||
t.Fatalf("non-Windows Cursor policy = %q, want unchanged base policy", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCursorBackgroundTaskGuardLauncherUsesCursorBundledNode(t *testing.T) {
|
||||
nodePath, err := exec.LookPath("node")
|
||||
if err != nil {
|
||||
t.Skip("node is required to execute the generated Cursor hook")
|
||||
}
|
||||
|
||||
pluginDir := t.TempDir()
|
||||
if err := installCursorBackgroundTaskGuard(filepath.Join(pluginDir, "hooks")); err != nil {
|
||||
t.Fatalf("installCursorBackgroundTaskGuard() error = %v", err)
|
||||
}
|
||||
installDir := filepath.Join(t.TempDir(), "cursor-version")
|
||||
binDir := filepath.Join(t.TempDir(), "bin")
|
||||
if err := os.MkdirAll(installDir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(binDir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(nodePath, filepath.Join(installDir, "node")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cursorPath := filepath.Join(installDir, "cursor-agent")
|
||||
if err := os.WriteFile(cursorPath, []byte("#!/usr/bin/env bash\n"), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(cursorPath, filepath.Join(binDir, "cursor-agent")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
launcherPath := filepath.Join(pluginDir, "hooks", "guard-background-task.sh")
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
input string
|
||||
wantDenied bool
|
||||
}{
|
||||
{name: "foreground", input: `{"tool_name":"Task","tool_input":{"run_in_background":false}}`},
|
||||
{name: "background", input: `{"tool_name":"Task","tool_input":{"run_in_background":true}}`, wantDenied: true},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
command := exec.Command(launcherPath)
|
||||
command.Stdin = strings.NewReader(tt.input)
|
||||
command.Env = append(os.Environ(),
|
||||
"CURSOR_INVOKED_AS=cursor-agent",
|
||||
"PATH="+binDir+string(os.PathListSeparator)+os.Getenv("PATH"),
|
||||
)
|
||||
output, err := command.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("generated launcher error = %v", err)
|
||||
}
|
||||
denied := strings.Contains(string(output), `"permission":"deny"`)
|
||||
if denied != tt.wantDenied {
|
||||
t.Fatalf("generated launcher output = %q, denied = %v want %v", output, denied, tt.wantDenied)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCursorBackgroundTaskGuardLauncherFailsClosedWithoutCursorNode(t *testing.T) {
|
||||
bashPath, err := exec.LookPath("bash")
|
||||
if err != nil {
|
||||
t.Skip("bash is required to execute the generated Cursor hook launcher")
|
||||
}
|
||||
|
||||
pluginDir := t.TempDir()
|
||||
if err := installCursorBackgroundTaskGuard(filepath.Join(pluginDir, "hooks")); err != nil {
|
||||
t.Fatalf("installCursorBackgroundTaskGuard() error = %v", err)
|
||||
}
|
||||
binDir := t.TempDir()
|
||||
if err := os.Symlink(bashPath, filepath.Join(binDir, "bash")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
launcherPath := filepath.Join(pluginDir, "hooks", "guard-background-task.sh")
|
||||
command := exec.Command(launcherPath)
|
||||
command.Stdin = strings.NewReader(`{"tool_name":"Task","tool_input":{"run_in_background":false}}`)
|
||||
command.Env = append(os.Environ(),
|
||||
"CURSOR_INVOKED_AS=missing-cursor-agent",
|
||||
"PATH="+strings.Join([]string{binDir, "/usr/bin", "/bin"}, string(os.PathListSeparator)),
|
||||
)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("generated launcher error = %v output = %q", err, output)
|
||||
}
|
||||
if !strings.Contains(string(output), `"permission":"deny"`) ||
|
||||
!strings.Contains(string(output), cursorBackgroundTaskGuardDeniedMessage) {
|
||||
t.Fatalf("generated launcher output = %q, want fail-closed denial", output)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user