mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-11 11:49:50 +08:00
Handle inactive PAT owner as invalid OAuth token
This commit is contained in:
@@ -149,6 +149,8 @@ fn status_proves_access_token_invalid(status_code: u16, response_text: Option<&s
|
|||||||
"expired access token",
|
"expired access token",
|
||||||
"authentication token has been invalidated",
|
"authentication token has been invalidated",
|
||||||
"token has been invalidated",
|
"token has been invalidated",
|
||||||
|
"personal access token owner is inactive",
|
||||||
|
"biscuit_baker_service_auth_credential_error_status",
|
||||||
"security token included in the request is expired",
|
"security token included in the request is expired",
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
@@ -196,6 +198,12 @@ mod tests {
|
|||||||
403,
|
403,
|
||||||
Some("The security token included in the request is expired")
|
Some("The security token included in the request is expired")
|
||||||
));
|
));
|
||||||
|
assert!(status_proves_access_token_invalid(
|
||||||
|
403,
|
||||||
|
Some(
|
||||||
|
r#"{"error":{"code":"biscuit_baker_service_auth_credential_error_status","message":"Personal access token owner is inactive."}}"#
|
||||||
|
)
|
||||||
|
));
|
||||||
assert!(!status_proves_access_token_invalid(403, None));
|
assert!(!status_proves_access_token_invalid(403, None));
|
||||||
assert!(!status_proves_access_token_invalid(
|
assert!(!status_proves_access_token_invalid(
|
||||||
403,
|
403,
|
||||||
|
|||||||
@@ -2103,6 +2103,49 @@ mod tests {
|
|||||||
assert_eq!(stored_key.oauth_invalid_reason, None);
|
assert_eq!(stored_key.oauth_invalid_reason, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn oauth_invalidation_marks_codex_inactive_pat_owner_403_as_token_invalid() {
|
||||||
|
let state = codex_state();
|
||||||
|
let plan = sample_codex_plan();
|
||||||
|
|
||||||
|
apply_local_execution_effect(
|
||||||
|
&state,
|
||||||
|
LocalExecutionEffectContext {
|
||||||
|
plan: &plan,
|
||||||
|
report_context: None,
|
||||||
|
},
|
||||||
|
LocalExecutionEffect::OauthInvalidation(LocalOAuthInvalidationEffect {
|
||||||
|
status_code: 403,
|
||||||
|
response_text: Some(
|
||||||
|
r#"{"error":{"code":"biscuit_baker_service_auth_credential_error_status","message":"Personal access token owner is inactive."},"status":403}"#,
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let stored_key = state
|
||||||
|
.read_provider_catalog_keys_by_ids(std::slice::from_ref(&plan.key_id))
|
||||||
|
.await
|
||||||
|
.expect("provider catalog keys should load")
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("stored key should exist");
|
||||||
|
assert!(stored_key.oauth_invalid_at_unix_secs.is_some());
|
||||||
|
assert_eq!(
|
||||||
|
stored_key.oauth_invalid_reason.as_deref(),
|
||||||
|
Some("[OAUTH_EXPIRED] Personal access token owner is inactive.")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
stored_key
|
||||||
|
.status_snapshot
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|value| value.get("oauth"))
|
||||||
|
.and_then(|value| value.get("code"))
|
||||||
|
.and_then(Value::as_str),
|
||||||
|
Some("invalid")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn health_failure_projection_updates_key_health_for_format() {
|
async fn health_failure_projection_updates_key_health_for_format() {
|
||||||
let state = health_state();
|
let state = health_state();
|
||||||
|
|||||||
@@ -952,6 +952,9 @@ pub fn codex_looks_like_token_invalidated(message: Option<&str>) -> bool {
|
|||||||
|| lowered.contains("authentication token has been invalidated")
|
|| lowered.contains("authentication token has been invalidated")
|
||||||
|| lowered.contains("token has been invalidated")
|
|| lowered.contains("token has been invalidated")
|
||||||
|| lowered.contains("token invalidated")
|
|| lowered.contains("token invalidated")
|
||||||
|
|| lowered.contains("personal access token owner is inactive")
|
||||||
|
|| lowered.contains("biscuit_baker_service_auth_credential_error_status")
|
||||||
|
|| lowered.contains("auth_credential")
|
||||||
|| lowered.contains("invalidated")
|
|| lowered.contains("invalidated")
|
||||||
|| lowered.contains("revoked")
|
|| lowered.contains("revoked")
|
||||||
|| lowered.contains("已撤销")
|
|| lowered.contains("已撤销")
|
||||||
@@ -1777,6 +1780,25 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn codex_runtime_invalid_reason_marks_inactive_pat_owner_403_as_token_invalid() {
|
||||||
|
assert_eq!(
|
||||||
|
codex_runtime_invalid_reason(403, Some("Personal access token owner is inactive.")),
|
||||||
|
Some(format!(
|
||||||
|
"{OAUTH_EXPIRED_PREFIX}Personal access token owner is inactive."
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
codex_runtime_invalid_reason(
|
||||||
|
403,
|
||||||
|
Some("biscuit_baker_service_auth_credential_error_status")
|
||||||
|
),
|
||||||
|
Some(format!(
|
||||||
|
"{OAUTH_EXPIRED_PREFIX}biscuit_baker_service_auth_credential_error_status"
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn codex_runtime_invalid_reason_marks_402_as_account_blocked() {
|
fn codex_runtime_invalid_reason_marks_402_as_account_blocked() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -158,6 +158,9 @@ pub fn oauth_token_reason_is_hard_invalid(reason: &str) -> bool {
|
|||||||
"authentication token has been invalidated",
|
"authentication token has been invalidated",
|
||||||
"token has been invalidated",
|
"token has been invalidated",
|
||||||
"token invalidated",
|
"token invalidated",
|
||||||
|
"personal access token owner is inactive",
|
||||||
|
"biscuit_baker_service_auth_credential_error_status",
|
||||||
|
"auth_credential",
|
||||||
"invalidated",
|
"invalidated",
|
||||||
"revoked",
|
"revoked",
|
||||||
"已撤销",
|
"已撤销",
|
||||||
@@ -722,6 +725,20 @@ mod tests {
|
|||||||
assert!(!snapshot.recoverable);
|
assert!(!snapshot.recoverable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn account_snapshot_marks_inactive_pat_owner_as_token_invalid() {
|
||||||
|
let snapshot = resolve_account_status_snapshot(
|
||||||
|
Some("codex"),
|
||||||
|
None,
|
||||||
|
Some("[OAUTH_EXPIRED] Personal access token owner is inactive."),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(snapshot.code, "oauth_token_invalid");
|
||||||
|
assert_eq!(snapshot.label.as_deref(), Some("Token 失效"));
|
||||||
|
assert!(snapshot.blocked);
|
||||||
|
assert!(!snapshot.recoverable);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn account_snapshot_marks_oauth_expired_as_token_expired() {
|
fn account_snapshot_marks_oauth_expired_as_token_expired() {
|
||||||
let snapshot = resolve_account_status_snapshot(
|
let snapshot = resolve_account_status_snapshot(
|
||||||
|
|||||||
Reference in New Issue
Block a user