Fix secrets required injection for fastify
This commit is contained in:
@@ -12,15 +12,21 @@ declare module 'fastify' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Docker secrets are mounted at /run/secrets/ by default in CapRover
|
// 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}`
|
const secretPath = `/run/secrets/${secretName}`
|
||||||
|
logger?.debug({ secretPath, exists: fs.existsSync(secretPath) }, `Checking secret file: ${secretName}`)
|
||||||
|
|
||||||
if (fs.existsSync(secretPath)) {
|
if (fs.existsSync(secretPath)) {
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
console.error(`Failed to read secret file ${secretPath}:`, error)
|
logger?.error({ error, secretPath }, `Failed to read secret file ${secretPath}`)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger?.warn({ secretPath }, `Secret file does not exist: ${secretPath}`)
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@@ -28,15 +34,39 @@ const readSecretFile = (secretName: string): string | undefined => {
|
|||||||
export default fp(async function (fastify) {
|
export default fp(async function (fastify) {
|
||||||
const isProd = process.env.NODE_ENV === 'production'
|
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 appId: string
|
||||||
let appSecret: string
|
let appSecret: string
|
||||||
let authKey: string
|
let authKey: string
|
||||||
|
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
// In production, read from Docker secrets (mounted files)
|
// In production, read from Docker secrets (mounted files)
|
||||||
appId = readSecretFile('PRIVY_APP_ID') || process.env.PRIVY_APP_ID || ''
|
appId = readSecretFile('PRIVY_APP_ID', fastify.log) || process.env.PRIVY_APP_ID || ''
|
||||||
appSecret = readSecretFile('PRIVY_APP_SECRET') || process.env.PRIVY_APP_SECRET || ''
|
appSecret = readSecretFile('PRIVY_APP_SECRET', fastify.log) || process.env.PRIVY_APP_SECRET || ''
|
||||||
authKey = readSecretFile('PRIVY_AUTHORIZATION_KEY') || process.env.PRIVY_AUTHORIZATION_KEY || ''
|
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 {
|
} else {
|
||||||
// In non-production, use env vars or file paths
|
// In non-production, use env vars or file paths
|
||||||
const readMaybeFile = (envKey: string, fileKey: string): string | undefined => {
|
const readMaybeFile = (envKey: string, fileKey: string): string | undefined => {
|
||||||
@@ -51,13 +81,14 @@ export default fp(async function (fastify) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!appId || !appSecret || !authKey) {
|
if (!appId || !appSecret || !authKey) {
|
||||||
fastify.log.warn('Privy secrets not fully resolved at plugin load.')
|
fastify.log.error({
|
||||||
fastify.log.warn({
|
|
||||||
appId: !!appId,
|
appId: !!appId,
|
||||||
appSecret: !!appSecret,
|
appSecret: !!appSecret,
|
||||||
authKey: !!authKey,
|
authKey: !!authKey,
|
||||||
isProd
|
isProd,
|
||||||
}, 'Privy secrets status')
|
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', {
|
fastify.decorate('privySecrets', {
|
||||||
@@ -66,5 +97,9 @@ export default fp(async function (fastify) {
|
|||||||
authKey
|
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' })
|
}, { name: 'privy-secrets' })
|
||||||
|
|||||||
@@ -86,9 +86,16 @@ export const autoConfig = {
|
|||||||
* @see {@link https://github.com/fastify/fastify-env}
|
* @see {@link https://github.com/fastify/fastify-env}
|
||||||
*/
|
*/
|
||||||
export default fp(async (fastify) => {
|
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 = {
|
const schema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['PRIVY_APP_ID', 'PRIVY_APP_SECRET', 'PRIVY_AUTHORIZATION_KEY', 'COOKIE_SECRET'],
|
required: required,
|
||||||
properties: {
|
properties: {
|
||||||
PRIVY_APP_ID: {
|
PRIVY_APP_ID: {
|
||||||
type: 'string'
|
type: 'string'
|
||||||
|
|||||||
Reference in New Issue
Block a user