diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts index 8e88a089..15afd8e8 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts @@ -38,15 +38,27 @@ export default fp(async function (fastify) { // Debug: List all files in /run/secrets/ directory const secretsDir = '/run/secrets' + let availableFiles: string[] = [] if (fs.existsSync(secretsDir)) { try { - const files = fs.readdirSync(secretsDir) - fastify.log.info({ files, dir: secretsDir }, 'Files found in /run/secrets/') + availableFiles = fs.readdirSync(secretsDir) + fastify.log.info({ files: availableFiles, dir: secretsDir, count: availableFiles.length }, 'Files found in /run/secrets/') + + // Also log full paths and their sizes + availableFiles.forEach(file => { + const fullPath = `${secretsDir}/${file}` + try { + const stats = fs.statSync(fullPath) + fastify.log.debug({ file, path: fullPath, size: stats.size, isFile: stats.isFile() }, `Secret file details: ${file}`) + } catch (err) { + fastify.log.warn({ file, path: fullPath, error: err }, `Could not stat secret file: ${file}`) + } + }) } catch (error) { fastify.log.warn({ error }, 'Could not list /run/secrets/ directory') } } else { - fastify.log.warn({ dir: secretsDir }, '/run/secrets/ directory does not exist') + fastify.log.error({ dir: secretsDir }, '/run/secrets/ directory does not exist - Docker secrets may not be mounted') } let appId: string @@ -55,17 +67,44 @@ export default fp(async function (fastify) { if (isProd) { // In production, read from Docker secrets (mounted files) + // Try exact names first appId = readSecretFile('PRIVY_APP_ID', fastify.log) || process.env.PRIVY_APP_ID || '' appSecret = readSecretFile('PRIVY_APP_SECRET', fastify.log) || process.env.PRIVY_APP_SECRET || '' authKey = readSecretFile('PRIVY_AUTHORIZATION_KEY', fastify.log) || process.env.PRIVY_AUTHORIZATION_KEY || '' + // If not found, try alternative names (maybe they're mounted with SecretName instead of File.Name) + if (!appId && availableFiles.length > 0) { + const appIdFile = availableFiles.find(f => f.toLowerCase().includes('app_id') || f.toLowerCase().includes('appid')) + if (appIdFile) { + fastify.log.info({ foundFile: appIdFile, trying: 'PRIVY_APP_ID' }, 'Trying alternative file name for PRIVY_APP_ID') + appId = readSecretFile(appIdFile, fastify.log) || '' + } + } + + if (!appSecret && availableFiles.length > 0) { + const appSecretFile = availableFiles.find(f => f.toLowerCase().includes('app_secret') || f.toLowerCase().includes('appsecret')) + if (appSecretFile) { + fastify.log.info({ foundFile: appSecretFile, trying: 'PRIVY_APP_SECRET' }, 'Trying alternative file name for PRIVY_APP_SECRET') + appSecret = readSecretFile(appSecretFile, fastify.log) || '' + } + } + + if (!authKey && availableFiles.length > 0) { + const authKeyFile = availableFiles.find(f => f.toLowerCase().includes('auth_key') || f.toLowerCase().includes('authkey') || f.toLowerCase().includes('authorization')) + if (authKeyFile) { + fastify.log.info({ foundFile: authKeyFile, trying: 'PRIVY_AUTHORIZATION_KEY' }, 'Trying alternative file name for PRIVY_AUTHORIZATION_KEY') + authKey = readSecretFile(authKeyFile, fastify.log) || '' + } + } + fastify.log.info({ appId: !!appId, appSecret: !!appSecret, authKey: !!authKey, appIdLength: appId.length, appSecretLength: appSecret.length, - authKeyLength: authKey.length + authKeyLength: authKey.length, + availableSecretFiles: availableFiles }, 'Privy secrets loaded from Docker secrets') } else { // In non-production, use env vars or file paths @@ -80,15 +119,38 @@ export default fp(async function (fastify) { authKey = readMaybeFile('PRIVY_AUTHORIZATION_KEY', 'PRIVY_AUTHORIZATION_KEY_FILE') || '' } + // Log error but don't throw - let the app start so we can see logs + // The actual error will be thrown when secrets are used if (!appId || !appSecret || !authKey) { fastify.log.error({ appId: !!appId, appSecret: !!appSecret, authKey: !!authKey, isProd, - nodeEnv: process.env.NODE_ENV - }, 'Privy secrets not fully resolved at plugin load') - throw new Error('Missing required Privy secrets. Check Docker secrets are mounted correctly.') + nodeEnv: process.env.NODE_ENV, + availableSecretFiles: availableFiles, + secretsDirExists: fs.existsSync(secretsDir) + }, '⚠️ WARNING: Privy secrets not fully resolved at plugin load - app will continue but Privy operations will fail') + + // Still decorate with empty strings so the app doesn't crash + // The actual error will be thrown in getPrivyClient when it's used + fastify.decorate('privySecrets', { + appId: appId || '', + appSecret: appSecret || '', + authKey: authKey || '' + }) + + fastify.log.error({ + message: 'Please check:', + checks: [ + '1. Docker secrets are created: docker secret ls', + '2. preDeployFunction in captain-definition is executing', + '3. Secret IDs in captain-definition match actual secret IDs', + '4. Container has access to /run/secrets/ directory' + ] + }, 'Debugging steps for missing secrets') + + return // Continue without throwing } fastify.decorate('privySecrets', { @@ -101,5 +163,5 @@ export default fp(async function (fastify) { appId: appId.substring(0, 10) + '...', appSecret: appSecret.substring(0, 10) + '...', authKey: authKey.substring(0, 20) + '...' - }, 'Privy secrets decorated on Fastify instance') + }, '✅ Privy secrets decorated on Fastify instance successfully') }, { name: 'privy-secrets' }) diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts index d0aa2a40..8c5f7e43 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts @@ -1329,13 +1329,20 @@ export default fp(async (fastify) => { return getWalletBalance.call(this, reply, address, assets, chains); }); - // Test the Privy client initialization + // Test the Privy client initialization (non-blocking) + // Don't throw on error - let the app start so we can debug try { const testClient = getPrivyClient(fastify); - fastify.log.info(`Privy client initialized successfully: ${(await testClient.getAppSettings()).id}`); + const appSettings = await testClient.getAppSettings(); + fastify.log.info({ appId: appSettings.id }, '✅ Privy client initialized successfully'); } catch (error) { - fastify.log.error(`Failed to initialize Privy client: ${error}`); - throw error; + fastify.log.error({ + error: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined + }, '❌ Failed to initialize Privy client during plugin registration'); + // Don't throw - let the app start so we can see debug logs + // The error will be thrown when Privy is actually used + fastify.log.warn('App will continue but Privy operations will fail until secrets are configured'); } }, { name: 'privy-plugin'