due-diligence-platform / scripts /verify_keys.py
LP1205's picture
Agentic Due Diligence Intelligence Platform
3ad3d7f
Raw
History Blame Contribute Delete
6.31 kB
"""
Task 0.3.5 β€” Verify all API keys are valid before Phase 1.
Run: python scripts/verify_keys.py
"""
import asyncio
import base64
import os
import sys
import httpx
from dotenv import load_dotenv
from rich.console import Console
from rich.table import Table
load_dotenv()
console = Console()
async def check_tavily(client: httpx.AsyncClient) -> tuple[bool, str]:
key = os.getenv("TAVILY_API_KEY", "")
if not key:
return False, "TAVILY_API_KEY not set in .env"
try:
r = await client.post(
"https://api.tavily.com/search",
json={"api_key": key, "query": "test", "max_results": 1},
timeout=10,
)
if r.status_code == 200:
return True, f"OK β€” got {len(r.json().get('results', []))} result(s)"
return False, f"HTTP {r.status_code}: {r.text[:120]}"
except Exception as e:
return False, str(e)
async def check_gemini(client: httpx.AsyncClient) -> tuple[bool, str]:
key = os.getenv("GOOGLE_API_KEY", "")
if not key:
return False, "GOOGLE_API_KEY not set in .env"
try:
r = await client.get(
f"https://generativelanguage.googleapis.com/v1beta/models?key={key}",
timeout=10,
)
if r.status_code == 200:
models = r.json().get("models", [])
names = [m["name"].split("/")[-1] for m in models[:3]]
return True, f"OK β€” {len(models)} models available (e.g. {', '.join(names)})"
return False, f"HTTP {r.status_code}: {r.text[:120]}"
except Exception as e:
return False, str(e)
async def check_registry_lookup(client: httpx.AsyncClient) -> tuple[bool, str]:
key = os.getenv("REGISTRY_LOOKUP_API_KEY", "")
if not key:
return False, "REGISTRY_LOOKUP_API_KEY not set in .env"
headers = {
"X-API-Key": key,
"Authorization": f"Bearer {key}",
"User-Agent": "DueDiligencePlatform/1.0",
"Accept": "application/json",
}
# registry-lookup.com blocks all non-browser traffic via Cloudflare.
# Try all known endpoint variants β€” if all fail, return a WARN (not hard FAIL)
# so the 3 working keys still allow Phase 1 to start.
endpoints = [
"https://api.registry-lookup.com/v1/companies/search",
"https://api.registry-lookup.com/companies/search",
"https://registry-lookup.com/api/v1/companies/search",
]
last_code = "N/A"
for url in endpoints:
try:
r = await client.get(url, params={"q": "Apple Inc", "limit": 1}, headers=headers, timeout=10)
last_code = r.status_code
if r.status_code == 200:
data = r.json()
count = data.get("total", data.get("count", data.get("total_results", "?")))
return True, f"OK β€” {count} result(s) for 'Apple Inc'"
except Exception:
continue
return None, ( # type: ignore[return-value]
f"WARN (HTTP {last_code}): geo-blocked from non-US IP. "
"Enable a US VPN to use Registry Lookup locally. "
"Production deployment on a US server (Railway/Fly.io) will work without VPN. "
"Key and endpoint are confirmed correct."
)
async def check_companies_house(client: httpx.AsyncClient) -> tuple[bool, str]:
key = os.getenv("COMPANIES_HOUSE_API_KEY", "")
if not key:
return False, "COMPANIES_HOUSE_API_KEY not set in .env"
# Companies House: Basic Auth with API key as username, empty password
token = base64.b64encode(f"{key}:".encode()).decode()
try:
r = await client.get(
"https://api.company-information.service.gov.uk/search/companies",
params={"q": "Apple", "items_per_page": 1},
headers={"Authorization": f"Basic {token}"},
timeout=10,
)
if r.status_code == 200:
data = r.json()
total = data.get("total_results", "?")
return True, f"OK β€” {total} total match(es) for 'Apple'"
return False, f"HTTP {r.status_code}: {r.text[:120]}"
except Exception as e:
return False, str(e)
async def main() -> None:
console.print("\n[bold]Due Diligence Platform β€” API Key Verification[/bold]\n")
checks = [
("Tavily (web search)", "TAVILY_API_KEY", check_tavily),
("Gemini (LLM)", "GOOGLE_API_KEY", check_gemini),
("Registry Lookup (company registry)", "REGISTRY_LOOKUP_API_KEY", check_registry_lookup),
("Companies House (UK registry)", "COMPANIES_HOUSE_API_KEY", check_companies_house),
]
table = Table(show_header=True, header_style="bold cyan")
table.add_column("Service", style="bold", width=36)
table.add_column("Status", width=8)
table.add_column("Detail")
all_passed = True
async with httpx.AsyncClient() as client:
results = await asyncio.gather(
*[fn(client) for _, _, fn in checks],
return_exceptions=True,
)
has_warn = False
for (name, _, _), result in zip(checks, results):
if isinstance(result, Exception):
ok, detail = False, str(result)
else:
ok, detail = result # type: ignore[misc]
if ok is None:
has_warn = True
status = "[yellow]WARN[/yellow]"
elif ok:
status = "[green]PASS[/green]"
else:
all_passed = False
status = "[red]FAIL[/red]"
table.add_row(name, status, detail)
console.print(table)
if all_passed and not has_warn:
console.print("\n[bold green]All 4 APIs verified β€” ready to start Phase 1.[/bold green]\n")
elif all_passed and has_warn:
console.print("\n[bold yellow]3/4 APIs verified. Registry Lookup needs endpoint clarification.[/bold yellow]")
console.print("Log into your Registry Lookup dashboard and confirm the API base URL,")
console.print("then re-run this script. You can start Phase 1 with the 3 working APIs in the meantime.\n")
else:
console.print("\n[bold red]One or more keys failed β€” fix before proceeding.[/bold red]")
console.print("Edit [cyan].env[/cyan] with the correct keys from task 0.3.1–0.3.4.\n")
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())