fix(auth): stop the API key placeholder from shadowing Oh My Pi /login credentials (#78)
Oh My Pi kept the unresolved $COMMAND_CODE_API_KEY placeholder as a literal config API key that shadowed its /login credential store and was sent as the Bearer token (401). The placeholder is now registered only on pi, where it keeps the API-key auth method and --api-key working next to OAuth; on OMP the provider omits apiKey unless a real key is configured. Host-supplied placeholders are resolved or stripped on every stream path, and the legacy generate transport uses the same rule. Stored /login OAuth and API-key credentials, --api-key, and env keys are now covered end to end on both pi and Oh My Pi, and CI runs the pi suite against a real binary. Co-authored-by: ebreen <ebreen@users.noreply.github.com>
This commit is contained in:
+21
-4
@@ -147,6 +147,13 @@ export const COMMAND_CODE_PLACEHOLDER_KEYS = new Set([
|
||||
"COMMANDCODE_API_KEY",
|
||||
])
|
||||
|
||||
function usableCommandCodeApiKey(value: string | undefined): string | undefined {
|
||||
const trimmed = typeof value === "string" ? value.trim() : undefined
|
||||
if (!trimmed) return undefined
|
||||
if (COMMAND_CODE_PLACEHOLDER_KEYS.has(trimmed)) return undefined
|
||||
return trimmed
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick the real API key from a host registry value and/or the env/auth-file
|
||||
* fallback, never returning a literal placeholder or an empty/whitespace value.
|
||||
@@ -156,10 +163,20 @@ export function pickCommandCodeApiKey(
|
||||
registryKey: string | undefined,
|
||||
hostKey: string | undefined,
|
||||
): string | undefined {
|
||||
const trimmed = typeof registryKey === "string" ? registryKey.trim() : undefined
|
||||
if (!trimmed) return hostKey
|
||||
if (COMMAND_CODE_PLACEHOLDER_KEYS.has(trimmed)) return hostKey
|
||||
return trimmed
|
||||
return usableCommandCodeApiKey(registryKey) ?? usableCommandCodeApiKey(hostKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a host-supplied placeholder (or missing key) with the configured
|
||||
* fallback. Used for both registerProvider and the Provider API stream path.
|
||||
*/
|
||||
export function withResolvedCommandCodeApiKey<T extends { apiKey?: string }>(
|
||||
options: T | undefined,
|
||||
configuredKey: string | undefined,
|
||||
): T | { apiKey?: string } {
|
||||
const apiKey = pickCommandCodeApiKey(options?.apiKey, configuredKey)
|
||||
if (options && apiKey === options.apiKey) return options
|
||||
return { ...options, apiKey }
|
||||
}
|
||||
|
||||
export function textContent(message: { content?: unknown }): string {
|
||||
|
||||
+5
-12
@@ -19,6 +19,7 @@ import {
|
||||
messagesToCC,
|
||||
numberValue,
|
||||
parseStreamEventLine,
|
||||
pickCommandCodeApiKey,
|
||||
recordOrEmpty,
|
||||
stringValue,
|
||||
toolsToJson,
|
||||
@@ -237,22 +238,14 @@ export function createStreamCommandCode(deps: CoreDependencies) {
|
||||
|
||||
async function run() {
|
||||
// Some hosts pass a literal env-var reference instead of resolving it.
|
||||
const PLACEHOLDER_API_KEYS = new Set([
|
||||
"$COMMAND_CODE_API_KEY",
|
||||
"COMMAND_CODE_API_KEY",
|
||||
"$COMMANDCODE_API_KEY",
|
||||
"COMMANDCODE_API_KEY",
|
||||
])
|
||||
const hostKey =
|
||||
options?.apiKey && !PLACEHOLDER_API_KEYS.has(options.apiKey) ? options.apiKey : undefined
|
||||
|
||||
const apiKey =
|
||||
hostKey ??
|
||||
const apiKey = pickCommandCodeApiKey(
|
||||
options?.apiKey,
|
||||
getApiKey({
|
||||
env: deps.env,
|
||||
authPaths: deps.authPaths,
|
||||
homeDir: deps.homeDir,
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
if (!apiKey) {
|
||||
const msg: AssistantMessageLike = {
|
||||
|
||||
Reference in New Issue
Block a user