All files / proxy/utils/customer-variables/secrets-manager secrets-manager-variables.ts

87.5% Statements 21/24
100% Branches 7/7
100% Functions 5/5
87.5% Lines 21/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75  6x   6x 6x   6x             6x 74x             74x 74x   74x   74x 7x 7x                     297x   297x       297x 275x     22x 22x                       74x 74x               74x      
import { CustomerVariableProvider, CustomerVariableName, CustomerVariableReturn } from '../types'
import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'
import { CloudFrontRequest } from 'aws-lambda'
import { getHeaderValue } from '../../headers'
import { retrieveSecret } from './retrieve-secret'
import { NonNullableObject } from '../../types'
import { DEFAULT_REGION, SECRET_NAME_HEADER_KEY } from '../defaults'
 
interface SecretsInfo {
  secretName: string | null
  secretRegion: string | null
}
 
export class SecretsManagerVariables implements CustomerVariableProvider {
  readonly name = 'SecretsManagerVariables'
 
  private secretsInfo?: SecretsInfo
 
  private readonly secretsManager?: SecretsManagerClient
 
  constructor(
    private readonly request: CloudFrontRequest,
    private readonly cacheTtlMs?: number
  ) {
    this.readSecretsInfoFromHeaders()
 
    if (SecretsManagerVariables.isValidSecretInfo(this.secretsInfo)) {
      try {
        this.secretsManager = new SecretsManagerClient({ region: this.secretsInfo.secretRegion })
      } catch (error) {
        console.error('Failed to create secrets manager', {
          error,
          secretsInfo: this.secretsInfo,
        })
      }
    }
  }
 
  async getVariable(variable: CustomerVariableName): Promise<CustomerVariableReturn> {
    const secretsObject = await this.retrieveSecrets()
 
    return secretsObject?.[variable]?.toString() ?? null
  }
 
  private async retrieveSecrets() {
    if (!this.secretsManager) {
      return null
    }
 
    try {
      return await retrieveSecret(this.secretsManager, this.secretsInfo!.secretName!, this.cacheTtlMs)
    } catch (error) {
      console.error('Error retrieving secret from secrets manager', {
        error,
        secretsInfo: this.secretsInfo,
      })
 
      return null
    }
  }
 
  private readSecretsInfoFromHeaders() {
    if (!this.secretsInfo) {
      this.secretsInfo = {
        secretName: getHeaderValue(this.request, SECRET_NAME_HEADER_KEY),
        secretRegion: DEFAULT_REGION,
      }
    }
  }
 
  private static isValidSecretInfo(secretsInfo?: SecretsInfo): secretsInfo is NonNullableObject<SecretsInfo> {
    return Boolean(secretsInfo?.secretRegion && secretsInfo?.secretName)
  }
}