From d3eb379e2c070fb891342b6eb388f72b40c9200b Mon Sep 17 00:00:00 2001 From: Scott Dickerson Date: Tue, 31 Oct 2023 11:10:39 -0400 Subject: [PATCH] :seedling: Enhance ENV handling (#1494) - Move from using `process.env` to `KONVEYOR_ENV` so all environment variables can be documented in Typescript/jsdoc - Add jsdoc to `KonveyorEnvType` - Setup the server to exclude any `KonveyorEnvType` keys that are for the server's use (keys in `SERVER_ENV_KEYS`) when encoding the environment variables for the client - With documenting `KonveyorEnvType.UI_INGRESS_PROXY_BODY_SIZE`, update `upload-binary.tsx` to consider the value as decimal megabytes when parsing and displaying the value Signed-off-by: Scott J Dickerson --- client/config/webpack.dev.ts | 11 +++++-- client/config/webpack.prod.ts | 3 +- .../components/upload-binary.tsx | 7 ++--- common/src/environment.ts | 30 +++++++++++++++---- common/src/index.ts | 10 ++++++- common/src/proxies.ts | 7 +++-- server/src/index.js | 15 ++++++---- 7 files changed, 62 insertions(+), 21 deletions(-) diff --git a/client/config/webpack.dev.ts b/client/config/webpack.dev.ts index 9eda05fc56..d935f8d63a 100644 --- a/client/config/webpack.dev.ts +++ b/client/config/webpack.dev.ts @@ -9,11 +9,16 @@ import ReactRefreshTypeScript from "react-refresh-typescript"; import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; -import { encodeEnv, KONVEYOR_ENV, proxyMap } from "@konveyor-ui/common"; +import { + encodeEnv, + KONVEYOR_ENV, + SERVER_ENV_KEYS, + proxyMap, +} from "@konveyor-ui/common"; import { stylePaths } from "./stylePaths"; import commonWebpackConfiguration from "./webpack.common"; -const brandType = process.env["PROFILE"] || "konveyor"; +const brandType = KONVEYOR_ENV.PROFILE; const pathTo = (relativePath: string) => path.resolve(__dirname, relativePath); interface Configuration extends WebpackConfiguration { @@ -96,7 +101,7 @@ const config: Configuration = mergeWithRules({ filename: "index.html", template: pathTo("../public/index.html.ejs"), templateParameters: { - _env: encodeEnv(KONVEYOR_ENV), + _env: encodeEnv(KONVEYOR_ENV, SERVER_ENV_KEYS), brandType, }, favicon: pathTo(`../public/${brandType}-favicon.ico`), diff --git a/client/config/webpack.prod.ts b/client/config/webpack.prod.ts index 5c1558f526..5b1f667e36 100644 --- a/client/config/webpack.prod.ts +++ b/client/config/webpack.prod.ts @@ -5,10 +5,11 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin"; import CssMinimizerPlugin from "css-minimizer-webpack-plugin"; import HtmlWebpackPlugin from "html-webpack-plugin"; +import { KONVEYOR_ENV } from "@konveyor-ui/common"; import { stylePaths } from "./stylePaths"; import commonWebpackConfiguration from "./webpack.common"; -const brandType = process.env["PROFILE"] || "konveyor"; +const brandType = KONVEYOR_ENV.PROFILE; const pathTo = (relativePath: string) => path.resolve(__dirname, relativePath); const config = merge(commonWebpackConfiguration, { diff --git a/client/src/app/pages/applications/analysis-wizard/components/upload-binary.tsx b/client/src/app/pages/applications/analysis-wizard/components/upload-binary.tsx index a63261d78c..060eacbc5c 100644 --- a/client/src/app/pages/applications/analysis-wizard/components/upload-binary.tsx +++ b/client/src/app/pages/applications/analysis-wizard/components/upload-binary.tsx @@ -145,8 +145,7 @@ export const UploadBinary: React.FC = () => { } }; - const uploadLimitInBytes = - parseInt(uploadLimit.slice(0, -1)) * Math.pow(1024, 2); + const uploadLimitInBytes = parseInt(uploadLimit.slice(0, -1)) * 1_000_000; const readFile = (file: File) => { return new Promise((resolve, reject) => { @@ -199,8 +198,8 @@ export const UploadBinary: React.FC = () => { <>
Accepted file types: war, ear, jar or zip
- Upload size limit: {Math.round(uploadLimitInBytes / 1000000)}{" "} - MB + Upload size limit: + {Math.round(uploadLimitInBytes / 1_000_000)} MB
} diff --git a/common/src/environment.ts b/common/src/environment.ts index dd1160a732..135719f57f 100644 --- a/common/src/environment.ts +++ b/common/src/environment.ts @@ -13,22 +13,44 @@ export type KonveyorEnvType = { NODE_ENV: "development" | "production" | "test"; VERSION: string; - /** Require keycloak authentication? */ + /** Enable RBAC authentication/authorization */ AUTH_REQUIRED: "true" | "false"; + + /** SSO / Keycloak realm */ KEYCLOAK_REALM: string; + + /** SSO / Keycloak client id */ KEYCLOAK_CLIENT_ID: string; - KEYCLOAK_SERVER_URL: string; /** Branding to apply to the UI */ PROFILE: "konveyor" | "mta"; - /** Upload file size limit */ + /** UI upload file size limit in megabytes (MB), suffixed with "m" */ UI_INGRESS_PROXY_BODY_SIZE: string; /** Allow clearing local maven artifact repository? Requires availability of RWX volumes for hub. */ RWX_SUPPORTED: "true" | "false"; + + /** The listen port for the UI's server */ + PORT?: string; + + /** Target URL for the UI server's `/auth` proxy */ + KEYCLOAK_SERVER_URL?: string; + + /** Target URL for the UI server's `/hub` proxy */ + TACKLE_HUB_URL?: string; }; +/** + * Keys in `KonveyorEnvType` that are only used on the server and therefore do not + * need to be sent to the client. + */ +export const SERVER_ENV_KEYS = [ + "PORT", + "KEYCLOAK_SERVER_URL", + "TACKLE_HUB_URL", +]; + /** * Create a `KonveyorEnv` from a partial `KonveyorEnv` with a set of default values. */ @@ -39,7 +61,6 @@ export const buildKonveyorEnv = ({ AUTH_REQUIRED = "false", KEYCLOAK_REALM = "tackle", KEYCLOAK_CLIENT_ID = "tackle-ui", - KEYCLOAK_SERVER_URL = "", PROFILE = "konveyor", UI_INGRESS_PROXY_BODY_SIZE = "500m", @@ -51,7 +72,6 @@ export const buildKonveyorEnv = ({ AUTH_REQUIRED, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, - KEYCLOAK_SERVER_URL, PROFILE, UI_INGRESS_PROXY_BODY_SIZE, diff --git a/common/src/index.ts b/common/src/index.ts index 5c39396bf2..12f839c15f 100644 --- a/common/src/index.ts +++ b/common/src/index.ts @@ -4,7 +4,15 @@ export * from "./proxies.js"; /** * Return a base64 encoded JSON string containing the given `env` object. */ -export const encodeEnv = (env: object): string => btoa(JSON.stringify(env)); +export const encodeEnv = (env: object, exclude?: string[]): string => { + const filtered = exclude + ? Object.fromEntries( + Object.entries(env).filter(([key]) => !exclude.includes(key)) + ) + : env; + + return btoa(JSON.stringify(filtered)); +}; /** * Return an objects from a base64 encoded JSON string. diff --git a/common/src/proxies.ts b/common/src/proxies.ts index b11caa840a..94246c544b 100644 --- a/common/src/proxies.ts +++ b/common/src/proxies.ts @@ -1,8 +1,9 @@ import type { Options } from "http-proxy-middleware"; +import { KONVEYOR_ENV } from "./environment.js"; export const proxyMap: Record = { "/auth": { - target: process.env.KEYCLOAK_SERVER_URL || "http://localhost:9001", + target: KONVEYOR_ENV.KEYCLOAK_SERVER_URL || "http://localhost:9001", logLevel: process.env.DEBUG ? "debug" : "info", changeOrigin: true, @@ -30,7 +31,7 @@ export const proxyMap: Record = { }, "/hub": { - target: process.env.TACKLE_HUB_URL || "http://localhost:9002", + target: KONVEYOR_ENV.TACKLE_HUB_URL || "http://localhost:9002", logLevel: process.env.DEBUG ? "debug" : "info", changeOrigin: true, @@ -39,6 +40,8 @@ export const proxyMap: Record = { }, onProxyReq: (proxyReq, req, _res) => { + // Add the Bearer token to the request if it is not already present, AND if + // the token is part of the request as a cookie if (req.cookies?.keycloak_cookie && !req.headers["authorization"]) { proxyReq.setHeader( "Authorization", diff --git a/server/src/index.js b/server/src/index.js index 7d84b240bb..895c4504d5 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -9,13 +9,18 @@ import cookieParser from "cookie-parser"; import { createHttpTerminator } from "http-terminator"; import { createProxyMiddleware } from "http-proxy-middleware"; -import { encodeEnv, KONVEYOR_ENV, proxyMap } from "@konveyor-ui/common"; +import { + encodeEnv, + KONVEYOR_ENV, + SERVER_ENV_KEYS, + proxyMap, +} from "@konveyor-ui/common"; const __dirname = fileURLToPath(new URL(".", import.meta.url)); const pathToClientDist = path.join(__dirname, "../../client/dist"); -const brandType = process.env["PROFILE"] || "konveyor"; -const port = 8080; +const brandType = KONVEYOR_ENV.PROFILE; +const port = parseInt(KONVEYOR_ENV.PORT, 10) || 8080; const app = express(); app.use(cookieParser()); @@ -32,7 +37,7 @@ app.use(express.static(pathToClientDist)); // Handle any request that hasn't already been handled by express.static or proxy app.get("*", (_, res) => { - if (process.env.NODE_ENV === "development") { + if (KONVEYOR_ENV.NODE_ENV === "development") { res.send(` You're running in development mode! The UI is served by webpack-dev-server on port 9000: http://localhost:9000

@@ -41,7 +46,7 @@ app.get("*", (_, res) => { `); } else { res.render("index.html.ejs", { - _env: encodeEnv(KONVEYOR_ENV), + _env: encodeEnv(KONVEYOR_ENV, SERVER_ENV_KEYS), brandType, }); }