github

package
v0.0.0-...-d11b0ee Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AppAuth

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

AppAuth manages GitHub App installation tokens with automatic refresh. Installation tokens expire after 1 hour; this refreshes at 45 minutes.

func NewAppAuth

func NewAppAuth(appID, installationID int64, keyPath string, log *slog.Logger) (*AppAuth, error)

NewAppAuth loads the PEM key and returns an AppAuth that mints and refreshes GitHub App installation tokens.

func (*AppAuth) Stop

func (a *AppAuth) Stop()

Stop halts the background refresh goroutine.

func (*AppAuth) Token

func (a *AppAuth) Token() string

Token returns the current valid installation token, refreshing it synchronously if the cached token expires within 5 minutes. The background refreshLoop is still the primary path; this is a safety net so a missed background refresh doesn't cause repeated 401s for hours.

type Client

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

Client handles GitHub API interactions and webhook events.

func New

func New(cfg Config) (*Client, error)

New creates a GitHub client. Uses AppAuth for dynamic token refresh when configured, otherwise a static PAT.

All GitHub API responses flow through rateTrackingTransport, which parses the X-RateLimit-* headers and updates the ephemerd_github_api_rate_* gauges. Operators use ephemerd_github_api_rate_updated_seconds to tell a current-but-exhausted budget from a stale reading.

func (*Client) CleanStaleWebhooks

func (c *Client) CleanStaleWebhooks(ctx context.Context)

CleanStaleWebhooks removes any workflow_job webhooks left behind by previous ephemerd instances that crashed or were killed without cleanup. Called on startup before registering new webhooks to avoid hitting GitHub's 20-hook limit.

Skipped entirely in pool mode: this sweep deletes every workflow_job hook it can see, and in a pooled fleet those are live hooks belonging to pool-mates (or other pools). Adoption in RegisterWebhooks makes the sweep unnecessary for pooled nodes — same-URL hooks are reused, not duplicated.

func (*Client) DeregisterWebhooks

func (c *Client) DeregisterWebhooks(ctx context.Context, hooks []ManagedWebhook)

DeregisterWebhooks removes all managed webhooks. Called on shutdown. No-op in pool mode: the hook is shared with pool-mates that are still serving; the pool's lifecycle owner (e.g. mayfly destroying the pool) removes it when the last member goes away.

func (*Client) FetchJobImage

func (c *Client) FetchJobImage(ctx context.Context, repo string, runID int64, jobID int64) string

FetchJobImage fetches the workflow run's job definition and reads the container image declared in the job's `container:` field. This requires an extra API call per job but lets users specify the image directly in their workflow:

jobs:
  build:
    runs-on: [self-hosted, linux, x64]
    container:
      image: ghcr.io/myorg/custom-build:latest
  quick:
    runs-on: [self-hosted, linux, x64]
    container: ghcr.io/myorg/quick:latest  # shorthand

Returns empty string if no container image is set.

func (*Client) IsOrgLevel

func (c *Client) IsOrgLevel() bool

IsOrgLevel returns true when no repos are configured, meaning ephemerd registers runners at the organization level (available to all repos).

func (*Client) PingWebhook

func (c *Client) PingWebhook(ctx context.Context, m ManagedWebhook) error

PingWebhook triggers a ping event for a managed webhook.

func (*Client) PollJobs

func (c *Client) PollJobs(ctx context.Context) ([]JobEvent, error)

PollJobs checks for queued workflow jobs targeting self-hosted runners. If repos are configured, polls those repos. Otherwise, polls all repos in the org.

func (*Client) RateSnapshot

func (c *Client) RateSnapshot() (remaining, limit int64, reset, updated time.Time)

RateSnapshot returns the last-observed rate-limit state. The scheduler uses this to bias retry backoff — when remaining==0 and now < reset, the next attempt is scheduled just after reset instead of blindly falling through the exponential-backoff ladder. Fields are zero-valued when the client hasn't yet made a request or was created via the bare test constructor.

func (*Client) RegisterJITRunner

func (c *Client) RegisterJITRunner(ctx context.Context, repo string, name string, labels []string) (*gh.JITRunnerConfig, error)

RegisterJITRunner creates a just-in-time runner. If repos are configured, registers at the repo level. If repos are empty, registers at the org level (available to all repos in the org).

func (*Client) RegisterWebhooks

func (c *Client) RegisterWebhooks(ctx context.Context, webhookURL, secret string) ([]ManagedWebhook, error)

RegisterWebhooks creates workflow_job webhooks on each configured repo (or the org) pointing at the given URL with the given secret. Returns the managed hooks for cleanup.

It is idempotent: before creating a hook it lists the existing hooks and, if one already points at webhookURL, reuses it instead of creating a duplicate. GitHub rejects a duplicate hook config with HTTP 422, so without this the external-tunnel path (which re-registers on every startup) would fail on the second boot.

In pool mode the reuse is upgraded to adopt: the existing hook (registered by a pool-mate) is edited in place so secret/events/active converge on this member's config — pool members must present one shared secret. A create that still races a pool-mate to a 422 resolves by adopting the winner's hook.

func (*Client) RemoveRunner

func (c *Client) RemoveRunner(ctx context.Context, repo string, runnerID int64) error

RemoveRunner removes a self-hosted runner by ID. Uses org-level or repo-level API depending on configuration.

func (*Client) SetHTTPClient

func (c *Client) SetHTTPClient(ghClient *gh.Client)

SetHTTPClient replaces the underlying go-github client. Used by test infrastructure to point at a fake server.

func (*Client) WebhookHandler

func (c *Client) WebhookHandler(secret string) (http.Handler, <-chan JobEvent)

WebhookHandler returns an http.Handler that processes workflow_job webhook events. Events are sent to the returned channel.

type Config

type Config struct {
	Token string
	Owner string
	Repos []string
	Log   *slog.Logger

	// App auth (used instead of Token when set)
	AppAuth *AppAuth

	// PoolMode changes webhook lifecycle semantics for nodes sharing one
	// public webhook URL: registration adopts an existing same-URL hook,
	// deregistration is a no-op, and the stale-hook sweep is skipped.
	PoolMode bool
}

Config for the GitHub client.

type JobEvent

type JobEvent struct {
	Action string
	Repo   string
	Job    *gh.WorkflowJob
}

JobEvent is emitted when a workflow_job webhook fires.

type ManagedWebhook

type ManagedWebhook struct {
	Repo   string // empty for org-level
	HookID int64
}

ManagedWebhook tracks a webhook created by ephemerd so it can be cleaned up on shutdown.

Jump to

Keyboard shortcuts

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