Skip to content

Commit

Permalink
[#175119553] Centralize environment variables in single config module (
Browse files Browse the repository at this point in the history
  • Loading branch information
infantesimone committed Oct 8, 2020
1 parent 707c5f0 commit e7f2130
Show file tree
Hide file tree
Showing 21 changed files with 456 additions and 89 deletions.
8 changes: 5 additions & 3 deletions CreateValidationTokenActivity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ 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 tableService = createTableService(storageConnectionString);
const tableService = createTableService(config.QueueStorageConnection);

const randomBytesGenerator = (size: number) =>
crypto.randomBytes(size).toString("hex");
Expand Down
10 changes: 5 additions & 5 deletions GetMessage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -18,19 +17,20 @@ 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 messageModel = new MessageModel(
cosmosdbInstance.container(MESSAGE_COLLECTION_NAME),
messageContainerName
config.MESSAGE_CONTAINER_NAME
);

const storageConnectionString = getRequiredStringEnv("QueueStorageConnection");
const blobService = createBlobService(storageConnectionString);
const blobService = createBlobService(config.QueueStorageConnection);

app.get(
"/api/v1/messages/:fiscalcode/:id",
Expand Down
7 changes: 4 additions & 3 deletions GetMessages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -16,15 +15,17 @@ 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 messageModel = new MessageModel(
cosmosdbInstance.container(MESSAGE_COLLECTION_NAME),
messageContainerName
config.MESSAGE_CONTAINER_NAME
);

app.get("/api/v1/messages/:fiscalcode", GetMessages(messageModel));
Expand Down
8 changes: 5 additions & 3 deletions GetVisibleServices/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ 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";

import createAzureFunctionHandler from "io-functions-express/dist/src/createAzureFunctionsHandler";

import { GetVisibleServices } from "./handler";

import { getConfigOrThrow } from "../utils/config";

// Setup Express
const app = express();
secureExpressApp(app);

const storageConnectionString = getRequiredStringEnv("QueueStorageConnection");
const blobService = createBlobService(storageConnectionString);
const config = getConfigOrThrow();

const blobService = createBlobService(config.QueueStorageConnection);

app.get("/api/v1/services", GetVisibleServices(blobService));

Expand Down
7 changes: 0 additions & 7 deletions HandleNHNotificationCallActivity/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +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"
};

import { NonEmptyString } from "italia-ts-commons/lib/strings";
import { context as contextMock } from "../../__mocks__/durable-functions";
import { PlatformEnum } from "../../generated/backend/Platform";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +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"
};
import { NonEmptyString } from "italia-ts-commons/lib/strings";
import { context as contextMock } from "../../__mocks__/durable-functions";
import { PlatformEnum } from "../../generated/backend/Platform";
Expand Down
29 changes: 14 additions & 15 deletions SendValidationEmailActivity/index.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -14,32 +13,32 @@ 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
).getOrElse(undefined);
const sendgridApiKey = NonEmptyString.decode(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");

// Needed to construct the email validation url
const functionsPublicUrl = getRequiredStringEnv("FUNCTIONS_PUBLIC_URL");

const HTML_TO_TEXT_OPTIONS: HtmlToTextOptions = {
ignoreImage: true, // Ignore all document images
tables: true
};

const emailDefaults = {
from: mailFrom,
from: config.MAIL_FROM,
htmlToTextOptions: HTML_TO_TEXT_OPTIONS,
title: EMAIL_TITLE
};
Expand All @@ -51,7 +50,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([]);
Expand All @@ -78,7 +77,7 @@ initTelemetryClient();
const activityFunctionHandler = getSendValidationEmailActivityHandler(
mailerTransporter,
emailDefaults,
functionsPublicUrl
config.FUNCTIONS_PUBLIC_URL
);

export default activityFunctionHandler;
14 changes: 9 additions & 5 deletions SendWelcomeMessagesActivity/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getRequiredStringEnv } from "io-functions-commons/dist/src/utils/env";
import { agent } from "italia-ts-commons";
import {
AbortableFetch,
Expand All @@ -8,12 +7,12 @@ 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;

// Needed to call notifications API
const publicApiUrl = getRequiredStringEnv("PUBLIC_API_URL");
const publicApiKey = getRequiredStringEnv("PUBLIC_API_KEY");
const config = getConfigOrThrow();

// HTTP-only fetch with optional keepalive agent
// @see https://github.com/pagopa/io-ts-commons/blob/master/src/agent.ts#L10
Expand All @@ -25,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;
13 changes: 0 additions & 13 deletions StoreSpidLogs/__test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
/* tslint:disable:no-any */
/* tslint:disable:no-object-mutation */

process.env = {
APPINSIGHTS_INSTRUMENTATIONKEY: "foo",
QueueStorageConnection: "foobar",
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-----`
};

import { format } from "date-fns";
import { toPlainText } from "italia-ts-commons/lib/encrypt";
import { IPString } from "italia-ts-commons/lib/strings";
Expand Down
6 changes: 3 additions & 3 deletions StoreSpidLogs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -12,9 +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 encrypt = curry(toEncryptedPayload)(rsaPublicKey);
const config = getConfigOrThrow();
const encrypt = curry(toEncryptedPayload)(config.SPID_LOGS_PUBLIC_KEY);

/**
* Payload of the stored blob item
Expand Down
22 changes: 14 additions & 8 deletions UpdateSubscriptionsFeedActivity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@ 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");
const tableService = createTableService(storageConnectionString);
import { getConfigOrThrow } from "../utils/config";

const config = getConfigOrThrow();

const tableService = createTableService(config.QueueStorageConnection);

const subscriptionsFeedTable = getRequiredStringEnv("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;

Expand Down Expand Up @@ -58,7 +64,7 @@ export type Input = t.TypeOf<typeof Input>;

// 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.
Expand Down
15 changes: 7 additions & 8 deletions docker/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +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();

export const cosmosdbClient = new CosmosClient({
endpoint: cosmosDbUri,
key: cosmosDbKey
endpoint: config.CUSTOMCONNSTR_COSMOSDB_URI,
key: config.CUSTOMCONNSTR_COSMOSDB_KEY
});

function createDatabase(databaseName: string): TaskEither<Error, Database> {
Expand Down Expand Up @@ -56,7 +55,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.");
Expand Down Expand Up @@ -88,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"),
Expand Down
22 changes: 22 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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
2 changes: 2 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require("dotenv").config({ path: "env.example" });

module.exports = {
preset: "ts-jest",
testEnvironment: "node",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading

0 comments on commit e7f2130

Please sign in to comment.