cairn/internal/forgejo/webhooks_test.go

98 lines
2.9 KiB
Go

package forgejo
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http/httptest"
"strings"
"testing"
)
func signBody(body, secret string) string {
mac := hmac.New(sha256.New, []byte(secret))
_, _ = mac.Write([]byte(body))
return hex.EncodeToString(mac.Sum(nil))
}
func TestVerifyAndParseWithForgejoHeaders(t *testing.T) {
secret := "supersecret"
body := `{"action":"closed","issue":{"number":7,"title":"[Cairn] crash"}}`
req := httptest.NewRequest("POST", "/webhooks/forgejo", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "issues")
req.Header.Set("X-Forgejo-Signature", signBody(body, secret))
event, eventType, err := VerifyAndParse(req, secret)
if err != nil {
t.Fatalf("VerifyAndParse returned error: %v", err)
}
if eventType != "issues" {
t.Fatalf("expected event type issues, got %q", eventType)
}
if event == nil || event.Issue == nil || event.Issue.Number != 7 {
t.Fatalf("unexpected parsed event: %#v", event)
}
}
func TestVerifyAndParseWithGiteaFallbackHeaders(t *testing.T) {
secret := "fallbacksecret"
body := `{"action":"reopened","issue":{"number":42,"title":"[Cairn] crash"}}`
req := httptest.NewRequest("POST", "/webhooks/forgejo", strings.NewReader(body))
req.Header.Set("X-Gitea-Event", "issues")
req.Header.Set("X-Gitea-Signature", signBody(body, secret))
event, eventType, err := VerifyAndParse(req, secret)
if err != nil {
t.Fatalf("VerifyAndParse returned error: %v", err)
}
if eventType != "issues" {
t.Fatalf("expected event type issues, got %q", eventType)
}
if event == nil || event.Issue == nil || event.Issue.Number != 42 {
t.Fatalf("unexpected parsed event: %#v", event)
}
}
func TestVerifyAndParseRejectsBadSignature(t *testing.T) {
secret := "supersecret"
body := `{"action":"closed"}`
req := httptest.NewRequest("POST", "/webhooks/forgejo", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "issues")
req.Header.Set("X-Forgejo-Signature", "bad-signature")
_, _, err := VerifyAndParse(req, secret)
if err == nil {
t.Fatal("expected error for bad signature, got nil")
}
}
func TestVerifyAndParseWithoutSecretSkipsHMAC(t *testing.T) {
body := `{"action":"closed"}`
req := httptest.NewRequest("POST", "/webhooks/forgejo", strings.NewReader(body))
req.Header.Set("X-Forgejo-Event", "issues")
event, eventType, err := VerifyAndParse(req, "")
if err != nil {
t.Fatalf("VerifyAndParse returned error: %v", err)
}
if eventType != "issues" {
t.Fatalf("expected event type issues, got %q", eventType)
}
if event == nil || event.Action != "closed" {
t.Fatalf("unexpected parsed event: %#v", event)
}
}
func TestVerifyHMAC(t *testing.T) {
body := []byte("payload")
secret := "abc123"
sig := signBody(string(body), secret)
if !verifyHMAC(body, sig, secret) {
t.Fatal("expected verifyHMAC to accept valid signature")
}
if verifyHMAC(body, "invalid", secret) {
t.Fatal("expected verifyHMAC to reject invalid signature")
}
}