package httpapi import ( "context" "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "io" "log/slog" "net/http" "net/http/httptest" "strings" "testing" "gitea-codex-bot/internal/config" "gitea-codex-bot/internal/gitea" "gitea-codex-bot/internal/store/sqlstore" ) func TestWebhookQueuesSignedReview(t *testing.T) { giteaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") switch { case strings.Contains(r.URL.Path, "/pulls/"): _, _ = w.Write([]byte(`{"base":{"ref":"main","sha":"base","repo":{"clone_url":"https://gitea.test/acme/repo.git","full_name":"acme/repo"}},"head":{"ref":"feature","sha":"head","repo":{"clone_url":"https://gitea.test/acme/repo.git","full_name":"acme/repo"}},"html_url":"https://gitea.test"}`)) case r.Method == http.MethodPost: _, _ = w.Write([]byte(`{"id":100}`)) case strings.Contains(r.URL.Path, "contents"): http.NotFound(w, r) default: http.NotFound(w, r) } })) defer giteaServer.Close() settings := config.Settings{GiteaBaseURL: giteaServer.URL, GiteaToken: "token", GiteaBotUsername: "codex-bot", GiteaWebhookSecret: "secret", AllowedRepos: []string{"acme/repo"}, DatabaseURL: "sqlite://" + t.TempDir() + "/test.db", WebhookMaxBytes: 1 << 20, CooldownSeconds: 60} st, err := sqlstore.Open(settings) if err != nil { t.Fatal(err) } defer st.Close() if err := st.Migrate(context.Background()); err != nil { t.Fatal(err) } server := New(settings, st, gitea.NewClient(settings), nilLogger()) payload := []byte(`{"repository":{"full_name":"acme/repo"},"sender":{"username":"alice"},"comment":{"id":11,"body":"@codex review security"},"issue":{"number":9,"pull_request":{"url":"x"}},"pull_request":{"head":{"sha":"head"}}}`) mac := hmac.New(sha256.New, []byte("secret")) _, _ = mac.Write(payload) req := httptest.NewRequest(http.MethodPost, "/webhook/gitea", strings.NewReader(string(payload))) req.Header.Set("X-Gitea-Event", "issue_comment") req.Header.Set("X-Gitea-Signature", hex.EncodeToString(mac.Sum(nil))) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("status %d", rec.Code) } var response map[string]any if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil { t.Fatal(err) } if response["status"] != "queued" { t.Fatalf("response %#v", response) } } func nilLogger() *slog.Logger { return slog.New(slog.NewTextHandler(io.Discard, nil)) }