Files
Agent-Native/exec/deliverable_test.go
T
weichenandCursor fedf671a48
ci / vet-and-test (push) Successful in 5s
ci / docker-checkout-hostgateway (push) Successful in 3s
Import the current agent-native module as a fresh history.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 12:29:04 +00:00

132 lines
3.9 KiB
Go

package exec
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestMatchDeliverableRel_Aliases(t *testing.T) {
workDir := filepath.Join(string(filepath.Separator), "app", "data", "workspaces", "bizdev", "prelim_x", "tasks", "01_draft")
abs := filepath.Join(workDir, "output.md")
cases := []struct {
rel string
want bool
}{
{"output.md", true},
{"./output.md", true},
{abs, true},
{"tasks/01_draft/output.md", true},
{"execution.log", false},
{"../output.md", false},
{"../../output.md", false},
{"/etc/passwd", false},
{"tasks/02_review/output.md", false},
}
for _, tc := range cases {
if got := MatchDeliverableRel(workDir, tc.rel, "output.md"); got != tc.want {
t.Errorf("MatchDeliverableRel(%q) = %v, want %v", tc.rel, got, tc.want)
}
}
}
func TestMaterializeTargets_MapsAbsoluteAndNested(t *testing.T) {
workDir := filepath.Join(t.TempDir(), "tasks", "01_draft")
if err := os.MkdirAll(workDir, 0o755); err != nil {
t.Fatal(err)
}
body := []byte("# 系统初步设计方案\n\n真实 runner 产物\n")
incoming := map[string][]byte{
filepath.Join(workDir, "output.md"): body,
}
got, err := MaterializeTargets(workDir, []string{"output.md"}, incoming)
if err != nil {
t.Fatalf("absolute rel_path must materialize: %v", err)
}
if string(got["output.md"]) != string(body) {
t.Fatalf("canonical patch missing")
}
onDisk, err := os.ReadFile(filepath.Join(workDir, "output.md"))
if err != nil {
t.Fatal(err)
}
if string(onDisk) != string(body) {
t.Fatalf("disk output.md mismatch")
}
nestedDir := filepath.Join(t.TempDir(), "ws", "tasks", "01_draft")
if err := os.MkdirAll(nestedDir, 0o755); err != nil {
t.Fatal(err)
}
if _, err := MaterializeTargets(nestedDir, []string{"output.md"}, map[string][]byte{
"tasks/01_draft/output.md": []byte("# nested alias\n"),
}); err != nil {
t.Fatalf("duplicated step prefix must map: %v", err)
}
}
func TestMaterializeTargets_MissingAndEmptyFail(t *testing.T) {
workDir := t.TempDir()
if _, err := MaterializeTargets(workDir, []string{"output.md"}, map[string][]byte{
"execution.log": []byte("Outcome: SUCCESS\n"),
}); err == nil || !strings.Contains(err.Error(), "missing target deliverable output.md") {
t.Fatalf("must fail closed without inventing output.md, got %v", err)
}
if _, err := os.Stat(filepath.Join(workDir, "output.md")); err == nil {
t.Fatal("must not write a stub output.md")
}
if _, err := MaterializeTargets(workDir, []string{"output.md"}, map[string][]byte{
"output.md": []byte(" \n"),
}); err == nil {
t.Fatal("whitespace-only body must not count as a deliverable")
}
}
func TestMaterializeTargets_EmptyPatchKeepsExistingFile(t *testing.T) {
workDir := t.TempDir()
body := []byte("# 调研报告\n已写在盘上的正文\n")
path := filepath.Join(workDir, "output.md")
if err := os.WriteFile(path, body, 0o644); err != nil {
t.Fatal(err)
}
got, err := MaterializeTargets(workDir, []string{"output.md"}, map[string][]byte{
"output.md": nil,
})
if err != nil {
t.Fatal(err)
}
if string(got["output.md"]) != string(body) {
t.Fatalf("collected %q", got["output.md"])
}
disk, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if string(disk) != string(body) {
t.Fatalf("disk overwritten with %q", disk)
}
}
func TestMaterializeTargets_RejectsSymlinkEscape(t *testing.T) {
root := t.TempDir()
outside := t.TempDir()
if err := os.WriteFile(filepath.Join(outside, "secret.md"), []byte("leak"), 0o644); err != nil {
t.Fatal(err)
}
link := filepath.Join(root, "out")
if err := os.Symlink(outside, link); err != nil {
t.Fatal(err)
}
_, err := MaterializeTargets(root, []string{"out/secret.md"}, map[string][]byte{
"out/secret.md": []byte("overwrite"),
})
if err == nil {
t.Fatal("symlink escape must fail closed")
}
got, _ := os.ReadFile(filepath.Join(outside, "secret.md"))
if string(got) != "leak" {
t.Fatalf("must not write through symlink, got %q", got)
}
}