diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts index 4b231d07..8e88a089 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy-secrets.ts @@ -12,21 +12,42 @@ declare module 'fastify' { } // Docker secrets are mounted at /run/secrets/ by default in CapRover -const readSecretFile = (secretName: string): string | undefined => { +const readSecretFile = (secretName: string, logger?: any): string | undefined => { const secretPath = `/run/secrets/${secretName}` + logger?.debug({ secretPath, exists: fs.existsSync(secretPath) }, `Checking secret file: ${secretName}`) + if (fs.existsSync(secretPath)) { try { - return fs.readFileSync(secretPath, 'utf8').trim() + const content = fs.readFileSync(secretPath, 'utf8').trim() + logger?.info({ secretName, path: secretPath, length: content.length }, `Successfully read secret: ${secretName}`) + return content } catch (error) { - console.error(`Failed to read secret file ${secretPath}:`, error) + logger?.error({ error, secretPath }, `Failed to read secret file ${secretPath}`) return undefined } + } else { + logger?.warn({ secretPath }, `Secret file does not exist: ${secretPath}`) } return undefined } export default fp(async function (fastify) { const isProd = process.env.NODE_ENV === 'production' + + fastify.log.info({ isProd, nodeEnv: process.env.NODE_ENV }, 'Loading Privy secrets') + + // Debug: List all files in /run/secrets/ directory + const secretsDir = '/run/secrets' + if (fs.existsSync(secretsDir)) { + try { + const files = fs.readdirSync(secretsDir) + fastify.log.info({ files, dir: secretsDir }, 'Files found in /run/secrets/') + } catch (error) { + fastify.log.warn({ error }, 'Could not list /run/secrets/ directory') + } + } else { + fastify.log.warn({ dir: secretsDir }, '/run/secrets/ directory does not exist') + } let appId: string let appSecret: string @@ -34,9 +55,18 @@ export default fp(async function (fastify) { if (isProd) { // In production, read from Docker secrets (mounted files) - appId = readSecretFile('PRIVY_APP_ID') || process.env.PRIVY_APP_ID || '' - appSecret = readSecretFile('PRIVY_APP_SECRET') || process.env.PRIVY_APP_SECRET || '' - authKey = readSecretFile('PRIVY_AUTHORIZATION_KEY') || process.env.PRIVY_AUTHORIZATION_KEY || '' + 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 || '' + + fastify.log.info({ + appId: !!appId, + appSecret: !!appSecret, + authKey: !!authKey, + appIdLength: appId.length, + appSecretLength: appSecret.length, + authKeyLength: authKey.length + }, 'Privy secrets loaded from Docker secrets') } else { // In non-production, use env vars or file paths const readMaybeFile = (envKey: string, fileKey: string): string | undefined => { @@ -51,13 +81,14 @@ export default fp(async function (fastify) { } if (!appId || !appSecret || !authKey) { - fastify.log.warn('Privy secrets not fully resolved at plugin load.') - fastify.log.warn({ + fastify.log.error({ appId: !!appId, appSecret: !!appSecret, authKey: !!authKey, - isProd - }, 'Privy secrets status') + 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.') } fastify.decorate('privySecrets', { @@ -66,5 +97,9 @@ export default fp(async function (fastify) { authKey }) - fastify.log.info('Privy secrets decorated on Fastify instance') + fastify.log.info({ + appId: appId.substring(0, 10) + '...', + appSecret: appSecret.substring(0, 10) + '...', + authKey: authKey.substring(0, 20) + '...' + }, 'Privy secrets decorated on Fastify instance') }, { name: 'privy-secrets' }) diff --git a/src/Managing.Web3Proxy/src/plugins/external/env.ts b/src/Managing.Web3Proxy/src/plugins/external/env.ts index 20f41668..1e75bcf2 100644 --- a/src/Managing.Web3Proxy/src/plugins/external/env.ts +++ b/src/Managing.Web3Proxy/src/plugins/external/env.ts @@ -86,9 +86,16 @@ export const autoConfig = { * @see {@link https://github.com/fastify/fastify-env} */ export default fp(async (fastify) => { + // In production, Privy secrets come from Docker secrets (mounted files), not env vars + // Make them optional in the schema to avoid validation errors + const isProd = process.env.NODE_ENV === 'production' + const required = isProd + ? ['COOKIE_SECRET'] // In production, only require COOKIE_SECRET from env + : ['PRIVY_APP_ID', 'PRIVY_APP_SECRET', 'PRIVY_AUTHORIZATION_KEY', 'COOKIE_SECRET'] + const schema = { type: 'object', - required: ['PRIVY_APP_ID', 'PRIVY_APP_SECRET', 'PRIVY_AUTHORIZATION_KEY', 'COOKIE_SECRET'], + required: required, properties: { PRIVY_APP_ID: { type: 'string'