github

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// EventApprove represents GitHub review event APPROVE.
	EventApprove = "APPROVE"
	// EventRequestChanges represents GitHub review event REQUEST_CHANGES.
	EventRequestChanges = "REQUEST_CHANGES"
)

Variables

View Source
var (
	ErrRetrievalAuthUnavailable = errors.New("retrieval credentials unavailable: GitHub App authentication is required for scoped private source retrieval, PAT substitution is forbidden (D-10)")
	ErrPushAuthUnavailable      = errors.New("push credentials unavailable: GitHub App authentication is required for scoped same-PR push, PAT substitution is forbidden (D-29)")
	ErrInvalidRepoID            = errors.New("invalid or empty repository ID")
	ErrScopeTooBroad            = errors.New("retrieval credential scope too broad or unverified")
	ErrServiceActorUnavailable  = errors.New("service actor unavailable")
	ErrServiceActorPermission   = errors.New("service actor permission error")
	ErrServiceActorMalformed    = errors.New("service actor response malformed")
)
View Source
var (
	// ErrHeadMoved indicates that the branch head moved away from expectedHeadOid.
	ErrHeadMoved = errors.New("branch head moved")
	// ErrInvalidCommitOID indicates that a commit SHA is not a 40- or 64-character hex string.
	ErrInvalidCommitOID = errors.New("commit SHA must be 40 or 64 hex characters (full OID required)")
)
View Source
var (
	// ErrInvalidDecisionEvent indicates that the decision event is not APPROVE or REQUEST_CHANGES.
	ErrInvalidDecisionEvent = errors.New("decision event must be APPROVE or REQUEST_CHANGES")
	// ErrMissingOwnerOrRepo indicates that owner or repo is empty.
	ErrMissingOwnerOrRepo = errors.New("owner and repo must not be empty")
)

Functions

func ClassifyWriteError

func ClassifyWriteError(err error) retry.Classification

ClassifyWriteError classifies an error from a GitHub write operation (comment create/edit, label or body mutation) using the shared retry classifier. It is the write-path reconcile-first guard: callers must route ClassUncertainWrite outcomes to reconciliation/operator attention instead of blind POST retries, because the remote effect is unprovable.

func IsUncertainWriteError

func IsUncertainWriteError(err error) bool

IsUncertainWriteError reports whether a write error has an unprovable remote outcome (timeout, lost response, ambiguous 5xx on POST).

func ParsePRURL

func ParsePRURL(prURL string) (owner string, repo string, number int, err error)

ParsePRURL extracts owner, repo, and PR number from a standard GitHub PR URL Supports various URL formats: - https://github.com/owner/repo/pull/123 - http://github.com/owner/repo/pull/123 - https://github.com/owner/repo/pull/123/ - https://github.com/owner/repo/pull/123?query=params

func ParseRepoOwner

func ParseRepoOwner(repoFlag string) []string

ParseRepoOwner splits "owner/repo" into [owner, repo]

func SanitizeCommitHeadline

func SanitizeCommitHeadline(englishSummary, originalInstruction, shortSHA string) string

SanitizeCommitHeadline builds the single bot-authored commit headline `pr-review: <english-summary> "<original>" (<short-sha>)`, capped at 140 chars on one line (D-32, D-35).

englishSummary is the caller-supplied English verdict summary (derived executor-side from the ClassifyEditIntent LLM session; this function never calls the LLM). originalInstruction is always quoted verbatim (TR preserved). When the summary is empty after whitespace-collapse, and only then, the TR-quote-only fallback `pr-review: "<original>" (<sha>)` is used. shortSHA must be 7 hex chars; anything else yields the 0000000 placeholder.

func ValidateCommitOID

func ValidateCommitOID(sha string) error

ValidateCommitOID ensures the commit hash is a full 40-char (SHA-1) or 64-char (SHA-256) hex string. Short prefixes, non-hex characters, and empty strings are rejected (SAFE-01, SAFE-03).

Types

type AppAuth

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

AppAuth manages repository-scoped GitHub App installation authentication. It resolves installations per requested repository (rather than globally caching the first installation returned) and isolates token refreshes per owner/repo.

func (*AppAuth) CreatePushCredential

func (a *AppAuth) CreatePushCredential(ctx context.Context, owner, repo string, repoID int64) (*PushCredential, error)

CreatePushCredential requests an uncached, short-lived GitHub App installation token restricted to exactly one head repository ID with contents:write permission (D-29). It verifies the returned token expiry, scope, and repository selection, rejecting broader or unverifiable credentials. It does not alter the cached review client tokens in a.repos.

func (*AppAuth) CreateRetrievalCredential

func (a *AppAuth) CreateRetrievalCredential(ctx context.Context, owner, repo string, repoID int64) (*RetrievalCredential, error)

CreateRetrievalCredential requests an uncached, short-lived GitHub App installation token restricted to exactly one head repository ID with contents:read permission (D-10, SAFE-01). It verifies the returned token expiry, scope, and repository selection, rejecting broader or unverifiable credentials. It does not alter the cached review client tokens in a.repos.

func (*AppAuth) GetServiceActor

func (a *AppAuth) GetServiceActor(ctx context.Context) (*ServiceActor, error)

func (*AppAuth) RevokePushCredential

func (a *AppAuth) RevokePushCredential(ctx context.Context, cred *PushCredential) error

RevokePushCredential revokes the short-lived push installation access token via DELETE /installation/token and wipes the token string from memory (D-29). Zeroize runs deferred so memory wipes even on revoke failure.

func (*AppAuth) RevokeRetrievalCredential

func (a *AppAuth) RevokeRetrievalCredential(ctx context.Context, cred *RetrievalCredential) error

RevokeRetrievalCredential revokes the short-lived installation access token via DELETE /installation/token and wipes the token string from memory (D-10, D-11).

type Client

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

func NewAppClient

func NewAppClient(appID int64, privateKeyPath string) (*Client, error)

func NewAppClientFromKey

func NewAppClientFromKey(appID int64, keyData []byte) (*Client, error)

NewAppClientFromKey creates a GitHub App client from raw PEM private key bytes.

func NewClient

func NewClient(token string) *Client

func NewClientFromConfig

func NewClientFromConfig(cfg *config.Config) *Client

func NewTestAppClient

func NewTestAppClient(baseURL string, appID int64, privateKey *rsa.PrivateKey) (*Client, error)

NewTestAppClient creates an App-authenticated client pointed at a custom base URL for testing.

func NewTestClient

func NewTestClient(baseURL string) (*Client, error)

NewTestClient creates a GitHub client pointed at a custom base URL for testing.

func NewTestClientWithToken

func NewTestClientWithToken(baseURL, token string) (*Client, error)

NewTestClientWithToken creates a GitHub client pointed at a custom base URL with a static token for testing.

func (*Client) AddLabels

func (c *Client) AddLabels(ctx context.Context, owner, repo string, number int, labels []string) error

func (*Client) AppAuth

func (c *Client) AppAuth() *AppAuth

AppAuth returns the underlying AppAuth instance if configured, or nil.

func (*Client) CanWriteRepository

func (c *Client) CanWriteRepository(ctx context.Context, owner, repo, username string) (bool, error)

CanWriteRepository checks the comment author's current repository permission.

func (*Client) CommitFileAtExpectedHead

func (c *Client) CommitFileAtExpectedHead(ctx context.Context, owner, repo, branch, expectedHeadOID, path, content, message string) (string, error)

CommitFileAtExpectedHead creates a single commit on branch containing only path with content, conditional on the branch head matching expectedHeadOID exactly, using GitHub GraphQL createCommitOnBranch (D-16, SAFE-03). If the branch head does not match expectedHeadOID, it maps the conflict to *HeadMovedError.

func (*Client) CommitFilesAtExpectedHead

func (c *Client) CommitFilesAtExpectedHead(ctx context.Context, owner, repo, branchName, expectedHeadOID, messageHeadline string, files map[string]string, deletions []string) (string, error)

CommitFilesAtExpectedHead creates a single atomic commit on the caller-supplied PR head branch containing every entry of files plus every path in deletions, conditional on the branch head matching expectedHeadOID exactly, using one GitHub GraphQL createCommitOnBranch mutation (D-22, D-24, D-31).

The branch is used exactly as passed (modulo a refs/heads/ prefix strip); this function never substitutes main or any other branch, and fork refusal plus branch selection stay executor-side. Exactly one HTTP mutation runs per call: no REST fallback, no retry on head-moved. Head-moved conflicts map to *HeadMovedError; 403/permission rejections surface as explanatory errors for the executor to relay as comments (D-25), never bypasses.

func (*Client) CreateComment

func (c *Client) CreateComment(ctx context.Context, owner, repo string, number int, body string) (int64, error)

CreateComment creates a comment on an issue or pull request and returns its numeric ID.

func (*Client) CreatePushCredential

func (c *Client) CreatePushCredential(ctx context.Context, owner, repo string, repoID int64) (*PushCredential, error)

CreatePushCredential creates a short-lived App token scoped to exactly one head repository with contents:write permission. If the client is configured with a PAT instead of a GitHub App, it returns ErrPushAuthUnavailable; broad PAT substitution is explicitly denied (D-29).

func (*Client) CreateRetrievalCredential

func (c *Client) CreateRetrievalCredential(ctx context.Context, owner, repo string, repoID int64) (*RetrievalCredential, error)

CreateRetrievalCredential creates a short-lived App token scoped to exactly one head repository with contents:read permission. If the client is configured with a PAT instead of a GitHub App, it returns ErrRetrievalAuthUnavailable; broad PAT substitution is explicitly denied (D-10, SAFE-01).

func (*Client) EditComment

func (c *Client) EditComment(ctx context.Context, owner, repo string, commentID int64, body string) error

EditComment updates an existing issue or pull request comment by its numeric ID.

func (*Client) FindOwnedComment

func (c *Client) FindOwnedComment(ctx context.Context, opts FindOwnedCommentOptions) (*OwnedCommentMatch, error)

FindOwnedComment scans pull request issue comments for a comment matching the verified service actor, stable marker, and optional body digest. Uses pagination (100/page, maximum 20 pages). An incomplete or failed scan yields uncertain, never an absent verdict. Copied markers from ordinary users are ignored.

func (*Client) GetBlob

func (c *Client) GetBlob(ctx context.Context, owner, repo, sha string) (*github.Blob, error)

GetBlob retrieves a git blob by SHA.

func (*Client) GetBlobRaw

func (c *Client) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, error)

GetBlobRaw retrieves raw bytes of a git blob by SHA.

func (*Client) GetComment

func (c *Client) GetComment(ctx context.Context, owner, repo string, commentID int64) (*github.IssueComment, error)

GetComment retrieves an existing issue or pull request comment by its numeric ID.

func (*Client) GetComments

func (c *Client) GetComments(ctx context.Context, owner, repo string, number int) ([]Comment, []DiscussionThread, error)

func (*Client) GetCommit

func (c *Client) GetCommit(ctx context.Context, owner, repo, sha string) (*github.RepositoryCommit, error)

GetCommit retrieves a commit by full SHA from the repository.

func (*Client) GetDiffAtCommits

func (c *Client) GetDiffAtCommits(ctx context.Context, owner, repo, baseOID, headOID string) (string, error)

GetDiffAtCommits retrieves the diff between baseOID and headOID using the GitHub commit comparison endpoint. It requires complete 40 or 64 hex character OIDs (SAFE-03) and sends the GitHub diff media type. Never generates from the mutable PR diff endpoint to prevent ABA head movement risks (D-16).

func (*Client) GetFileContent

func (c *Client) GetFileContent(ctx context.Context, owner, repo, path, ref string) (*FileContent, error)

func (*Client) GetLabels

func (c *Client) GetLabels(ctx context.Context, owner, repo string, number int) ([]string, error)

func (*Client) GetPR

func (c *Client) GetPR(ctx context.Context, owner, repo string, number int) (*PRDetails, error)

func (*Client) GetRawDiff

func (c *Client) GetRawDiff(ctx context.Context, owner, repo string, number int) (string, error)

func (*Client) GetRepoID

func (c *Client) GetRepoID(ctx context.Context, owner, repo string) (int64, error)

GetRepoID returns the numeric GitHub repository ID for owner/repo.

func (*Client) GetTree

func (c *Client) GetTree(ctx context.Context, owner, repo, sha string, recursive bool) (*github.Tree, error)

GetTree retrieves a git tree by SHA, optionally recursive.

func (*Client) NewScopedClient

func (c *Client) NewScopedClient(token string) *Client

NewScopedClient returns a new Client configured with the provided access token while preserving custom BaseURL if set on this client.

func (*Client) PostComment

func (c *Client) PostComment(ctx context.Context, owner, repo string, number int, body string) error

func (*Client) PostDecisionReview

func (c *Client) PostDecisionReview(ctx context.Context, owner, repo string, number int, commitSHA string, event string, body string, suggestions []InlineSuggestion) (*github.PullRequestReview, error)

PostDecisionReview creates ONE review with event APPROVE or REQUEST_CHANGES containing summary body, inline comments, and bound to the exact commit SHA (D-02, D-15).

func (*Client) PostSuggestions

func (c *Client) PostSuggestions(ctx context.Context, owner, repo string, number int, commitSHA string, suggestions []InlineSuggestion) error

PostSuggestions creates one COMMENT review containing inline GitHub suggestion blocks.

func (*Client) RevokePushCredential

func (c *Client) RevokePushCredential(ctx context.Context, cred *PushCredential) error

RevokePushCredential revokes the scoped App push token and zeroes it in memory.

func (*Client) RevokeRetrievalCredential

func (c *Client) RevokeRetrievalCredential(ctx context.Context, cred *RetrievalCredential) error

RevokeRetrievalCredential revokes the scoped App retrieval token and zeroes it in memory.

func (*Client) ServiceActor

func (c *Client) ServiceActor(ctx context.Context, owner, repo string) (*ServiceActor, error)

ServiceActor returns the authenticated user or bot identity of the service.

func (*Client) ServiceActorID

func (c *Client) ServiceActorID(ctx context.Context, owner, repo string) (int64, error)

ServiceActorID returns the numeric user/bot ID of the authenticated service actor.

func (*Client) SetClock

func (c *Client) SetClock(clk retry.Clock)

SetClock allows injecting a fake clock for testing.

func (*Client) SetGraphQLURL

func (c *Client) SetGraphQLURL(u string)

SetGraphQLURL sets an explicit GraphQL endpoint override (for testing or custom enterprise setups).

func (*Client) SetRetryPolicy

func (c *Client) SetRetryPolicy(p retry.Policy)

SetRetryPolicy customizes retry policy for GitHub read operations.

func (*Client) UpdateFile

func (c *Client) UpdateFile(ctx context.Context, owner, repo, path, branch, sha, content, message string) (string, error)

UpdateFile creates one commit on branch containing only path.

func (*Client) UpdatePRBody

func (c *Client) UpdatePRBody(ctx context.Context, owner, repo string, number int, body string) error

UpdatePRBody replaces only the PR description, not its title or other metadata.

type Comment

type Comment struct {
	ID        int64     `json:"id"`
	User      string    `json:"user"`
	Body      string    `json:"body"`
	CreatedAt time.Time `json:"created_at"`

	// Inline review comment specific fields
	Path        string `json:"path,omitempty"`
	Line        int    `json:"line,omitempty"`
	DiffHunk    string `json:"diff_hunk,omitempty"`
	InReplyToID int64  `json:"in_reply_to_id,omitempty"`
}

Comment represents either an issue comment or inline review comment

type DecisionWriteError

type DecisionWriteError struct {
	Err            error
	Classification retry.Classification
}

DecisionWriteError wraps an error from a decision review write and captures its retry classification.

func (*DecisionWriteError) Error

func (e *DecisionWriteError) Error() string

func (*DecisionWriteError) IsUncertain

func (e *DecisionWriteError) IsUncertain() bool

IsUncertain reports whether the write error has an unprovable remote outcome (D-16).

func (*DecisionWriteError) Unwrap

func (e *DecisionWriteError) Unwrap() error

type DiscussionThread

type DiscussionThread struct {
	Path     string    `json:"path"`
	Line     int       `json:"line"`
	DiffHunk string    `json:"diff_hunk"`
	Comments []Comment `json:"comments"`
}

DiscussionThread groups inline comments on the same code location

type FileContent

type FileContent struct {
	Content string
	SHA     string
}

type FindOwnedCommentOptions

type FindOwnedCommentOptions struct {
	Owner      string
	Repo       string
	PRNumber   int
	Marker     string
	BodyDigest string // hex SHA-256; if non-empty, requires matching body digest
	Actor      *ServiceActor
	MaxPages   int // defaults to 20 if <= 0
}

FindOwnedCommentOptions configures bounded owned-comment searches.

type HeadMovedError

type HeadMovedError struct {
	ExpectedHeadOID string
	ActualHeadOID   string
	Message         string
}

HeadMovedError indicates that an expected-head conditional commit mutation failed because the branch head on GitHub moved away from the expected commit OID (D-16, SAFE-03).

func (*HeadMovedError) Error

func (e *HeadMovedError) Error() string

func (*HeadMovedError) Is

func (e *HeadMovedError) Is(target error) bool

type InlineSuggestion

type InlineSuggestion struct {
	Path string
	Line int
	Body string
}

InlineSuggestion is a one-click replacement attached to a changed PR line.

type OwnedCommentMatch

type OwnedCommentMatch struct {
	Found     bool
	CommentID int64
	Body      string
	Uncertain bool
	Reason    string
}

OwnedCommentMatch carries the outcome of an owned-comment lookup.

type PRDetails

type PRDetails struct {
	Owner         string
	Repo          string
	Number        int
	Title         string
	Body          string
	Author        string
	BaseRef       string
	BaseSHA       string // Captured immutable base commit OID (D-16, SAFE-03)
	HeadRef       string
	HeadSHA       string
	HeadRepoOwner string
	HeadRepoName  string
	HeadRepoID    int64
	CloneURL      string
	CreatedAt     time.Time
}

PRDetails holds basic metadata of the pull request

func (*PRDetails) IsFork

func (p *PRDetails) IsFork() bool

IsFork returns true if the pull request originates from a fork or if head repository metadata is missing.

type PushCredential

type PushCredential struct {
	Token        string            `json:"token"`
	ExpiresAt    time.Time         `json:"expires_at"`
	RepositoryID int64             `json:"repository_id"`
	RepoOwner    string            `json:"repo_owner"`
	RepoName     string            `json:"repo_name"`
	Permissions  map[string]string `json:"permissions"`
	// contains filtered or unexported fields
}

PushCredential holds a short-lived, least-privilege App token scoped to exactly one PR head repository with contents:write permission for the gated same-PR push path (D-24, D-29). It lives only in host gateway memory: it is never passed into the container or the LLM prompt/context (T-05-02), and it is revoked plus zeroized after exactly one push call.

func (*PushCredential) IsRevoked

func (c *PushCredential) IsRevoked() bool

IsRevoked returns true if the credential has been revoked or zeroized.

func (*PushCredential) Zeroize

func (c *PushCredential) Zeroize()

Zeroize securely wipes the token from memory, even on revoke failure.

type RetrievalCredential

type RetrievalCredential struct {
	Token        string            `json:"token"`
	ExpiresAt    time.Time         `json:"expires_at"`
	RepositoryID int64             `json:"repository_id"`
	RepoOwner    string            `json:"repo_owner"`
	RepoName     string            `json:"repo_name"`
	Permissions  map[string]string `json:"permissions"`
	// contains filtered or unexported fields
}

RetrievalCredential holds a short-lived, least-privilege App token scoped to exactly one head repository with contents:read permission for private source retrieval (D-10, SAFE-01).

func (*RetrievalCredential) IsRevoked

func (c *RetrievalCredential) IsRevoked() bool

IsRevoked returns true if the credential has been revoked or zeroized.

func (*RetrievalCredential) Zeroize

func (c *RetrievalCredential) Zeroize()

Zeroize securely wipes the token from memory.

type ServiceActor

type ServiceActor struct {
	ID    int64  `json:"id"`
	Login string `json:"login"`
}

ServiceActor represents the verified authenticated identity of the service.

Jump to

Keyboard shortcuts

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