|
24 | 24 |
|
25 | 25 | router = APIRouter(tags=["config"]) |
26 | 26 |
|
| 27 | +_SECRETS_CHECK_ALLOWLIST = { |
| 28 | + # Provider secrets |
| 29 | + "OPENAI_API_KEY", |
| 30 | + "OPENROUTER_API_KEY", |
| 31 | + "ANTHROPIC_API_KEY", |
| 32 | + "GOOGLE_API_KEY", |
| 33 | + "COHERE_API_KEY", |
| 34 | + "VOYAGE_API_KEY", |
| 35 | + "JINA_API_KEY", |
| 36 | + # Integrations (UI surfaces these; backend does not expose values) |
| 37 | + "LANGTRACE_API_KEY", |
| 38 | + "LANGCHAIN_API_KEY", |
| 39 | + "LANGSMITH_API_KEY", |
| 40 | + "NETLIFY_API_KEY", |
| 41 | + "GRAFANA_API_KEY", |
| 42 | + "SLACK_WEBHOOK_URL", |
| 43 | + "DISCORD_WEBHOOK_URL", |
| 44 | +} |
| 45 | + |
| 46 | + |
27 | 47 | @router.get("/config", response_model=TriBridConfig) |
28 | 48 | async def get_config(scope: CorpusScope = Depends()) -> TriBridConfig: |
29 | 49 | repo_id = scope.resolved_repo_id |
@@ -106,7 +126,35 @@ async def reset_config(scope: CorpusScope = Depends()) -> TriBridConfig: |
106 | 126 | async def check_secrets(keys: str = Query(..., description="Comma-separated env var names")) -> dict[str, bool]: |
107 | 127 | """Return which secret env vars are configured (never returns values).""" |
108 | 128 | names = [k.strip() for k in (keys or "").split(",") if k.strip()] |
109 | | - return {name: bool(os.getenv(name)) for name in names} |
| 129 | + if not names: |
| 130 | + return {} |
| 131 | + |
| 132 | + invalid = [name for name in names if name not in _SECRETS_CHECK_ALLOWLIST] |
| 133 | + if invalid: |
| 134 | + raise HTTPException( |
| 135 | + status_code=400, |
| 136 | + detail=f"Unsupported secret key(s): {', '.join(sorted(set(invalid)))}", |
| 137 | + ) |
| 138 | + |
| 139 | + # Use explicit getenv calls (no dynamic env lookups) to keep env usage auditable/"LAW"-compliant. |
| 140 | + status = { |
| 141 | + "OPENAI_API_KEY": bool(os.getenv("OPENAI_API_KEY")), |
| 142 | + "OPENROUTER_API_KEY": bool(os.getenv("OPENROUTER_API_KEY")), |
| 143 | + "ANTHROPIC_API_KEY": bool(os.getenv("ANTHROPIC_API_KEY")), |
| 144 | + "GOOGLE_API_KEY": bool(os.getenv("GOOGLE_API_KEY")), |
| 145 | + "COHERE_API_KEY": bool(os.getenv("COHERE_API_KEY")), |
| 146 | + "VOYAGE_API_KEY": bool(os.getenv("VOYAGE_API_KEY")), |
| 147 | + "JINA_API_KEY": bool(os.getenv("JINA_API_KEY")), |
| 148 | + "LANGTRACE_API_KEY": bool(os.getenv("LANGTRACE_API_KEY")), |
| 149 | + "LANGCHAIN_API_KEY": bool(os.getenv("LANGCHAIN_API_KEY")), |
| 150 | + "LANGSMITH_API_KEY": bool(os.getenv("LANGSMITH_API_KEY")), |
| 151 | + "NETLIFY_API_KEY": bool(os.getenv("NETLIFY_API_KEY")), |
| 152 | + "GRAFANA_API_KEY": bool(os.getenv("GRAFANA_API_KEY")), |
| 153 | + "SLACK_WEBHOOK_URL": bool(os.getenv("SLACK_WEBHOOK_URL")), |
| 154 | + "DISCORD_WEBHOOK_URL": bool(os.getenv("DISCORD_WEBHOOK_URL")), |
| 155 | + } |
| 156 | + |
| 157 | + return {name: status[name] for name in names} |
110 | 158 |
|
111 | 159 |
|
112 | 160 | @router.get("/mcp/status", response_model=MCPStatusResponse) |
|
0 commit comments