github

package
v0.22.127 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package github — GitHub OAuth Device Flow + tiny REST helpers scoped to clawtool's needs. Today: device-code authorisation + `PUT /user/starred/{owner}/{repo}` for the star feature. More will land as engagement / source-management features need them.

Why Device Flow over web-redirect OAuth: clawtool is a CLI; we have no http server to receive a callback. Device Flow is designed exactly for this — we POST a device-code request, show the user a `user_code` and a verification URL, the user authorises in their browser, we poll the token endpoint until they finish. No redirect URI, no localhost listener, no port collision.

Token storage: handled by the caller via internal/secrets, not here. This package is the wire-protocol shim and stays stateless so tests can drive it with httptest fixtures.

Index

Constants

View Source
const DefaultAPIBaseURL = "https://api.github.com"

DefaultAPIBaseURL is api.github.com's REST root. Same override shape as DefaultBaseURL.

View Source
const DefaultBaseURL = "https://github.com"

DefaultBaseURL is github.com's well-known endpoint. Overridable in tests (httptest fixture) by setting BaseURL on the Client.

Variables

View Source
var ClientID = ""

ClientID is the GitHub OAuth App client_id used by clawtool's CLI surface. Public-by-design (Device Flow doesn't use a client secret; the user-code + browser confirmation IS the security boundary). Empty when the operator hasn't registered an OAuth app yet — the device flow then errors out cleanly via ErrNoClientID instead of crashing.

To wire this in: create a GitHub OAuth App at github.com/settings/developers, set Device flow enabled, copy the resulting client_id into the build via -ldflags '-X github.com/cogitave/clawtool/internal/github.ClientID=<id>' or hard-code below at release time.

View Source
var ErrAuthorizationDenied = errors.New("github: authorization denied by user")

ErrAuthorizationDenied is returned when the user explicitly declined the consent screen.

View Source
var ErrDeviceCodeExpired = errors.New("github: device code expired before authorisation")

ErrDeviceCodeExpired is returned by PollAccessToken when the device code's lifetime ran out before the user authorised. Callers typically restart the flow with a fresh code.

View Source
var ErrNoClientID = errors.New("github: clawtool's GitHub OAuth client_id is not configured")

ErrNoClientID surfaces the "we don't have an OAuth app registered yet" state cleanly so the caller can fall back to a browser-redirect-to-action-page flow.

Functions

func StarPageURL

func StarPageURL(owner, repo string) string

StarPageURL returns the human-facing star page on github.com for the given owner/repo. Used as the OAuth-disabled fallback: open this in the user's browser and let them click Star themselves.

Types

type Client

type Client struct {
	HTTP        *http.Client
	BaseURL     string // for /login/device/code + /login/oauth/access_token
	APIBaseURL  string // for REST endpoints
	UserAgent   string // GitHub asks every API call to set a UA
	ClientIDStr string // override for tests; falls back to package ClientID
}

Client wraps an *http.Client with the URLs and credentials the clawtool→GitHub flows need. Construct via NewClient() and override fields for tests.

func NewClient

func NewClient() *Client

NewClient returns a Client with sane defaults. 30s overall timeout protects against a hung github.com from stranding the CLI; the per-call ctx the caller passes may impose a tighter budget for individual phases.

func (*Client) PollAccessToken

func (c *Client) PollAccessToken(ctx context.Context, dc *DeviceCode) (string, error)

PollAccessToken polls /login/oauth/access_token at the device-code's documented interval until either the user authorises (returns the access token), the code expires (returns ErrDeviceCodeExpired), or the user denies it (returns ErrAuthorizationDenied). ctx cancellation aborts the poll cleanly so a Ctrl-C in the CLI doesn't hang.

func (*Client) RequestDeviceCode

func (c *Client) RequestDeviceCode(ctx context.Context, scopes string) (*DeviceCode, error)

RequestDeviceCode kicks off the device flow with the given space-separated scope list (e.g. "public_repo" for starring public repos). Returns the device code envelope or an error.

func (*Client) StarRepo

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

StarRepo calls `PUT /user/starred/{owner}/{repo}` on the authenticated user's behalf. token is the bearer from PollAccessToken. owner+repo identify the target. Returns nil on success (idempotent — already-starred returns 204 too).

type DeviceCode

type DeviceCode struct {
	DeviceCodeStr   string        `json:"device_code"`
	UserCode        string        `json:"user_code"`
	VerificationURI string        `json:"verification_uri"`
	ExpiresIn       int           `json:"expires_in"` // seconds
	Interval        int           `json:"interval"`   // poll interval, seconds
	Expires         time.Time     `json:"-"`          // computed
	PollEvery       time.Duration `json:"-"`          // computed
}

DeviceCode is the response from the device authorisation endpoint. The CLI shows VerificationURI + UserCode to the operator (and ideally OpenBrowser's the URI), then polls /login/oauth/access_token using DeviceCodeStr until the user authorises or the code expires.

Jump to

Keyboard shortcuts

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