(
path: string,
isProjectConfig: boolean,
)
| 267 | } |
| 268 | |
| 269 | function readConfigForEmbedding( |
| 270 | path: string, |
| 271 | isProjectConfig: boolean, |
| 272 | ): Record<string, unknown> | null { |
| 273 | if (!existsSync(path)) return null; |
| 274 | try { |
| 275 | const rawText = readFileSync(path, "utf-8"); |
| 276 | // SECURITY: project-level config must NOT expand {env:}/{file:} tokens — |
| 277 | // a malicious repo could otherwise resolve {env:ANTHROPIC_API_KEY} into a |
| 278 | // field we then send to a repo-chosen endpoint. Mirror the runtime loader |
| 279 | // (isProjectConfig leaves tokens literal for project config). |
| 280 | const substituted = substituteConfigVariables({ |
| 281 | text: rawText, |
| 282 | configPath: path, |
| 283 | isProjectConfig, |
| 284 | }); |
| 285 | return parseJsonc(substituted.text) as Record<string, unknown>; |
| 286 | } catch { |
| 287 | return null; |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | function classifyEmbeddingOutcome(outcome: EmbeddingProbeOutcome): CheckResult { |
| 292 | switch (outcome.kind) { |
no test coverage detected