yaju-is-always-watching-you/internal/webhook/handler_test.go
awayatan f47fef177b
Some checks failed
CI / test (push) Failing after 4s
Add yaju-is-always-watching-you: Forgejo goroku-check webhook bot
Watches issue/PR comments and pushes for flagged phrases; warns commenters
via reply and opens a redacted correction PR for flagged file content,
never rewriting history or deleting content directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 22:47:12 +09:00

114 lines
2.9 KiB
Go

package webhook
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"net/http/httptest"
"strings"
"testing"
"git.folja.dev/awayatan/yaju-is-always-watching-you/internal/forgejo"
)
type fakeDispatcher struct {
comments int
pushes int
}
func (f *fakeDispatcher) HandleIssueComment(forgejo.IssueCommentPayload) error {
f.comments++
return nil
}
func (f *fakeDispatcher) HandlePush(forgejo.PushPayload) error {
f.pushes++
return nil
}
func sign(secret, body string) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(body))
return hex.EncodeToString(mac.Sum(nil))
}
func TestServeHTTP_RejectsBadSignature(t *testing.T) {
fd := &fakeDispatcher{}
h := NewHandler("secret", fd)
body := `{}`
req := httptest.NewRequest(http.MethodPost, "/webhook", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "push")
req.Header.Set("X-Forgejo-Signature", "deadbeef")
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusUnauthorized)
}
if fd.pushes != 0 {
t.Fatalf("dispatcher should not run on bad signature, pushes = %d", fd.pushes)
}
}
func TestServeHTTP_DispatchesPush(t *testing.T) {
fd := &fakeDispatcher{}
h := NewHandler("secret", fd)
body := `{"ref":"refs/heads/main"}`
req := httptest.NewRequest(http.MethodPost, "/webhook", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "push")
req.Header.Set("X-Forgejo-Signature", sign("secret", body))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusNoContent {
t.Fatalf("status = %d, want %d, body=%s", rec.Code, http.StatusNoContent, rec.Body.String())
}
if fd.pushes != 1 {
t.Fatalf("pushes = %d, want 1", fd.pushes)
}
}
func TestServeHTTP_DispatchesIssueComment(t *testing.T) {
fd := &fakeDispatcher{}
h := NewHandler("secret", fd)
body := `{"action":"created"}`
req := httptest.NewRequest(http.MethodPost, "/webhook", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "issue_comment")
req.Header.Set("X-Forgejo-Signature", sign("secret", body))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusNoContent {
t.Fatalf("status = %d, want %d, body=%s", rec.Code, http.StatusNoContent, rec.Body.String())
}
if fd.comments != 1 {
t.Fatalf("comments = %d, want 1", fd.comments)
}
}
func TestServeHTTP_IgnoresUnhandledEvent(t *testing.T) {
fd := &fakeDispatcher{}
h := NewHandler("secret", fd)
body := `{}`
req := httptest.NewRequest(http.MethodPost, "/webhook", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "fork")
req.Header.Set("X-Forgejo-Signature", sign("secret", body))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusNoContent {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusNoContent)
}
if fd.comments != 0 || fd.pushes != 0 {
t.Fatalf("dispatcher should not be called for unhandled events")
}
}