package handlers import ( "context" "net/http" "github.com/go-chi/chi/v5" "github.com/orchard9/rdev/internal/domain" "github.com/orchard9/rdev/internal/logging" "github.com/orchard9/rdev/internal/service" "github.com/orchard9/rdev/pkg/api" ) // SDLCCallbackHandler handles internal SDLC callback endpoints. type SDLCCallbackHandler struct { callbackSvc *service.SDLCCallbackService internalToken string } // NewSDLCCallbackHandler creates a new SDLC callback handler. func NewSDLCCallbackHandler(callbackSvc *service.SDLCCallbackService, internalToken string) *SDLCCallbackHandler { return &SDLCCallbackHandler{ callbackSvc: callbackSvc, internalToken: internalToken, } } // Mount registers the internal callback endpoint on the router. func (h *SDLCCallbackHandler) Mount(r api.Router) { r.Route("/internal/sdlc", func(r chi.Router) { r.Post("/callback", h.Callback) }) } // Callback handles POST /internal/sdlc/callback. // This is called by the work queue when a build task completes. // The endpoint is protected by an internal token to prevent external access. func (h *SDLCCallbackHandler) Callback(w http.ResponseWriter, r *http.Request) { // Verify internal token token := r.Header.Get("X-Internal-Token") if h.internalToken != "" && token != h.internalToken { api.WriteUnauthorized(w, r, "invalid internal token") return } var payload domain.SDLCCallbackPayload if err := api.DecodeJSON(r, &payload); err != nil { api.WriteBadRequest(w, r, "invalid request body") return } // Validate required fields if payload.ProjectID == "" { api.WriteBadRequest(w, r, "project_id is required") return } if payload.Feature == "" { api.WriteBadRequest(w, r, "feature is required") return } if payload.ArtifactType == "" { api.WriteBadRequest(w, r, "artifact_type is required") return } ctx, cancel := context.WithTimeout(r.Context(), TimeoutStandard) defer cancel() if err := h.callbackSvc.HandleCallback(ctx, &payload); err != nil { log := logging.FromContext(ctx).WithHandler("Callback") log.Error("SDLC callback handling failed", logging.FieldError, err.Error(), "task_id", payload.TaskID, logging.FieldProjectID, payload.ProjectID, "feature", payload.Feature, ) api.WriteInternalError(w, r, "callback handling failed") return } api.WriteJSON(w, r, http.StatusOK, map[string]bool{"ok": true}) }