Documentation
¶
Overview ¶
Package infrastructure holds the notification adapters: the messages repository over the store, the Slack messenger over the platform client, and the GitHub inbound receiver.
Index ¶
- Constants
- Variables
- func BitbucketSignatureMiddleware(verifier security.SignatureVerifier) func(http.Handler) http.Handler
- func NewBitbucketHandler(dispatcher domain.EventDispatcher) http.Handler
- func NewGitHubHandler(dispatcher domain.EventDispatcher) http.Handler
- func SignatureMiddleware(verifier security.SignatureVerifier) func(http.Handler) http.Handler
- type MessageRepo
- func (r *MessageRepo) AddMessage(ctx context.Context, repository string, prNumber int, ...) error
- func (r *MessageRepo) Delete(ctx context.Context, repository string, prNumber int) error
- func (r *MessageRepo) MarkClosed(ctx context.Context, repository string, prNumber int) error
- func (r *MessageRepo) Messages(ctx context.Context, repository string, prNumber int) ([]domain.Message, error)
- func (r *MessageRepo) Touch(ctx context.Context, repository string, prNumber int) error
- type Payload
- type PullRequest
- type Review
- type Sender
- type SlackMessenger
- func (m *SlackMessenger) AddReaction(ctx context.Context, channel, messageID, emoji string) error
- func (m *SlackMessenger) Delete(ctx context.Context, channel, messageID string) error
- func (m *SlackMessenger) PostOpen(ctx context.Context, channel string, req domain.OpenRequest) (string, error)
- func (m *SlackMessenger) UpdateClosed(ctx context.Context, channel, messageID string, req domain.ClosedRequest) error
- func (m *SlackMessenger) UpdateReviewFinished(ctx context.Context, channel, messageID string, ...) error
Constants ¶
const MaxBodyBytes int64 = 1 << 20 // 1 MiB
MaxBodyBytes caps the size of an accepted webhook body. GitHub limits its own webhook payloads to ~25 MiB but our handler needs nowhere near that — a generous 1 MiB protects against memory exhaustion.
Variables ¶
var ErrMissingPRNumber = errors.New("notification: missing pull_request.number")
ErrMissingPRNumber is returned when the payload lacks a pull request number.
Functions ¶
func BitbucketSignatureMiddleware ¶ added in v0.22.0
func BitbucketSignatureMiddleware(verifier security.SignatureVerifier) func(http.Handler) http.Handler
BitbucketSignatureMiddleware returns an HTTP middleware that rejects any request whose body exceeds MaxBodyBytes (413) or whose X-Hub-Signature header does not match the HMAC of the body (401), and passes a fresh body reader to next so downstream handlers read the verified body. Bitbucket sends no signature header when no secret is configured, so a missing header is rejected 401 — unsigned deliveries are never trusted.
func NewBitbucketHandler ¶ added in v0.22.0
func NewBitbucketHandler(dispatcher domain.EventDispatcher) http.Handler
NewBitbucketHandler returns an http.Handler that parses the JSON body of an inbound Bitbucket webhook, maps it to a kernel.Event, and dispatches it. It assumes the body has already been validated by BitbucketSignatureMiddleware. It returns 400 if the body is not valid JSON or has no pullrequest.id, 200 with body "ok" after a successful dispatch, and 500 if dispatch returns an error.
func NewGitHubHandler ¶
func NewGitHubHandler(dispatcher domain.EventDispatcher) http.Handler
NewGitHubHandler returns an http.Handler that parses the JSON body of an inbound GitHub webhook, maps it to a kernel.Event, and dispatches it. It assumes the body has already been validated by SignatureMiddleware. It returns 400 if the body is not valid JSON or has no pull_request.number, 200 with body "ok" after a successful dispatch, and 500 if dispatch returns an error.
func SignatureMiddleware ¶
SignatureMiddleware returns an HTTP middleware that rejects any request whose body exceeds MaxBodyBytes (413) or whose X-Hub-Signature-256 header does not match the HMAC of the body (401), and passes a fresh body reader to next so downstream handlers read the verified body.
Types ¶
type MessageRepo ¶
type MessageRepo struct {
// contains filtered or unexported fields
}
MessageRepo adapts the store's PullRequests repository to the notification MessageStore port, mapping store persistence models to domain DTOs at the boundary so no gorm-tagged type crosses a port. The "not found" sentinel passes through unchanged (persistence.ErrNotFound aliases the routing domain sentinel handlers compare against).
func NewMessageRepo ¶
func NewMessageRepo(pullRequests *persistence.PullRequests) *MessageRepo
NewMessageRepo wraps the store's PullRequests repository.
func (*MessageRepo) AddMessage ¶
func (r *MessageRepo) AddMessage(ctx context.Context, repository string, prNumber int, channel, messageID string) error
AddMessage implements domain.MessageStore.
func (*MessageRepo) MarkClosed ¶
MarkClosed implements domain.MessageStore.
type Payload ¶
type Payload struct {
Event string
Action string
Repository string
PullRequest PullRequest
// Review is non-nil only for pull_request_review events.
Review *Review
// PRComment is true for issue_comment events fired on a pull request.
PRComment bool
// Sender is the actor who fired the event.
Sender Sender
}
Payload is the parsed view of an inbound GitHub webhook body, holding only the fields the notifier uses.
func ParsePayload ¶
ParsePayload decodes a raw GitHub webhook body into a Payload. It validates only what the dispatcher needs (a PR number); everything else is best-effort.
type PullRequest ¶
type PullRequest struct {
Number int
Title string
URL string
Author string
Merged bool
Draft bool
Body string
CreatedAt time.Time
}
PullRequest holds the PR fields extracted from the payload.
type Review ¶
type Review struct {
State string
}
Review carries the review state (approved | commented | changes_requested).
type SlackMessenger ¶
type SlackMessenger struct {
// contains filtered or unexported fields
}
SlackMessenger implements the notification Messenger port over the Slack client and composer. It owns the message shaping: which composer template and which marker blocks each notification intent renders to. The application hands it domain intent; no Slack type crosses the port.
func NewSlackMessenger ¶
func NewSlackMessenger(client *slack.Client, composer *slack.Composer) *SlackMessenger
NewSlackMessenger wraps the platform Slack client and composer.
func (*SlackMessenger) AddReaction ¶
func (m *SlackMessenger) AddReaction(ctx context.Context, channel, messageID, emoji string) error
AddReaction implements domain.Messenger.
func (*SlackMessenger) Delete ¶
func (m *SlackMessenger) Delete(ctx context.Context, channel, messageID string) error
Delete implements domain.Messenger.
func (*SlackMessenger) PostOpen ¶
func (m *SlackMessenger) PostOpen(ctx context.Context, channel string, req domain.OpenRequest) (string, error)
PostOpen implements domain.Messenger.
func (*SlackMessenger) UpdateClosed ¶
func (m *SlackMessenger) UpdateClosed(ctx context.Context, channel, messageID string, req domain.ClosedRequest) error
UpdateClosed implements domain.Messenger.
func (*SlackMessenger) UpdateReviewFinished ¶
func (m *SlackMessenger) UpdateReviewFinished(ctx context.Context, channel, messageID string, req domain.ReviewFinishedRequest) error
UpdateReviewFinished implements domain.Messenger.