CP4D 인증 방식을 등록 단계에서 분리
Some checks failed
Release Gate / gate (push) Has been cancelled

모델 등록 UI에 CP4D 사용자 이름+비밀번호 방식과 사용자 이름+API 키 방식을 별도 인증 유형으로 추가하고 선택에 따라 입력 라벨이 달라지도록 정리했습니다.

LlmService, SettingsViewModel, AppSettings를 갱신해 cp4d_password와 cp4d_api_key 저장값을 공식 지원하고 기존 cp4d 값은 비밀번호 방식으로 계속 호환되게 유지했습니다.

README와 DEVELOPMENT 문서를 2026-04-06 17:01 (KST) 기준으로 갱신했고 Release 빌드 경고 0 오류 0을 확인했습니다.
This commit is contained in:
2026-04-06 16:55:10 +09:00
parent fd3af15e54
commit 17d7b515ce
6 changed files with 36 additions and 16 deletions

View File

@@ -1383,7 +1383,7 @@ public class RegisteredModel
// ── CP4D (IBM Cloud Pak for Data) 인증 ──────────────────────────────
/// <summary>인증 방식. bearer (기본) | ibm_iam | cp4d</summary>
/// <summary>인증 방식. bearer (기본) | ibm_iam | cp4d_password | cp4d_api_key</summary>
[JsonPropertyName("authType")]
public string AuthType { get; set; } = "bearer";
@@ -1395,7 +1395,7 @@ public class RegisteredModel
[JsonPropertyName("cp4dUsername")]
public string Cp4dUsername { get; set; } = "";
/// <summary>CP4D 비밀번호 또는 API 키 (EncryptionEnabled=true 시 암호화 저장)</summary>
/// <summary>CP4D 비밀번호 또는 API 키 (인증 방식에 따라 사용, EncryptionEnabled=true 시 암호화 저장)</summary>
[JsonPropertyName("cp4dPassword")]
public string Cp4dPassword { get; set; } = "";
}

View File

@@ -344,7 +344,9 @@ public partial class LlmService : IDisposable
// CP4D 인증 방식인 경우
if (registered != null &&
registered.AuthType.Equals("cp4d", StringComparison.OrdinalIgnoreCase) &&
(registered.AuthType.Equals("cp4d", StringComparison.OrdinalIgnoreCase) ||
registered.AuthType.Equals("cp4d_password", StringComparison.OrdinalIgnoreCase) ||
registered.AuthType.Equals("cp4d_api_key", StringComparison.OrdinalIgnoreCase)) &&
!string.IsNullOrWhiteSpace(registered.Cp4dUrl))
{
var password = CryptoService.DecryptIfEnabled(registered.Cp4dPassword, llm.EncryptionEnabled);

View File

@@ -2028,7 +2028,7 @@ public class RegisteredModelRow : INotifyPropertyChanged
private string _cp4dUsername = "";
private string _cp4dPassword = "";
/// <summary>인증 방식. bearer | ibm_iam | cp4d</summary>
/// <summary>인증 방식. bearer | ibm_iam | cp4d_password | cp4d_api_key</summary>
public string AuthType
{
get => _authType;
@@ -2059,7 +2059,9 @@ public class RegisteredModelRow : INotifyPropertyChanged
/// <summary>인증 방식 라벨</summary>
public string AuthLabel => (_authType ?? "bearer").ToLowerInvariant() switch
{
"cp4d" => "CP4D",
"cp4d" => "CP4D 비밀번호",
"cp4d_password" => "CP4D 비밀번호",
"cp4d_api_key" => "CP4D API 키",
"ibm_iam" => "IBM IAM",
_ => "Bearer",
};

View File

@@ -272,13 +272,17 @@ internal sealed class ModelRegistrationDialog : Window
};
var bearerItem = new ComboBoxItem { Content = "Bearer 토큰 (API 키)", Tag = "bearer" };
var ibmIamItem = new ComboBoxItem { Content = "IBM IAM (토큰 교환)", Tag = "ibm_iam" };
var cp4dItem = new ComboBoxItem { Content = "CP4D (IBM Cloud Pak for Data)", Tag = "cp4d" };
var cp4dPasswordItem = new ComboBoxItem { Content = "CP4D (사용자 이름 + 비밀번호)", Tag = "cp4d_password" };
var cp4dApiKeyItem = new ComboBoxItem { Content = "CP4D (사용자 이름 + API 키)", Tag = "cp4d_api_key" };
_authTypeBox.Items.Add(bearerItem);
_authTypeBox.Items.Add(ibmIamItem);
_authTypeBox.Items.Add(cp4dItem);
_authTypeBox.Items.Add(cp4dPasswordItem);
_authTypeBox.Items.Add(cp4dApiKeyItem);
_authTypeBox.SelectedItem = existingAuthType switch
{
"cp4d" => cp4dItem,
"cp4d" => cp4dPasswordItem,
"cp4d_password" => cp4dPasswordItem,
"cp4d_api_key" => cp4dApiKeyItem,
"ibm_iam" => ibmIamItem,
_ => bearerItem,
};
@@ -302,8 +306,9 @@ internal sealed class ModelRegistrationDialog : Window
apiKeyPanel.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _apiKeyBox });
stack.Children.Add(apiKeyPanel);
// ── CP4D 인증: URL + 사용자명 + 비밀번호 ────────────────────────────
_cp4dPanel = new StackPanel { Visibility = existingAuthType == "cp4d" ? Visibility.Visible : Visibility.Collapsed };
// ── CP4D 인증: URL + 사용자명 + 비밀번호/API 키 ───────────────────────
var initialCp4dAuth = existingAuthType is "cp4d" or "cp4d_password" or "cp4d_api_key";
_cp4dPanel = new StackPanel { Visibility = initialCp4dAuth ? Visibility.Visible : Visibility.Collapsed };
_cp4dPanel.Children.Add(new TextBlock
{
@@ -340,12 +345,13 @@ internal sealed class ModelRegistrationDialog : Window
};
_cp4dPanel.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _cp4dUsernameBox });
_cp4dPanel.Children.Add(new TextBlock
var cp4dSecretLabel = new TextBlock
{
Text = "비밀번호 / API 키",
Text = "비밀번호",
FontSize = 12, FontWeight = FontWeights.SemiBold,
Foreground = primaryText, Margin = new Thickness(0, 10, 0, 6),
});
};
_cp4dPanel.Children.Add(cp4dSecretLabel);
_cp4dPasswordBox = new PasswordBox
{
Password = existingCp4dPassword,
@@ -358,14 +364,19 @@ internal sealed class ModelRegistrationDialog : Window
stack.Children.Add(_cp4dPanel);
// 인증 방식 전환 시 패널 표시/숨김
_authTypeBox.SelectionChanged += (_, _) =>
void UpdateAuthPanels()
{
var isCp4d = AuthType == "cp4d";
var isCp4d = AuthType is "cp4d" or "cp4d_password" or "cp4d_api_key";
_cp4dPanel.Visibility = isCp4d ? Visibility.Visible : Visibility.Collapsed;
apiKeyPanel.Visibility = isCp4d ? Visibility.Collapsed : Visibility.Visible;
cp4dSecretLabel.Text = AuthType == "cp4d_api_key" ? "API 키" : "비밀번호";
}
_authTypeBox.SelectionChanged += (_, _) =>
{
UpdateAuthPanels();
};
// 초기 상태 설정
apiKeyPanel.Visibility = existingAuthType == "cp4d" ? Visibility.Collapsed : Visibility.Visible;
UpdateAuthPanels();
// 보안 안내
var securityNote = new StackPanel