Documentation
¶
Overview ¶
Package config implements the "config" CLI command and its subcommands for programmatic read/write access to individual configuration keys. It is intended for CI automation and scripted setup rather than interactive use (for interactive reconfiguration, use "init <subsystem>" instead).
Index ¶
- func NewCmdConfig(props *p.Props, opts ...MaskerOption) *setup.Command
- func NewCmdEdit(props *p.Props, opts ...EditOption) *cobra.Command
- func NewCmdGet(props *p.Props, masker *Masker) *cobra.Command
- func NewCmdList(props *p.Props, masker *Masker) *cobra.Command
- func NewCmdMigrate(props *p.Props, options ...MigrateCmdOption) *cobra.Command
- func NewCmdPath(props *p.Props) *cobra.Command
- func NewCmdSet(props *p.Props) *cobra.Command
- func NewCmdTrust(props *p.Props) *cobra.Command
- func NewCmdUnset(props *p.Props) *cobra.Command
- func NewCmdValidate(props *p.Props) *cobra.Command
- func PrintResult(w io.Writer, result *MigrateResult, dryRun bool)
- type EditOption
- type Masker
- type MaskerOption
- type MigrateCmdOption
- type MigrateOptions
- type MigrateResult
- type MigrationAction
- type Verification
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewCmdConfig ¶
func NewCmdConfig(props *p.Props, opts ...MaskerOption) *setup.Command
NewCmdConfig returns the top-level "config" command with all subcommands attached. MaskerOptions extend the built-in sensitive key and value patterns, allowing tool authors to register their own credential formats.
func NewCmdEdit ¶ added in v0.22.0
func NewCmdEdit(props *p.Props, opts ...EditOption) *cobra.Command
NewCmdEdit returns the "config edit" subcommand. It opens the writable config file in the user's editor, re-validates the result on save, and persists only if it is valid — aborting (and leaving the original untouched) on a non-zero editor exit, a YAML syntax error, or a schema validation failure.
func NewCmdList ¶
NewCmdList returns the "config list" subcommand.
func NewCmdMigrate ¶
func NewCmdMigrate(props *p.Props, options ...MigrateCmdOption) *cobra.Command
NewCmdMigrate returns the `config migrate-credentials` subcommand. The command is wired into NewCmdConfig alongside get / set / list / validate.
func NewCmdPath ¶ added in v0.22.0
NewCmdPath returns the "config path" subcommand. It prints the ordered list of config files that contributed to the live configuration (in merge order) followed by the writable target that set/unset/edit mutate. With --writable it prints only that target, for use in scripts.
func NewCmdTrust ¶ added in v0.34.0
NewCmdTrust returns the "config trust" subcommand. A project-local ".<tool>.yaml" at a repository root can tune workflow settings, but its security-sensitive keys (self-update verification, telemetry consent, credentials) are IGNORED until the user explicitly trusts the file — so a hostile clone cannot downgrade security posture just by shipping one. This command records the current content of the discovered (or named) project-local file as trusted, direnv-style: editing the file afterwards revokes trust until it is re-run.
func NewCmdUnset ¶ added in v0.22.0
NewCmdUnset returns the "config unset <key>" subcommand — the inverse of "config set". It removes a single dot-notation key from the user's writable config file, re-validates the result, and persists atomically only if valid.
func NewCmdValidate ¶
NewCmdValidate returns the "config validate" subcommand.
func PrintResult ¶
func PrintResult(w io.Writer, result *MigrateResult, dryRun bool)
PrintResult writes a human-readable summary of result to w. Used by NewCmdMigrate but exported for reuse in tests and custom output paths.
Types ¶
type EditOption ¶ added in v0.22.0
type EditOption func(*editConfig)
EditOption configures NewCmdEdit. Used by tests to inject a fake editor and interactivity check; production uses the defaults.
func WithEditorRunner ¶ added in v0.22.0
func WithEditorRunner(r editorRunner) EditOption
WithEditorRunner overrides the editor-launch seam (default: a real subprocess via exec.CommandContext). Tests inject a deterministic mutator.
func WithInteractiveCheck ¶ added in v0.22.0
func WithInteractiveCheck(fn func() bool) EditOption
WithInteractiveCheck overrides the TTY gate (default: utils.IsInteractive). Tests inject a constant so the round-trip runs without a real terminal.
type Masker ¶
type Masker struct {
// contains filtered or unexported fields
}
Masker detects and masks sensitive configuration values using two independent strategies: key-name pattern matching and value content regular expressions. The zero value is not useful; construct with NewMasker.
func NewMasker ¶
func NewMasker(opts ...MaskerOption) *Masker
NewMasker constructs a Masker with built-in key patterns and value regexes, extended by any provided options. Built-in defaults are never mutated.
func (*Masker) IsSensitive ¶
IsSensitive returns true if any dot-segment of the key matches a sensitive key pattern OR the value matches a sensitive value pattern. Segment-level matching catches credential keys like "github.auth.value" or "bitbucket.username.env" whose leaf is generic ("value", "env") but whose mid-path identifies the credential.
func (*Masker) Mask ¶
Mask returns the value with all but the last 4 characters replaced by asterisks. Returns a fully asterisked string if the value is 4 characters or fewer.
func (*Masker) MaskIfSensitive ¶
MaskIfSensitive applies Mask only when IsSensitive returns true for the given key/value pair; otherwise returns the value unchanged.
type MaskerOption ¶
type MaskerOption func(*Masker)
MaskerOption configures a Masker.
func WithKeyPattern ¶
func WithKeyPattern(pattern string) MaskerOption
WithKeyPattern registers an additional key-name substring (case-insensitive) that marks a key as sensitive. Extends the built-in list; does not replace it.
func WithValuePattern ¶
func WithValuePattern(re *regexp.Regexp) MaskerOption
WithValuePattern registers an additional compiled regexp that, when matched against a value, marks it as sensitive regardless of the key name.
type MigrateCmdOption ¶ added in v0.38.0
type MigrateCmdOption func(*migrateCmdSettings)
MigrateCmdOption configures NewCmdMigrate.
func WithModeEnvironment ¶ added in v0.38.0
func WithModeEnvironment(env credentialposture.ModeEnvironment) MigrateCmdOption
WithModeEnvironment fixes the environment the command uses to pick a default target, instead of discovering it from the process.
Tests need this. Discovery reads whether stdin is a terminal and whether a keychain answers, and a test asserting on the default target otherwise passes or fails on facts about the machine running it — which is how this landed a red pipeline: GitLab's runners allocate a TTY, so a command test that was green here was not there.
type MigrateOptions ¶
type MigrateOptions struct {
// DryRun prints the planned changes but does not write the
// config or call the keychain backend.
DryRun bool
// Target selects the destination storage mode. Defaults to
// [credentials.ModeEnvVar] if unset.
Target credentials.Mode
// AssumeYes skips every interactive prompt. Env-var names fall
// back to the upstream-standard defaults; keychain account names
// follow the wizard convention. Intended for CI pipelines and
// scripted migrations.
AssumeYes bool
// EnvVarOverrides maps source config key → chosen env var name.
// Lets non-interactive callers pin a specific env var per
// credential (e.g. `--env-var anthropic.api.key=MYTOOL_ANTHROPIC`).
// Overrides both defaults and interactive prompts.
EnvVarOverrides map[string]string
// KeychainService overrides the keychain service (the first half
// of the <service>/<account> reference). Defaults to the tool's
// name (`props.Tool.Name`), matching the setup wizards.
KeychainService string
// ModeEnv describes the environment used to pick a default target when
// neither --target nor the config key states one. The zero value means
// "non-interactive, no usable keychain", which resolves to an
// environment-variable reference. Commands populate it with
// [credentialposture.DiscoverModeEnvironment]; tests state it outright.
ModeEnv credentialposture.ModeEnvironment
// SkipVerify disables the post-export verification step in
// interactive env-var mode. Useful for headless automation
// where the user sets env vars via /etc/profile or systemd
// drop-ins rather than an interactive shell.
SkipVerify bool
}
MigrateOptions configures the migrate-credentials flow. The zero value is a dry-run against credentials.ModeEnvVar with interactive prompting — safe to run without fear of mutation.
type MigrateResult ¶
type MigrateResult struct {
// Actions is the set of candidate migrations found in config,
// with status filled in. Useful for machine-readable output.
Actions []MigrationAction
// WroteConfig is true when the config file on disk was rewritten.
// Always false in DryRun mode.
WroteConfig bool
}
MigrateResult summarises the outcome of a migrate run.
func Migrate ¶
func Migrate(ctx context.Context, props *p.Props, opts MigrateOptions) (*MigrateResult, error)
Migrate performs the migration described by opts against [props.Config]. Safe to call multiple times — already-migrated credentials are detected and skipped.
type MigrationAction ¶
type MigrationAction struct {
// Verified records what was proved before the literal was removed.
Verified Verification
// RotationRequired is always true for a migrated literal: the value has
// already been on disk, so wherever that config travelled — a dotfile
// repository, a backup, a support bundle — it is still there. Moving which
// copy WINS does not retire the one that leaked.
RotationRequired bool
// SourceKey is the config key currently holding the literal
// credential (e.g. `anthropic.api.key`, `github.auth.value`).
// For dual credentials this is the "primary" half (username).
SourceKey string
// PartnerKey is set for dual-credential pairs where both halves
// migrate together (only `bitbucket.username` + `bitbucket.app_password`
// today). Empty for single-value credentials.
PartnerKey string
// Target is the mode this credential was migrated to.
Target credentials.Mode
// DestKey is the config key written after migration. For
// env-var targets: `<prefix>.env`. For keychain: `<prefix>.keychain`.
// For Bitbucket dual-cred keychain target, only one key is
// written (the shared `bitbucket.keychain`); PartnerKey is still
// set so the report lists both removed literals.
DestKey string
// DestValue is the written value — an env var name (env-var
// target) or a `<service>/<account>` reference (keychain
// target). The source credential value is NEVER included here.
DestValue string
// Skipped is true when the credential was already migrated or
// could not be migrated (e.g. keychain target with no backend
// registered). Reason explains why.
Skipped bool
Reason string
}
type Verification ¶ added in v0.38.0
type Verification string
MigrationAction describes a single migration the command will perform (dry-run) or has performed. Verification records what was proved about a migrated credential before its literal was destroyed.
It exists because "migrated" meant different things per target mode and the difference was invisible: the env-var path confirmed the replacement resolved, the keychain path confirmed only that a write returned nil.
const ( // VerifiedNone means nothing was proved — the operator passed --skip-verify. VerifiedNone Verification = "not verified" // VerifiedEnvVarSet means the named environment variable was readable in // this process before the literal was staged for removal. VerifiedEnvVarSet Verification = "environment variable resolves" // VerifiedKeychainReadBack means the secret was written to the keychain and // read back unchanged before the literal was staged for removal. VerifiedKeychainReadBack Verification = "keychain entry reads back" // VerifiedResolvesAfterRewrite means the credential still resolved from its // new home once the rewritten config was re-read. // // Named for what it proves rather than what was asked for. The issue this // closes wanted proof that a fresh process AUTHENTICATES; that needs // per-provider knowledge GTB does not have, so this is the weaker, // truthful claim. VerifiedResolvesAfterRewrite Verification = "resolves from its new home" )