package webhooks_test import ( "context" "crypto/hmac" "crypto/sha256" "encoding/hex" "errors" "io" "net/http" "net/http/httptest" "testing" "atlas9.dev/c/core/assert" "atlas9.dev/c/core/iam" "atlas9.dev/c/demo/lib/access" "atlas9.dev/c/demo/lib/webhooks" ) func TestSign_MatchesHMAC(t *testing.T) { secret := []byte("s3cret") body := []byte("payload") mac := hmac.New(sha256.New, secret) mac.Write(body) want := "sha256=" + hex.EncodeToString(mac.Sum(nil)) assert.Eq(t, webhooks.Sign(secret, body), want) } func TestSender_Deliver_SignsAndSends(t *testing.T) { var gotSig, gotEvent string var gotBody []byte srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotSig = r.Header.Get(webhooks.SignatureHeader) gotEvent = r.Header.Get(webhooks.EventHeader) gotBody, _ = io.ReadAll(r.Body) w.WriteHeader(http.StatusOK) })) defer srv.Close() sender := &webhooks.Sender{Client: srv.Client(), Guard: access.ContextGuard{}} ctx := access.PutSystem(context.Background(), webhooks.Cap_Webhooks_Send) body := []byte("hello") status, err := sender.Deliver(ctx, webhooks.Endpoint{URL: srv.URL}, []byte("secret"), "Todos_ItemCreated", body) assert.Ok(t, err) assert.Eq(t, status, 200) assert.Eq(t, string(gotBody), "hello") assert.Eq(t, gotEvent, "Todos_ItemCreated") assert.Eq(t, gotSig, webhooks.Sign([]byte("secret"), body)) } // The egress cap is a chokepoint: without it, nothing is sent. func TestSender_Deliver_DeniedWithoutCap(t *testing.T) { hit := false srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { hit = true })) defer srv.Close() sender := &webhooks.Sender{Client: srv.Client(), Guard: access.ContextGuard{}} _, err := sender.Deliver(context.Background(), webhooks.Endpoint{URL: srv.URL}, []byte("s"), "e", []byte("b")) assert.Eq(t, errors.Is(err, iam.ErrForbidden), true) assert.Eq(t, hit, false) }