feat(server): read secrets from env variables

This commit is contained in:
Sam Tolmay 2020-11-12 14:18:42 +02:00
parent 5f2a43bb81
commit 6478d266a4
9 changed files with 173 additions and 52 deletions

29
.pnp.js generated
View File

@ -3983,18 +3983,21 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/server/",
"packageDependencies": [
["@lowdefy/server", "workspace:packages/server"],
["@babel/cli", "virtual:4a7337632ff6e9ee5a1c45a62a9ff4cc325a9367b21424babda93e269fe01b671e885bc41bdeebafb83c81f2a8eebbf0102043354a4e58905f61c8c3387cda1e#npm:7.12.1"],
["@babel/core", "npm:7.12.3"],
["@babel/preset-env", "virtual:4a7337632ff6e9ee5a1c45a62a9ff4cc325a9367b21424babda93e269fe01b671e885bc41bdeebafb83c81f2a8eebbf0102043354a4e58905f61c8c3387cda1e#npm:7.12.1"],
["@babel/preset-react", "virtual:22157ea722f8d6428f1fcf0a6f7f6c7d6b902d9c785256c60a65fe6cd0db76ebccc7c1457ee047df0ba6909ff018e300c4f4957a60f5b670089810dfc417af9b#npm:7.12.5"],
["@lowdefy/block-tools", "workspace:packages/blockTools"],
["@lowdefy/graphql", "workspace:packages/graphql"],
["apollo-server-express", "virtual:1e43113c7dc84a5d03308bf7ffaf00574d351ca16282af6c6c0b9576804fb03914bdf2200961292f439926b2e537dce172d7529f79013ce51b9f2d56e9cd836b#npm:2.19.0"],
["babel-jest", "virtual:caddf51df4928b33a437ca87b8f5ddfb6205ebd6d8231f74d4ee7223f3866e6f815b221aa1e2bd33e98915f701e95bae72a93d2288b49a34a6246bdbc2a4a132#npm:26.6.3"],
["babel-loader", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:8.2.1"],
["clean-webpack-plugin", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:3.0.0"],
["copy-webpack-plugin", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:6.3.0"],
["css-loader", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:5.0.1"],
["express", "npm:4.17.1"],
["graphql", "npm:15.4.0"],
["html-webpack-plugin", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:4.5.0"],
["jest", "npm:26.6.3"],
["nodemon", "npm:2.0.6"],
["react", "npm:17.0.1"],
["react-dom", "virtual:22157ea722f8d6428f1fcf0a6f7f6c7d6b902d9c785256c60a65fe6cd0db76ebccc7c1457ee047df0ba6909ff018e300c4f4957a60f5b670089810dfc417af9b#npm:17.0.1"],
@ -9129,30 +9132,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]
]],
["copy-webpack-plugin", [
["virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:6.3.0", {
"packageLocation": "./.yarn/$$virtual/copy-webpack-plugin-virtual-9c7083a2fa/0/cache/copy-webpack-plugin-npm-6.3.0-0a315a2450-edca6ec5cd.zip/node_modules/copy-webpack-plugin/",
"packageDependencies": [
["copy-webpack-plugin", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:6.3.0"],
["@types/webpack", null],
["cacache", "npm:15.0.5"],
["fast-glob", "npm:3.2.4"],
["find-cache-dir", "npm:3.3.1"],
["glob-parent", "npm:5.1.1"],
["globby", "npm:11.0.1"],
["loader-utils", "npm:2.0.0"],
["normalize-path", "npm:3.0.0"],
["p-limit", "npm:3.0.2"],
["schema-utils", "npm:3.0.0"],
["serialize-javascript", "npm:5.0.1"],
["webpack", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:5.4.0"],
["webpack-sources", "npm:1.4.3"]
],
"packagePeers": [
"@types/webpack",
"webpack"
],
"linkType": "HARD",
}],
["virtual:65bbdbc833194d48af8b473ccb9eb396af4cb12a8148bcea865208cb4df1306b9afb0a62408cbd348e6f2af9b92764096868c744881c07da8a59708a1c9cb4f4#npm:6.3.0", {
"packageLocation": "./.yarn/$$virtual/copy-webpack-plugin-virtual-30f062ffd9/0/cache/copy-webpack-plugin-npm-6.3.0-0a315a2450-edca6ec5cd.zip/node_modules/copy-webpack-plugin/",
"packageDependencies": [

14
packages/server/.babelrc Normal file
View File

@ -0,0 +1,14 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12",
"esmodules": true
}
}
]
],
"ignore": ["./src/shell"]
}

View File

@ -0,0 +1,11 @@
module.exports = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: ['src/**/*.js'],
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/test/', '<rootDir>/src/shell/'],
coverageReporters: [['lcov', { projectRoot: '../..' }], 'text', 'clover'],
errorOnDeprecated: true,
testEnvironment: 'node',
testPathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/.lowdefy/'],
};

View File

@ -25,17 +25,22 @@
"dist/*"
],
"scripts": {
"build": "webpack --config webpack.prod.js",
"build:dev": "webpack --config webpack.dev.js",
"babel": "babel src --out-dir dist",
"babel:dev": "babel src --out-dir dev",
"build": "yarn webpack && yarn babel",
"build:dev": "yarn webpack:dev && yarn babel:dev",
"build:docker": "docker build --tag lowdefy/lowdefy .",
"clean": "rm -rf dist",
"clean": "rm -rf dist && rm -rf dev",
"npm-publish": "npm publish --access public",
"prepublishOnly": "yarn build",
"start": "nodemon dev/server.js",
"test": "jest --coverage",
"version:prerelease": "yarn version prerelease",
"version:patch": "yarn version patch -d",
"version:minor": "yarn version minor -d",
"version:major": "yarn version major -d"
"version:major": "yarn version major -d",
"webpack": "webpack --config webpack.prod.js",
"webpack:dev": "webpack --config webpack.dev.js"
},
"dependencies": {
"@lowdefy/block-tools": "1.0.2",
@ -47,13 +52,16 @@
"react-dom": "17.0.1"
},
"devDependencies": {
"@babel/cli": "7.12.1",
"@babel/core": "7.12.3",
"@babel/preset-env": "7.12.1",
"@babel/preset-react": "7.12.5",
"babel-jest": "26.6.3",
"babel-loader": "8.2.1",
"clean-webpack-plugin": "3.0.0",
"copy-webpack-plugin": "6.3.0",
"css-loader": "5.0.1",
"html-webpack-plugin": "4.5.0",
"jest": "26.6.3",
"nodemon": "2.0.6",
"style-loader": "2.0.0",
"webpack": "5.4.0",

View File

@ -0,0 +1,29 @@
/*
Copyright 2020 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
function createGetSecretsFromEnv() {
const secrets = {};
Object.keys(process.env).forEach((key) => {
if (key.startsWith('LOWDEFY_SECRET_')) {
secrets[key.replace('LOWDEFY_SECRET_', '')] = process.env[key];
}
});
Object.freeze(secrets);
return () => secrets;
}
export default createGetSecretsFromEnv;

View File

@ -14,21 +14,17 @@
limitations under the License.
*/
const path = require('path');
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { typeDefs, resolvers, createContext } = require('@lowdefy/graphql');
import path from 'path';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { typeDefs, resolvers, createContext } from '@lowdefy/graphql';
import createGetSecretsFromEnv from './createGetSecretsFromEnv';
const config = {
DEPLOYMENT_ID: 'DEPLOYMENT_ID',
DEPLOYMENT_NAME: 'DEPLOYMENT_NAME',
DOMAIN_NAME: 'DOMAIN_NAME',
CONFIGURATION_BASE_PATH: path.resolve(process.cwd(), './.lowdefy/build'),
logger: console,
getHeadersFromInput: ({ req }) => req.headers,
getSecrets: () => ({
CONNECTION_SECRETS: {},
}),
getSecrets: createGetSecretsFromEnv(),
};
const context = createContext(config);

View File

@ -0,0 +1,90 @@
/*
Copyright 2020 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import createGetSecretsFromEnv from '../src/createGetSecretsFromEnv';
const realEnv = process.env;
afterEach(() => {
process.env = realEnv;
});
test('Get secret from env', () => {
process.env = {
LOWDEFY_SECRET_TEST: 'supersecret',
};
const getSecrets = createGetSecretsFromEnv();
expect(getSecrets()).toEqual({
TEST: 'supersecret',
});
});
test('Get multiple secrets from env, ignore other env variable', () => {
process.env = {
LOWDEFY_SECRET_TEST_1: 'supersecret1',
LOWDEFY_SECRET_TEST_2: 'supersecret2',
OTHER_VAR: 'other',
ANOTHER_VAR: 'another',
ASDF_GHJK: 'asdfghjk',
};
const getSecrets = createGetSecretsFromEnv();
expect(getSecrets()).toEqual({
TEST_1: 'supersecret1',
TEST_2: 'supersecret2',
});
});
test('Only replace first occurrence of "LOWDEFY_SECRET_"', () => {
process.env = {
LOWDEFY_SECRET_LOWDEFY_SECRET_TEST: 'supersecret',
};
const getSecrets = createGetSecretsFromEnv();
expect(getSecrets()).toEqual({
LOWDEFY_SECRET_TEST: 'supersecret',
});
});
test('Return an empty object if no secrets', () => {
process.env = {
OTHER_VAR: 'other',
ANOTHER_VAR: 'another',
ASDF_GHJK: 'asdfghjk',
};
const getSecrets = createGetSecretsFromEnv();
expect(getSecrets()).toEqual({});
});
test('Return the same object', () => {
process.env = {
LOWDEFY_SECRET_TEST: 'supersecret',
};
const getSecrets = createGetSecretsFromEnv();
expect(getSecrets()).toBe(getSecrets());
});
test('Secrets are immutable', () => {
process.env = {
LOWDEFY_SECRET_TEST: 'supersecret',
};
const getSecrets = createGetSecretsFromEnv();
const secrets = getSecrets();
expect(secrets).toEqual({
TEST: 'supersecret',
});
expect(() => {
secrets.test = 'changed';
}).toThrow(TypeError);
});

View File

@ -1,5 +1,3 @@
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
@ -12,6 +10,7 @@ module.exports = {
loader: 'babel-loader',
exclude: /node_modules/,
options: {
babelrc: false,
presets: ['@babel/preset-react'],
},
},
@ -33,13 +32,5 @@ module.exports = {
new HtmlWebpackPlugin({
template: './src/shell/index.html',
}),
new CopyPlugin({
patterns: [
{
from: 'src/server.js',
to: '../server.js',
},
],
}),
],
};

View File

@ -3122,18 +3122,21 @@ __metadata:
version: 0.0.0-use.local
resolution: "@lowdefy/server@workspace:packages/server"
dependencies:
"@babel/cli": 7.12.1
"@babel/core": 7.12.3
"@babel/preset-env": 7.12.1
"@babel/preset-react": 7.12.5
"@lowdefy/block-tools": 1.0.2
"@lowdefy/graphql": 0.0.0-alpha.3
apollo-server-express: 2.19.0
babel-jest: 26.6.3
babel-loader: 8.2.1
clean-webpack-plugin: 3.0.0
copy-webpack-plugin: 6.3.0
css-loader: 5.0.1
express: 4.17.1
graphql: 15.4.0
html-webpack-plugin: 4.5.0
jest: 26.6.3
nodemon: 2.0.6
react: 17.0.1
react-dom: 17.0.1