blob: 706790d168795f4af1d844d4e8328c3af8ae4df4 [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001package bashkit
2
3import (
4 "strings"
5 "testing"
6)
7
8func TestCheck(t *testing.T) {
9 tests := []struct {
10 name string
11 script string
12 wantErr bool
13 errMatch string // string to match in error message, if wantErr is true
14 }{
15 {
16 name: "valid script",
17 script: "echo hello world",
18 wantErr: false,
19 errMatch: "",
20 },
21 {
22 name: "invalid syntax",
23 script: "echo 'unterminated string",
24 wantErr: false, // As per implementation, syntax errors are not flagged
25 errMatch: "",
26 },
27 {
28 name: "git config user.name",
29 script: "git config user.name 'John Doe'",
30 wantErr: true,
31 errMatch: "changing git config username/email is not allowed",
32 },
33 {
34 name: "git config user.email",
35 script: "git config user.email 'john@example.com'",
36 wantErr: true,
37 errMatch: "changing git config username/email is not allowed",
38 },
39 {
40 name: "git config with flag user.name",
41 script: "git config --global user.name 'John Doe'",
42 wantErr: true,
43 errMatch: "changing git config username/email is not allowed",
44 },
45 {
46 name: "git config with other setting",
47 script: "git config core.editor vim",
48 wantErr: false,
49 errMatch: "",
50 },
51 {
52 name: "git without config",
53 script: "git commit -m 'Add feature'",
54 wantErr: false,
55 errMatch: "",
56 },
57 {
58 name: "multiline script with proper escaped newlines",
59 script: "echo 'Setting up git...' && git config user.name 'John Doe' && echo 'Done!'",
60 wantErr: true,
61 errMatch: "changing git config username/email is not allowed",
62 },
63 {
64 name: "multiline script with backticks",
65 script: `echo 'Setting up git...'
66git config user.name 'John Doe'
67echo 'Done!'`,
68 wantErr: true,
69 errMatch: "changing git config username/email is not allowed",
70 },
71 {
72 name: "git config with variable",
73 script: "NAME='John Doe'\ngit config user.name $NAME",
74 wantErr: true,
75 errMatch: "changing git config username/email is not allowed",
76 },
77 {
78 name: "only git command",
79 script: "git",
80 wantErr: false,
81 errMatch: "",
82 },
83 {
84 name: "read git config",
85 script: "git config user.name",
86 wantErr: false,
87 errMatch: "",
88 },
89 {
90 name: "commented git config",
91 script: "# git config user.name 'John Doe'",
92 wantErr: false,
93 errMatch: "",
94 },
Josh Bleecher Snyderdbfd36a2025-05-23 20:57:50 +000095 // Git add validation tests
96 {
97 name: "git add with -A flag",
98 script: "git add -A",
99 wantErr: true,
100 errMatch: "blind git add commands",
101 },
102 {
103 name: "git add with --all flag",
104 script: "git add --all",
105 wantErr: true,
106 errMatch: "blind git add commands",
107 },
108 {
109 name: "git add with dot",
110 script: "git add .",
111 wantErr: true,
112 errMatch: "blind git add commands",
113 },
114 {
115 name: "git add with asterisk",
116 script: "git add *",
117 wantErr: true,
118 errMatch: "blind git add commands",
119 },
120 {
121 name: "git add with multiple flags including -A",
122 script: "git add -v -A",
123 wantErr: true,
124 errMatch: "blind git add commands",
125 },
126 {
127 name: "git add with specific file",
128 script: "git add main.go",
129 wantErr: false,
130 errMatch: "",
131 },
132 {
133 name: "git add with multiple specific files",
134 script: "git add main.go utils.go",
135 wantErr: false,
136 errMatch: "",
137 },
138 {
139 name: "git add with directory path",
140 script: "git add src/main.go",
141 wantErr: false,
142 errMatch: "",
143 },
144 {
145 name: "git add with git flags before add",
146 script: "git -C /path/to/repo add -A",
147 wantErr: true,
148 errMatch: "blind git add commands",
149 },
150 {
151 name: "git add with valid flags",
152 script: "git add -v main.go",
153 wantErr: false,
154 errMatch: "",
155 },
156 {
157 name: "git command without add",
158 script: "git status",
159 wantErr: false,
160 errMatch: "",
161 },
162 {
163 name: "multiline script with blind git add",
164 script: "echo 'Adding files' && git add -A && git commit -m 'Update'",
165 wantErr: true,
166 errMatch: "blind git add commands",
167 },
168 {
169 name: "git add with pattern that looks like blind but is specific",
170 script: "git add file.A",
171 wantErr: false,
172 errMatch: "",
173 },
174 {
175 name: "commented blind git add",
176 script: "# git add -A",
177 wantErr: false,
178 errMatch: "",
179 },
Earl Lee2e463fb2025-04-17 11:22:22 -0700180 }
181
182 for _, tc := range tests {
183 t.Run(tc.name, func(t *testing.T) {
184 err := Check(tc.script)
185 if (err != nil) != tc.wantErr {
186 t.Errorf("Check() error = %v, wantErr %v", err, tc.wantErr)
187 return
188 }
189 if tc.wantErr && err != nil && !strings.Contains(err.Error(), tc.errMatch) {
190 t.Errorf("Check() error message = %v, want containing %v", err, tc.errMatch)
191 }
192 })
193 }
194}
Josh Bleecher Snyderdae19072025-04-30 01:08:57 +0000195
196func TestWillRunGitCommit(t *testing.T) {
197 tests := []struct {
198 name string
199 script string
200 wantCommit bool
201 }{
202 {
203 name: "simple git commit",
204 script: "git commit -m 'Add feature'",
205 wantCommit: true,
206 },
207 {
208 name: "git command without commit",
209 script: "git status",
210 wantCommit: false,
211 },
212 {
213 name: "multiline script with git commit",
214 script: "echo 'Making changes' && git add . && git commit -m 'Update files'",
215 wantCommit: true,
216 },
217 {
218 name: "multiline script without git commit",
219 script: "echo 'Checking status' && git status",
220 wantCommit: false,
221 },
222 {
223 name: "script with commented git commit",
224 script: "# git commit -m 'This is commented out'",
225 wantCommit: false,
226 },
227 {
228 name: "git commit with variables",
229 script: "MSG='Fix bug' && git commit -m 'Using variable'",
230 wantCommit: true,
231 },
232 {
233 name: "only git command",
234 script: "git",
235 wantCommit: false,
236 },
237 {
238 name: "script with invalid syntax",
239 script: "git commit -m 'unterminated string",
240 wantCommit: false,
241 },
242 {
243 name: "commit used in different context",
244 script: "echo 'commit message'",
245 wantCommit: false,
246 },
247 {
248 name: "git with flags before commit",
249 script: "git -C /path/to/repo commit -m 'Update'",
250 wantCommit: true,
251 },
252 {
253 name: "git with multiple flags",
254 script: "git --git-dir=.git -C repo commit -a -m 'Update'",
255 wantCommit: true,
256 },
257 {
258 name: "git with env vars",
259 script: "GIT_AUTHOR_NAME=\"Josh Bleecher Snyder\" GIT_AUTHOR_EMAIL=\"josharian@gmail.com\" git commit -am \"Updated code\"",
260 wantCommit: true,
261 },
262 {
263 name: "git with redirections",
264 script: "git commit -m 'Fix issue' > output.log 2>&1",
265 wantCommit: true,
266 },
267 {
268 name: "git with piped commands",
269 script: "echo 'Committing' | git commit -F -",
270 wantCommit: true,
271 },
272 }
273
274 for _, tc := range tests {
275 t.Run(tc.name, func(t *testing.T) {
276 gotCommit, err := WillRunGitCommit(tc.script)
277 if err != nil {
278 t.Errorf("WillRunGitCommit() error = %v", err)
279 return
280 }
281 if gotCommit != tc.wantCommit {
282 t.Errorf("WillRunGitCommit() = %v, want %v", gotCommit, tc.wantCommit)
283 }
284 })
285 }
286}