Add per-provider auth.json keys; make auth methods registry-generic (P0b)
Platform API keys now live in auth.json under the platform-id scope (the per-provider auth.json key contract), resolved env > auth.json > legacy [platforms.*] config.toml (read-only fallback). The TUI login picker, paste box, auth-method advertising, and authenticate handler are all registry-generic: a new PlatformSpec row appears in the login UI and authenticates with zero UI changes. Spec rows gained vendor/console_host/ login_label display fields (moonshot strings byte-identical, pinned by tests). Adversarial review caught that auth.json keys were validated at login but never stamped onto catalog entries (completions would 401; restart lost eager auth). Fixed red-green: resolve_model_list/resolve_model_catalog now take a resolved PlatformApiKeys snapshot consumed by the credential- stamping layer (auth.json beats stale config.toml, matching the login validator), with production callers resolving fresh per catalog build. Also from review: the new auth.json writer takes the manager's cross- process flock (bounded retry — an unlocked RMW racing a token refresh could revert a rotated refresh token); the oauth-401 wiremock test is hermetic (KIGI_SHARE_DIR tempdir; it could read a dev's real auth.json and hit live moonshot); cli_models resolves real keys; auth.json is read once per registry sweep; caller-less lock_config_writes deleted; catalog resolvers tightened to pub(crate); stale config.toml doc comments and the no-credentials error copy updated.
This commit is contained in:
1 parent
99d99fb47a
commit
c5ddaec71e
19 files changed
+731
-375
No files matched your search
@@ -290,7 +290,7 @@ pub(super) fn dispatch_cancel_platform_key_entry(app: &mut AppView) -> Vec<Effec
|
||||
}
|
||||
|
||||
/// Enter with a non-empty key in the API-key paste box: persist the key to
|
||||
/// `[platforms.<id>]` in config.toml, then authenticate with the platform's
|
||||
/// auth.json (platform-id scope), then authenticate with the platform's
|
||||
/// method id (one sequential background task — see the effect handler).
|
||||
/// The screen shows the connecting state while the key is validated; a
|
||||
/// failure lands back on the picker with the error line (`AuthFailed`).
|
||||
|
||||
@@ -112,14 +112,14 @@ fn submit_platform_api_key_dispatches_persist_then_authenticate() {
|
||||
app.auth_state = AuthState::Pending { error: None };
|
||||
|
||||
let effects = dispatch(
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin::MoonshotCn),
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin(kigi_shell::models::PlatformId::MoonshotCn)),
|
||||
&mut app,
|
||||
);
|
||||
assert!(effects.is_empty(), "entering key entry is UI-only");
|
||||
let seq = match &app.auth_state {
|
||||
AuthState::Authenticating {
|
||||
request_seq,
|
||||
mode: AuthMode::ApiKeyEntry(PlatformLogin::MoonshotCn),
|
||||
mode: AuthMode::ApiKeyEntry(PlatformLogin(kigi_shell::models::PlatformId::MoonshotCn)),
|
||||
..
|
||||
} => *request_seq,
|
||||
other => panic!("expected ApiKeyEntry(MoonshotCn), got {other:?}"),
|
||||
@@ -135,7 +135,10 @@ fn submit_platform_api_key_dispatches_persist_then_authenticate() {
|
||||
},
|
||||
] => {
|
||||
assert_eq!(*request_seq, seq);
|
||||
assert_eq!(*target, PlatformLogin::MoonshotCn);
|
||||
assert_eq!(
|
||||
*target,
|
||||
PlatformLogin(kigi_shell::models::PlatformId::MoonshotCn)
|
||||
);
|
||||
assert_eq!(key, "sk-test-key");
|
||||
assert_eq!(
|
||||
target.method_id().0.as_ref(),
|
||||
@@ -179,7 +182,7 @@ fn cancel_platform_key_entry_returns_to_picker() {
|
||||
let mut app = test_app();
|
||||
app.auth_state = AuthState::Pending { error: None };
|
||||
dispatch(
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin::MoonshotAi),
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin(kigi_shell::models::PlatformId::MoonshotAi)),
|
||||
&mut app,
|
||||
);
|
||||
app.auth_code_input = "sk-half-typed".into();
|
||||
@@ -200,7 +203,7 @@ fn submit_platform_api_key_ignores_blank_key() {
|
||||
let mut app = test_app();
|
||||
app.auth_state = AuthState::Pending { error: None };
|
||||
dispatch(
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin::MoonshotCn),
|
||||
Action::BeginPlatformKeyEntry(PlatformLogin(kigi_shell::models::PlatformId::MoonshotCn)),
|
||||
&mut app,
|
||||
);
|
||||
let effects = dispatch(Action::SubmitPlatformApiKey(" ".into()), &mut app);
|
||||
@@ -208,7 +211,7 @@ fn submit_platform_api_key_ignores_blank_key() {
|
||||
assert!(matches!(
|
||||
app.auth_state,
|
||||
AuthState::Authenticating {
|
||||
mode: AuthMode::ApiKeyEntry(PlatformLogin::MoonshotCn),
|
||||
mode: AuthMode::ApiKeyEntry(PlatformLogin(kigi_shell::models::PlatformId::MoonshotCn)),
|
||||
..
|
||||
}
|
||||
));
|
||||
|
||||
Reference in new issue
Block a user