Documentation
¶
Overview ¶
@index Repository and branch allowlist rules for webhook-triggered sync.
@index Authentication helpers for webhook-driven git access.
@index Clone URL resolution for webhook-triggered repository sync.
@index Repository locking and clone-or-pull operations for webhook sync.
@index HTTP webhook intake for repository sync dispatch.
@index Deduplicating work queue for webhook-driven repository sync.
Index ¶
- Variables
- func AllowRuleOwners(rules []RepoRule) []string
- func AllowRulesSpanMultipleOwners(rules []RepoRule) (bool, []string)
- func CloneOrPull(ctx context.Context, repoURL, repoRoot, namespace string, ...) error
- func CloneOrPullBranch(ctx context.Context, repoURL, repoRoot, namespace, branch string, ...) error
- func CloneOrPullBranchLocked(ctx context.Context, locker *RepoLocker, ...) error
- func ExtractNamespace(repoFullName string) string
- func GenerateAppJWT(appID int64, privateKeyPEM []byte) (string, error)
- func IsNonRetryable(err error) bool
- func NonRetryable(err error) error
- func NormalizeBranchRef(ref string) (string, bool)
- func RepoDir(repoRoot, namespace string) string
- func ResolveCloneURL(repoFullName, payloadCloneURL string, baseURLs []string, allowPayload bool) (string, error)
- type GitAuth
- type QueueConfig
- type RepoFilter
- type RepoLocker
- type RepoRule
- type RepoStats
- type RetryConfig
- type SyncFunc
- type SyncHandlerFunc
- type SyncQueue
- func NewSyncQueue(workers int, handler SyncHandlerFunc) *SyncQueue
- func NewSyncQueueWithConfig(ctx context.Context, workers int, handler SyncHandlerFunc, cfg QueueConfig) *SyncQueue
- func NewSyncQueueWithContext(ctx context.Context, workers int, handler SyncHandlerFunc) *SyncQueue
- func NewSyncQueueWithOptions(ctx context.Context, workers int, handler SyncHandlerFunc, retry RetryConfig) *SyncQueue
- type SyncQueueStats
- type WebhookHandler
- type WebhookHandlerConfig
Constants ¶
This section is empty.
Variables ¶
var ( ErrSyncQueueFull = errors.New("sync queue full") ErrSyncQueueShuttingDown = errors.New("sync queue shutting down") )
var ErrRepoLockTimeout = errors.New("repo lock timeout")
@intent signal that a per-repository lock could not be acquired within the configured wait window.
Functions ¶
func AllowRuleOwners ¶
AllowRuleOwners returns the positive repository owner prefixes present in allow rules. @intent let server startup warn when repo-name namespace extraction is used with multi-owner webhook allowlists. @domainRule deny rules are ignored because they only narrow the positive admission surface.
func AllowRulesSpanMultipleOwners ¶
AllowRulesSpanMultipleOwners reports whether webhook rules admit repositories under more than one owner prefix. @intent identify configurations that can collide under the current repo-name namespace strategy.
func CloneOrPull ¶
func CloneOrPull(ctx context.Context, repoURL, repoRoot, namespace string, auth transport.AuthMethod) error
CloneOrPull syncs the repository namespace to the default remote branch. @intent give webhook handlers a branch-agnostic entry point for standard repo refresh. @param auth is the git transport auth method to use when the remote requires credentials. @sideEffect may clone or hard-reset the target repository checkout on disk.
func CloneOrPullBranch ¶
func CloneOrPullBranch(ctx context.Context, repoURL, repoRoot, namespace, branch string, auth transport.AuthMethod) error
CloneOrPullBranch ensures the namespace checkout exists and matches the requested branch head. @intent reuse the same repo sync path for first clone and subsequent updates. @sideEffect creates or hard-resets the namespace checkout on disk. @param branch is optional; when empty the repository's current HEAD branch is used during sync. @ensures the checkout at RepoDir(repoRoot, namespace) matches the requested remote branch head on success.
func CloneOrPullBranchLocked ¶
func CloneOrPullBranchLocked(ctx context.Context, locker *RepoLocker, repoURL, repoRoot, repoFullName, namespace, branch string, auth transport.AuthMethod) error
CloneOrPullBranchLocked wraps branch sync with repository locking. @intent prevent overlapping webhook deliveries from cloning or resetting the same checkout simultaneously. @ensures branch sync runs under repository locking even when caller passes a nil locker.
func ExtractNamespace ¶
ExtractNamespace derives a filesystem-safe namespace from a repository full name. @intent keep repo-backed namespaces predictable when organizations contain nested path segments. @param repoFullName is the full repository name, typically org/repo. @return returns the repository portion after the first slash, with any remaining slashes replaced by dashes.
func GenerateAppJWT ¶
GenerateAppJWT signs a short-lived GitHub App JWT from the configured private key. @intent mint the app identity token needed to exchange for installation-scoped repository access. @requires privateKeyPEM must decode to an RSA PKCS#1 private key. @ensures returns an RS256 JWT whose iss claim matches appID and whose exp claim is set to now+10 minutes. @domainRule issued-at is backdated by 60 seconds to tolerate small clock skew.
func IsNonRetryable ¶
IsNonRetryable reports whether a sync error should bypass queue retries. @intent let retry logic stop early when a failure is known to be permanent for the current payload. @param err is the sync failure returned by the queue handler. @return returns true when err unwraps to nonRetryableError.
func NonRetryable ¶
@intent wrap permanent sync failures so queue retry logic can short-circuit them.
func NormalizeBranchRef ¶
NormalizeBranchRef extracts the branch name from a refs/heads/* git ref. @intent ignore tag and non-branch webhook refs before repository policy evaluation. @param ref is the raw git reference from the webhook payload. @return returns the branch name and true only for refs/heads/* values.
func RepoDir ¶
RepoDir maps a namespace to the checkout directory used for repository sync. @intent keep namespace naming stable across clone, pull, and downstream build steps. @return returns the repository checkout path rooted under repoRoot.
func ResolveCloneURL ¶
func ResolveCloneURL(repoFullName, payloadCloneURL string, baseURLs []string, allowPayload bool) (string, error)
ResolveCloneURL selects a safe clone target from configured base URLs or the payload. @intent keep repository sync deterministic and prevent untrusted webhook payloads from choosing arbitrary clone endpoints unless explicitly allowed.
Types ¶
type GitAuth ¶
type GitAuth struct {
SSHKeyPath string
SSHKeyData []byte
SSHPassword string
AppID int64
AppKey []byte
InstallToken string
}
@intent bundle the supported git authentication inputs (SSH key, GitHub App credentials, install token) for webhook clone and fetch.
func (*GitAuth) Resolve ¶
func (a *GitAuth) Resolve() (transport.AuthMethod, error)
Resolve picks the first configured git authentication strategy. @intent allow webhook sync to switch between SSH and GitHub App token auth without branching at call sites. @domainRule prefer SSHKeyPath first, then inline SSHKeyData, then InstallToken, and return nil auth if none are configured. @sideEffect reads the SSH private key file when SSHKeyPath is used. @ensures returns the first usable transport.AuthMethod for the configured credentials.
type QueueConfig ¶
type QueueConfig struct {
RetryConfig
ShutdownTimeout time.Duration
MaxTrackedRepos int
}
@intent configure queue retry policy and memory bounds when constructing a SyncQueue.
type RepoFilter ¶
type RepoFilter struct {
// contains filtered or unexported fields
}
RepoFilter holds the ordered rule list used to decide repo and branch admission. @intent provide a single matcher whose result depends on rule declaration order, where later matching rules override earlier ones.
func NewRepoFilter ¶
func NewRepoFilter(patterns []string) *RepoFilter
NewRepoFilter expands simple string patterns into webhook repo rules. @intent keep CLI-style allowlist configuration compatible with the richer rule matcher. @param patterns is the ordered allow/deny rule list in compact string form. @ensures returns a filter whose rule order matches the caller input order.
func NewRepoFilterFromRules ¶
func NewRepoFilterFromRules(rules []RepoRule) *RepoFilter
NewRepoFilterFromRules compiles repository and branch rules into a matcher. @intent centralize Atlantis-style repo filtering so webhook dispatch can make one consistent allow decision. @param rules is the ordered repo rule list whose later matches override earlier ones. @ensures returns a filter that preserves the source rule order for evaluation.
func (*RepoFilter) IsAllowed ¶
func (f *RepoFilter) IsAllowed(repoFullName string) bool
IsAllowed reports whether a repository matches the configured allow and deny rules. @intent let callers gate repository-level sync before looking at branch-specific restrictions. @domainRule rules are evaluated in declaration order and the last matching rule wins; a later allow rule overrides an earlier deny match and vice versa. @domainRule a repository with no matching rule is denied (default-deny).
func (*RepoFilter) IsAllowedBranch ¶
func (f *RepoFilter) IsAllowedBranch(repoFullName, branch string) bool
IsAllowedBranch reports whether a repository and branch pair should be processed. @intent combine repo allowlist and branch policy so webhook handlers can skip unsupported pushes cheaply. @domainRule with no rules configured the result is always false (default-deny). @domainRule rules are evaluated in declaration order; each later matching rule replaces the prior decision, so a negate rule clears any previous allow and a subsequent allow rule re-enables the repo. @domainRule when a non-negate rule matches but specifies no branches, the built-in defaults ("main", "master") are used.
func (*RepoFilter) IsAllowedRef ¶
func (f *RepoFilter) IsAllowedRef(repoFullName, ref string) bool
IsAllowedRef resolves a git ref to a branch and applies branch allowlist rules. @intent reject non-branch webhook refs before they can enter the sync pipeline. @return returns false for non-branch refs and otherwise defers to branch policy evaluation.
type RepoLocker ¶
type RepoLocker struct {
// contains filtered or unexported fields
}
@intent keep repository-scoped git operations serialized across concurrent webhook deliveries.
func NewRepoLocker ¶
func NewRepoLocker(timeout time.Duration) *RepoLocker
NewRepoLocker creates a per-repository lock coordinator with a bounded wait time. @intent serialize concurrent webhook sync for the same repo so git operations do not corrupt the working tree. @param timeout bounds how long callers wait before ErrRepoLockTimeout is returned. @ensures non-positive timeout falls back to 30 seconds.
func (*RepoLocker) WithLock ¶
func (l *RepoLocker) WithLock(ctx context.Context, lockRoot, repoFullName string, fn func(context.Context) error) error
WithLock runs a sync operation while holding both in-process and filesystem repo locks. @intent coordinate webhook workers across goroutines and processes before touching a repository checkout. @sideEffect creates and removes filesystem lock files under the repo root. @param lockRoot is the filesystem root under which lock files are created. @param repoFullName is the repository key used for in-memory and filesystem lock scoping. @ensures fn runs at most once concurrently per repository across cooperating workers/processes.
type RepoRule ¶
RepoRule is the user-facing config form pairing a repo pattern with optional branch globs. @intent expose a stable shape for CLI/YAML config without leaking the internal compiled rule layout.
func ParseRepoRule ¶
ParseRepoRule decodes a repo rule string with optional comma-separated branch patterns. @intent preserve compact CLI config while still supporting per-repository branch restrictions. @param s follows pattern or pattern:branch1,branch2 syntax. @return returns a RepoRule with branch restrictions only when the colon form is present.
type RepoStats ¶
type RepoStats struct {
Repo string `json:"repo"`
Branch string `json:"branch"`
Queued bool `json:"queued"`
Processing bool `json:"processing"`
EnqueuedAt time.Time `json:"enqueued_at,omitempty"`
ProcessingAt time.Time `json:"processing_at,omitempty"`
LastSuccessTime time.Time `json:"last_success_time,omitempty"`
LastErrorTime time.Time `json:"last_error_time,omitempty"`
LastError string `json:"last_error,omitempty"`
}
@intent expose per-repository queue state so operators can inspect backlog and failure hotspots.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the total number of attempts (1 = no retry). Default: 3.
MaxAttempts int
// BaseDelay is the initial backoff duration. Default: 1s.
BaseDelay time.Duration
// MaxDelay caps the backoff duration. Default: 30s.
MaxDelay time.Duration
}
RetryConfig configures exponential backoff retry for sync handlers. @intent tune retry backoff so transient webhook sync failures can recover without overwhelming the remote.
type SyncFunc ¶
@intent define the callback signature webhook intake invokes to trigger repository sync.
type SyncHandlerFunc ¶
@intent share the same sync callback shape between direct handler wiring and queue-based processing.
type SyncQueue ¶
type SyncQueue struct {
// contains filtered or unexported fields
}
@intent coordinate deduplicated per-repository sync execution across a worker pool.
func NewSyncQueue ¶
func NewSyncQueue(workers int, handler SyncHandlerFunc) *SyncQueue
NewSyncQueue creates a queue with background workers and default lifecycle settings. @intent provide the smallest constructor for production webhook dispatch. @param workers is the number of background workers to start. @param handler processes one deduplicated repository sync payload. @sideEffect starts background worker goroutines immediately.
func NewSyncQueueWithConfig ¶
func NewSyncQueueWithConfig(ctx context.Context, workers int, handler SyncHandlerFunc, cfg QueueConfig) *SyncQueue
NewSyncQueueWithConfig creates a deduplicating repo work queue and starts its workers. @intent coalesce bursty webhook pushes per repository while still allowing different repos to sync concurrently. @param cfg controls retry behavior and how many repositories may be tracked at once. @sideEffect starts worker goroutines and allocates queue state maps. @ensures non-positive MaxAttempts becomes 1, non-positive ShutdownTimeout becomes 30s, and non-positive MaxTrackedRepos becomes 1024.
func NewSyncQueueWithContext ¶
func NewSyncQueueWithContext(ctx context.Context, workers int, handler SyncHandlerFunc) *SyncQueue
NewSyncQueueWithContext binds queue workers to a parent lifecycle context. @intent allow server shutdown to cancel retries and worker waits cleanly. @param ctx controls worker lifetime and retry cancellation. @sideEffect starts background worker goroutines immediately.
func NewSyncQueueWithOptions ¶
func NewSyncQueueWithOptions(ctx context.Context, workers int, handler SyncHandlerFunc, retry RetryConfig) *SyncQueue
NewSyncQueueWithOptions applies retry tuning while keeping default queue limits. @intent expose backoff customization without forcing every caller to build a full queue config. @param retry overrides exponential backoff behavior for sync retries. @ensures queue memory bounds still use default MaxTrackedRepos when not specified.
func (*SyncQueue) Add ¶
Add records the latest payload for a repository and enqueues it if needed. @intent collapse repeated push events into one queued sync while preserving the newest branch and clone data. @mutates SyncQueue.queue, SyncQueue.dirty, SyncQueue.payloads. @param repoFullName identifies the deduplication key for queueing. @return returns ErrSyncQueueFull when a new repository would exceed the bounded tracked-repo set and ErrSyncQueueShuttingDown after graceful shutdown begins. @domainRule repeated events for the same repository replace payload data instead of enqueueing duplicate work.
func (*SyncQueue) Shutdown ¶
func (q *SyncQueue) Shutdown()
Shutdown stops accepting new work and waits for workers to finish or time out. @intent give the server a bounded, graceful shutdown path for in-flight webhook sync. @sideEffect flips queue shutdown state, wakes waiting workers, and may record a timeout failure.
func (*SyncQueue) Stats ¶
func (q *SyncQueue) Stats() SyncQueueStats
Stats snapshots queue health and recent repository activity for operators. @intent expose enough queue state to diagnose backlog, failures, and hot repositories. @return returns a point-in-time snapshot without mutating queue execution state.
type SyncQueueStats ¶
type SyncQueueStats struct {
Queued int `json:"queued"`
Dirty int `json:"dirty"`
Processing int `json:"processing"`
TrackedRepos int `json:"tracked_repos"`
MaxTrackedRepos int `json:"max_tracked_repos"`
QueueFullTotal int64 `json:"queue_full_total"`
FailureTotal int64 `json:"failure_total"`
LastError string `json:"last_error,omitempty"`
LastErrorTime time.Time `json:"last_error_time,omitempty"`
OldestQueuedAge time.Duration `json:"oldest_queued_age"`
OldestProcessingAge time.Duration `json:"oldest_processing_age"`
LastSuccessTime time.Time `json:"last_success_time,omitempty"`
Shutdown bool `json:"shutdown"`
RecentRepos []RepoStats `json:"recent_repos,omitempty"`
}
@intent summarize queue-wide health and recent repository activity for observability.
type WebhookHandler ¶
type WebhookHandler struct {
// contains filtered or unexported fields
}
@intent bundle webhook validation policy and dispatch dependencies into one reusable HTTP handler.
func NewWebhookHandler ¶
func NewWebhookHandler(secret []byte, filter *RepoFilter, onSync SyncFunc) *WebhookHandler
NewWebhookHandler wires a webhook handler from the common secret/filter/sync callback inputs. @intent keep the default construction path small while routing all configuration through the shared config builder. @param secret is the shared webhook secret used for signature validation. @param filter decides which repo and branch combinations are eligible for sync. @param onSync dispatches the validated sync request. @ensures returns a handler configured with the default secure validation path.
func NewWebhookHandlerWithConfig ¶
func NewWebhookHandlerWithConfig(cfg WebhookHandlerConfig) *WebhookHandler
NewWebhookHandlerWithConfig assembles webhook validation and clone URL policy into one handler. @intent make webhook intake configurable without duplicating constructor logic across CLI and tests. @param cfg carries webhook secret, filtering, sync callback, and clone URL policy. @ensures returns a handler whose clone base URLs preserve config ordering with CloneBaseURL first when provided.
func NewWebhookHandlerWithOptions ¶
func NewWebhookHandlerWithOptions(secret []byte, filter *RepoFilter, onSync SyncFunc, insecure bool) *WebhookHandler
NewWebhookHandlerWithOptions builds a handler with the legacy option-style constructor. @intent preserve older call sites while the config-based constructor owns the actual assembly logic. @param insecure allows payload delivery without signature validation when true. @ensures returns a handler configured equivalently to the legacy constructor inputs.
func (*WebhookHandler) ServeHTTP ¶
func (h *WebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP validates a webhook push event and dispatches repository sync when it passes policy checks. @intent turn GitHub or Gitea push deliveries into safe, filtered sync requests for the build pipeline. @sideEffect reads the request body and invokes the configured sync callback. @domainRule only signed push events for allowed repository/branch pairs are dispatched. @ensures writes an HTTP status describing acceptance, rejection, or sync backpressure for the delivery.
type WebhookHandlerConfig ¶
type WebhookHandlerConfig struct {
Secret []byte
Filter *RepoFilter
OnSync SyncFunc
Insecure bool
CloneBaseURL string
CloneBaseURLs []string
}
@intent carry all constructor options for webhook validation, clone URL policy, and sync dispatch.