返回 DeepSeek-Reasonix
gitstatus_repoprograms_test.go
根目录 / internal / cli / gitstatus_repoprograms_test.go
1 package cli
2
3 import (
4 "context"
5 "os"
6 "os/exec"
7 "path/filepath"
8 "runtime"
9 "testing"
10 "time"
11 )
12
13 // The status readout inspects a repository an agent can write into, so none
14 // of the programs that repository's config names may run while it is read —
15 // and the readout must still be right. Startup runs it from a subdirectory.
16 func TestLoadGitStatusDoesNotRunRepositoryConfiguredPrograms(t *testing.T) {
17 if runtime.GOOS == "windows" {
18 t.Skip("payload script is POSIX shell")
19 }
20 if _, err := exec.LookPath("git"); err != nil {
21 t.Skip("git not installed")
22 }
23 repo := t.TempDir()
24 git := func(args ...string) {
25 t.Helper()
26 if out, err := exec.Command("git", append([]string{"-C", repo}, args...)...).CombinedOutput(); err != nil {
27 t.Fatalf("git %v: %v: %s", args, err, out)
28 }
29 }
30 write := func(rel, content string) {
31 t.Helper()
32 if err := os.WriteFile(filepath.Join(repo, rel), []byte(content), 0o644); err != nil {
33 t.Fatal(err)
34 }
35 }
36 git("init", "-q")
37 git("config", "user.email", "t@example.com")
38 git("config", "user.name", "t")
39 if err := os.Mkdir(filepath.Join(repo, "sub"), 0o755); err != nil {
40 t.Fatal(err)
41 }
42 write(".gitattributes", "f.txt filter=pwn diff=pwn\n")
43 write("f.txt", "hello\n")
44 write("sub/keep.txt", "keep\n")
45 git("add", ".")
46 git("commit", "-qm", "base")
47
48 marker := filepath.Join(t.TempDir(), "executed")
49 payload := filepath.Join(t.TempDir(), "payload.sh")
50 if err := os.WriteFile(payload, []byte("#!/bin/sh\necho ran >> '"+marker+"'\ncat\n"), 0o755); err != nil {
51 t.Fatal(err)
52 }
53 cfg, err := os.OpenFile(filepath.Join(repo, ".git", "config"), os.O_APPEND|os.O_WRONLY, 0)
54 if err != nil {
55 t.Fatal(err)
56 }
57 _, err = cfg.WriteString("[filter.pwn]\n\tclean = " + payload + "\n[diff \"pwn\"]\n\ttextconv = " + payload + "\n")
58 _ = cfg.Close()
59 if err != nil {
60 t.Fatal(err)
61 }
62 write("f.txt", "hellx\n")
63 old := time.Now().Add(-48 * time.Hour)
64 if err := os.Chtimes(filepath.Join(repo, "f.txt"), old, old); err != nil {
65 t.Fatal(err)
66 }
67
68 status, err := loadGitStatus(context.Background(), openedRepo(t, filepath.Join(repo, "sub")))
69 if err != nil {
70 t.Fatal(err)
71 }
72 if status.Added != 1 || status.Removed != 1 {
73 t.Fatalf("status = %+v, want +1 -1 for the same-size edit", status)
74 }
75 if _, err := os.Stat(marker); err == nil {
76 t.Fatal("the status readout ran a repository-configured program")
77 }
78 }
79
80 // The status line reads the repository the session resolved when it opened,
81 // even after the workspace — a subdirectory of it — gains its own .git whose
82 // local config names a filter.
83 func TestLoadGitStatusKeepsRepositoryResolvedAtOpen(t *testing.T) {
84 if runtime.GOOS == "windows" {
85 t.Skip("payload script is POSIX shell")
86 }
87 if _, err := exec.LookPath("git"); err != nil {
88 t.Skip("git not installed")
89 }
90 mono := t.TempDir()
91 pkg := filepath.Join(mono, "pkg")
92 git := func(dir string, args ...string) {
93 t.Helper()
94 cmd := exec.Command("git", append([]string{"-C", dir}, args...)...)
95 cmd.Env = append(os.Environ(), "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@t", "GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@t")
96 if out, err := cmd.CombinedOutput(); err != nil {
97 t.Fatalf("git %v: %v: %s", args, err, out)
98 }
99 }
100 if err := os.MkdirAll(pkg, 0o755); err != nil {
101 t.Fatal(err)
102 }
103 if err := os.WriteFile(filepath.Join(pkg, "f.txt"), []byte("a\n"), 0o644); err != nil {
104 t.Fatal(err)
105 }
106 git(mono, "init", "-q")
107 git(mono, "add", ".")
108 git(mono, "commit", "-qm", "base")
109 session := openedRepo(t, pkg)
110
111 marker := filepath.Join(t.TempDir(), "executed")
112 payload := filepath.Join(t.TempDir(), "payload.sh")
113 if err := os.WriteFile(payload, []byte("#!/bin/sh\necho ran >> '"+marker+"'\ncat\n"), 0o755); err != nil {
114 t.Fatal(err)
115 }
116 git(pkg, "init", "-q")
117 git(pkg, "config", "filter.pwn.clean", payload)
118 if err := os.WriteFile(filepath.Join(pkg, ".gitattributes"), []byte("f.txt filter=pwn\n"), 0o644); err != nil {
119 t.Fatal(err)
120 }
121 if err := os.WriteFile(filepath.Join(pkg, "f.txt"), []byte("b\n"), 0o644); err != nil {
122 t.Fatal(err)
123 }
124
125 status, err := loadGitStatus(context.Background(), session)
126 if err != nil {
127 t.Fatal(err)
128 }
129 if status.Repo != filepath.Base(mono) || status.Added != 1 || status.Removed != 1 {
130 t.Fatalf("status = %+v, want the enclosing repository's +1 -1", status)
131 }
132 if _, err := os.Stat(marker); err == nil {
133 t.Fatal("the status readout ran the nested repository's filter")
134 }
135 }
136
136 lines GO