credentials

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package credentials provides secure (preferred) + plaintext (fallback) storage for Sting authentication material.

Isolation Guarantee

This package is deliberately isolated from the user's real GitHub CLI (gh) configuration:

  • We never mutate the GH_CONFIG_DIR environment variable.
  • We never use github.com/cli/go-gh/v2/pkg/config for writing credentials. (That package only supports configuration via GH_CONFIG_DIR, which creates too much risk of accidental leakage or corruption of ~/.config/gh during development, testing, or error conditions.)
  • All insecure (plaintext) credential storage is written exclusively to Sting's own hosts.yml using our own minimal implementation.

The design follows the same logical "hosts.<composite>" structure that gh uses for familiarity, but everything under Sting's own directory.

This package is intentionally internal. The public config package remains focused on query defaults and does not grow auth token concerns.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CredentialRef

type CredentialRef struct {
	Provider Provider
	Host     string
	Username string // may be empty
	Source   Source
}

CredentialRef is a lightweight reference returned by List.

type KeyringBackend

type KeyringBackend interface {
	Set(service, user, secret string) error
	Get(service, user string) (string, error)
	Delete(service, user string) error
}

KeyringBackend is the minimal interface we need from a keyring implementation. This allows tests to inject a mock.

type Provider

type Provider string

Provider identifies a source control system.

const (
	ProviderGitHub Provider = "github"
	ProviderGitLab Provider = "gitlab"
)

type Source

type Source string

Source describes where a token came from (for status + messaging).

const (
	SourceKeyring Source = "keyring"
	SourceFile    Source = "file"
	SourceEnv     Source = "environment" // legacy PATs from STING_TOKEN etc.
	SourceConfig  Source = "config"      // legacy PATs from config file (viper)
)

type Store

type Store interface {
	// Save persists a credential for the given provider + host.
	// secureOnly=true forces an error instead of falling back to plaintext.
	Save(ctx context.Context, provider Provider, host string, tok Token, secureOnly bool) (usedInsecure bool, err error)

	// Load returns the best available token for (provider, host).
	// It applies precedence rules (OAuth > PAT for the same provider+host)
	// and returns the Source so callers (e.g. auth status) can produce
	// appropriate messaging.
	Load(ctx context.Context, provider Provider, host string) (tok Token, src Source, err error)

	// Delete removes credentials for the given provider + host.
	// It attempts to clean both secure and insecure locations.
	Delete(ctx context.Context, provider Provider, host string) error

	// List returns known (provider, host) combinations that have stored credentials.
	// Useful for `auth status --all` or similar.
	List(ctx context.Context) ([]CredentialRef, error)
}

Store is the main abstraction for credential lifecycle.

func New

func New() (Store, error)

New creates a Store using the default discovery order: 1. Try secure keyring via our internal/keyring wrapper. 2. Fall back to our own hosts.yml (no env var mutation, no risk to gh config). The returned Store is safe for concurrent use.

func NewInsecure

func NewInsecure() (Store, error)

NewInsecure creates a Store rooted at Sting's config directory that never uses the system keyring: credentials are always written to the plaintext hosts.yml. This backs the `--insecure-storage` flag so it deterministically forces file storage instead of merely permitting fallback.

func WithFilePath

func WithFilePath(dir string) Store

WithFilePath returns a file-only Store that uses a specific directory for plaintext storage (primarily for hermetic tests). It never consults the system keyring and never touches GH_CONFIG_DIR, so test behavior is deterministic regardless of whether a real keyring is available on the host.

func WithKeyringForTest

func WithKeyringForTest(backend KeyringBackend, configDir string) Store

WithKeyringForTest returns a Store that uses the provided KeyringBackend for the secure path (useful for hermetic tests). A nil backend selects file-only mode (no keyring), matching WithFilePath. The insecure path uses our own file-based storage under the given directory.

type Token

type Token struct {
	Type         TokenType
	AccessToken  string
	RefreshToken string    // may be empty for some providers
	Expiry       time.Time // zero value means no expiry / does not expire
	Username     string    // best-effort; populated after successful auth
}

Token represents a stored credential. For PATs, only AccessToken is populated. For OAuth, the full set may be present.

type TokenType

type TokenType string

TokenType distinguishes the kind of credential.

const (
	TokenTypeOAuth TokenType = "oauth"
	TokenTypePAT   TokenType = "pat"
)

Jump to

Keyboard shortcuts

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