From 505fd6192ddab661881d74e6fee5dbdcd0bd1878 Mon Sep 17 00:00:00 2001 From: Yoo_LCD Date: Wed, 11 Mar 2026 21:19:59 +0900 Subject: [PATCH 1/4] Add fuzz test for ParseWebHook --- github/fuzz_messages_test.go | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 github/fuzz_messages_test.go diff --git a/github/fuzz_messages_test.go b/github/fuzz_messages_test.go new file mode 100644 index 00000000000..442b1eef5cd --- /dev/null +++ b/github/fuzz_messages_test.go @@ -0,0 +1,70 @@ +package github + +import ( + "encoding/json" + "fmt" + "testing" +) + +// FuzzParseWebHook tests ParseWebHook against arbitrary event types and payloads. +// It verifies that no input causes a panic or nil pointer dereference. +func FuzzParseWebHook(f *testing.F) { + seeds := []struct { + eventType string + payload string + }{ + {"push", `{"ref": "refs/heads/main", "before": "000000", "after": "123456", "commits": [{"id": "abc", "message": "msg", "added": [], "removed": [], "modified": []}]}`}, + {"pull_request", `{"action": "opened", "number": 1, "pull_request": {"title": "test", "state": "open", "user": {"login": "u"}}}`}, + {"issues", `{"action": "opened", "issue": {"number": 42, "title": "bug", "state": "open"}}`}, + {"release", `{"action": "published", "release": {"tag_name": "v1.0.0", "draft": false}}`}, + {"check_run", `{"action": "created", "check_run": {"status": "in_progress", "id": 1}}`}, + {"check_suite", `{"action": "completed", "check_suite": {"id": 1, "status": "completed"}}`}, + {"workflow_run", `{"action": "requested", "workflow_run": {"id": 123, "status": "queued"}}`}, + {"workflow_job", `{"action": "queued", "workflow_job": {"id": 1, "status": "queued"}}`}, + {"discussion", `{"action": "created", "discussion": {"title": "hello", "number": 1}}`}, + {"ping", `{"zen": "Keep it logically awesome.", "hook_id": 1}`}, + {"repository", `{"action": "created", "repository": {"name": "test-repo", "private": false}}`}, + {"star", `{"action": "created", "starred_at": "2026-03-11T00:00:00Z"}`}, + {"create", `{"ref": "main", "ref_type": "branch"}`}, + {"delete", `{"ref": "old-branch", "ref_type": "branch"}`}, + {"fork", `{"forkee": {"name": "forked-repo"}}`}, + {"deployment", `{"action": "created", "deployment": {"id": 1, "ref": "main"}}`}, + {"deployment_status", `{"action": "created", "deployment_status": {"id": 1, "state": "pending"}}`}, + {"member", `{"action": "added", "member": {"login": "user"}}`}, + {"public", `{"repository": {"name": "now-public"}}`}, + {"commit_comment", `{"action": "created", "comment": {"id": 1, "body": "comment"}}`}, + } + for _, s := range seeds { + f.Add(s.eventType, []byte(s.payload)) + } + + for _, messageType := range MessageTypes() { + proto := EventForType(messageType) + if proto == nil { + f.Add(messageType, []byte(`{}`)) + continue + } + // Generate a seed by marshaling the zero-value struct so the fuzzer + // starts from a structurally valid JSON skeleton for each event type. + b, err := json.Marshal(proto) + if err != nil { + f.Add(messageType, []byte(`{}`)) + continue + } + f.Add(messageType, b) + } + + f.Fuzz(func(t *testing.T, eventType string, payload []byte) { + if len(payload) > 1<<20 { + return + } + event, err := ParseWebHook(eventType, payload) + if err != nil { + return + } + if event != nil { + // Traverse all fields recursively to catch nil pointer dereferences + _ = fmt.Sprintf("%+v", event) + } + }) +} \ No newline at end of file From 21108855c519796f76a52bb229735cea9f9307ef Mon Sep 17 00:00:00 2001 From: Yoo_LCD Date: Wed, 11 Mar 2026 22:24:42 +0900 Subject: [PATCH 2/4] Fix lint errors: add license header, rename unused parameter --- github/fuzz_messages_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/github/fuzz_messages_test.go b/github/fuzz_messages_test.go index 442b1eef5cd..5de014ec012 100644 --- a/github/fuzz_messages_test.go +++ b/github/fuzz_messages_test.go @@ -1,3 +1,8 @@ +// Copyright 2026 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package github import ( @@ -54,7 +59,7 @@ func FuzzParseWebHook(f *testing.F) { f.Add(messageType, b) } - f.Fuzz(func(t *testing.T, eventType string, payload []byte) { + f.Fuzz(func(_ *testing.T, eventType string, payload []byte) { if len(payload) > 1<<20 { return } From 019a84a23a2b7c0ced3c718205152deece986a44 Mon Sep 17 00:00:00 2001 From: YooLCD Date: Wed, 11 Mar 2026 13:41:25 +0000 Subject: [PATCH 3/4] Fix: add newline at end of file --- github/fuzz_messages_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/fuzz_messages_test.go b/github/fuzz_messages_test.go index 5de014ec012..540538b96c6 100644 --- a/github/fuzz_messages_test.go +++ b/github/fuzz_messages_test.go @@ -72,4 +72,4 @@ func FuzzParseWebHook(f *testing.F) { _ = fmt.Sprintf("%+v", event) } }) -} \ No newline at end of file +} From 9aa8f509c69fa22ca9c1106a68658222e3910e2a Mon Sep 17 00:00:00 2001 From: Yoo_LCD Date: Wed, 11 Mar 2026 23:39:40 +0900 Subject: [PATCH 4/4] Add OSS-Fuzz link and fix formatting --- github/fuzz_messages_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/github/fuzz_messages_test.go b/github/fuzz_messages_test.go index 540538b96c6..137bfb3cc1d 100644 --- a/github/fuzz_messages_test.go +++ b/github/fuzz_messages_test.go @@ -12,7 +12,14 @@ import ( ) // FuzzParseWebHook tests ParseWebHook against arbitrary event types and payloads. -// It verifies that no input causes a panic or nil pointer dereference. +// It verifies that no input triggers a panic or nil pointer dereference. +// +// This fuzz test is intended for integration with OSS-Fuzz (https://google.github.io/oss-fuzz/) +// for continuous fuzzing in the cloud. +// +// To run: +// +// go test -fuzz=^FuzzParseWebHook$ -fuzztime=30s . func FuzzParseWebHook(f *testing.F) { seeds := []struct { eventType string