v0.x: setup.Initialiser.Configure gains a context parameter¶
What changed¶
The 2026-07-23 architectural review found (CRITICAL) that the forge setup
wizard ran its entire interactive credential stage — storage-mode forms, the
OAuth device flow, and the keychain write — under one 5-second
credentials.KeychainOpTimeout context, so interactive OAuth login always
timed out and silently fell back to manual token entry (spec
2026-07-23-setup-credential-stage-context-scoping).
The fix threads the command context through the initialiser seam and scopes keychain deadlines to individual operations. Three public signatures changed:
| Before | After |
|---|---|
Initialiser.Configure(p *props.Props, cfg Editor) error |
Configure(ctx context.Context, p *props.Props, cfg Editor) error |
forge.RunGitHubInit(p, cfg) |
forge.RunGitHubInit(ctx, p, cfg) |
forge.RunBitbucketInit(p, cfg, opts...) |
forge.RunBitbucketInit(ctx, p, cfg, opts...) |
setup.Initialise, forge.RunGitHubInitCmd, and forge.RunBitbucketInitCmd
already accepted a context and now forward it instead of dropping it.
Migrating a custom Initialiser¶
Add the context parameter to your Configure implementation. The contract:
- The caller's context carries no deadline — interactive stages run at human pace, and cancellation (Ctrl-C) must abort in-flight work.
- Derive a fresh
context.WithTimeout(ctx, credentials.KeychainOpTimeout)at each keychain/backend call site, never spanning a form or OAuth stage.
func (i *MyInitialiser) Configure(ctx context.Context, p *props.Props, cfg setup.Editor) error {
// forms, prompts ... (ctx unbounded)
storeCtx, cancel := context.WithTimeout(ctx, credentials.KeychainOpTimeout)
defer cancel()
return credentials.Store(storeCtx, toolName, account, secret)
}
Callers that invoked Configure directly should pass the cobra command's
context (cmd.Context()); in tests, t.Context().