gh

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package gh holds GitHub client plumbing shared by the sync engine and the fake GitHub test server.

Index

Constants

View Source
const (
	// WebhookJSONContentType identifies GitHub's direct JSON delivery mode.
	WebhookJSONContentType = "application/json"
	// WebhookFormContentType identifies GitHub's form-wrapped JSON mode.
	WebhookFormContentType = "application/x-www-form-urlencoded"
)
View Source
const MaxPullRequestBatch = 25

MaxPullRequestBatch is GitHub's nodes-per-gang cap used by the coordinator.

Variables

View Source
var ErrUnsupportedWebhookContentType = errors.New(
	"unsupported webhook content type",
)

ErrUnsupportedWebhookContentType marks content types GitHub does not use.

Functions

func DecodeWebhookPayload

func DecodeWebhookPayload(contentType string, body []byte) ([]byte, error)

DecodeWebhookPayload validates a GitHub webhook body and returns its JSON payload. Form deliveries keep their encoded wire body in durable storage; callers use the decoded bytes only for classification.

func SignBody

func SignBody(secret, body []byte) string

SignBody computes the X-Hub-Signature-256 header value for a webhook body.

func VerifySignature

func VerifySignature(secret, body []byte, header string) bool

VerifySignature reports whether header is a valid signature for body. Constant-time; unverifiable deliveries must be rejected before parsing (SYNC_ENGINE C-I2).

Types

type AppHookDelivery

type AppHookDelivery struct {
	ID             int64     `json:"id"`
	GUID           string    `json:"guid"`
	DeliveredAt    time.Time `json:"delivered_at"`
	Redelivery     bool      `json:"redelivery"`
	Status         string    `json:"status"`
	StatusCode     int       `json:"status_code"`
	Event          string    `json:"event"`
	Action         string    `json:"action"`
	InstallationID int64     `json:"installation_id"`
	RepositoryID   int64     `json:"repository_id"`
}

AppHookDelivery is the compact delivery-list representation used by C-R4. The list endpoint intentionally omits request payloads.

type AppTokens

type AppTokens struct {
	// contains filtered or unexported fields
}

AppTokens signs short-lived GitHub App JWTs for App-only endpoints such as the webhook deliveries API used by C-R4.

func NewAppTokens

func NewAppTokens(
	appID int64,
	privateKeyPEM []byte,
) (*AppTokens, error)

NewAppTokens constructs an App-JWT provider for App-only endpoints.

func (*AppTokens) Token

func (m *AppTokens) Token(_ context.Context) (string, error)

Token signs a fresh short-lived App JWT.

type CheckRun

type CheckRun struct {
	ID          int64           `json:"id"`
	NodeID      string          `json:"node_id"`
	HeadSHA     string          `json:"head_sha"`
	Name        string          `json:"name"`
	Status      string          `json:"status"`
	Conclusion  string          `json:"conclusion"`
	DetailsURL  string          `json:"details_url"`
	AppSlug     string          `json:"-"`
	StartedAt   *time.Time      `json:"started_at"`
	CompletedAt *time.Time      `json:"completed_at"`
	Raw         json.RawMessage `json:"-"`
}

CheckRun is the cache-relevant check-run shape.

func (*CheckRun) UnmarshalJSON

func (c *CheckRun) UnmarshalJSON(data []byte) error

UnmarshalJSON flattens GitHub's nested App slug.

type DeliveriesClient

type DeliveriesClient struct {
	// contains filtered or unexported fields
}

DeliveriesClient is separate from RESTClient because GitHub requires an App JWT for /app/hook/deliveries and rejects installation access tokens.

func NewDeliveriesClient

func NewDeliveriesClient(
	baseURL string,
	gate budget.Doer,
	appTokens TokenProvider,
) (*DeliveriesClient, error)

NewDeliveriesClient constructs an App-JWT-authenticated deliveries client.

func (*DeliveriesClient) ListAppHookDeliveries

func (c *DeliveriesClient) ListAppHookDeliveries(
	ctx context.Context,
	options ListAppHookDeliveriesOptions,
	etag string,
) ([]AppHookDelivery, *RESTResponse, error)

ListAppHookDeliveries fetches deliveries newest first.

func (*DeliveriesClient) RedeliverAppHookDelivery

func (c *DeliveriesClient) RedeliverAppHookDelivery(
	ctx context.Context,
	deliveryID int64,
) error

RedeliverAppHookDelivery requests a new attempt for one delivery.

type GraphQLClient

type GraphQLClient struct {
	// contains filtered or unexported fields
}

GraphQLClient executes budget-gated installation GraphQL calls.

func NewGraphQLClient

func NewGraphQLClient(
	baseURL string,
	gate budget.Doer,
	tokens TokenProvider,
	options ...GraphQLClientOptions,
) (*GraphQLClient, error)

NewGraphQLClient validates dependencies and constructs a GraphQL client.

func (*GraphQLClient) BatchPullRequests

func (c *GraphQLClient) BatchPullRequests(
	ctx context.Context,
	class budget.Class,
	nodeIDs []string,
) ([]*PullRequestNode, *GraphQLResponse, error)

BatchPullRequests satisfies up to 25 due PR refreshes with one nodes() call (C-P4). The returned order matches the input node-ID order.

func (*GraphQLClient) Call

func (c *GraphQLClient) Call(
	ctx context.Context,
	class budget.Class,
	query string,
	variables map[string]any,
	target any,
) (*GraphQLResponse, error)

Call executes a query that includes a top-level data.rateLimit block. extractGraphQLRate reads that block for Gate before Call decodes data.

type GraphQLClientOptions

type GraphQLClientOptions struct {
	MaxResponseBytes int64
}

GraphQLClientOptions bounds response buffering.

type GraphQLError

type GraphQLError struct {
	Type       string         `json:"type"`
	Message    string         `json:"message"`
	Path       []any          `json:"path"`
	Extensions map[string]any `json:"extensions"`
}

GraphQLError is one GitHub GraphQL error entry.

type GraphQLErrors

type GraphQLErrors []GraphQLError

GraphQLErrors implements error for a non-empty GraphQL error list.

func (GraphQLErrors) Error

func (e GraphQLErrors) Error() string

Error reports the first GraphQL error message.

type GraphQLResponse

type GraphQLResponse struct {
	RateLimit budget.GraphQLRate
	Errors    []GraphQLError
}

GraphQLResponse carries authoritative point accounting and GraphQL errors.

type HTTPError

type HTTPError struct {
	StatusCode int
	Message    string
}

HTTPError is a non-success response from GitHub. Response bodies are bounded before being retained.

func (*HTTPError) Error

func (e *HTTPError) Error() string

type InstallationTokenOptions

type InstallationTokenOptions struct {
	BaseURL        string
	AppID          int64
	InstallationID int64
	PrivateKey     *rsa.PrivateKey
	PrivateKeyPEM  []byte
	RefreshBefore  time.Duration
	Clock          interface{ Now() time.Time }
}

InstallationTokenOptions configures App-to-installation token exchange.

type InstallationTokens

type InstallationTokens struct {
	// contains filtered or unexported fields
}

InstallationTokens exchanges an App JWT for installation access tokens, caches them until shortly before expiry, and collapses concurrent renewals. The hand-rolled exchange keeps the token endpoint inside Gate.Do; it uses ghinstallation's signer rather than its RoundTripper, whose internal refresh request would otherwise bypass C-B1.

func NewInstallationTokens

func NewInstallationTokens(
	gate budget.Doer,
	options InstallationTokenOptions,
) (*InstallationTokens, error)

NewInstallationTokens validates App credentials and constructs a cached installation-token provider.

func (*InstallationTokens) Expiry

func (m *InstallationTokens) Expiry() time.Time

Expiry returns the cached installation-token expiry, or zero before renewal.

func (*InstallationTokens) Token

func (m *InstallationTokens) Token(ctx context.Context) (string, error)

Token returns a cached installation token or performs one shared renewal.

type ListAppHookDeliveriesOptions

type ListAppHookDeliveriesOptions struct {
	PerPage int
	Cursor  string
}

ListAppHookDeliveriesOptions controls newest-first delivery pagination.

type ListCheckRunsOptions

type ListCheckRunsOptions struct {
	PerPage int
	Page    int
}

ListCheckRunsOptions controls checks pagination.

type ListPullsOptions

type ListPullsOptions struct {
	State     string
	Sort      string
	Direction string
	PerPage   int
	Page      int
}

ListPullsOptions controls pull-request filtering and pagination.

type ListRepositoriesOptions

type ListRepositoriesOptions struct {
	PerPage int
	Page    int
}

ListRepositoriesOptions controls installation repository pagination.

type ListStacksOptions

type ListStacksOptions struct {
	PullRequest int
	PerPage     int
	Page        int
}

ListStacksOptions controls stack filtering and pagination.

type PageInfo

type PageInfo struct {
	HasNextPage bool    `json:"hasNextPage"`
	EndCursor   *string `json:"endCursor"`
}

PageInfo is GraphQL connection pagination metadata.

type PullRequest

type PullRequest struct {
	*github.PullRequest
	Stack          *StackRef `json:"stack,omitempty"`
	ReviewDecision string    `json:"review_decision,omitempty"`
}

PullRequest keeps google/go-github's typed pull request while preserving the preview-only stack extension that the library does not yet model.

func (*PullRequest) UnmarshalJSON

func (p *PullRequest) UnmarshalJSON(data []byte) error

UnmarshalJSON preserves the private-preview stack extension.

type PullRequestBranch

type PullRequestBranch struct {
	Ref string `json:"ref"`
	SHA string `json:"sha"`
}

PullRequestBranch identifies one pull request branch.

type PullRequestNode

type PullRequestNode struct {
	ID             string    `json:"id"`
	DatabaseID     int64     `json:"databaseId"`
	Number         int       `json:"number"`
	Title          string    `json:"title"`
	State          string    `json:"state"`
	IsDraft        bool      `json:"isDraft"`
	UpdatedAt      time.Time `json:"updatedAt"`
	ReviewDecision string    `json:"reviewDecision"`
	Mergeable      string    `json:"mergeable"`
	HeadRefName    string    `json:"headRefName"`
	HeadRefOID     string    `json:"headRefOid"`
	BaseRefName    string    `json:"baseRefName"`
	BaseRefOID     string    `json:"baseRefOid"`
	Author         struct {
		Login string `json:"login"`
	} `json:"author"`
	Repository    RepositoryNode `json:"repository"`
	ReviewThreads struct {
		Nodes    []ReviewThreadNode `json:"nodes"`
		PageInfo PageInfo           `json:"pageInfo"`
	} `json:"reviewThreads"`
}

PullRequestNode is the authoritative GraphQL detail shape used by the M3 nodes() coordinator. Stack membership is intentionally absent from the query because the private-preview stack extension is REST-only; the resolve_stack_membership worker covers that authoritative dimension.

type RESTClient

type RESTClient struct {
	// contains filtered or unexported fields
}

RESTClient fetches installation-authenticated GitHub REST resources.

func NewRESTClient

func NewRESTClient(
	baseURL string,
	gate budget.Doer,
	tokens TokenProvider,
) (*RESTClient, error)

NewRESTClient validates dependencies and constructs a REST client.

func (*RESTClient) GetPull

func (c *RESTClient) GetPull(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	number int,
	etag string,
) (*PullRequest, *RESTResponse, error)

GetPull fetches one pull request. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the pull request.

func (*RESTClient) GetRepository

func (c *RESTClient) GetRepository(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	etag string,
) (*Repository, *RESTResponse, error)

GetRepository fetches one repository. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the repository.

func (*RESTClient) GetStack

func (c *RESTClient) GetStack(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	number int,
	etag string,
) (*Stack, *RESTResponse, error)

GetStack fetches one stack. A conditional 304 returns (nil, response, nil); callers must inspect response.NotModified before dereferencing the stack.

func (*RESTClient) ListCheckRuns

func (c *RESTClient) ListCheckRuns(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	headSHA string,
	options ListCheckRunsOptions,
	etag string,
) ([]CheckRun, *RESTResponse, error)

ListCheckRuns fetches one checks page for a head SHA.

func (*RESTClient) ListInstallationRepositories

func (c *RESTClient) ListInstallationRepositories(
	ctx context.Context,
	class budget.Class,
	options ListRepositoriesOptions,
	etag string,
) ([]Repository, *RESTResponse, error)

ListInstallationRepositories fetches one installation repository page.

func (*RESTClient) ListPulls

func (c *RESTClient) ListPulls(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	options ListPullsOptions,
	etag string,
) ([]PullRequest, *RESTResponse, error)

ListPulls fetches one pull-request page.

func (*RESTClient) ListRepositoryRules

func (c *RESTClient) ListRepositoryRules(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	etag string,
) ([]RepositoryRule, *RESTResponse, error)

ListRepositoryRules fetches the complete ruleset page for one repository.

func (*RESTClient) ListStacks

func (c *RESTClient) ListStacks(
	ctx context.Context,
	class budget.Class,
	owner string,
	repo string,
	options ListStacksOptions,
	etag string,
) ([]Stack, *RESTResponse, error)

ListStacks fetches one gh-stack preview page.

type RESTResponse

type RESTResponse struct {
	StatusCode  int
	ETag        string
	NotModified bool
	NextPage    int
	NextCursor  string
}

RESTResponse is typed 304/pagination metadata. NotModified is a successful conditional result, not an error (C-B4).

type Repository

type Repository struct {
	ID            int64     `json:"id"`
	NodeID        string    `json:"node_id"`
	Owner         string    `json:"-"`
	Name          string    `json:"name"`
	FullName      string    `json:"full_name"`
	DefaultBranch string    `json:"default_branch"`
	Archived      bool      `json:"archived"`
	UpdatedAt     time.Time `json:"updated_at"`
	PushedAt      time.Time `json:"pushed_at"`
}

Repository is the subset of repository truth needed by the mirror.

func (*Repository) UnmarshalJSON

func (r *Repository) UnmarshalJSON(data []byte) error

UnmarshalJSON flattens GitHub's nested owner login.

type RepositoryNode

type RepositoryNode struct {
	ID               string    `json:"id"`
	DatabaseID       int64     `json:"databaseId"`
	Name             string    `json:"name"`
	NameWithOwner    string    `json:"nameWithOwner"`
	IsArchived       bool      `json:"isArchived"`
	UpdatedAt        time.Time `json:"updatedAt"`
	DefaultBranchRef *struct {
		Name   string `json:"name"`
		Target struct {
			OID string `json:"oid"`
		} `json:"target"`
	} `json:"defaultBranchRef"`
	Owner struct {
		Login string `json:"login"`
	} `json:"owner"`
}

RepositoryNode is the cache-relevant repository GraphQL shape.

type RepositoryRule

type RepositoryRule struct {
	ID        int64
	UpdatedAt *time.Time
	Raw       json.RawMessage
}

RepositoryRule preserves the complete ruleset payload while exposing the immutable key and optional semantic timestamp used by the mirror CAS.

func (*RepositoryRule) UnmarshalJSON

func (r *RepositoryRule) UnmarshalJSON(data []byte) error

UnmarshalJSON retains the complete raw rule while extracting CAS metadata.

type ReviewCommentNode

type ReviewCommentNode struct {
	ID        string    `json:"id"`
	Body      string    `json:"body"`
	UpdatedAt time.Time `json:"updatedAt"`
	Author    *struct {
		Login string `json:"login"`
	} `json:"author"`
}

ReviewCommentNode is one review-comment connection node.

type ReviewThreadNode

type ReviewThreadNode struct {
	ID         string `json:"id"`
	IsResolved bool   `json:"isResolved"`
	IsOutdated bool   `json:"isOutdated"`
	Path       string `json:"path"`
	Line       *int   `json:"line"`
	Comments   struct {
		Nodes    []ReviewCommentNode `json:"nodes"`
		PageInfo PageInfo            `json:"pageInfo"`
	} `json:"comments"`
}

ReviewThreadNode is one review-thread connection node.

type Stack

type Stack struct {
	ID           int64              `json:"id"`
	Number       int                `json:"number"`
	NodeID       string             `json:"node_id"`
	URL          string             `json:"url"`
	Base         StackBase          `json:"base"`
	Open         bool               `json:"open"`
	CreatedAt    time.Time          `json:"created_at"`
	UpdatedAt    time.Time          `json:"updated_at"`
	PullRequests []StackPullRequest `json:"pull_requests"` // bottom to top
}

Stack is the gh-stack private-preview REST resource.

type StackBase

type StackBase struct {
	Ref string `json:"ref"`
	SHA string `json:"sha,omitempty"`
}

StackBase identifies a stack's base ref and commit.

type StackPullRequest

type StackPullRequest struct {
	Number    int               `json:"number"`
	State     string            `json:"state"`
	Draft     bool              `json:"draft"`
	MergedAt  *time.Time        `json:"merged_at"`
	UpdatedAt time.Time         `json:"updated_at"`
	Head      PullRequestBranch `json:"head"`
}

StackPullRequest is one ordered layer in a stack.

type StackRef

type StackRef struct {
	ID       int64     `json:"id"`
	Number   int       `json:"number"`
	Size     int       `json:"size"`
	Position int       `json:"position"`
	Base     StackBase `json:"base"`
}

StackRef is the private-preview extension carried by ordinary pull request responses.

type StaticToken

type StaticToken string

StaticToken is useful for fake-GitHub conformance tests.

func (StaticToken) Token

func (t StaticToken) Token(context.Context) (string, error)

Token returns the static test token.

type TokenProvider

type TokenProvider interface {
	Token(context.Context) (string, error)
}

TokenProvider supplies an installation token without exposing it outside the GitHub client layer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL