From c90239fd4c035fda3f879902d4bc098e5f4b7444 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Tue, 6 Oct 2020 13:12:22 +0200 Subject: [PATCH 1/8] [#175119553] Added config module --- utils/config.ts | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 utils/config.ts diff --git a/utils/config.ts b/utils/config.ts new file mode 100644 index 00000000..615771c8 --- /dev/null +++ b/utils/config.ts @@ -0,0 +1,144 @@ +/** + * Config module + * + * Single point of access for the application confguration. Handles validation on required environment variables. + * The configuration is evaluate eagerly at the first access to the module. The module exposes convenient methods to access such value. + */ + +import { MailMultiTransportConnectionsFromString } from "io-functions-commons/dist/src/utils/multi_transport_connection"; +import * as t from "io-ts"; +import { readableReport } from "italia-ts-commons/lib/reporters"; +import { NonEmptyString } from "italia-ts-commons/lib/strings"; + +// exclude a specific value from a type +// as strict equality is performed, allowed input types are constrained to be values not references (object, arrays, etc) +// tslint:disable-next-line max-union-size +const AnyBut = ( + but: A, + base: t.Type = t.any +) => + t.brand( + base, + ( + s + ): s is t.Branded< + t.TypeOf, + { readonly AnyBut: unique symbol } + > => s !== but, + "AnyBut" + ); + +// configuration to send email +export type MailerConfig = t.TypeOf; +export const MailerConfig = t.intersection([ + // common required fields + t.interface({ + MAIL_FROM: NonEmptyString + }), + // the following union includes the possible configuration variants for different mail transports we use in prod + // undefined values are kept for easy usage + t.union([ + // Using sendgrid + // we allow mailup values as well, as sendgrid would be selected first if present + t.intersection([ + t.interface({ + MAILHOG_HOSTNAME: t.undefined, + MAIL_TRANSPORTS: t.undefined, + NODE_ENV: t.literal("production"), + SENDGRID_API_KEY: NonEmptyString + }), + t.partial({ + MAILUP_SECRET: NonEmptyString, + MAILUP_USERNAME: NonEmptyString + }) + ]), + // using mailup + t.interface({ + MAILHOG_HOSTNAME: t.undefined, + MAILUP_SECRET: NonEmptyString, + MAILUP_USERNAME: NonEmptyString, + MAIL_TRANSPORTS: t.undefined, + NODE_ENV: t.literal("production"), + SENDGRID_API_KEY: t.undefined + }), + // Using multi-transport definition + // Optional multi provider connection string + // The connection string must be in the format: + // [mailup:username:password;][sendgrid:apikey:;] + // Note that multiple instances of the same provider can be provided. + t.interface({ + MAILHOG_HOSTNAME: t.undefined, + MAILUP_SECRET: t.undefined, + MAILUP_USERNAME: t.undefined, + MAIL_TRANSPORTS: MailMultiTransportConnectionsFromString, + NODE_ENV: t.literal("production"), + SENDGRID_API_KEY: t.undefined + }), + // the following states that a mailhog configuration is optional and can be provided only if not in prod + t.interface({ + MAILHOG_HOSTNAME: NonEmptyString, + MAILUP_SECRET: t.undefined, + MAILUP_USERNAME: t.undefined, + MAIL_TRANSPORTS: t.undefined, + NODE_ENV: AnyBut("production", t.string), + SENDGRID_API_KEY: t.undefined + }) + ]) +]); + +// global app configuration +export type IConfig = t.TypeOf; +export const IConfig = t.intersection([ + t.interface({ + QueueStorageConnection: NonEmptyString, + MESSAGE_CONTAINER_NAME: NonEmptyString, + SUBSCRIPTIONS_FEED_TABLE: NonEmptyString, + + CUSTOMCONNSTR_COSMOSDB_KEY: NonEmptyString, + CUSTOMCONNSTR_COSMOSDB_URI: NonEmptyString, + COSMOSDB_NAME: NonEmptyString, + + FUNCTION_PUBLIC_URL: NonEmptyString, + PUBLIC_API_URL: NonEmptyString, + PUBLIC_API_KEY: NonEmptyString, + + SPID_LOGS_PUBLIC_KEY: NonEmptyString, + + AZURE_NH_HUB_NAME: NonEmptyString, + AZURE_NH_ENDPOINT: NonEmptyString, + + REQ_SERVICE_ID: t.undefined, + + isProduction: t.boolean + }), + MailerConfig +]); + +// No need to re-evaluate this object for each call +const errorOrConfig: t.Validation = IConfig.decode({ + ...process.env, + isProduction: process.env.NODE_ENV === "production" +}); + +/** + * Read the application configuration and check for invalid values. + * Configuration is eagerly evalued when the application starts. + * + * @returns either the configuration values or a list of validation errors + */ +export function getConfig(): t.Validation { + return errorOrConfig; +} + +/** + * Read the application configuration and check for invalid values. + * If the application is not valid, raises an exception. + * + * @returns the configuration values + * @throws validation errors found while parsing the application configuration + */ +export function getConfigOrThrow(): IConfig { + return errorOrConfig.getOrElseL(errors => { + throw new Error(`Invalid configuration: ${readableReport(errors)}`); + }); +} From 3d56063a7f22f03d8a76a31879b93b2d25b1b4aa Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Tue, 6 Oct 2020 17:07:49 +0200 Subject: [PATCH 2/8] [#175119553] use config module for configurations --- CreateValidationTokenActivity/index.ts | 7 +- GetMessage/index.ts | 9 +- GetMessages/index.ts | 7 +- GetVisibleServices/index.ts | 7 +- .../__tests__/handler.test.ts | 18 +- .../__tests__/handler.test.ts | 18 +- SendValidationEmailActivity/index.ts | 21 +- SendWelcomeMessagesActivity/index.ts | 9 +- StoreSpidLogs/__test__/index.test.ts | 19 +- StoreSpidLogs/index.ts | 5 +- UpdateSubscriptionsFeedActivity/index.ts | 10 +- docker/fixtures/index.ts | 13 +- utils/__tests__/config.test.ts | 181 ++++++++++++++++++ utils/config.ts | 23 ++- utils/cosmosdb.ts | 11 +- utils/email.ts | 6 +- utils/notification.ts | 8 +- 17 files changed, 325 insertions(+), 47 deletions(-) create mode 100644 utils/__tests__/config.test.ts diff --git a/CreateValidationTokenActivity/index.ts b/CreateValidationTokenActivity/index.ts index 146814db..0acbd5ae 100644 --- a/CreateValidationTokenActivity/index.ts +++ b/CreateValidationTokenActivity/index.ts @@ -5,16 +5,19 @@ import { createTableService } from "azure-storage"; import { Millisecond } from "italia-ts-commons/lib/units"; import { VALIDATION_TOKEN_TABLE_NAME } from "io-functions-commons/dist/src/entities/validation_token"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { ulidGenerator } from "io-functions-commons/dist/src/utils/strings"; import { getCreateValidationTokenActivityHandler } from "./handler"; +import { getConfigOrThrow } from "../utils/config"; + +const config = getConfigOrThrow(); + const TOKEN_INVALID_AFTER_MS = (1000 * 60 * 60 * 24 * 30) as Millisecond; // 30 days // TODO: Rename this env to `StorageConnection` // https://www.pivotaltracker.com/story/show/169591817 -const storageConnectionString = getRequiredStringEnv("QueueStorageConnection"); +const storageConnectionString = config.QueueStorageConnection; const tableService = createTableService(storageConnectionString); diff --git a/GetMessage/index.ts b/GetMessage/index.ts index d41cf407..10436b36 100644 --- a/GetMessage/index.ts +++ b/GetMessage/index.ts @@ -2,7 +2,6 @@ import { Context } from "@azure/functions"; import * as express from "express"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { secureExpressApp } from "io-functions-commons/dist/src/utils/express"; import { setAppContext } from "io-functions-commons/dist/src/utils/middlewares/context_middleware"; @@ -18,18 +17,22 @@ import createAzureFunctionHandler from "io-functions-express/dist/src/createAzur import { cosmosdbInstance } from "../utils/cosmosdb"; import { GetMessage } from "./handler"; +import { getConfigOrThrow } from "../utils/config"; + // Setup Express const app = express(); secureExpressApp(app); -const messageContainerName = getRequiredStringEnv("MESSAGE_CONTAINER_NAME"); +const config = getConfigOrThrow(); + +const messageContainerName = config.MESSAGE_CONTAINER_NAME; const messageModel = new MessageModel( cosmosdbInstance.container(MESSAGE_COLLECTION_NAME), messageContainerName ); -const storageConnectionString = getRequiredStringEnv("QueueStorageConnection"); +const storageConnectionString = config.QueueStorageConnection; const blobService = createBlobService(storageConnectionString); app.get( diff --git a/GetMessages/index.ts b/GetMessages/index.ts index f9e77678..fee71eda 100644 --- a/GetMessages/index.ts +++ b/GetMessages/index.ts @@ -2,7 +2,6 @@ import { Context } from "@azure/functions"; import * as express from "express"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { secureExpressApp } from "io-functions-commons/dist/src/utils/express"; import { setAppContext } from "io-functions-commons/dist/src/utils/middlewares/context_middleware"; @@ -16,11 +15,15 @@ import createAzureFunctionHandler from "io-functions-express/dist/src/createAzur import { cosmosdbInstance } from "../utils/cosmosdb"; import { GetMessages } from "./handler"; +import { getConfigOrThrow } from "../utils/config"; + // Setup Express const app = express(); secureExpressApp(app); -const messageContainerName = getRequiredStringEnv("MESSAGE_CONTAINER_NAME"); +const config = getConfigOrThrow(); + +const messageContainerName = config.MESSAGE_CONTAINER_NAME; const messageModel = new MessageModel( cosmosdbInstance.container(MESSAGE_COLLECTION_NAME), diff --git a/GetVisibleServices/index.ts b/GetVisibleServices/index.ts index 5f6850e2..f1e378db 100644 --- a/GetVisibleServices/index.ts +++ b/GetVisibleServices/index.ts @@ -3,7 +3,6 @@ import { createBlobService } from "azure-storage"; import * as express from "express"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { secureExpressApp } from "io-functions-commons/dist/src/utils/express"; import { setAppContext } from "io-functions-commons/dist/src/utils/middlewares/context_middleware"; @@ -11,11 +10,15 @@ import createAzureFunctionHandler from "io-functions-express/dist/src/createAzur import { GetVisibleServices } from "./handler"; +import { getConfigOrThrow } from "../utils/config"; + // Setup Express const app = express(); secureExpressApp(app); -const storageConnectionString = getRequiredStringEnv("QueueStorageConnection"); +const config = getConfigOrThrow(); + +const storageConnectionString = config.QueueStorageConnection; const blobService = createBlobService(storageConnectionString); app.get("/api/v1/services", GetVisibleServices(blobService)); diff --git a/HandleNHNotificationCallActivity/__tests__/handler.test.ts b/HandleNHNotificationCallActivity/__tests__/handler.test.ts index ba34024e..dd91c9fc 100644 --- a/HandleNHNotificationCallActivity/__tests__/handler.test.ts +++ b/HandleNHNotificationCallActivity/__tests__/handler.test.ts @@ -2,9 +2,25 @@ // tslint:disable-next-line: no-object-mutation process.env = { ...process.env, + MESSAGE_CONTAINER_NAME: "msg", + QueueStorageConnection: "foobar", AZURE_NH_ENDPOINT: "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=XXX", - AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME" + AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", + SUBSCRIPTIONS_FEED_TABLE: "feed", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", + COSMOSDB_NAME: "cosmoname", + COSMOSDB_URI: "uri", + COSMOSDB_KEY: "key", + FUNCTIONS_PUBLIC_URL: "url", + PUBLIC_API_URL: "url", + PUBLIC_API_KEY: "key", + MAILHOG_HOSTNAME: "mailhog", + MAIL_FROM: "mail@example.it", + NODE_ENV: "dev", + REQ_SERVICE_ID: "req_id_dev", + SPID_LOGS_PUBLIC_KEY: "key" }; import { NonEmptyString } from "italia-ts-commons/lib/strings"; diff --git a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts index fc456178..8f2efe70 100644 --- a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts +++ b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts @@ -2,9 +2,25 @@ // tslint:disable-next-line: no-object-mutation process.env = { ...process.env, + QueueStorageConnection: "foobar", + MESSAGE_CONTAINER_NAME: "msg", + SUBSCRIPTIONS_FEED_TABLE: "feed", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", + COSMOSDB_NAME: "cosmoname", + COSMOSDB_URI: "uri", AZURE_NH_ENDPOINT: "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=C4xIzNZv4VrUnu5jkmPH635MApRUj8wABky8VfduYqg=", - AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME" + AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", + COSMOSDB_KEY: "key", + FUNCTIONS_PUBLIC_URL: "url", + PUBLIC_API_URL: "url", + PUBLIC_API_KEY: "key", + MAILHOG_HOSTNAME: "mailhog", + MAIL_FROM: "mail@example.it", + NODE_ENV: "dev", + REQ_SERVICE_ID: "req_id_dev", + SPID_LOGS_PUBLIC_KEY: "key" }; import { NonEmptyString } from "italia-ts-commons/lib/strings"; import { context as contextMock } from "../../__mocks__/durable-functions"; diff --git a/SendValidationEmailActivity/index.ts b/SendValidationEmailActivity/index.ts index cbe9ba2d..9cf2608d 100644 --- a/SendValidationEmailActivity/index.ts +++ b/SendValidationEmailActivity/index.ts @@ -1,5 +1,4 @@ -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; -import { MailMultiTransportConnectionsFromString } from "io-functions-commons/dist/src/utils/multi_transport_connection"; +import { MailMultiTransportConnectionsFromString } from "io-functions-commons/dist/src/utils/multi_transport_connection"; import { MultiTransport } from "io-functions-commons/dist/src/utils/nodemailer"; import { NonEmptyString } from "italia-ts-commons/lib/strings"; @@ -14,24 +13,28 @@ import { import { initTelemetryClient } from "../utils/appinsights"; +import { getConfigOrThrow } from "../utils/config"; + +const config = getConfigOrThrow(); + // Whether we're in a production environment -const isProduction = process.env.NODE_ENV === "production"; +const isProduction = config.NODE_ENV === "production"; // Optional SendGrid key const sendgridApiKey = NonEmptyString.decode( - process.env.SENDGRID_API_KEY + config.SENDGRID_API_KEY ).getOrElse(undefined); // Mailup -const mailupUsername = getRequiredStringEnv("MAILUP_USERNAME"); -const mailupSecret = getRequiredStringEnv("MAILUP_SECRET"); +const mailupUsername = config.MAILUP_USERNAME; +const mailupSecret = config.MAILUP_SECRET; // Email data const EMAIL_TITLE = "Valida l’indirizzo email che usi su IO"; -const mailFrom = getRequiredStringEnv("MAIL_FROM"); +const mailFrom = config.MAIL_FROM; // Needed to construct the email validation url -const functionsPublicUrl = getRequiredStringEnv("FUNCTIONS_PUBLIC_URL"); +const functionsPublicUrl = config.FUNCTIONS_PUBLIC_URL; const HTML_TO_TEXT_OPTIONS: HtmlToTextOptions = { ignoreImage: true, // Ignore all document images @@ -51,7 +54,7 @@ export type EmailDefaults = typeof emailDefaults; // [mailup:username:password;][sendgrid:apikey:;] // Note that multiple instances of the same provider can be provided. const transports = MailMultiTransportConnectionsFromString.decode( - process.env.MAIL_TRANSPORTS + config.MAIL_TRANSPORTS ) .map(getTransportsForConnections) .getOrElse([]); diff --git a/SendWelcomeMessagesActivity/index.ts b/SendWelcomeMessagesActivity/index.ts index 5a520fd9..4ffb00b0 100644 --- a/SendWelcomeMessagesActivity/index.ts +++ b/SendWelcomeMessagesActivity/index.ts @@ -1,4 +1,3 @@ -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { agent } from "italia-ts-commons"; import { AbortableFetch, @@ -8,12 +7,16 @@ import { import { Millisecond } from "italia-ts-commons/lib/units"; import { getActivityFunction } from "./handler"; +import { getConfigOrThrow } from "../utils/config"; + // HTTP external requests timeout in milliseconds const DEFAULT_REQUEST_TIMEOUT_MS = 10000; +const config = getConfigOrThrow(); + // Needed to call notifications API -const publicApiUrl = getRequiredStringEnv("PUBLIC_API_URL"); -const publicApiKey = getRequiredStringEnv("PUBLIC_API_KEY"); +const publicApiUrl = config.PUBLIC_API_URL; +const publicApiKey = config.PUBLIC_API_KEY; // HTTP-only fetch with optional keepalive agent // @see https://github.com/pagopa/io-ts-commons/blob/master/src/agent.ts#L10 diff --git a/StoreSpidLogs/__test__/index.test.ts b/StoreSpidLogs/__test__/index.test.ts index 86e10073..4eab1b9e 100644 --- a/StoreSpidLogs/__test__/index.test.ts +++ b/StoreSpidLogs/__test__/index.test.ts @@ -2,8 +2,10 @@ /* tslint:disable:no-object-mutation */ process.env = { + UBSCRIPTIONS_FEED_TABLE: "feed", APPINSIGHTS_INSTRUMENTATIONKEY: "foo", QueueStorageConnection: "foobar", + SUBSCRIPTIONS_FEED_TABLE: "feed", SPID_BLOB_CONTAINER_NAME: "spidblob", SPID_BLOB_STORAGE_CONNECTION_STRING: "foobar", SPID_LOGS_PUBLIC_KEY: `-----BEGIN PUBLIC KEY----- @@ -11,7 +13,22 @@ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhiXpvLD8UMMUy1T2JCzo/Sj5E l09Fs0z2U4aA37BrXlSo1DwQ2O9i2XFxXGJmE83siSWEfRlMWlabMu7Yj6dkZvmj dGIO4gotO33TgiAQcwRo+4pwjoCN7Td47yssCcj9C727zBt+Br+XK7B1bRcqjc0J YdF4yiVtD7G4RDXmRQIDAQAB ------END PUBLIC KEY-----` +-----END PUBLIC KEY-----`, + MESSAGE_CONTAINER_NAME: "msg", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + COSMOSDB_NAME: "cosmoname", + COSMOSDB_URI: "uri", + COSMOSDB_KEY: "key", + FUNCTIONS_PUBLIC_URL: "url", + PUBLIC_API_URL: "url", + PUBLIC_API_KEY: "key", + MAILHOG_HOSTNAME: "mailhog", + MAIL_FROM: "mail@example.it", + NODE_ENV: "dev", + REQ_SERVICE_ID: "req_id_dev", + AZURE_NH_HUB_NAME: "azhub", + AZURE_NH_ENDPOINT: "azendpoint", }; import { format } from "date-fns"; diff --git a/StoreSpidLogs/index.ts b/StoreSpidLogs/index.ts index bee3fe59..d8e1d310 100644 --- a/StoreSpidLogs/index.ts +++ b/StoreSpidLogs/index.ts @@ -2,7 +2,6 @@ import { Context } from "@azure/functions"; import { sequenceS } from "fp-ts/lib/Apply"; import { either } from "fp-ts/lib/Either"; import { curry } from "fp-ts/lib/function"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import * as t from "io-ts"; import { UTCISODateFromString } from "italia-ts-commons/lib/dates"; import { @@ -12,8 +11,10 @@ import { import { readableReport } from "italia-ts-commons/lib/reporters"; import { IPString, PatternString } from "italia-ts-commons/lib/strings"; import { initTelemetryClient } from "../utils/appinsights"; +import { getConfigOrThrow } from "../utils/config"; -const rsaPublicKey = getRequiredStringEnv("SPID_LOGS_PUBLIC_KEY"); +const config = getConfigOrThrow(); +const rsaPublicKey = config.SPID_LOGS_PUBLIC_KEY; const encrypt = curry(toEncryptedPayload)(rsaPublicKey); /** diff --git a/UpdateSubscriptionsFeedActivity/index.ts b/UpdateSubscriptionsFeedActivity/index.ts index 0aa27b70..ed30aaf3 100644 --- a/UpdateSubscriptionsFeedActivity/index.ts +++ b/UpdateSubscriptionsFeedActivity/index.ts @@ -8,17 +8,19 @@ import { createTableService, TableUtilities } from "azure-storage"; import { readableReport } from "italia-ts-commons/lib/reporters"; import { FiscalCode } from "italia-ts-commons/lib/strings"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; - import { ServiceId } from "io-functions-commons/dist/generated/definitions/ServiceId"; import { isNone } from "fp-ts/lib/Option"; import { deleteTableEntity, insertTableEntity } from "../utils/storage"; -const storageConnectionString = getRequiredStringEnv("QueueStorageConnection"); +import { getConfigOrThrow } from "../utils/config"; + +const config = getConfigOrThrow(); + +const storageConnectionString = config.QueueStorageConnection; const tableService = createTableService(storageConnectionString); -const subscriptionsFeedTable = getRequiredStringEnv("SUBSCRIPTIONS_FEED_TABLE"); +const subscriptionsFeedTable = config.SUBSCRIPTIONS_FEED_TABLE; const insertEntity = insertTableEntity(tableService, subscriptionsFeedTable); const deleteEntity = deleteTableEntity(tableService, subscriptionsFeedTable); diff --git a/docker/fixtures/index.ts b/docker/fixtures/index.ts index c4a904e5..674ab16b 100644 --- a/docker/fixtures/index.ts +++ b/docker/fixtures/index.ts @@ -18,11 +18,14 @@ import { import { sequenceT } from "fp-ts/lib/Apply"; import { TaskEither, taskEitherSeq, tryCatch } from "fp-ts/lib/TaskEither"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; -const cosmosDbKey = getRequiredStringEnv("CUSTOMCONNSTR_COSMOSDB_KEY"); -const cosmosDbUri = getRequiredStringEnv("CUSTOMCONNSTR_COSMOSDB_URI"); -const cosmosDbName = getRequiredStringEnv("COSMOSDB_NAME"); +import { getConfigOrThrow } from "../../utils/config"; + +const config = getConfigOrThrow(); + +const cosmosDbKey = config.CUSTOMCONNSTR_COSMOSDB_KEY; +const cosmosDbUri = config.CUSTOMCONNSTR_COSMOSDB_URI; +const cosmosDbName = config.COSMOSDB_NAME; export const cosmosdbClient = new CosmosClient({ endpoint: cosmosDbUri, @@ -56,7 +59,7 @@ const aService: Service = Service.decode({ organizationFiscalCode: "01234567890", organizationName: "Organization name", requireSecureChannels: false, - serviceId: process.env.REQ_SERVICE_ID, + serviceId: config.REQ_SERVICE_ID, serviceName: "MyServiceName" }).getOrElseL(() => { throw new Error("Cannot decode service payload."); diff --git a/utils/__tests__/config.test.ts b/utils/__tests__/config.test.ts new file mode 100644 index 00000000..3eb664a0 --- /dev/null +++ b/utils/__tests__/config.test.ts @@ -0,0 +1,181 @@ +import { Either } from "fp-ts/lib/Either"; +import { IConfig, MailerConfig } from "../config"; + +const aMailFrom = "example@test.com"; + +const noop = () => {}; +const expectRight = (e: Either, t: (r: R) => void = noop) => + e.fold( + _ => + fail(`Expecting right, received left. Value: ${JSON.stringify(e.value)}`), + _ => t(_) + ); + +const expectLeft = (e: Either, t: (l: L) => void = noop) => + e.fold( + _ => t(_), + _ => + fail(`Expecting left, received right. Value: ${JSON.stringify(e.value)}`) + ); + +describe("MailerConfig", () => { + it("should decode configuration for sendgrid", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + SENDGRID_API_KEY: "a-sg-key" + }; + const result = MailerConfig.decode(rawConf); + + expectRight(result, value => { + expect(value.SENDGRID_API_KEY).toBe("a-sg-key"); + expect(typeof value.MAILUP_USERNAME).toBe("undefined"); + }); + }); + + it("should decode configuration for sendgrid even if mailup conf is passed", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + SENDGRID_API_KEY: "a-sg-key", + MAILUP_USERNAME: "a-mu-username", + MAILUP_SECRET: "a-mu-secret" + }; + const result = MailerConfig.decode(rawConf); + + expectRight(result, value => { + expect(value.SENDGRID_API_KEY).toBe("a-sg-key"); + }); + }); + + it("should decode configuration for mailup", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + MAILUP_USERNAME: "a-mu-username", + MAILUP_SECRET: "a-mu-secret" + }; + const result = MailerConfig.decode(rawConf); + + expectRight(result, value => { + expect(value.MAILUP_USERNAME).toBe("a-mu-username"); + expect(value.MAILUP_SECRET).toBe("a-mu-secret"); + }); + }); + + it("should decode configuration with multi transport", () => { + const aTransport = { + password: "abc".repeat(5), + transport: "transport-name", + username: "t-username" + }; + const aRawTrasport = [ + aTransport.transport, + aTransport.username, + aTransport.password + ].join(":"); + + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + MAIL_TRANSPORTS: [aRawTrasport, aRawTrasport].join(";") + }; + const result = MailerConfig.decode(rawConf); + + expectRight(result, value => { + expect(value.MAIL_TRANSPORTS).toEqual([aTransport, aTransport]); + }); + }); + + it("should decode configuration for mailhog", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "dev", + MAILHOG_HOSTNAME: "a-mh-host" + }; + const result = MailerConfig.decode(rawConf); + + expectRight(result, value => { + expect(value.MAILHOG_HOSTNAME).toBe("a-mh-host"); + }); + }); + + it("should require mailhog if not in prod", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "dev" + }; + const result = MailerConfig.decode(rawConf); + + expectLeft(result); + }); + + it("should require at least on transporter if in prod", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production" + }; + const result = MailerConfig.decode(rawConf); + + expectLeft(result); + }); + + it("should not allow mailhog if in prod", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + MAILHOG_HOSTNAME: "a-mh-host" + }; + const result = MailerConfig.decode(rawConf); + + expectLeft(result); + }); + + it("should not decode configuration with empty transport", () => { + const rawConf = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production", + MAIL_TRANSPORTS: "" + }; + const result = MailerConfig.decode(rawConf); + + expectLeft(result); + }); + + it("should not decode configuration when no transporter is specified", () => { + const rawConf = { + MAIL_FROM: aMailFrom + }; + const result = MailerConfig.decode(rawConf); + + expectLeft(result); + }); + + it("should not decode ambiguos configuration", () => { + const withMailUp = { + MAILUP_USERNAME: "a-mu-username", + MAILUP_SECRET: "a-mu-secret" + }; + const withSendGrid = { + SENDGRID_API_KEY: "a-sg-key" + }; + const withMultiTransport = { + MAIL_TRANSPORTS: "a-trasnport-name" + }; + const base = { + MAIL_FROM: aMailFrom, + NODE_ENV: "production" + }; + + const examples = [ + // the following configuration is not ambiguos as sendgrid would override mailup anyway + // see here for the rationale: https://github.com/pagopa/io-functions-admin/pull/89#commitcomment-42917672 + // { ...base, ...withMailUp, ...withSendGrid }, + { ...base, ...withMultiTransport, ...withSendGrid }, + { ...base, ...withMailUp, ...withMultiTransport }, + { ...base, ...withMailUp, ...withSendGrid, ...withMultiTransport } + ]; + + examples.map(MailerConfig.decode).forEach(_ => expectLeft(_)); + }); +}); diff --git a/utils/config.ts b/utils/config.ts index 615771c8..87e20bc7 100644 --- a/utils/config.ts +++ b/utils/config.ts @@ -1,3 +1,4 @@ +import { nonEmptyArray } from "fp-ts/lib/NonEmptyArray2v"; /** * Config module * @@ -86,6 +87,19 @@ export const MailerConfig = t.intersection([ ]) ]); +// configuration for REQ_SERVICE_ID in dev +export type ReqServiceIdConfig = t.TypeOf; +export const ReqServiceIdConfig = t.union([ + t.interface({ + REQ_SERVICE_ID: t.undefined, + NODE_ENV: t.literal("production") + }), + t.interface({ + REQ_SERVICE_ID: NonEmptyString, + NODE_ENV: AnyBut("production", t.string), + }) +]); + // global app configuration export type IConfig = t.TypeOf; export const IConfig = t.intersection([ @@ -97,8 +111,10 @@ export const IConfig = t.intersection([ CUSTOMCONNSTR_COSMOSDB_KEY: NonEmptyString, CUSTOMCONNSTR_COSMOSDB_URI: NonEmptyString, COSMOSDB_NAME: NonEmptyString, + COSMOSDB_URI: NonEmptyString, + COSMOSDB_KEY: NonEmptyString, - FUNCTION_PUBLIC_URL: NonEmptyString, + FUNCTIONS_PUBLIC_URL: NonEmptyString, PUBLIC_API_URL: NonEmptyString, PUBLIC_API_KEY: NonEmptyString, @@ -107,11 +123,10 @@ export const IConfig = t.intersection([ AZURE_NH_HUB_NAME: NonEmptyString, AZURE_NH_ENDPOINT: NonEmptyString, - REQ_SERVICE_ID: t.undefined, - isProduction: t.boolean }), - MailerConfig + MailerConfig, + ReqServiceIdConfig ]); // No need to re-evaluate this object for each call diff --git a/utils/cosmosdb.ts b/utils/cosmosdb.ts index 62b373c7..f561d178 100644 --- a/utils/cosmosdb.ts +++ b/utils/cosmosdb.ts @@ -2,12 +2,15 @@ * Use a singleton CosmosDB client across functions. */ import { CosmosClient } from "@azure/cosmos"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; + +import { getConfigOrThrow } from "../utils/config"; + +const config = getConfigOrThrow(); // Setup DocumentDB -export const cosmosDbUri = getRequiredStringEnv("COSMOSDB_URI"); -export const cosmosDbName = getRequiredStringEnv("COSMOSDB_NAME"); -export const cosmosDbKey = getRequiredStringEnv("COSMOSDB_KEY"); +export const cosmosDbUri = config.COSMOSDB_URI; +export const cosmosDbName = config.COSMOSDB_NAME; +export const cosmosDbKey = config.COSMOSDB_KEY; export const cosmosdbClient = new CosmosClient({ endpoint: cosmosDbUri, diff --git a/utils/email.ts b/utils/email.ts index ad5bb609..8eff8421 100644 --- a/utils/email.ts +++ b/utils/email.ts @@ -18,6 +18,8 @@ import * as NodeMailer from "nodemailer"; import nodemailerSendgrid = require("nodemailer-sendgrid"); import Mail = require("nodemailer/lib/mailer"); +import { getConfigOrThrow } from "../utils/config"; + // 5 seconds timeout by default const DEFAULT_EMAIL_REQUEST_TIMEOUT_MS = 5000; @@ -28,6 +30,8 @@ const fetchWithTimeout = setFetchTimeout( abortableFetch ); +const config = getConfigOrThrow(); + interface IMailUpOptions { mailupSecret: NonEmptyString; mailupUsername: NonEmptyString; @@ -60,7 +64,7 @@ export function getMailerTransporter(opts: MailTransportOptions): Mail { : // For development we use mailhog to intercept emails // Use the `docker-compose.yml` file to run the mailhog server NodeMailer.createTransport({ - host: process.env.MAILHOG_HOSTNAME || "localhost", + host: config.MAILHOG_HOSTNAME || "localhost", port: 1025, secure: false }); diff --git a/utils/notification.ts b/utils/notification.ts index 9b31fb1c..55639d65 100644 --- a/utils/notification.ts +++ b/utils/notification.ts @@ -7,8 +7,8 @@ import { NonEmptyString } from "italia-ts-commons/lib/strings"; import * as azure from "azure-sb"; import { tryCatch } from "fp-ts/lib/TaskEither"; -import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env"; import { Platform, PlatformEnum } from "../generated/backend/Platform"; +import { getConfigOrThrow } from "../utils/config"; /** * Notification template. @@ -35,8 +35,10 @@ export enum APNSPushType { MDM = "mdm" } -const hubName = getRequiredStringEnv("AZURE_NH_HUB_NAME"); -const endpointOrConnectionString = getRequiredStringEnv("AZURE_NH_ENDPOINT"); +const config = getConfigOrThrow(); + +const hubName = config.AZURE_NH_HUB_NAME; +const endpointOrConnectionString = config.AZURE_NH_ENDPOINT; const notificationHubService = azure.createNotificationHubService( hubName, From 43c5e3e5aa89290deb9be3765b757acf60cb87d5 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Tue, 6 Oct 2020 18:41:39 +0200 Subject: [PATCH 3/8] Refactoring accorting to lint --- .../__tests__/handler.test.ts | 18 ++--- .../__tests__/handler.test.ts | 20 ++--- SendValidationEmailActivity/index.ts | 6 +- StoreSpidLogs/__test__/index.test.ts | 34 ++++----- utils/__tests__/config.test.ts | 73 ++++++++----------- utils/config.ts | 30 ++++---- utils/email.ts | 4 +- 7 files changed, 89 insertions(+), 96 deletions(-) diff --git a/HandleNHNotificationCallActivity/__tests__/handler.test.ts b/HandleNHNotificationCallActivity/__tests__/handler.test.ts index dd91c9fc..30849735 100644 --- a/HandleNHNotificationCallActivity/__tests__/handler.test.ts +++ b/HandleNHNotificationCallActivity/__tests__/handler.test.ts @@ -2,25 +2,25 @@ // tslint:disable-next-line: no-object-mutation process.env = { ...process.env, - MESSAGE_CONTAINER_NAME: "msg", - QueueStorageConnection: "foobar", AZURE_NH_ENDPOINT: "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=XXX", AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", - SUBSCRIPTIONS_FEED_TABLE: "feed", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", + COSMOSDB_KEY: "key", COSMOSDB_NAME: "cosmoname", COSMOSDB_URI: "uri", - COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", FUNCTIONS_PUBLIC_URL: "url", - PUBLIC_API_URL: "url", - PUBLIC_API_KEY: "key", MAILHOG_HOSTNAME: "mailhog", MAIL_FROM: "mail@example.it", + MESSAGE_CONTAINER_NAME: "msg", NODE_ENV: "dev", + PUBLIC_API_KEY: "key", + PUBLIC_API_URL: "url", + QueueStorageConnection: "foobar", REQ_SERVICE_ID: "req_id_dev", - SPID_LOGS_PUBLIC_KEY: "key" + SPID_LOGS_PUBLIC_KEY: "key", + SUBSCRIPTIONS_FEED_TABLE: "feed" }; import { NonEmptyString } from "italia-ts-commons/lib/strings"; diff --git a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts index 8f2efe70..c64682ca 100644 --- a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts +++ b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts @@ -2,25 +2,25 @@ // tslint:disable-next-line: no-object-mutation process.env = { ...process.env, - QueueStorageConnection: "foobar", - MESSAGE_CONTAINER_NAME: "msg", - SUBSCRIPTIONS_FEED_TABLE: "feed", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", - COSMOSDB_NAME: "cosmoname", - COSMOSDB_URI: "uri", AZURE_NH_ENDPOINT: "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=C4xIzNZv4VrUnu5jkmPH635MApRUj8wABky8VfduYqg=", AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", COSMOSDB_KEY: "key", + COSMOSDB_NAME: "cosmoname", + COSMOSDB_URI: "uri", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", FUNCTIONS_PUBLIC_URL: "url", - PUBLIC_API_URL: "url", - PUBLIC_API_KEY: "key", MAILHOG_HOSTNAME: "mailhog", MAIL_FROM: "mail@example.it", + MESSAGE_CONTAINER_NAME: "msg", NODE_ENV: "dev", + PUBLIC_API_KEY: "key", + PUBLIC_API_URL: "url", + QueueStorageConnection: "foobar", REQ_SERVICE_ID: "req_id_dev", - SPID_LOGS_PUBLIC_KEY: "key" + SPID_LOGS_PUBLIC_KEY: "key", + SUBSCRIPTIONS_FEED_TABLE: "feed" }; import { NonEmptyString } from "italia-ts-commons/lib/strings"; import { context as contextMock } from "../../__mocks__/durable-functions"; diff --git a/SendValidationEmailActivity/index.ts b/SendValidationEmailActivity/index.ts index 9cf2608d..86a8e8c4 100644 --- a/SendValidationEmailActivity/index.ts +++ b/SendValidationEmailActivity/index.ts @@ -21,9 +21,9 @@ const config = getConfigOrThrow(); const isProduction = config.NODE_ENV === "production"; // Optional SendGrid key -const sendgridApiKey = NonEmptyString.decode( - config.SENDGRID_API_KEY -).getOrElse(undefined); +const sendgridApiKey = NonEmptyString.decode(config.SENDGRID_API_KEY).getOrElse( + undefined +); // Mailup const mailupUsername = config.MAILUP_USERNAME; diff --git a/StoreSpidLogs/__test__/index.test.ts b/StoreSpidLogs/__test__/index.test.ts index 4eab1b9e..4b86db05 100644 --- a/StoreSpidLogs/__test__/index.test.ts +++ b/StoreSpidLogs/__test__/index.test.ts @@ -2,10 +2,23 @@ /* tslint:disable:no-object-mutation */ process.env = { - UBSCRIPTIONS_FEED_TABLE: "feed", APPINSIGHTS_INSTRUMENTATIONKEY: "foo", + AZURE_NH_ENDPOINT: "azendpoint", + AZURE_NH_HUB_NAME: "azhub", + COSMOSDB_KEY: "key", + COSMOSDB_NAME: "cosmoname", + COSMOSDB_URI: "uri", + CUSTOMCONNSTR_COSMOSDB_KEY: "key", + CUSTOMCONNSTR_COSMOSDB_URI: "uri", + FUNCTIONS_PUBLIC_URL: "url", + MAILHOG_HOSTNAME: "mailhog", + MAIL_FROM: "mail@example.it", + MESSAGE_CONTAINER_NAME: "msg", + NODE_ENV: "dev", + PUBLIC_API_KEY: "key", + PUBLIC_API_URL: "url", QueueStorageConnection: "foobar", - SUBSCRIPTIONS_FEED_TABLE: "feed", + REQ_SERVICE_ID: "req_id_dev", SPID_BLOB_CONTAINER_NAME: "spidblob", SPID_BLOB_STORAGE_CONNECTION_STRING: "foobar", SPID_LOGS_PUBLIC_KEY: `-----BEGIN PUBLIC KEY----- @@ -14,21 +27,8 @@ l09Fs0z2U4aA37BrXlSo1DwQ2O9i2XFxXGJmE83siSWEfRlMWlabMu7Yj6dkZvmj dGIO4gotO33TgiAQcwRo+4pwjoCN7Td47yssCcj9C727zBt+Br+XK7B1bRcqjc0J YdF4yiVtD7G4RDXmRQIDAQAB -----END PUBLIC KEY-----`, - MESSAGE_CONTAINER_NAME: "msg", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - COSMOSDB_NAME: "cosmoname", - COSMOSDB_URI: "uri", - COSMOSDB_KEY: "key", - FUNCTIONS_PUBLIC_URL: "url", - PUBLIC_API_URL: "url", - PUBLIC_API_KEY: "key", - MAILHOG_HOSTNAME: "mailhog", - MAIL_FROM: "mail@example.it", - NODE_ENV: "dev", - REQ_SERVICE_ID: "req_id_dev", - AZURE_NH_HUB_NAME: "azhub", - AZURE_NH_ENDPOINT: "azendpoint", + SUBSCRIPTIONS_FEED_TABLE: "feed", + UBSCRIPTIONS_FEED_TABLE: "feed" }; import { format } from "date-fns"; diff --git a/utils/__tests__/config.test.ts b/utils/__tests__/config.test.ts index 3eb664a0..9b42c1b4 100644 --- a/utils/__tests__/config.test.ts +++ b/utils/__tests__/config.test.ts @@ -1,9 +1,13 @@ import { Either } from "fp-ts/lib/Either"; -import { IConfig, MailerConfig } from "../config"; +import { MailerConfig } from "../config"; const aMailFrom = "example@test.com"; +const mailSecret = "a-mu-secret"; +const mailUsername = "a-mu-username"; +const devEnv = "dev"; +const prodEnv = "production"; -const noop = () => {}; +const noop = () => null; const expectRight = (e: Either, t: (r: R) => void = noop) => e.fold( _ => @@ -22,7 +26,7 @@ describe("MailerConfig", () => { it("should decode configuration for sendgrid", () => { const rawConf = { MAIL_FROM: aMailFrom, - NODE_ENV: "production", + NODE_ENV: prodEnv, SENDGRID_API_KEY: "a-sg-key" }; const result = MailerConfig.decode(rawConf); @@ -35,11 +39,11 @@ describe("MailerConfig", () => { it("should decode configuration for sendgrid even if mailup conf is passed", () => { const rawConf = { + MAILUP_SECRET: mailSecret, + MAILUP_USERNAME: mailUsername, MAIL_FROM: aMailFrom, - NODE_ENV: "production", - SENDGRID_API_KEY: "a-sg-key", - MAILUP_USERNAME: "a-mu-username", - MAILUP_SECRET: "a-mu-secret" + NODE_ENV: prodEnv, + SENDGRID_API_KEY: "a-sg-key" }; const result = MailerConfig.decode(rawConf); @@ -50,10 +54,10 @@ describe("MailerConfig", () => { it("should decode configuration for mailup", () => { const rawConf = { + MAILUP_SECRET: mailSecret, + MAILUP_USERNAME: mailUsername, MAIL_FROM: aMailFrom, - NODE_ENV: "production", - MAILUP_USERNAME: "a-mu-username", - MAILUP_SECRET: "a-mu-secret" + NODE_ENV: prodEnv }; const result = MailerConfig.decode(rawConf); @@ -77,8 +81,8 @@ describe("MailerConfig", () => { const rawConf = { MAIL_FROM: aMailFrom, - NODE_ENV: "production", - MAIL_TRANSPORTS: [aRawTrasport, aRawTrasport].join(";") + MAIL_TRANSPORTS: [aRawTrasport, aRawTrasport].join(";"), + NODE_ENV: prodEnv }; const result = MailerConfig.decode(rawConf); @@ -89,9 +93,9 @@ describe("MailerConfig", () => { it("should decode configuration for mailhog", () => { const rawConf = { + MAILHOG_HOSTNAME: "a-mh-host", MAIL_FROM: aMailFrom, - NODE_ENV: "dev", - MAILHOG_HOSTNAME: "a-mh-host" + NODE_ENV: devEnv }; const result = MailerConfig.decode(rawConf); @@ -103,7 +107,7 @@ describe("MailerConfig", () => { it("should require mailhog if not in prod", () => { const rawConf = { MAIL_FROM: aMailFrom, - NODE_ENV: "dev" + NODE_ENV: devEnv }; const result = MailerConfig.decode(rawConf); @@ -113,7 +117,7 @@ describe("MailerConfig", () => { it("should require at least on transporter if in prod", () => { const rawConf = { MAIL_FROM: aMailFrom, - NODE_ENV: "production" + NODE_ENV: prodEnv }; const result = MailerConfig.decode(rawConf); @@ -122,9 +126,9 @@ describe("MailerConfig", () => { it("should not allow mailhog if in prod", () => { const rawConf = { + MAILHOG_HOSTNAME: "a-mh-host", MAIL_FROM: aMailFrom, - NODE_ENV: "production", - MAILHOG_HOSTNAME: "a-mh-host" + NODE_ENV: prodEnv }; const result = MailerConfig.decode(rawConf); @@ -134,8 +138,8 @@ describe("MailerConfig", () => { it("should not decode configuration with empty transport", () => { const rawConf = { MAIL_FROM: aMailFrom, - NODE_ENV: "production", - MAIL_TRANSPORTS: "" + MAIL_TRANSPORTS: "", + NODE_ENV: prodEnv }; const result = MailerConfig.decode(rawConf); @@ -152,30 +156,17 @@ describe("MailerConfig", () => { }); it("should not decode ambiguos configuration", () => { - const withMailUp = { - MAILUP_USERNAME: "a-mu-username", - MAILUP_SECRET: "a-mu-secret" - }; - const withSendGrid = { - SENDGRID_API_KEY: "a-sg-key" - }; - const withMultiTransport = { - MAIL_TRANSPORTS: "a-trasnport-name" - }; - const base = { + const rawConf = { + MAILUP_SECRET: mailSecret, + MAILUP_USERNAME: mailUsername, MAIL_FROM: aMailFrom, - NODE_ENV: "production" + MAIL_TRANSPORTS: "a-trasnport-name", + NODE_ENV: prodEnv, + SENDGRID_API_KEY: "a-sg-key" }; - const examples = [ - // the following configuration is not ambiguos as sendgrid would override mailup anyway - // see here for the rationale: https://github.com/pagopa/io-functions-admin/pull/89#commitcomment-42917672 - // { ...base, ...withMailUp, ...withSendGrid }, - { ...base, ...withMultiTransport, ...withSendGrid }, - { ...base, ...withMailUp, ...withMultiTransport }, - { ...base, ...withMailUp, ...withSendGrid, ...withMultiTransport } - ]; + const result = MailerConfig.decode(rawConf); - examples.map(MailerConfig.decode).forEach(_ => expectLeft(_)); + expectLeft(result); }); }); diff --git a/utils/config.ts b/utils/config.ts index 87e20bc7..83111b7e 100644 --- a/utils/config.ts +++ b/utils/config.ts @@ -1,4 +1,3 @@ -import { nonEmptyArray } from "fp-ts/lib/NonEmptyArray2v"; /** * Config module * @@ -91,12 +90,12 @@ export const MailerConfig = t.intersection([ export type ReqServiceIdConfig = t.TypeOf; export const ReqServiceIdConfig = t.union([ t.interface({ - REQ_SERVICE_ID: t.undefined, - NODE_ENV: t.literal("production") + NODE_ENV: t.literal("production"), + REQ_SERVICE_ID: t.undefined }), t.interface({ - REQ_SERVICE_ID: NonEmptyString, NODE_ENV: AnyBut("production", t.string), + REQ_SERVICE_ID: NonEmptyString }) ]); @@ -104,24 +103,27 @@ export const ReqServiceIdConfig = t.union([ export type IConfig = t.TypeOf; export const IConfig = t.intersection([ t.interface({ - QueueStorageConnection: NonEmptyString, - MESSAGE_CONTAINER_NAME: NonEmptyString, - SUBSCRIPTIONS_FEED_TABLE: NonEmptyString, + AZURE_NH_ENDPOINT: NonEmptyString, + AZURE_NH_HUB_NAME: NonEmptyString, - CUSTOMCONNSTR_COSMOSDB_KEY: NonEmptyString, - CUSTOMCONNSTR_COSMOSDB_URI: NonEmptyString, + COSMOSDB_KEY: NonEmptyString, COSMOSDB_NAME: NonEmptyString, COSMOSDB_URI: NonEmptyString, - COSMOSDB_KEY: NonEmptyString, + + CUSTOMCONNSTR_COSMOSDB_KEY: NonEmptyString, + CUSTOMCONNSTR_COSMOSDB_URI: NonEmptyString, FUNCTIONS_PUBLIC_URL: NonEmptyString, - PUBLIC_API_URL: NonEmptyString, + + MESSAGE_CONTAINER_NAME: NonEmptyString, + PUBLIC_API_KEY: NonEmptyString, + PUBLIC_API_URL: NonEmptyString, - SPID_LOGS_PUBLIC_KEY: NonEmptyString, + QueueStorageConnection: NonEmptyString, - AZURE_NH_HUB_NAME: NonEmptyString, - AZURE_NH_ENDPOINT: NonEmptyString, + SPID_LOGS_PUBLIC_KEY: NonEmptyString, + SUBSCRIPTIONS_FEED_TABLE: NonEmptyString, isProduction: t.boolean }), diff --git a/utils/email.ts b/utils/email.ts index 8eff8421..803b9285 100644 --- a/utils/email.ts +++ b/utils/email.ts @@ -30,7 +30,7 @@ const fetchWithTimeout = setFetchTimeout( abortableFetch ); -const config = getConfigOrThrow(); +const conf = getConfigOrThrow(); interface IMailUpOptions { mailupSecret: NonEmptyString; @@ -64,7 +64,7 @@ export function getMailerTransporter(opts: MailTransportOptions): Mail { : // For development we use mailhog to intercept emails // Use the `docker-compose.yml` file to run the mailhog server NodeMailer.createTransport({ - host: config.MAILHOG_HOSTNAME || "localhost", + host: conf.MAILHOG_HOSTNAME || "localhost", port: 1025, secure: false }); From e2bc1bf2b747200a06c1451b2f8253b98647d13d Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 7 Oct 2020 09:56:11 +0200 Subject: [PATCH 4/8] Disabled readonly-array lint rule for test --- utils/__tests__/config.test.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/utils/__tests__/config.test.ts b/utils/__tests__/config.test.ts index 9b42c1b4..a11c9bba 100644 --- a/utils/__tests__/config.test.ts +++ b/utils/__tests__/config.test.ts @@ -156,17 +156,28 @@ describe("MailerConfig", () => { }); it("should not decode ambiguos configuration", () => { - const rawConf = { + const withMailUp = { MAILUP_SECRET: mailSecret, - MAILUP_USERNAME: mailUsername, - MAIL_FROM: aMailFrom, - MAIL_TRANSPORTS: "a-trasnport-name", - NODE_ENV: prodEnv, + MAILUP_USERNAME: mailUsername + }; + const withSendGrid = { SENDGRID_API_KEY: "a-sg-key" }; + const withMultiTransport = { + MAIL_TRANSPORTS: "a-trasnport-name" + }; + const base = { + MAIL_FROM: aMailFrom, + NODE_ENV: prodEnv + }; - const result = MailerConfig.decode(rawConf); + // tslint:disable-next-line readonly-array + const examples = [ + { ...base, ...withMultiTransport, ...withSendGrid }, + { ...base, ...withMailUp, ...withMultiTransport }, + { ...base, ...withMailUp, ...withSendGrid, ...withMultiTransport } + ]; - expectLeft(result); + examples.map(MailerConfig.decode).forEach(_ => expectLeft(_)); }); }); From ed1c98db5984ccef8afb128d19437cef9d3781aa Mon Sep 17 00:00:00 2001 From: Simone infante <52280205+infantesimone@users.noreply.github.com> Date: Wed, 7 Oct 2020 10:09:16 +0200 Subject: [PATCH 5/8] Remove constant aliasing Co-authored-by: Daniele Manni --- GetMessage/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GetMessage/index.ts b/GetMessage/index.ts index 10436b36..baf504f0 100644 --- a/GetMessage/index.ts +++ b/GetMessage/index.ts @@ -25,11 +25,9 @@ secureExpressApp(app); const config = getConfigOrThrow(); -const messageContainerName = config.MESSAGE_CONTAINER_NAME; - const messageModel = new MessageModel( cosmosdbInstance.container(MESSAGE_COLLECTION_NAME), - messageContainerName + config.MESSAGE_CONTAINER_NAME ); const storageConnectionString = config.QueueStorageConnection; From 5e76ea2a70de355022da02cba468314a4f84fb30 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 7 Oct 2020 15:45:29 +0200 Subject: [PATCH 6/8] Refactoring to remove static constant aliasing --- CreateValidationTokenActivity/index.ts | 3 +-- GetMessage/index.ts | 3 +-- GetMessages/index.ts | 4 +--- GetVisibleServices/index.ts | 3 +-- SendValidationEmailActivity/index.ts | 8 ++------ SendWelcomeMessagesActivity/index.ts | 11 ++++++----- StoreSpidLogs/index.ts | 3 +-- UpdateSubscriptionsFeedActivity/index.ts | 16 ++++++++++------ docker/fixtures/index.ts | 10 +++------- utils/notification.ts | 7 ++----- 10 files changed, 28 insertions(+), 40 deletions(-) diff --git a/CreateValidationTokenActivity/index.ts b/CreateValidationTokenActivity/index.ts index 0acbd5ae..09e5c63c 100644 --- a/CreateValidationTokenActivity/index.ts +++ b/CreateValidationTokenActivity/index.ts @@ -17,9 +17,8 @@ const TOKEN_INVALID_AFTER_MS = (1000 * 60 * 60 * 24 * 30) as Millisecond; // 30 // TODO: Rename this env to `StorageConnection` // https://www.pivotaltracker.com/story/show/169591817 -const storageConnectionString = config.QueueStorageConnection; -const tableService = createTableService(storageConnectionString); +const tableService = createTableService(config.QueueStorageConnection); const randomBytesGenerator = (size: number) => crypto.randomBytes(size).toString("hex"); diff --git a/GetMessage/index.ts b/GetMessage/index.ts index baf504f0..54b71a53 100644 --- a/GetMessage/index.ts +++ b/GetMessage/index.ts @@ -30,8 +30,7 @@ const messageModel = new MessageModel( config.MESSAGE_CONTAINER_NAME ); -const storageConnectionString = config.QueueStorageConnection; -const blobService = createBlobService(storageConnectionString); +const blobService = createBlobService(config.QueueStorageConnection); app.get( "/api/v1/messages/:fiscalcode/:id", diff --git a/GetMessages/index.ts b/GetMessages/index.ts index fee71eda..fbbf2734 100644 --- a/GetMessages/index.ts +++ b/GetMessages/index.ts @@ -23,11 +23,9 @@ secureExpressApp(app); const config = getConfigOrThrow(); -const messageContainerName = config.MESSAGE_CONTAINER_NAME; - const messageModel = new MessageModel( cosmosdbInstance.container(MESSAGE_COLLECTION_NAME), - messageContainerName + config.MESSAGE_CONTAINER_NAME ); app.get("/api/v1/messages/:fiscalcode", GetMessages(messageModel)); diff --git a/GetVisibleServices/index.ts b/GetVisibleServices/index.ts index f1e378db..8ffc90ec 100644 --- a/GetVisibleServices/index.ts +++ b/GetVisibleServices/index.ts @@ -18,8 +18,7 @@ secureExpressApp(app); const config = getConfigOrThrow(); -const storageConnectionString = config.QueueStorageConnection; -const blobService = createBlobService(storageConnectionString); +const blobService = createBlobService(config.QueueStorageConnection); app.get("/api/v1/services", GetVisibleServices(blobService)); diff --git a/SendValidationEmailActivity/index.ts b/SendValidationEmailActivity/index.ts index 86a8e8c4..4f905b3c 100644 --- a/SendValidationEmailActivity/index.ts +++ b/SendValidationEmailActivity/index.ts @@ -31,10 +31,6 @@ const mailupSecret = config.MAILUP_SECRET; // Email data const EMAIL_TITLE = "Valida l’indirizzo email che usi su IO"; -const mailFrom = config.MAIL_FROM; - -// Needed to construct the email validation url -const functionsPublicUrl = config.FUNCTIONS_PUBLIC_URL; const HTML_TO_TEXT_OPTIONS: HtmlToTextOptions = { ignoreImage: true, // Ignore all document images @@ -42,7 +38,7 @@ const HTML_TO_TEXT_OPTIONS: HtmlToTextOptions = { }; const emailDefaults = { - from: mailFrom, + from: config.MAIL_FROM, htmlToTextOptions: HTML_TO_TEXT_OPTIONS, title: EMAIL_TITLE }; @@ -81,7 +77,7 @@ initTelemetryClient(); const activityFunctionHandler = getSendValidationEmailActivityHandler( mailerTransporter, emailDefaults, - functionsPublicUrl + config.FUNCTIONS_PUBLIC_URL ); export default activityFunctionHandler; diff --git a/SendWelcomeMessagesActivity/index.ts b/SendWelcomeMessagesActivity/index.ts index 4ffb00b0..271c8b69 100644 --- a/SendWelcomeMessagesActivity/index.ts +++ b/SendWelcomeMessagesActivity/index.ts @@ -14,10 +14,6 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 10000; const config = getConfigOrThrow(); -// Needed to call notifications API -const publicApiUrl = config.PUBLIC_API_URL; -const publicApiKey = config.PUBLIC_API_KEY; - // HTTP-only fetch with optional keepalive agent // @see https://github.com/pagopa/io-ts-commons/blob/master/src/agent.ts#L10 const httpApiFetch = agent.getHttpFetch(process.env); @@ -28,6 +24,11 @@ const timeoutFetch = toFetch( setFetchTimeout(DEFAULT_REQUEST_TIMEOUT_MS as Millisecond, abortableFetch) ); -const index = getActivityFunction(publicApiUrl, publicApiKey, timeoutFetch); +// Needed to call notifications API +const index = getActivityFunction( + config.PUBLIC_API_URL, + config.PUBLIC_API_KEY, + timeoutFetch +); export default index; diff --git a/StoreSpidLogs/index.ts b/StoreSpidLogs/index.ts index d8e1d310..d392f329 100644 --- a/StoreSpidLogs/index.ts +++ b/StoreSpidLogs/index.ts @@ -14,8 +14,7 @@ import { initTelemetryClient } from "../utils/appinsights"; import { getConfigOrThrow } from "../utils/config"; const config = getConfigOrThrow(); -const rsaPublicKey = config.SPID_LOGS_PUBLIC_KEY; -const encrypt = curry(toEncryptedPayload)(rsaPublicKey); +const encrypt = curry(toEncryptedPayload)(config.SPID_LOGS_PUBLIC_KEY); /** * Payload of the stored blob item diff --git a/UpdateSubscriptionsFeedActivity/index.ts b/UpdateSubscriptionsFeedActivity/index.ts index ed30aaf3..661bca86 100644 --- a/UpdateSubscriptionsFeedActivity/index.ts +++ b/UpdateSubscriptionsFeedActivity/index.ts @@ -17,13 +17,17 @@ import { getConfigOrThrow } from "../utils/config"; const config = getConfigOrThrow(); -const storageConnectionString = config.QueueStorageConnection; -const tableService = createTableService(storageConnectionString); +const tableService = createTableService(config.QueueStorageConnection); -const subscriptionsFeedTable = config.SUBSCRIPTIONS_FEED_TABLE; +const insertEntity = insertTableEntity( + tableService, + config.SUBSCRIPTIONS_FEED_TABLE +); -const insertEntity = insertTableEntity(tableService, subscriptionsFeedTable); -const deleteEntity = deleteTableEntity(tableService, subscriptionsFeedTable); +const deleteEntity = deleteTableEntity( + tableService, + config.SUBSCRIPTIONS_FEED_TABLE +); const eg = TableUtilities.entityGenerator; @@ -60,7 +64,7 @@ export type Input = t.TypeOf; // When the function starts, attempt to create the table if it does not exist // Note that we cannot log anything just yet since we don't have a Context -tableService.createTableIfNotExists(subscriptionsFeedTable, () => 0); +tableService.createTableIfNotExists(config.SUBSCRIPTIONS_FEED_TABLE, () => 0); /** * Updates the subscrption status of a user. diff --git a/docker/fixtures/index.ts b/docker/fixtures/index.ts index 674ab16b..ec03e874 100644 --- a/docker/fixtures/index.ts +++ b/docker/fixtures/index.ts @@ -23,13 +23,9 @@ import { getConfigOrThrow } from "../../utils/config"; const config = getConfigOrThrow(); -const cosmosDbKey = config.CUSTOMCONNSTR_COSMOSDB_KEY; -const cosmosDbUri = config.CUSTOMCONNSTR_COSMOSDB_URI; -const cosmosDbName = config.COSMOSDB_NAME; - export const cosmosdbClient = new CosmosClient({ - endpoint: cosmosDbUri, - key: cosmosDbKey + endpoint: config.CUSTOMCONNSTR_COSMOSDB_URI, + key: config.CUSTOMCONNSTR_COSMOSDB_KEY }); function createDatabase(databaseName: string): TaskEither { @@ -91,7 +87,7 @@ const aNewProfile = NewProfile.decode({ throw new Error("Cannot decode new profile."); }); -createDatabase(cosmosDbName) +createDatabase(config.COSMOSDB_NAME) .chain(db => sequenceT(taskEitherSeq)( createCollection(db, "message-status", "messageId"), diff --git a/utils/notification.ts b/utils/notification.ts index 55639d65..dd586e0a 100644 --- a/utils/notification.ts +++ b/utils/notification.ts @@ -37,12 +37,9 @@ export enum APNSPushType { const config = getConfigOrThrow(); -const hubName = config.AZURE_NH_HUB_NAME; -const endpointOrConnectionString = config.AZURE_NH_ENDPOINT; - const notificationHubService = azure.createNotificationHubService( - hubName, - endpointOrConnectionString + config.AZURE_NH_HUB_NAME, + config.AZURE_NH_ENDPOINT ); /** From dc2145e56b1438aa231bceff99807316a8e2b2c9 Mon Sep 17 00:00:00 2001 From: Simone Infante Date: Wed, 7 Oct 2020 18:50:35 +0200 Subject: [PATCH 7/8] add dotenv dependency and env.example for testing --- .../__tests__/handler.test.ts | 23 -------------- .../__tests__/handler.test.ts | 22 ------------- StoreSpidLogs/__test__/index.test.ts | 31 +------------------ env.example | 24 ++++++++++++++ jest.config.js | 1 + package.json | 1 + yarn.lock | 5 +++ 7 files changed, 32 insertions(+), 75 deletions(-) create mode 100644 env.example diff --git a/HandleNHNotificationCallActivity/__tests__/handler.test.ts b/HandleNHNotificationCallActivity/__tests__/handler.test.ts index 30849735..ade5acef 100644 --- a/HandleNHNotificationCallActivity/__tests__/handler.test.ts +++ b/HandleNHNotificationCallActivity/__tests__/handler.test.ts @@ -1,28 +1,5 @@ /* tslint:disable: no-any */ // tslint:disable-next-line: no-object-mutation -process.env = { - ...process.env, - AZURE_NH_ENDPOINT: - "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=XXX", - AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", - COSMOSDB_KEY: "key", - COSMOSDB_NAME: "cosmoname", - COSMOSDB_URI: "uri", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", - FUNCTIONS_PUBLIC_URL: "url", - MAILHOG_HOSTNAME: "mailhog", - MAIL_FROM: "mail@example.it", - MESSAGE_CONTAINER_NAME: "msg", - NODE_ENV: "dev", - PUBLIC_API_KEY: "key", - PUBLIC_API_URL: "url", - QueueStorageConnection: "foobar", - REQ_SERVICE_ID: "req_id_dev", - SPID_LOGS_PUBLIC_KEY: "key", - SUBSCRIPTIONS_FEED_TABLE: "feed" -}; - import { NonEmptyString } from "italia-ts-commons/lib/strings"; import { context as contextMock } from "../../__mocks__/durable-functions"; import { PlatformEnum } from "../../generated/backend/Platform"; diff --git a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts index c64682ca..66b5a4ad 100644 --- a/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts +++ b/HandleNHNotificationCallOrchestrator/__tests__/handler.test.ts @@ -1,27 +1,5 @@ /* tslint:disable:no-any */ // tslint:disable-next-line: no-object-mutation -process.env = { - ...process.env, - AZURE_NH_ENDPOINT: - "Endpoint=sb://anendpoint.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=C4xIzNZv4VrUnu5jkmPH635MApRUj8wABky8VfduYqg=", - AZURE_NH_HUB_NAME: "AZURE_NH_HUB_NAME", - COSMOSDB_KEY: "key", - COSMOSDB_NAME: "cosmoname", - COSMOSDB_URI: "uri", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", - FUNCTIONS_PUBLIC_URL: "url", - MAILHOG_HOSTNAME: "mailhog", - MAIL_FROM: "mail@example.it", - MESSAGE_CONTAINER_NAME: "msg", - NODE_ENV: "dev", - PUBLIC_API_KEY: "key", - PUBLIC_API_URL: "url", - QueueStorageConnection: "foobar", - REQ_SERVICE_ID: "req_id_dev", - SPID_LOGS_PUBLIC_KEY: "key", - SUBSCRIPTIONS_FEED_TABLE: "feed" -}; import { NonEmptyString } from "italia-ts-commons/lib/strings"; import { context as contextMock } from "../../__mocks__/durable-functions"; import { PlatformEnum } from "../../generated/backend/Platform"; diff --git a/StoreSpidLogs/__test__/index.test.ts b/StoreSpidLogs/__test__/index.test.ts index 4b86db05..0155eb46 100644 --- a/StoreSpidLogs/__test__/index.test.ts +++ b/StoreSpidLogs/__test__/index.test.ts @@ -1,36 +1,6 @@ /* tslint:disable:no-any */ /* tslint:disable:no-object-mutation */ -process.env = { - APPINSIGHTS_INSTRUMENTATIONKEY: "foo", - AZURE_NH_ENDPOINT: "azendpoint", - AZURE_NH_HUB_NAME: "azhub", - COSMOSDB_KEY: "key", - COSMOSDB_NAME: "cosmoname", - COSMOSDB_URI: "uri", - CUSTOMCONNSTR_COSMOSDB_KEY: "key", - CUSTOMCONNSTR_COSMOSDB_URI: "uri", - FUNCTIONS_PUBLIC_URL: "url", - MAILHOG_HOSTNAME: "mailhog", - MAIL_FROM: "mail@example.it", - MESSAGE_CONTAINER_NAME: "msg", - NODE_ENV: "dev", - PUBLIC_API_KEY: "key", - PUBLIC_API_URL: "url", - QueueStorageConnection: "foobar", - REQ_SERVICE_ID: "req_id_dev", - SPID_BLOB_CONTAINER_NAME: "spidblob", - SPID_BLOB_STORAGE_CONNECTION_STRING: "foobar", - SPID_LOGS_PUBLIC_KEY: `-----BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhiXpvLD8UMMUy1T2JCzo/Sj5E -l09Fs0z2U4aA37BrXlSo1DwQ2O9i2XFxXGJmE83siSWEfRlMWlabMu7Yj6dkZvmj -dGIO4gotO33TgiAQcwRo+4pwjoCN7Td47yssCcj9C727zBt+Br+XK7B1bRcqjc0J -YdF4yiVtD7G4RDXmRQIDAQAB ------END PUBLIC KEY-----`, - SUBSCRIPTIONS_FEED_TABLE: "feed", - UBSCRIPTIONS_FEED_TABLE: "feed" -}; - import { format } from "date-fns"; import { toPlainText } from "italia-ts-commons/lib/encrypt"; import { IPString } from "italia-ts-commons/lib/strings"; @@ -109,6 +79,7 @@ describe("StoreSpidLogs", () => { } }; const blobItem = await index(mockedContext as any, aSpidMsgItem); + console.log(blobItem); const blob = blobItem as IOutputBinding; const encryptedSpidBlobItem = blob.spidRequestResponse; const decryptedRequestPayload = toPlainText( diff --git a/env.example b/env.example new file mode 100644 index 00000000..3b587212 --- /dev/null +++ b/env.example @@ -0,0 +1,24 @@ +#This file is used for testing (jest), +#and must be renamed to .env (but not committed) +APPINSIGHTS_INSTRUMENTATIONKEY=foo +AZURE_NH_HUB_NAME=azhub +AZURE_NH_ENDPOINT=Endpoint=sb://host.docker.internal:30000;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=foobar +COSMOSDB_KEY=key +COSMOSDB_NAME=cosmoname +COSMOSDB_URI=uri +CUSTOMCONNSTR_COSMOSDB_KEY=key +CUSTOMCONNSTR_COSMOSDB_URI=uri +FUNCTIONS_PUBLIC_URL=url +MAILHOG_HOSTNAME=mailhog +MAIL_FROM=mail@example.it +MESSAGE_CONTAINER_NAME=msg +NODE_ENV=dev +PUBLIC_API_KEY=key +PUBLIC_API_URL=url +QueueStorageConnection=foobar +REQ_SERVICE_ID=req_id_dev +SPID_BLOB_CONTAINER_NAME=spidblob +SPID_BLOB_STORAGE_CONNECTION_STRING=foobar +SPID_LOGS_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhiXpvLD8UMMUy1T2JCzo/Sj5E\nl09Fs0z2U4aA37BrXlSo1DwQ2O9i2XFxXGJmE83siSWEfRlMWlabMu7Yj6dkZvmj\ndGIO4gotO33TgiAQcwRo+4pwjoCN7Td47yssCcj9C727zBt+Br+XK7B1bRcqjc0J\nYdF4yiVtD7G4RDXmRQIDAQAB\n-----END PUBLIC KEY-----" +SUBSCRIPTIONS_FEED_TABLE=feed +UBSCRIPTIONS_FEED_TABLE=feed \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 8866385e..5242c6a5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,6 @@ module.exports = { preset: "ts-jest", + setupFiles: ["dotenv/config"], testEnvironment: "node", testPathIgnorePatterns: ["dist", "/node_modules"] }; diff --git a/package.json b/package.json index 309bcc87..4d70650b 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@types/nodemailer": "^4.6.8", "danger": "^4.0.2", "danger-plugin-digitalcitizenship": "^0.3.1", + "dotenv": "^8.2.0", "fast-check": "^1.16.0", "italia-tslint-rules": "^1.1.3", "italia-utils": "^4.1.0", diff --git a/yarn.lock b/yarn.lock index 3852a653..6ed42afc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2508,6 +2508,11 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" From fc47ef14f1171c1ab47f7338ba0b5255ef83c420 Mon Sep 17 00:00:00 2001 From: Danilo Spinelli Date: Wed, 7 Oct 2020 23:02:29 +0200 Subject: [PATCH 8/8] fix dotenv integration with jest (#111) Co-authored-by: danilo spinelli --- StoreSpidLogs/__test__/index.test.ts | 1 - env.example | 2 -- jest.config.js | 3 ++- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/StoreSpidLogs/__test__/index.test.ts b/StoreSpidLogs/__test__/index.test.ts index 0155eb46..601af49c 100644 --- a/StoreSpidLogs/__test__/index.test.ts +++ b/StoreSpidLogs/__test__/index.test.ts @@ -79,7 +79,6 @@ describe("StoreSpidLogs", () => { } }; const blobItem = await index(mockedContext as any, aSpidMsgItem); - console.log(blobItem); const blob = blobItem as IOutputBinding; const encryptedSpidBlobItem = blob.spidRequestResponse; const decryptedRequestPayload = toPlainText( diff --git a/env.example b/env.example index 3b587212..c28c30b1 100644 --- a/env.example +++ b/env.example @@ -1,5 +1,3 @@ -#This file is used for testing (jest), -#and must be renamed to .env (but not committed) APPINSIGHTS_INSTRUMENTATIONKEY=foo AZURE_NH_HUB_NAME=azhub AZURE_NH_ENDPOINT=Endpoint=sb://host.docker.internal:30000;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=foobar diff --git a/jest.config.js b/jest.config.js index 5242c6a5..d2eef61f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,7 @@ +require("dotenv").config({ path: "env.example" }); + module.exports = { preset: "ts-jest", - setupFiles: ["dotenv/config"], testEnvironment: "node", testPathIgnorePatterns: ["dist", "/node_modules"] };