forge

package
v0.3.12 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package forge holds provider-agnostic helpers shared by forge providers - Gitea/Forgejo today, GitHub Enterprise and self-managed GitLab in future: host parsing, same-origin checks, and OAuth PKCE/Link primitives. Everything here is pure and stateless; each provider keeps its own endpoints, token store, and auth flow.

Index

Constants

View Source
const (
	KeySource      = "source"
	SourceTags     = "tags"
	SourceReleases = "releases"
)

KeySource selects what a forge marker discovers; SourceTags and SourceReleases are its two values. Every forge serves both.

Variables

This section is empty.

Functions

func Authorization added in v0.1.1

func Authorization(scheme, token string) string

Authorization joins an auth scheme and token into an Authorization header value, or "" when the token is empty.

func Bearer added in v0.1.1

func Bearer(token string) string

Bearer returns the Authorization value attaching token as a Bearer credential, or "" when the token is empty.

func DeviceLogin added in v0.1.1

func DeviceLogin(
	ctx context.Context,
	cfg DeviceConfig,
	host, clientID string,
	prompt func(Code),
) error

DeviceLogin runs the OAuth device flow cfg describes against host and stores the minted token: it requests a code, hands it to prompt so the caller can show it to the user, polls until the user authorises in the browser, then persists the token under the host so the credential chain finds it. It needs no client secret and binds no local port, so it works headless. host and clientID default to cfg's host and embedded app; a private instance has no embeddable app, so it requires an explicit --client-id. The context bounds the poll.

func Host added in v0.1.1

func Host(label string, d directive.Directive, defaultHost string) (string, error)

Host resolves the optional host key against a forge's default host, normalizing and validating an explicit value.

func NormalizeHost

func NormalizeHost(host string) (string, bool)

NormalizeHost parses a forge host given as a bare name (codeberg.org), a host:port, or a full URL (https://git.example.com/), returning the lowercased host[:port]. ok is false when the value is empty or carries userinfo, a path, query, or fragment - anything that is not a plain network authority - so a marker-controlled host cannot smuggle a path or credentials.

func OwnerName added in v0.1.1

func OwnerName(label string, d directive.Directive) (string, string, error)

OwnerName parses the required repository key as owner/name, framing errors with the provider label.

func PATHost

func PATHost(hostEnv, defaultHost string, pinned bool) string

PATHost returns the single host a host-independent personal access token may be sent to. A PAT is attached to whichever host a marker names, so a marker-controlled host= could otherwise redirect the token to an attacker; the PAT is bound to one host - the hostEnv override (normalized) when set, else defaultHost. When pinned (a test transport), ambient env is ignored and defaultHost is returned, keeping a test hermetic and its auth path deterministic.

func PKCE

func PKCE() (string, string, error)

PKCE returns an RFC 7636 verifier (32 random bytes, 43 base64url chars) and its S256 challenge (the base64url SHA-256 of the verifier), as required by a public OAuth client.

func RandomState

func RandomState() (string, error)

RandomState returns an unguessable OAuth state value (16 random bytes) binding an authorization request to its callback.

func RequireReleasesForAsset added in v0.1.1

func RequireReleasesForAsset(label string, d directive.Directive, source string) error

RequireReleasesForAsset rejects asset= on a non-releases source: asset= filters on release asset filenames, which only releases publish, so a tag candidate has none and the filter would always fail later.

func SameOrigin

func SameOrigin(a, b string) bool

SameOrigin reports whether two URLs share a scheme and host. It guards a paginated lookup from forwarding a credential to a different origin than the one the lookup started on.

func Source added in v0.1.1

func Source(label string, d directive.Directive) (string, error)

Source resolves the optional source key, defaulting to tags and rejecting anything but tags or releases.

Types

type Code added in v0.1.1

type Code struct {
	UserCode        string
	VerificationURL string
}

Code is the user-facing half of the device flow: the one-time code to enter and the URL to enter it at.

type DeviceConfig added in v0.1.1

type DeviceConfig struct {
	Label           string
	DefaultHost     string
	DefaultClientID string
	ClientIDHint    string
	Scopes          []string
	DeviceCodeURL   func(host string) string
	AccessTokenURL  func(host string) string
}

DeviceConfig describes one forge's OAuth device flow: the label framing its errors, the default host and the public client ID embedded for it, the hint shown when a private instance needs --client-id, the scopes to request, and the host-relative endpoints.

type RESTClient added in v0.1.1

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

RESTClient issues a forge's REST GETs over a shared transport. It holds no host or credential: each call carries its own absolute URL and its own Authorization value, since both the host and the credential are per-marker values.

func NewRESTClient added in v0.1.1

func NewRESTClient(httpClient *http.Client, accept string) RESTClient

NewRESTClient returns a client issuing GETs through httpClient, sending accept as the Accept header on every request.

func (RESTClient) DoWithContext added in v0.1.1

func (c RESTClient) DoWithContext(
	ctx context.Context,
	url, authorization string,
	response any,
) (http.Header, error)

DoWithContext issues a GET against the absolute url, attaching authorization (a full header value, e.g. "Bearer <token>") when non-empty, fails on a non-2xx status, decodes the JSON body into response when non-nil, and returns the response headers (for pagination). A stored credential that has expired or been revoked would 401 every request, including public reads that work anonymously; rather than fail those outright, a 401 from a credentialed request is retried once without the credential, so a stale token degrades to anonymous access. Only nil-body GETs are issued here, so the retry is always safe.

func (RESTClient) HTTPClient added in v0.1.1

func (c RESTClient) HTTPClient() *http.Client

HTTPClient returns the underlying client, for requests that go beyond the GET-and-decode surface (e.g. an OAuth token refresh POST) but must share the same transport.

type StatusError added in v0.3.11

type StatusError struct {
	Code   int    // the HTTP status code
	Status string // the status line, e.g. "404 Not Found"
	Body   string // the trimmed response body
}

StatusError is the error RESTClient.DoWithContext returns for a non-2xx response, carrying the status code so a caller can branch on a specific status - e.g. a compare 404 that means two refs share no history rather than a transport failure.

func (*StatusError) Error added in v0.3.11

func (e *StatusError) Error() string

Jump to

Keyboard shortcuts

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