mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-14 04:02:26 +00:00
fix(google-workspace): detect disabled_client in --check and add --check-live
setup.py --check only validated token shape/expiry but did not detect when Google had disabled the OAuth client or account. Users got AUTHENTICATED even when actual API calls failed with disabled_client. Changes: - Catch disabled_client and invalid_client in check_auth() refresh path with actionable guidance (check Cloud Console, check account status, do not retry) - Add check_auth_live() that performs a real Calendar API call to detect disabled_client errors that survive token refresh - Add --check-live CLI flag backed by check_auth_live() Fixes #19570
This commit is contained in:
parent
80775d7585
commit
5fa493a2ca
1 changed files with 43 additions and 1 deletions
|
|
@ -130,6 +130,31 @@ def _ensure_deps():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def check_auth_live():
|
||||||
|
"""Check auth with a real API call to detect disabled_client/account issues.""""
|
||||||
|
if not check_auth():
|
||||||
|
return False
|
||||||
|
_ensure_deps()
|
||||||
|
try:
|
||||||
|
from googleapiclient.discovery import build
|
||||||
|
from google.oauth2.credentials import Credentials
|
||||||
|
creds = Credentials.from_authorized_user_file(str(TOKEN_PATH))
|
||||||
|
service = build("calendar", "v3", credentials=creds)
|
||||||
|
service.calendarList().list(maxResults=1).execute()
|
||||||
|
print("LIVE_CHECK_OK: Real API call succeeded.")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
err_str = str(e).lower()
|
||||||
|
if "disabled_client" in err_str or "invalid_client" in err_str:
|
||||||
|
print(f"LIVE_CHECK_FAILED: OAuth client or account disabled: {e}")
|
||||||
|
print(" 1. Check Google Cloud Console for disabled OAuth client")
|
||||||
|
print(" 2. Check myaccount.google.com for account status")
|
||||||
|
print(" 3. Do NOT retry with a disabled account")
|
||||||
|
else:
|
||||||
|
print(f"LIVE_CHECK_FAILED: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check_auth():
|
def check_auth():
|
||||||
"""Check if stored credentials are valid. Prints status, exits 0 or 1."""
|
"""Check if stored credentials are valid. Prints status, exits 0 or 1."""
|
||||||
if not TOKEN_PATH.exists():
|
if not TOKEN_PATH.exists():
|
||||||
|
|
@ -177,7 +202,21 @@ def check_auth():
|
||||||
print(f"AUTHENTICATED: Token refreshed at {TOKEN_PATH}")
|
print(f"AUTHENTICATED: Token refreshed at {TOKEN_PATH}")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"REFRESH_FAILED: {e}")
|
err_str = str(e).lower()
|
||||||
|
if "disabled_client" in err_str or "invalid_client" in err_str:
|
||||||
|
print(f"OAUTH_CLIENT_DISABLED: {e}")
|
||||||
|
print(" The OAuth client or Google account has been disabled.")
|
||||||
|
print(" Steps to resolve:")
|
||||||
|
print(" 1. Check your Google Cloud Console — verify the OAuth client is not disabled")
|
||||||
|
print(" 2. Check if your Google account itself has been disabled at myaccount.google.com")
|
||||||
|
print(" 3. If the account is disabled, you can appeal at accounts.google.com/signin/recovery")
|
||||||
|
print(" 4. Do NOT retry API calls with a disabled account — this may worsen the situation")
|
||||||
|
print(" 5. If the OAuth client is disabled, create a new one in Google Cloud Console")
|
||||||
|
elif "token_revoked" in err_str or "invalid_grant" in err_str:
|
||||||
|
print(f"TOKEN_REVOKED: {e}")
|
||||||
|
print(" Re-run setup to re-authenticate.")
|
||||||
|
else:
|
||||||
|
print(f"REFRESH_FAILED: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print("TOKEN_INVALID: Re-run setup.")
|
print("TOKEN_INVALID: Re-run setup.")
|
||||||
|
|
@ -384,6 +423,7 @@ def main():
|
||||||
parser = argparse.ArgumentParser(description="Google Workspace OAuth setup for Hermes")
|
parser = argparse.ArgumentParser(description="Google Workspace OAuth setup for Hermes")
|
||||||
group = parser.add_mutually_exclusive_group(required=True)
|
group = parser.add_mutually_exclusive_group(required=True)
|
||||||
group.add_argument("--check", action="store_true", help="Check if auth is valid (exit 0=yes, 1=no)")
|
group.add_argument("--check", action="store_true", help="Check if auth is valid (exit 0=yes, 1=no)")
|
||||||
|
group.add_argument("--check-live", action="store_true", help="Check auth with a real API call (detects disabled_client)")
|
||||||
group.add_argument("--client-secret", metavar="PATH", help="Store OAuth client_secret.json")
|
group.add_argument("--client-secret", metavar="PATH", help="Store OAuth client_secret.json")
|
||||||
group.add_argument("--auth-url", action="store_true", help="Print OAuth URL for user to visit")
|
group.add_argument("--auth-url", action="store_true", help="Print OAuth URL for user to visit")
|
||||||
group.add_argument("--auth-code", metavar="CODE", help="Exchange auth code for token")
|
group.add_argument("--auth-code", metavar="CODE", help="Exchange auth code for token")
|
||||||
|
|
@ -393,6 +433,8 @@ def main():
|
||||||
|
|
||||||
if args.check:
|
if args.check:
|
||||||
sys.exit(0 if check_auth() else 1)
|
sys.exit(0 if check_auth() else 1)
|
||||||
|
if getattr(args, "check_live", False):
|
||||||
|
sys.exit(0 if check_auth_live() else 1)
|
||||||
elif args.client_secret:
|
elif args.client_secret:
|
||||||
store_client_secret(args.client_secret)
|
store_client_secret(args.client_secret)
|
||||||
elif args.auth_url:
|
elif args.auth_url:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue