fix: authorize CLI probes and preserve executable identity

This commit is contained in:
amosblomqvist
2026-10-28 19:26:36 +02:00
parent c5a756d707
commit 5093809ea0
9 changed files with 138 additions and 7 deletions
+5 -2
View File
@@ -6,6 +6,7 @@ type BinaryLookup = {
env: Record<string, string | undefined>;
platform: NodeJS.Platform;
homeDir: string;
cwd?: string;
isExecutable: (path: string) => boolean;
};
@@ -51,7 +52,7 @@ function getPosixSearchSpec(env: BinaryLookup["env"], homeDir: string): SearchSp
};
}
export function resolveClaudeBinary({ env, platform, homeDir, isExecutable }: BinaryLookup): string | null {
export function resolveClaudeBinary({ env, platform, homeDir, cwd = process.cwd(), isExecutable }: BinaryLookup): string | null {
const { paths, names, knownDirs } = platform === "win32"
? getWindowsSearchSpec(env, homeDir)
: getPosixSearchSpec(env, homeDir);
@@ -60,7 +61,9 @@ export function resolveClaudeBinary({ env, platform, homeDir, isExecutable }: Bi
for (const name of names) {
for (const dir of [...pathDirs, ...knownDirs]) {
const candidate = paths.join(dir, name);
// Discovery is relative to the server cwd; probes/model work use
// different directories and must receive the same absolute identity.
const candidate = paths.resolve(cwd, dir, name);
if (isExecutable(candidate)) return candidate;
}
}
+19
View File
@@ -1,8 +1,27 @@
import { inspectClaudeInstallation } from "../agent/claude-code/installation.ts";
import { initAuthEnv } from "./keys.ts";
import { subscriptionRequestOrigin } from "./web-subscription-http.ts";
/** The Settings status seam: initialize provenance before any child env is copied. */
export async function claudeCodeInstallationStatus() {
initAuthEnv();
return inspectClaudeInstallation();
}
/** Same-origin browser intent, not user authentication. No CORS grants.
* A public/shared server still requires its own access-control boundary. */
export async function claudeCodeInstallationResponse(
request: Request,
inspect = claudeCodeInstallationStatus,
): Promise<Response> {
const origin = subscriptionRequestOrigin(request);
const supplied = request.headers.get("origin");
const headers = { "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" };
if (request.method !== "GET" || !origin
|| request.headers.get("x-learnharness-claude-code") !== "1"
|| request.headers.get("sec-fetch-site") === "cross-site"
|| (supplied !== null && supplied !== origin)) {
return Response.json({ error: "Claude Code checks require a same-origin LearnHarness request." }, { status: 403, headers });
}
return Response.json(await inspect(), { headers });
}
+1 -1
View File
@@ -45,4 +45,4 @@ export * from "./observability.ts";
export * from "./model-catalog.ts";
export { subscriptionControlsResponse, subscriptionBrowserResponse } from "./web-subscription-http.ts";
export { sessionCost } from "./pricing.ts";
export { claudeCodeInstallationStatus } from "./claude-code.ts";
export { claudeCodeInstallationResponse } from "./claude-code.ts";