feat: add multi-profile credential support#7
Conversation
Add multi-profile credential management matching solapi-crm-core CLI
options. Users can now store and switch between multiple API key/secret
pairs using named profiles.
New features:
- `--profile` persistent flag for all commands
- `solactl configure list` to show saved profiles
- `solactl configure use <profile>` to switch active profile
- `solactl configure delete <profile>` to remove a profile
- Backward-compatible auto-migration from old flat credential format
- Profile-aware `configure` and `configure show` commands
File format changed from flat `{api_key, api_secret}` to multi-profile
`{profiles: {...}, active_profile: "..."}` with automatic detection
and migration of the old format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces multi-profile support for the CLI configuration, allowing users to manage multiple sets of API credentials. Key changes include the addition of list, use, and delete subcommands under configure, a new persistent --profile flag, and an updated storage format in credentials.json that maintains backward compatibility with the previous flat structure. Feedback focuses on strengthening error handling: specifically, preventing potential data loss in the Save function when the configuration file is corrupted and improving the specificity of error messages in the list command to distinguish between a missing file and other I/O or parsing errors.
| profileName = DefaultProfile | ||
| } | ||
|
|
||
| cf, _ := loadCredentialsFile() |
There was a problem hiding this comment.
The error from loadCredentialsFile() is being ignored. If the credentials file exists but is corrupted (e.g., invalid JSON), loadCredentialsFile() will return an error and a nil configuration. By ignoring this error, the Save function will proceed to initialize a fresh CredentialsFile and overwrite the existing file, potentially causing data loss of all other stored profiles. You should check if the error is something other than 'file not found' before proceeding.
| cf, _ := loadCredentialsFile() | |
| cf, err := loadCredentialsFile() | |
| if err != nil && !os.IsNotExist(err) { | |
| return fmt.Errorf("설정 파일 로드 실패: %w", err) | |
| } |
| package cmd | ||
|
|
||
| import ( | ||
| "fmt" |
| if err != nil { | ||
| _, _ = fmt.Fprintf(errOut(), "프로필이 없습니다. 'solactl configure'를 실행하세요.\n") | ||
| return nil | ||
| } |
There was a problem hiding this comment.
The current implementation swallows all errors from config.ListProfiles() and provides a generic "No profiles" message. If the configuration file is corrupted or unreadable due to permission issues, this message is misleading and the command incorrectly returns a success exit code (0). It is better to specifically check for the 'file not found' case and return other errors to the caller.
if err != nil {
if os.IsNotExist(err) {
_, _ = fmt.Fprintf(errOut(), "프로필이 없습니다. 'solactl configure'를 실행하세요.\n")
return nil
}
return err
}- Fix nil profile pointer dereference (null value in JSON map) - Fix Load precedence: don't short-circuit on missing profile before applying env vars and CLI flag overrides - Fix Save error handling: propagate parse/permission errors instead of silently overwriting (only treat file-not-exist as empty state) - Fix detectAndLoad: infer active profile from available profiles instead of hardcoding "default" when active_profile is missing - Add atomic file writes (temp file + rename) for crash safety - Add profile name validation (alphanumeric, _, -, max 64 chars) - Fix configure list: distinguish file-not-found from other errors - Add nil profile guard in ListProfiles and mergeConfig - Add tests: nil profile, missing profile with env/flag overrides, corrupt file rejection, profile name validation, inferActiveProfile Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix inferActiveProfile to skip nil profile values (not just missing keys) - Fix temp file leak when os.Rename fails in saveCredentialsFile - Fix gofmt formatting in config_test.go Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add stderr warning when --profile references a non-existent profile so users are not silently redirected to env/flag credentials - Document the unlocked read-modify-write limitation in Save godoc Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevent setting a null profile value as active or failing to reject deletion of a null profile entry. Consistent with inferActiveProfile nil-value handling from round 2. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
nurigo/solapi-crm-coreCLI와 동일한 멀티 프로필 credential 옵션 지원 추가--profilepersistent flag,configure list/use/delete서브커맨드 구현{api_key, api_secret}) → 멀티프로필 format 자동 마이그레이션 (하위 호환)Changes
New files
cmd/configure_list.go—solactl configure list프로필 목록 표시cmd/configure_use.go—solactl configure use <profile>활성 프로필 전환cmd/configure_delete.go—solactl configure delete <profile>프로필 삭제Modified files
pkg/config/config.go—CredentialsFile,LoadOptions,ProfileInfo구조체 추가,Load/Save시그니처 변경, 프로필 관리 함수(SetActiveProfile, DeleteProfile, ListProfiles, ActiveProfileName),detectAndLoad하위 호환 마이그레이션cmd/root.go—--profilepersistent flag 추가,loadConfig()→LoadOptions사용cmd/configure.go— 프로필 인식runConfigure/saveConfigure, 진단 메시지errOut()준수cmd/configure_show.go— Profile 이름 표시,LoadOptions전달pkg/config/config_test.go— 기존 테스트 시그니처 업데이트 + 신규 프로필 테스트 20개 + fuzz 테스트cmd/configure_test.go— 신규 서브커맨드 테스트 12개Test plan
go build ./...컴파일 성공go test ./...전체 테스트 통과go test -race ./...race condition 없음go vet ./...경고 없음solactl configure --profile staging --api-key K --api-secret S프로필 저장solactl configure list프로필 목록 확인solactl configure use staging활성 프로필 전환solactl configure delete staging프로필 삭제solactl configure show자동 마이그레이션 확인🤖 Generated with Claude Code