From 80a88bf076735a5170d101ce7603da069d2c4ab9 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 4 Apr 2026 04:30:44 +0000 Subject: [PATCH] fix: add defensive checks in storage resolvers instead of non-null assertions Replace cdn! and credential! non-null assertions with explicit error messages in both bucket-provisioner-resolver.ts and presigned-url-resolver.ts. If CDN env vars are missing, the resolvers now throw clear errors explaining which variables to set, instead of silently passing undefined to S3 clients. --- .../src/bucket-provisioner-resolver.ts | 22 +++++++++++--- .../src/presigned-url-resolver.ts | 29 ++++++++++++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/graphile/graphile-settings/src/bucket-provisioner-resolver.ts b/graphile/graphile-settings/src/bucket-provisioner-resolver.ts index a999030ec..28107a0d6 100644 --- a/graphile/graphile-settings/src/bucket-provisioner-resolver.ts +++ b/graphile/graphile-settings/src/bucket-provisioner-resolver.ts @@ -29,8 +29,22 @@ export function getBucketProvisionerConnection(): StorageConnectionConfig { const { cdn } = getEnvOptions(); - // cdn is guaranteed populated — pgpmDefaults provides all CDN fields - const { provider, awsRegion, awsAccessKey, awsSecretKey, endpoint } = cdn!; + if (!cdn) { + throw new Error( + '[bucket-provisioner-resolver] CDN config not found. ' + + 'Ensure CDN environment variables (AWS_ACCESS_KEY, AWS_SECRET_KEY, etc.) ' + + 'are set or that pgpmDefaults provides CDN fields.', + ); + } + + const { provider, awsRegion, awsAccessKey, awsSecretKey, endpoint } = cdn; + + if (!awsAccessKey || !awsSecretKey) { + throw new Error( + '[bucket-provisioner-resolver] Missing S3 credentials. ' + + 'Set AWS_ACCESS_KEY and AWS_SECRET_KEY environment variables.', + ); + } log.info( `[bucket-provisioner-resolver] Initializing: provider=${provider} endpoint=${endpoint}`, @@ -39,8 +53,8 @@ export function getBucketProvisionerConnection(): StorageConnectionConfig { connectionConfig = { provider: (provider as StorageConnectionConfig['provider']) || 'minio', region: awsRegion || 'us-east-1', - accessKeyId: awsAccessKey!, - secretAccessKey: awsSecretKey!, + accessKeyId: awsAccessKey, + secretAccessKey: awsSecretKey, ...(endpoint ? { endpoint, forcePathStyle: true } : {}), }; diff --git a/graphile/graphile-settings/src/presigned-url-resolver.ts b/graphile/graphile-settings/src/presigned-url-resolver.ts index 72af621bb..1d317fb26 100644 --- a/graphile/graphile-settings/src/presigned-url-resolver.ts +++ b/graphile/graphile-settings/src/presigned-url-resolver.ts @@ -29,8 +29,29 @@ export function getPresignedUrlS3Config(): S3Config { const { cdn } = getEnvOptions(); - // cdn is guaranteed populated — pgpmDefaults provides all CDN fields - const { bucketName, awsRegion, awsAccessKey, awsSecretKey, endpoint, publicUrlPrefix } = cdn!; + if (!cdn) { + throw new Error( + '[presigned-url-resolver] CDN config not found. ' + + 'Ensure CDN environment variables (AWS_ACCESS_KEY, AWS_SECRET_KEY, etc.) ' + + 'are set or that pgpmDefaults provides CDN fields.', + ); + } + + const { bucketName, awsRegion, awsAccessKey, awsSecretKey, endpoint, publicUrlPrefix } = cdn; + + if (!awsAccessKey || !awsSecretKey) { + throw new Error( + '[presigned-url-resolver] Missing S3 credentials. ' + + 'Set AWS_ACCESS_KEY and AWS_SECRET_KEY environment variables.', + ); + } + + if (!bucketName) { + throw new Error( + '[presigned-url-resolver] Missing CDN bucket name. ' + + 'Set CDN_BUCKET_NAME environment variable.', + ); + } log.info( `[presigned-url-resolver] Initializing: bucket=${bucketName} endpoint=${endpoint}`, @@ -38,13 +59,13 @@ export function getPresignedUrlS3Config(): S3Config { const client = new S3Client({ region: awsRegion, - credentials: { accessKeyId: awsAccessKey!, secretAccessKey: awsSecretKey! }, + credentials: { accessKeyId: awsAccessKey, secretAccessKey: awsSecretKey }, ...(endpoint ? { endpoint, forcePathStyle: true } : {}), }); s3Config = { client, - bucket: bucketName!, + bucket: bucketName, region: awsRegion, publicUrlPrefix, ...(endpoint ? { endpoint, forcePathStyle: true } : {}),