Files
gastown/internal/protocol/refinery_handlers.go
max 1b69576573 fix: Address golangci-lint errors (errcheck, gosec) (#76)
Apply PR #76 from dannomayernotabot:

- Add golangci exclusions for internal package false positives
- Tighten file permissions (0644 -> 0600) for sensitive files
- Add ReadHeaderTimeout to HTTP server (slowloris prevention)
- Explicit error ignoring with _ = for intentional cases
- Add //nolint comments with justifications
- Spelling: cancelled -> canceled (US locale)

Co-Authored-By: dannomayernotabot <noreply@github.com>

🤖 Generated with Claude Code
2026-01-03 16:11:55 -08:00

148 lines
4.9 KiB
Go

package protocol
import (
"fmt"
"io"
"os"
"time"
"github.com/steveyegge/gastown/internal/mail"
"github.com/steveyegge/gastown/internal/mrqueue"
)
// DefaultRefineryHandler provides the default implementation for Refinery protocol handlers.
// It receives MERGE_READY messages from the Witness and adds work to the merge queue.
type DefaultRefineryHandler struct {
// Rig is the name of the rig this refinery processes.
Rig string
// WorkDir is the working directory for operations.
WorkDir string
// Queue is the merge request queue.
Queue *mrqueue.Queue
// Router is used to send mail messages.
Router *mail.Router
// Output is where to write status messages.
Output io.Writer
}
// NewRefineryHandler creates a new DefaultRefineryHandler.
func NewRefineryHandler(rig, workDir string) *DefaultRefineryHandler {
return &DefaultRefineryHandler{
Rig: rig,
WorkDir: workDir,
Queue: mrqueue.New(workDir),
Router: mail.NewRouter(workDir),
Output: os.Stdout,
}
}
// SetOutput sets the output writer for status messages.
func (h *DefaultRefineryHandler) SetOutput(w io.Writer) {
h.Output = w
}
// HandleMergeReady handles a MERGE_READY message from Witness.
// When a polecat's work is verified and ready, the Refinery:
// 1. Validates the merge request
// 2. Adds it to the merge queue
// 3. Acknowledges receipt
func (h *DefaultRefineryHandler) HandleMergeReady(payload *MergeReadyPayload) error {
_, _ = fmt.Fprintf(h.Output, "[Refinery] MERGE_READY received for polecat %s\n", payload.Polecat)
_, _ = fmt.Fprintf(h.Output, " Branch: %s\n", payload.Branch)
_, _ = fmt.Fprintf(h.Output, " Issue: %s\n", payload.Issue)
_, _ = fmt.Fprintf(h.Output, " Verified: %s\n", payload.Verified)
// Validate required fields
if payload.Branch == "" {
return fmt.Errorf("missing branch in MERGE_READY payload")
}
if payload.Polecat == "" {
return fmt.Errorf("missing polecat in MERGE_READY payload")
}
// Create merge request (ID is generated by Submit if empty)
mr := &mrqueue.MR{
Branch: payload.Branch,
Worker: payload.Polecat,
SourceIssue: payload.Issue,
Target: "main", // Default target, could be passed in payload
Rig: payload.Rig,
Title: fmt.Sprintf("Merge %s work on %s", payload.Polecat, payload.Issue),
CreatedAt: time.Now(),
}
// Add to queue
if err := h.Queue.Submit(mr); err != nil {
_, _ = fmt.Fprintf(h.Output, "[Refinery] Error adding to queue: %v\n", err)
return fmt.Errorf("failed to add merge request to queue: %w", err)
}
_, _ = fmt.Fprintf(h.Output, "[Refinery] ✓ Added to merge queue: %s\n", mr.ID)
_, _ = fmt.Fprintf(h.Output, " Queue length: %d\n", h.Queue.Count())
return nil
}
// SendMerged sends a MERGED message to the Witness.
// Called by the Refinery after successfully merging a branch.
func (h *DefaultRefineryHandler) SendMerged(polecat, branch, issue, targetBranch, mergeCommit string) error {
msg := NewMergedMessage(h.Rig, polecat, branch, issue, targetBranch, mergeCommit)
return h.Router.Send(msg)
}
// SendMergeFailed sends a MERGE_FAILED message to the Witness.
// Called by the Refinery when a merge fails.
func (h *DefaultRefineryHandler) SendMergeFailed(polecat, branch, issue, targetBranch, failureType, errorMsg string) error {
msg := NewMergeFailedMessage(h.Rig, polecat, branch, issue, targetBranch, failureType, errorMsg)
return h.Router.Send(msg)
}
// SendReworkRequest sends a REWORK_REQUEST message to the Witness.
// Called by the Refinery when a branch has conflicts.
func (h *DefaultRefineryHandler) SendReworkRequest(polecat, branch, issue, targetBranch string, conflictFiles []string) error {
msg := NewReworkRequestMessage(h.Rig, polecat, branch, issue, targetBranch, conflictFiles)
return h.Router.Send(msg)
}
// NotifyMergeOutcome is a convenience method that sends the appropriate message
// based on the merge result.
type MergeOutcome struct {
// Success indicates whether the merge was successful.
Success bool
// Conflict indicates the failure was due to conflicts (needs rebase).
Conflict bool
// FailureType categorizes the failure (e.g., "tests", "build").
FailureType string
// Error is the error message if the merge failed.
Error string
// MergeCommit is the SHA of the merge commit on success.
MergeCommit string
// ConflictFiles lists files with conflicts (if Conflict is true).
ConflictFiles []string
}
// NotifyMergeOutcome sends the appropriate protocol message based on the outcome.
func (h *DefaultRefineryHandler) NotifyMergeOutcome(polecat, branch, issue, targetBranch string, outcome MergeOutcome) error {
if outcome.Success {
return h.SendMerged(polecat, branch, issue, targetBranch, outcome.MergeCommit)
}
if outcome.Conflict {
return h.SendReworkRequest(polecat, branch, issue, targetBranch, outcome.ConflictFiles)
}
return h.SendMergeFailed(polecat, branch, issue, targetBranch, outcome.FailureType, outcome.Error)
}
// Ensure DefaultRefineryHandler implements RefineryHandler.
var _ RefineryHandler = (*DefaultRefineryHandler)(nil)