setup

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2026 License: MIT Imports: 42 Imported by: 0

README

Setup

Bootstrapping logic for tool initialization and self-updating capabilities.

Features

  • Interactive tool initialization (init flow)
  • GitHub & GitLab authentication and SSH key management
  • Automated self-update system with pluggable release providers
  • Semantic version management

For detailed documentation and integration guides, see the Setup Component Documentation.

Documentation

Overview

Package setup provides initialisation helpers for GTB-based tools, including configuration directory bootstrapping, default config file creation, and self-update orchestration.

The Initialiser interface supports a modular hook-based pattern for extending the init process — SSH key setup, authentication configuration, and custom post-init steps can be composed and ordered. Update checks use semantic version comparison against the configured release source (GitHub or GitLab).

Package setup provides self-update and bootstrap functionality for GTB-based tools. This file registers all built-in release providers via blank imports so that they are available whenever pkg/setup is imported.

Index

Constants

View Source
const (
	UpdatedKey = timeSinceKey("updated")
	CheckedKey = timeSinceKey("checked")
)
View Source
const (
	DefaultConfigFilename = "config.yaml"
)

Variables

View Source
var (
	// MaxChecksumsSize caps the byte length of a downloaded checksums
	// manifest. A GoReleaser manifest for a typical multi-OS release
	// is ~1 KiB; 1 MiB is 1000× headroom.
	MaxChecksumsSize int64 = 1 << 20

	// MaxBinaryDownloadSize caps the byte length of a downloaded
	// binary asset. 512 MiB is far above any realistic CLI binary;
	// raise this only for tools that legitimately ship larger artefacts.
	MaxBinaryDownloadSize int64 = 512 << 20
)

Size bounds on untrusted inputs. Exported as variables so tools with exceptional release layouts can reassign them before calling Update; the defaults are generous but protect against a hostile server streaming an unbounded response.

View Source
var DefaultConfig []byte
View Source
var DefaultRequireChecksum = false

DefaultRequireChecksum is the compile-time default for checksum enforcement when neither config nor env var provides one. Tool authors should set this to true in main() for security-critical tools that want fail-closed verification from day one.

View Source
var ErrChecksumAssetNotFound = errors.New("asset not found in checksums manifest")

ErrChecksumAssetNotFound is returned when the target filename is not listed in the checksums manifest. The release may have been created without GoReleaser or with a non-default checksums layout.

View Source
var ErrChecksumManifestMalformed = errors.New("checksums manifest is malformed")

ErrChecksumManifestMalformed is returned when the checksums manifest does not conform to the expected GoReleaser format (`<sha256-hex> <filename>` per line). Rather than silently skip malformed lines, the parser rejects the entire manifest so a truncated or corrupted download never produces a false pass.

View Source
var ErrChecksumTooLarge = errors.New("download exceeds maximum size")

ErrChecksumTooLarge is returned when either the checksums manifest or the binary download exceeds its configured size bound. Indicates a hostile or misbehaving server; the update aborts before hashing.

Functions

func AddCommandWithMiddleware deprecated

func AddCommandWithMiddleware(parent, cmd *cobra.Command, feature props.FeatureCmd)

AddCommandWithMiddleware adds cmd as a subcommand of parent and wraps cmd.RunE with the middleware Chain for feature.

Deprecated: use Command.Register instead. AddCommandWithMiddleware remains as a thin shim that delegates to Register and will be removed in v1.0. Unlike the prior implementation it does NOT recursively re-wrap descendants with feature — each command should be wrapped with its own feature at construction (via Wrap) and added to its parent via the parent's Register method, which wires middleware exactly once per command.

func ApplyMiddlewareRecursively deprecated

func ApplyMiddlewareRecursively(cmd *cobra.Command, feature props.FeatureCmd)

ApplyMiddlewareRecursively applies middleware to cmd and all of its descendants with the same feature key.

Deprecated: prefer wrapping each command with its own feature at construction (via Wrap) and registering subcommands via Command.Register, which wires middleware exactly once per command. ApplyMiddlewareRecursively remains for backward compatibility and will be removed in v1.0.

func Chain

func Chain(feature props.FeatureCmd, runE func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error

Chain applies all registered middleware (global + feature-specific) to the given RunE function and returns the wrapped function.

func GetChecks

func GetChecks() map[props.FeatureCmd][]CheckProvider

GetChecks returns a snapshot of all registered check providers.

func GetDefaultConfigDir

func GetDefaultConfigDir(fs afero.Fs, name string) string

GetDefaultConfigDir returns the default config directory for the named tool (~/.toolname/).

func GetFeatureFlags

func GetFeatureFlags() map[props.FeatureCmd][]FeatureFlag

GetFeatureFlags returns a snapshot of all registered feature flag providers.

func GetInitialisers

func GetInitialisers() map[props.FeatureCmd][]InitialiserProvider

GetInitialisers returns a snapshot of all registered initialiser providers.

func GetSubcommands

func GetSubcommands() map[props.FeatureCmd][]SubcommandProvider

GetSubcommands returns a snapshot of all registered subcommand providers.

func GetTimeSinceLast

func GetTimeSinceLast(fs afero.Fs, name string, status timeSinceKey) time.Duration

GetTimeSinceLast returns the duration since the last update check or update.

func Initialise

func Initialise(props *props.Props, opts InitOptions) (string, error)

Initialise creates the default configuration file in the specified directory.

func Register

func Register(feature props.FeatureCmd, ips []InitialiserProvider, sps []SubcommandProvider, fps []FeatureFlag)

Register adds initialisers, subcommands, and flags for a specific feature. Panics if the registry has been sealed.

func RegisterChecks

func RegisterChecks(feature props.FeatureCmd, cps []CheckProvider)

RegisterChecks adds diagnostic check providers for a specific feature. Panics if the registry has been sealed.

func RegisterGlobalMiddleware

func RegisterGlobalMiddleware(mw ...Middleware)

RegisterGlobalMiddleware adds middleware that is applied to all feature commands. Global middleware runs before feature-specific middleware in the chain.

func RegisterMiddleware

func RegisterMiddleware(feature props.FeatureCmd, mw ...Middleware)

RegisterMiddleware adds middleware that will be applied to commands belonging to the specified feature. Middleware is applied in registration order.

func ResetRegistryForTesting

func ResetRegistryForTesting()

ResetRegistryForTesting clears both the middleware and feature registries. This should only be used in tests to avoid state leakage between test runs.

func Seal

func Seal()

Seal prevents further middleware registration. Called after all commands have been registered.

func SealRegistry

func SealRegistry()

SealRegistry prevents further feature registration. Called after all commands have been registered. Subsequent Register* calls will panic.

func SetTimeSinceLast

func SetTimeSinceLast(fs afero.Fs, name string, status timeSinceKey) error

SetTimeSinceLast records the current time as the last check or update timestamp.

func SkipUpdateCheck

func SkipUpdateCheck(fs afero.Fs, name string, cmd *cobra.Command) bool

SkipUpdateCheck returns true if the update check should be skipped for this invocation.

func VerifyChecksum

func VerifyChecksum(fs afero.Fs, sidecarPath string, data []byte) error

VerifyChecksum reads a SHA-256 sidecar file and verifies it against the provided data. The sidecar format is "<hex-hash> <filename>" (matching sha256sum output and GoReleaser checksums.txt entries). Returns nil if the checksum matches, or an error with a hint on mismatch.

Hash comparison uses subtle.ConstantTimeCompare on decoded bytes. This is defence-in-depth — practical timing attacks on checksum comparison of unknown binary content are infeasible, but the constant-time primitive eliminates the class of concern at near-zero cost and makes future audits simpler.

func VerifyChecksumFromManifest

func VerifyChecksumFromManifest(manifest []byte, filename string, data []byte) error

VerifyChecksumFromManifest verifies data against a named entry in a GoReleaser-style checksums manifest. The manifest format is one "<hex-sha256> <filename>" entry per line; blank lines are permitted at end-of-file. Every non-blank line must match the expected shape or the manifest is rejected as malformed.

Returns nil if the checksum matches, ErrChecksumAssetNotFound if the filename is not listed, ErrChecksumManifestMalformed on invalid syntax, or an error wrapping errors.WithHint on mismatch.

func VerifyChecksumFromManifestReader

func VerifyChecksumFromManifestReader(
	manifest []byte,
	filename string,
	dataReader io.Reader,
	dst io.Writer,
	maxBytes int64,
) (int64, error)

VerifyChecksumFromManifestReader is the streaming equivalent of VerifyChecksumFromManifest. It computes the SHA-256 of dataReader while copying into dst, avoiding a second pass over multi-megabyte binary data.

maxBytes bounds the total copied; exceeding it returns ErrChecksumTooLarge. A typical caller passes MaxBinaryDownloadSize.

Returns the number of bytes copied on success, or an error on checksum mismatch, size-limit violation, or copy/IO failure. The manifest is parsed before any bytes are hashed, so a manifest- lookup failure aborts without touching dst.

Types

type CheckFunc

type CheckFunc func(ctx context.Context, props *props.Props) CheckResult

CheckFunc is the signature for individual diagnostic checks.

type CheckProvider

type CheckProvider func(p *props.Props) []CheckFunc

CheckProvider is a function that returns diagnostic checks for a feature.

type CheckResult

type CheckResult struct {
	Name    string `json:"name"`
	Status  string `json:"status"`
	Message string `json:"message"`
	Details string `json:"details,omitempty"`
}

CheckResult represents the outcome of a single diagnostic check.

type Command added in v0.5.0

type Command struct {
	*cobra.Command

	// Feature is the middleware lookup key. The empty string means "no
	// feature-specific middleware" (global middleware still applies).
	Feature props.FeatureCmd
}

Command composes cobra.Command with the middleware feature key it belongs to. The feature is the lookup key Chain uses to find feature-specific middleware (registered via RegisterMiddleware).

Composing rather than wrapping means callers can use any cobra.Command method directly (the embedded pointer satisfies the interface), and code that needs the raw *cobra.Command — e.g. to pass to a cobra API or store in a parent's Commands() slice — accesses it via .Command.

Commands are typically built via Wrap in each generated NewCmd<Name> constructor and attached to a parent via the parent's Command.Register method, which wires middleware automatically. See the `2026-05-30-command-composition-registration` spec.

func Wrap added in v0.5.0

func Wrap(feature props.FeatureCmd, cmd *cobra.Command) *Command

Wrap pairs a cobra command with the feature it belongs to. The returned *Command embeds cmd, so it behaves as a cobra.Command for every method cobra offers; .Command exposes the underlying pointer when the cobra API needs *cobra.Command directly.

func (*Command) Register added in v0.5.0

func (c *Command) Register(children ...*Command)

Register adds each child as a subcommand and wraps the child's RunE with the middleware Chain for the child's own feature.

Each child is wrapped exactly once, at the point its parent registers it. A child's own descendants are wired when the child registers them, so Register never re-wraps a subtree (unlike the legacy recursive ApplyMiddlewareRecursively path, which re-applied the parent's feature down the tree).

Children with a nil RunE (pure command groups) are still attached but receive no RunE-wrapping — there is nothing to wrap.

type FeatureFlag

type FeatureFlag func(cmd *cobra.Command)

FeatureFlag is a function that registers flags on a cobra command.

type FeatureRegistry

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

FeatureRegistry holds the registered initialisers, subcommands, flags, and checks for features. All access is serialised by registryMu so concurrent init() calls and parallel tests are race-free.

type InitOptions

type InitOptions struct {
	Dir          string
	Clean        bool
	SkipLogin    bool
	SkipKey      bool
	SkipAI       bool
	Initialisers []Initialiser
}

InitOptions holds the options for the Initialise function.

type Initialiser

type Initialiser interface {
	// Name returns a human-readable name for logging.
	Name() string
	// IsConfigured returns true if this initialiser's config is already present.
	IsConfigured(cfg config.Containable) bool
	// Configure runs the interactive config and writes values into cfg.
	Configure(p *props.Props, cfg config.Containable) error
}

Initialiser is an optional config step that can check if it's already configured and, if not, interactively populate the shared viper config.

type InitialiserProvider

type InitialiserProvider func(p *props.Props) Initialiser

InitialiserProvider is a function that creates an Initialiser.

type Middleware

type Middleware func(next func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) error

Middleware wraps a cobra RunE function with additional behaviour. The middleware receives the next handler in the chain and returns a new handler that may execute logic before and/or after calling next.

func WithAuthCheck

func WithAuthCheck(keys ...string) Middleware

WithAuthCheck returns middleware that validates the specified configuration keys are non-empty before allowing command execution. If any key is empty, a descriptive error is returned without executing the command.

func WithRecovery

func WithRecovery(l logger.Logger) Middleware

WithRecovery returns middleware that catches panics in the command handler and converts them to errors. The panic value and stack trace are logged at Error level.

func WithTelemetry

func WithTelemetry(p *props.Props) Middleware

WithTelemetry returns middleware that automatically tracks command invocations via the telemetry collector on Props. Records command name, duration, and exit code for every command execution. No-op when the collector is nil or telemetry is disabled (the collector is a noop in that case).

func WithTiming

func WithTiming(l logger.Logger) Middleware

WithTiming returns middleware that logs command execution duration.

type SelfUpdater

type SelfUpdater struct {
	Tool props.Tool

	CurrentVersion string
	NextRelease    release.Release
	Fs             afero.Fs
	// contains filtered or unexported fields
}

SelfUpdater manages checking for and applying tool updates.

func NewOfflineUpdater

func NewOfflineUpdater(tool props.Tool, log logger.Logger, fs afero.Fs, opts ...UpdaterOption) *SelfUpdater

NewOfflineUpdater creates a SelfUpdater configured for file-based updates that do not require a VCS client or network access.

func NewUpdater

func NewUpdater(ctx context.Context, p *props.Props, version string, force bool) (*SelfUpdater, error)

NewUpdater creates a SelfUpdater configured with the tools release source. The context is forwarded to vcs.ResolveTokenContext for private-repository token resolution, so remote-store credential backends (Vault, SSM) honour the caller's deadline when fetching the release token.

func (*SelfUpdater) DownloadAsset

func (s *SelfUpdater) DownloadAsset(ctx context.Context, asset release.ReleaseAsset) (bytes.Buffer, error)

DownloadAsset downloads the raw bytes of a release asset.

func (*SelfUpdater) GetCurrentVersion

func (s *SelfUpdater) GetCurrentVersion() string

func (*SelfUpdater) GetLatestRelease

func (s *SelfUpdater) GetLatestRelease(ctx context.Context) (release.Release, error)

func (*SelfUpdater) GetLatestVersionString

func (s *SelfUpdater) GetLatestVersionString(ctx context.Context) (string, error)

func (*SelfUpdater) GetReleaseNotes

func (s *SelfUpdater) GetReleaseNotes(ctx context.Context, from string, to string) (string, error)

GetReleaseNotes retrieves the release notes for releases between the specified 'from' and 'to' versions (inclusive).

func (*SelfUpdater) GetStructuredReleaseNotes

func (s *SelfUpdater) GetStructuredReleaseNotes(ctx context.Context, from, to string, archive ...bytes.Buffer) (*changelog.Changelog, error)

GetStructuredReleaseNotes retrieves release notes between two versions and returns them as a parsed Changelog. If an archive buffer is provided, it attempts to extract a bundled CHANGELOG.md first, falling back to per-release API calls when the archive contains no changelog.

func (*SelfUpdater) IsLatestVersion

func (s *SelfUpdater) IsLatestVersion(ctx context.Context) (bool, string, error)

IsLatestVersion checks if the current running binary is the latest version.

func (*SelfUpdater) Update

func (s *SelfUpdater) Update(ctx context.Context) (string, error)

Update installs the latest version of the binary to the resolved target path.

func (*SelfUpdater) UpdateFromFile

func (s *SelfUpdater) UpdateFromFile(filePath string) (string, error)

UpdateFromFile installs a binary from a local .tar.gz file. If a .sha256 sidecar file exists at filePath+".sha256", the checksum is verified before extraction. Returns the installation target path.

type SubcommandProvider

type SubcommandProvider func(p *props.Props) []*cobra.Command

SubcommandProvider is a function that creates a slice of cobra subcommands.

type UpdaterOption

type UpdaterOption func(*SelfUpdater)

UpdaterOption configures a SelfUpdater.

func WithExecLookPath

func WithExecLookPath(fn func(string) (string, error)) UpdaterOption

WithExecLookPath overrides exec.LookPath for testing.

func WithOsExecutable

func WithOsExecutable(fn func() (string, error)) UpdaterOption

WithOsExecutable overrides os.Executable for testing.

Directories

Path Synopsis
Package ai provides factory functions that construct chat.ChatClient instances from Props configuration, resolving the configured provider (Claude, OpenAI, Gemini) and wiring API keys, model selection, and token limits for use in documentation generation and agentic verification loops.
Package ai provides factory functions that construct chat.ChatClient instances from Props configuration, resolving the configured provider (Claude, OpenAI, Gemini) and wiring API keys, model selection, and token limits for use in documentation generation and agentic verification loops.
Package bitbucket implements the interactive setup wizard for Bitbucket Cloud authentication.
Package bitbucket implements the interactive setup wizard for Bitbucket Cloud authentication.
Package github provides GitHub-specific setup helpers including token resolution from configuration and environment, and authenticated HTTP client construction for use with the GitHub API.
Package github provides GitHub-specific setup helpers including token resolution from configuration and environment, and authenticated HTTP client construction for use with the GitHub API.
Package telemetry registers the telemetry initialiser with the setup system.
Package telemetry registers the telemetry initialiser with the setup system.

Jump to

Keyboard shortcuts

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