- scripts/trigger_gmail_scout.py: manually fire ScoutEngine.trigger_scout - scripts/inspect_gmail_scout_token.py: decrypt + show stored OAuth scopes - scripts/show_gmail_scout_state.py: print scout config + queue/log counts - scripts/reset_triage_queue_to_queued.py: revert delivered → queued for re-delivery - engine.py: info logs around deliver_pending (rows found, send_json roundtrip) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
57 lines
1.6 KiB
Python
57 lines
1.6 KiB
Python
"""Decrypt and inspect the Gmail scout's stored OAuth token.
|
|
|
|
Shows what scopes were granted at consent time. If gmail.readonly / gmail.modify
|
|
are missing, the consent screen didn't actually grant them.
|
|
|
|
Usage:
|
|
python scripts/inspect_gmail_scout_token.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
_API_ROOT = Path(__file__).resolve().parent.parent
|
|
if str(_API_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(_API_ROOT))
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.db import async_session
|
|
from app.integrations import decrypt_token
|
|
from app.models import CloudScoutConfig
|
|
|
|
|
|
async def main() -> None:
|
|
async with async_session() as session:
|
|
scouts = (
|
|
await session.execute(
|
|
select(CloudScoutConfig).where(CloudScoutConfig.provider == "gmail")
|
|
)
|
|
).scalars().all()
|
|
|
|
if not scouts:
|
|
print("No Gmail scouts found.")
|
|
return
|
|
|
|
for scout in scouts:
|
|
print(f"\nScout: {scout.name} (id={scout.id})")
|
|
if not scout.oauth_token_encrypted:
|
|
print(" (no token stored)")
|
|
continue
|
|
try:
|
|
creds = decrypt_token(scout.oauth_token_encrypted)
|
|
except Exception as exc:
|
|
print(f" decrypt failed: {exc}")
|
|
continue
|
|
print(f" has refresh_token: {bool(creds.get('refresh_token'))}")
|
|
print(f" stored scopes: {creds.get('scopes')}")
|
|
print(f" token_uri: {creds.get('token_uri')}")
|
|
print(f" client_id (last 8): ...{(creds.get('client_id') or '')[-8:]}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|