diff --git a/README.md b/README.md index f3b8957..1b31f38 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ err = SetupWebhook( log, ctx, dbPool, + nil, "https://your.domain.com/some/entity/webhook", "https://your.domain.com/some/submission/webhook", "https://your.domain.com/some/review/webhook", diff --git a/main.go b/main.go index cd1cbfb..4b8af9e 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,7 @@ func SetupWebhook( log *slog.Logger, ctx context.Context, dbPool *pgxpool.Pool, + apiKey *string, // use a pointer so it's possible to pass 'nil; updateEntityUrl, newSubmissionUrl, reviewSubmissionUrl string, ) error { // setup the listener @@ -84,13 +85,12 @@ func SetupWebhook( // Only send the request for correctly parsed (supported) events if parsedData != nil { if parsedData.Type == "entity.update.version" && updateEntityUrl != "" { - webhook.SendRequest(log, ctx, updateEntityUrl, *parsedData) + webhook.SendRequest(log, ctx, updateEntityUrl, *parsedData, apiKey) } else if parsedData.Type == "submission.create" && newSubmissionUrl != "" { - webhook.SendRequest(log, ctx, newSubmissionUrl, *parsedData) + webhook.SendRequest(log, ctx, newSubmissionUrl, *parsedData, apiKey) } else if parsedData.Type == "submission.update" && reviewSubmissionUrl != "" { - webhook.SendRequest(log, ctx, reviewSubmissionUrl, *parsedData) + webhook.SendRequest(log, ctx, reviewSubmissionUrl, *parsedData, apiKey) } else { - log.Debug( fmt.Sprintf( "%s event type was triggered, but no webhook url was provided", @@ -164,6 +164,9 @@ func main() { var reviewSubmissionUrl string flag.StringVar(&reviewSubmissionUrl, "reviewSubmissionUrl", defaultReviewSubmissionUrl, "Webhook URL for review submission events") + var apiKey string + flag.StringVar(&apiKey, "apiKey", "", "X-API-Key header value, for autenticating with webhook API") + var debug bool flag.BoolVar(&debug, "debug", false, "Enable debug logging") @@ -200,7 +203,7 @@ func main() { } printStartupMsg() - err = SetupWebhook(log, ctx, dbPool, updateEntityUrl, newSubmissionUrl, reviewSubmissionUrl) + err = SetupWebhook(log, ctx, dbPool, &apiKey, updateEntityUrl, newSubmissionUrl, reviewSubmissionUrl) if err != nil { fmt.Fprintf(os.Stderr, "error setting up webhook: %v", err) os.Exit(1) diff --git a/main_test.go b/main_test.go index 678978e..886f441 100644 --- a/main_test.go +++ b/main_test.go @@ -114,7 +114,7 @@ package main // go func() { // defer wg.Done() // log.Info("starting webhook listener") -// err := SetupWebhook(log, ctx, dbPool, mockServer.URL, mockServer.URL, mockServer.URL) +// err := SetupWebhook(log, ctx, dbPool, nil, mockServer.URL, mockServer.URL, mockServer.URL) // if err != nil && ctx.Err() == nil { // log.Error("webhook listener error", "error", err) // } diff --git a/webhook/request.go b/webhook/request.go index 8af74cb..9c22164 100644 --- a/webhook/request.go +++ b/webhook/request.go @@ -4,10 +4,10 @@ import ( "bytes" "context" "encoding/json" + "io" "log/slog" "net/http" "time" - "io" "github.com/hotosm/central-webhook/parser" ) @@ -19,6 +19,7 @@ func SendRequest( ctx context.Context, apiEndpoint string, eventJson parser.ProcessedEvent, + apiKey *string, ) { // Marshal the payload to JSON marshaledPayload, err := json.Marshal(eventJson) @@ -34,6 +35,10 @@ func SendRequest( return } req.Header.Set("Content-Type", "application/json") + // Add X-API-Key header if apiKey is provided + if apiKey != nil { + req.Header.Set("X-API-Key", *apiKey) + } // Send the request client := &http.Client{Timeout: 10 * time.Second} diff --git a/webhook/request_test.go b/webhook/request_test.go index 3cc3069..d939e21 100644 --- a/webhook/request_test.go +++ b/webhook/request_test.go @@ -22,10 +22,14 @@ func TestSendRequest(t *testing.T) { // Set up a mock server var receivedPayload parser.ProcessedEvent + var receivedApiKey string server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Verify content type is.Equal("application/json", r.Header.Get("Content-Type")) + // Verify API key was received + receivedApiKey = r.Header.Get("X-API-Key") + // Read and parse request body body, err := io.ReadAll(r.Body) is.NoErr(err) @@ -87,13 +91,16 @@ func TestSendRequest(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - // Call the SendRequest function - SendRequest(log, ctx, server.URL, tc.event) + testApiKey := "test-api-key" + SendRequest(log, ctx, server.URL, tc.event, &testApiKey) // Validate the received payload is.Equal(tc.expectedId, receivedPayload.ID) is.Equal(tc.expectedType, receivedPayload.Type) is.Equal(tc.expectedData, receivedPayload.Data) + + // Validate that the API key header was sent correctly + is.Equal("test-api-key", receivedApiKey) }) } }