fix: mount credential file to fixed container path for Vertex AI

GOOGLE_APPLICATION_CREDENTIALS was forwarded as-is to the container,
causing the relative host path to resolve against the repo mount
instead of the credentials mount. Now both local and npx modes mount
the resolved file to /app/credentials/google-sa-key.json and rewrite
the env var to match.
This commit is contained in:
ezl-keygraph
2026-03-22 16:13:28 +05:30
parent c408eabc62
commit c689ef0de0
3 changed files with 9 additions and 23 deletions
+7 -5
View File
@@ -10,7 +10,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { ensureImage, ensureInfra, randomSuffix, spawnWorker } from '../docker.js';
import { buildEnvFlags, isRouterConfigured, loadEnv, validateCredentials } from '../env.js';
import { getCredentialsDir, getCredentialsPath, getWorkspacesDir, initHome } from '../home.js';
import { getCredentialsPath, getWorkspacesDir, initHome } from '../home.js';
import { isLocal } from '../mode.js';
import { ensureDeliverables, resolveConfig, resolveRepo } from '../paths.js';
import { displaySplash } from '../splash.js';
@@ -68,10 +68,13 @@ export async function start(args: StartArgs): Promise<void> {
const workspace =
args.workspace ?? `${new URL(args.url).hostname.replace(/[^a-zA-Z0-9-]/g, '-')}_shannon-${Date.now()}`;
// 9. Resolve credentials
const credentialsDir = getCredentialsDir();
// 9. Resolve credentials — mount single file to fixed container path
const credentialsPath = getCredentialsPath();
const hasCredentials = !credentialsDir && fs.existsSync(credentialsPath);
const hasCredentials = fs.existsSync(credentialsPath);
if (hasCredentials) {
process.env.GOOGLE_APPLICATION_CREDENTIALS = '/app/credentials/google-sa-key.json';
}
// 10. Resolve output directory
const outputDir = args.output ? path.resolve(args.output) : undefined;
@@ -95,7 +98,6 @@ export async function start(args: StartArgs): Promise<void> {
containerName,
envFlags: buildEnvFlags(),
...(config && { config }),
...(credentialsDir && { credentialsDir }),
...(hasCredentials && { credentials: credentialsPath }),
...(promptsDir && { promptsDir }),
...(outputDir && { outputDir }),
+2 -5
View File
@@ -192,7 +192,6 @@ export interface WorkerOptions {
envFlags: string[];
config?: { hostPath: string; containerPath: string };
credentials?: string;
credentialsDir?: string;
promptsDir?: string;
outputDir?: string;
workspace?: string;
@@ -231,10 +230,8 @@ export function spawnWorker(opts: WorkerOptions): ChildProcess {
args.push('-v', `${opts.outputDir}:/app/output`);
}
// Local mode: mount entire credentials directory. NPX mode: single file.
if (opts.credentialsDir) {
args.push('-v', `${opts.credentialsDir}:/app/credentials:ro`);
} else if (opts.credentials) {
// Mount credentials file to fixed container path
if (opts.credentials) {
args.push('-v', `${opts.credentials}:/app/credentials/google-sa-key.json:ro`);
}
-13
View File
@@ -37,19 +37,6 @@ export function getCredentialsPath(): string {
return path.join(SHANNON_HOME, 'google-sa-key.json');
}
/**
* In dev mode, return the credentials directory if it exists and has files.
* In npx mode, there is no credentials directory (single file mount instead).
*/
export function getCredentialsDir(): string | undefined {
if (getMode() !== 'local') return undefined;
const dir = path.resolve('credentials');
if (!fs.existsSync(dir)) return undefined;
const entries = fs.readdirSync(dir);
return entries.length > 0 ? dir : undefined;
}
/**
* Initialize state directories.