This is an automated email from the ASF dual-hosted git repository.

thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 26689ddb9ad kie-tools#3349: [cors-proxy] Implement domains filtering 
(#3353)
26689ddb9ad is described below

commit 26689ddb9ad8f89f9fd6915a5df5c34b614ce6de
Author: Fabrizio Antonangeli <[email protected]>
AuthorDate: Tue Dec 9 15:08:02 2025 +0100

    kie-tools#3349: [cors-proxy] Implement domains filtering (#3353)
---
 packages/cors-proxy-image/Containerfile            |   2 +
 packages/cors-proxy-image/README.md                |   3 +-
 packages/cors-proxy-image/env/index.js             |   5 +
 packages/cors-proxy-image/package.json             |   2 +-
 packages/cors-proxy/README.md                      |   3 +
 packages/cors-proxy/env/index.js                   |   6 +
 packages/cors-proxy/package.json                   |   6 +-
 packages/cors-proxy/src/index.ts                   |  16 ++
 packages/cors-proxy/src/proxy/ExpressCorsProxy.ts  |  16 +-
 packages/cors-proxy/src/proxy/server.ts            |   2 +
 packages/cors-proxy/tests/ExpressCorsProxy.test.ts | 187 +++++++++++++++++++++
 packages/cors-proxy/tests/index.test.ts            |  57 ++++++-
 packages/cors-proxy/tests/server.test.ts           |  37 ++++
 packages/online-editor/package.json                |   4 +-
 pnpm-lock.yaml                                     |   8 +-
 15 files changed, 337 insertions(+), 17 deletions(-)

diff --git a/packages/cors-proxy-image/Containerfile 
b/packages/cors-proxy-image/Containerfile
index 84450e5b32c..3505965e50b 100644
--- a/packages/cors-proxy-image/Containerfile
+++ b/packages/cors-proxy-image/Containerfile
@@ -20,6 +20,7 @@ FROM --platform=linux/amd64 
registry.access.redhat.com/ubi9/ubi-minimal:9.5
 ARG CORS_PROXY_DEFAULT_PORT=8080
 ARG CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=
 ARG CORS_PROXY_DEFAULT_VERBOSE=false
+ARG CORS_PROXY_DEFAULT_ALLOW_HOSTS=localhost,*.github.com
 
 ENV HOME          /home/kie-sandbox
 ENV NVM_DIR       $HOME/.nvm
@@ -28,6 +29,7 @@ ENV NODE_VERSION  v22.14.0
 ENV CORS_PROXY_HTTP_PORT=$CORS_PROXY_DEFAULT_PORT
 ENV CORS_PROXY_ALLOWED_ORIGINS=$CORS_PROXY_DEFAULT_ALLOWED_ORIGINS
 ENV CORS_PROXY_VERBOSE=$CORS_PROXY_DEFAULT_VERBOSE
+ENV CORS_PROXY_ALLOW_HOSTS=$CORS_PROXY_DEFAULT_ALLOW_HOSTS
 
 RUN mkdir $HOME \
   && chgrp -R 0 $HOME \
diff --git a/packages/cors-proxy-image/README.md 
b/packages/cors-proxy-image/README.md
index 98f17ba6100..01f8a9eccd1 100644
--- a/packages/cors-proxy-image/README.md
+++ b/packages/cors-proxy-image/README.md
@@ -41,6 +41,7 @@ export CORS_PROXY_IMAGE__imageBuildTag=<image-tag>
 export CORS_PROXY_IMAGE__imagePort=<port>
 export CORS_PROXY_IMAGE__imageAllowedOrigins=<allowed-origins>  # 
Comma-separated list
 export CORS_PROXY_IMAGE__imageVerbose=<verbose>
+export CORS_PROXY_IMAGE__imageAllowHosts=<allow-hosts>  # e.g., 
"*.example.com,*.github.com,localhost"
 ```
 
 Default values can be found [here](./env/index.js).
@@ -68,7 +69,7 @@ docker run -p 8080:8080 -i --rm -e 
CORS_PROXY_ALLOWED_ORIGINS="http://localhost:
 Or in production:
 
 ```bash
-docker run -p 8080:8080 -i --rm -e 
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com"; 
docker.io/apache/incubator-kie-cors-proxy:main
+docker run -p 8080:8080 -i --rm -e 
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com"; -e 
CORS_PROXY_ALLOW_HOSTS="*.example.com,*.github.com,localhost" 
docker.io/apache/incubator-kie-cors-proxy:main
 ```
 
 The service will be up at http://localhost:8080
diff --git a/packages/cors-proxy-image/env/index.js 
b/packages/cors-proxy-image/env/index.js
index 411050ddea1..cecfcb1af31 100644
--- a/packages/cors-proxy-image/env/index.js
+++ b/packages/cors-proxy-image/env/index.js
@@ -52,6 +52,10 @@ module.exports = composeEnv([rootEnv], {
       default: false,
       description: "Toggle verbose mode on the CORS proxy logs.",
     },
+    CORS_PROXY_IMAGE__imageAllowHosts: {
+      default: corsProxyEnv.env.corsProxy.dev.allowedHosts,
+      description: "Comma-separated list of allowed host patterns for domain 
filtering. Supports wildcards.",
+    },
   }),
   get env() {
     return {
@@ -64,6 +68,7 @@ module.exports = composeEnv([rootEnv], {
           port: getOrDefault(this.vars.CORS_PROXY_IMAGE__imagePort),
           allowedOrigins: 
getOrDefault(this.vars.CORS_PROXY_IMAGE__imageAllowedOrigins),
           verbose: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageVerbose),
+          allowedHosts: 
getOrDefault(this.vars.CORS_PROXY_IMAGE__imageAllowHosts),
         },
       },
     };
diff --git a/packages/cors-proxy-image/package.json 
b/packages/cors-proxy-image/package.json
index d518b2b0fab..840fe25224f 100644
--- a/packages/cors-proxy-image/package.json
+++ b/packages/cors-proxy-image/package.json
@@ -19,7 +19,7 @@
     "copy:cors-proxy-package": "run-script-os",
     "copy:cors-proxy-package:linux:darwin": "cp -R 
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/",
     "copy:cors-proxy-package:win32": "pnpm powershell \"Copy-Item -R 
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/\"",
-    "docker:build": "kie-tools--image-builder build -r \"$(build-env 
corsProxyImage.image.registry)\" -a \"$(build-env 
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\" 
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg 
\"CORS_PROXY_DEFAULT_PORT=$(build-env corsProxyImage.image.port)\" --build-arg 
\"CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=$(build-env 
corsProxyImage.image.allowedOrigins)\" --build-arg 
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImag [...]
+    "docker:build": "kie-tools--image-builder build -r \"$(build-env 
corsProxyImage.image.registry)\" -a \"$(build-env 
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\" 
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg 
\"CORS_PROXY_DEFAULT_PORT=$(build-env corsProxyImage.image.port)\" --build-arg 
\"CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=$(build-env 
corsProxyImage.image.allowedOrigins)\" --build-arg 
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImag [...]
   },
   "devDependencies": {
     "@kie-tools/cors-proxy": "workspace:*",
diff --git a/packages/cors-proxy/README.md b/packages/cors-proxy/README.md
index 9a4edc4d157..9eddcc989ef 100644
--- a/packages/cors-proxy/README.md
+++ b/packages/cors-proxy/README.md
@@ -27,6 +27,7 @@ The `cors-proxy` can be configured via environment variables:
 - CORS_PROXY_HTTP_PORT: Sets the HTTP Port the proxy should listen to. 
Defaults to `8080`
 - CORS_PROXY_VERBOSE: Allows the proxy to run in verbose mode... useful to 
trace requests on development environments. Defaults to `false`
 - CORS_PROXY_USE_HTTP_FOR_HOSTS: Comma-separated list of hosts that should use 
the `http` protocol for proxied requests. Defaults to an empty list.
+- CORS_PROXY_ALLOWED_HOSTS: Comma-separated list of allowed host patterns for 
domain filtering. Supports wildcards (e.g., `*.example.com`, `*.github.com`). 
Only requests to matching hosts will be proxied. Defaults to 
`localhost,*.github.com`.
 - HTTP_PROXY or HTTPS_PROXY: Url of a proxy that will be used to proxy the 
requests `cors-proxy` is already proxying.
 - NODE_EXTRA_CA_CERTS: This is used by NodeJS itself to add cartificates to 
the chain. See more at https://nodejs.org/api/cli.html#node_extra_ca_certsfile
 
@@ -37,6 +38,7 @@ export CORS_PROXY_HTTP_PORT=8080
 export 
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com";
 export CORS_PROXY_VERBOSE=false
 export CORS_PROXY_USE_HTTP_FOR_HOSTS="localhost:8080,localhost:8081"
+export CORS_PROXY_ALLOWED_HOSTS="*.example.com,*.github.com"
 ```
 
 # Build
@@ -66,6 +68,7 @@ export CORS_PROXY__allowedOrigins="http://localhost:9001";
 export CORS_PROXY__port=*
 export CORS_PROXY__verbose=false
 export CORS_PROXY__useHttpForHosts="localhost:8080,localhost:8081"
+export CORS_PROXY__allowedHosts="*.example.com,*.github.com,localhost"
 ```
 
 Default values can be found [here](./env/index.js).
diff --git a/packages/cors-proxy/env/index.js b/packages/cors-proxy/env/index.js
index c7ace6d1fed..4703529f6d1 100644
--- a/packages/cors-proxy/env/index.js
+++ b/packages/cors-proxy/env/index.js
@@ -37,6 +37,11 @@ module.exports = 
composeEnv([require("@kie-tools/root-env/env")], {
       default: true,
       description: "Use `http` as default protocol for proxied requests. If 
`false`, `https` is used.",
     },
+    CORS_PROXY__allowedHosts: {
+      default: "*",
+      description:
+        "Comma-separated list of allowed host patterns. Supports wildcards 
(e.g., '*.target.example.com,*.github.com').",
+    },
   }),
   get env() {
     return {
@@ -46,6 +51,7 @@ module.exports = 
composeEnv([require("@kie-tools/root-env/env")], {
           port: getOrDefault(this.vars.CORS_PROXY__port),
           verbose: getOrDefault(this.vars.CORS_PROXY__verbose),
           useHttpForHosts: getOrDefault(this.vars.CORS_PROXY__useHttpForHosts),
+          allowedHosts: getOrDefault(this.vars.CORS_PROXY__allowedHosts),
         },
       },
     };
diff --git a/packages/cors-proxy/package.json b/packages/cors-proxy/package.json
index 82cc1781adf..91a61e20027 100644
--- a/packages/cors-proxy/package.json
+++ b/packages/cors-proxy/package.json
@@ -21,14 +21,15 @@
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
     "start": "run-script-os",
-    "start:darwin:linux": "pnpm build:dev && cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js",
-    "start:win32": "pnpm build:dev && pnpm powershell \"cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js\"",
+    "start:darwin:linux": "pnpm build:dev && cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) 
CORS_PROXY_ALLOWED_HOSTS=$(build-env corsProxy.dev.allowedHosts) node 
dist/index.js",
+    "start:win32": "pnpm build:dev && pnpm powershell \"cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) 
CORS_PROXY_ALLOWED_HOSTS=$(build-env corsProxy.dev.allowedHosts) node 
dist/index.js\"",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\""
   },
   "dependencies": {
     "cors": "^2.8.5",
     "express": "^4.21.2",
     "https-proxy-agent": "^7.0.6",
+    "minimatch": "^3.0.5",
     "node-fetch": "^3.3.2"
   },
   "devDependencies": {
@@ -43,6 +44,7 @@
     "@types/cors": "^2.8.13",
     "@types/express": "^4.17.17",
     "@types/jest": "^29.5.12",
+    "@types/minimatch": "^3.0.5",
     "@types/node": "^22.14.1",
     "cross-env": "^7.0.3",
     "jest": "^29.7.0",
diff --git a/packages/cors-proxy/src/index.ts b/packages/cors-proxy/src/index.ts
index 6020b615b0e..7caec5711f0 100644
--- a/packages/cors-proxy/src/index.ts
+++ b/packages/cors-proxy/src/index.ts
@@ -42,12 +42,28 @@ function getAllowedOrigins(): string[] {
   return originsList;
 }
 
+function getAllowedHosts(): string[] {
+  const hosts = process.env.CORS_PROXY_ALLOWED_HOSTS || 
"localhost,*.github.com";
+  const hostsList = hosts.split(",").map((o) => o.trim());
+
+  if (hostsList.some((o) => o === "")) {
+    throw new Error("Invalid host: empty hosts are not allowed in 
CORS_PROXY_ALLOWED_HOSTS.");
+  }
+
+  if (hostsList.some((o) => o === "*")) {
+    console.warn('Wildcard alone "*" is strongly discouraged in 
CORS_PROXY_ALLOWED_HOSTS production environments.');
+  }
+
+  return hostsList;
+}
+
 export const run = () => {
   startServer({
     allowedOrigins: getAllowedOrigins(),
     port: getPort(),
     verbose: process.env.CORS_PROXY_VERBOSE === "true",
     hostsToUseHttp: (process.env.CORS_PROXY_USE_HTTP_FOR_HOSTS || 
undefined)?.split(",") ?? [],
+    allowedHosts: getAllowedHosts(),
   });
 };
 
diff --git a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts 
b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
index 9ae560ab737..edc367daed9 100644
--- a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
+++ b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
@@ -21,6 +21,7 @@ import * as https from "https";
 import fetch from "node-fetch";
 import { Request, Response } from "express";
 import { HttpsProxyAgent } from "https-proxy-agent";
+import * as minimatch from "minimatch";
 import { GIT_CORS_CONFIG, isGitOperation } from "./git";
 import { CorsProxyHeaderKeys, CorsConfig, CorsProxy } from 
"@kie-tools/cors-proxy-api/dist";
 
@@ -38,6 +39,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
   constructor(
     private readonly args: {
       allowedOrigins: string[];
+      allowedHosts: string[];
       verbose: boolean;
       hostsToUseHttp: string[];
     }
@@ -117,7 +119,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
 
       res.status(proxyResponse.status);
 
-      this.logger.debug("Writting Response...");
+      this.logger.debug("Writing Response...");
       if (proxyResponse.body) {
         const stream = proxyResponse.body.pipe(res);
         stream.on("close", () => {
@@ -138,9 +140,17 @@ export class ExpressCorsProxy implements 
CorsProxy<Request, Response> {
     }
   }
 
+  private validateTargetUrl(targetUrl: string): boolean {
+    const protocol = /^https?:\/\//.test(targetUrl) ? "" : "https:/";
+    const parsedTargetUrl = new URL(protocol + targetUrl);
+
+    return this.args.allowedHosts.some((pattern) => 
minimatch(parsedTargetUrl.hostname, pattern));
+  }
+
   private resolveRequestInfo(request: Request): ProxyRequestInfo {
     const origin = request.header("origin");
     const targetUrl: string = (request.headers[CorsProxyHeaderKeys.TARGET_URL] 
as string) ?? request.url;
+
     if (!origin || !this.args.allowedOrigins.includes(origin)) {
       throw new Error(`Origin ${origin} is not allowed`);
     }
@@ -149,6 +159,10 @@ export class ExpressCorsProxy implements 
CorsProxy<Request, Response> {
       throw new Error("Couldn't resolve the target URL...");
     }
 
+    if (!this.validateTargetUrl(targetUrl)) {
+      throw new Error(`The target URL is not allowed. Requested: 
${targetUrl}`);
+    }
+
     const proxyUrl = new URL(`protocol://${targetUrl.substring(1)}`);
     const protocol = this.args.hostsToUseHttp.includes(proxyUrl.host) ? "http" 
: "https";
     const proxyUrlString = targetUrl.startsWith("/") ? 
`${protocol}:/${targetUrl}` : undefined;
diff --git a/packages/cors-proxy/src/proxy/server.ts 
b/packages/cors-proxy/src/proxy/server.ts
index cb71c6e9cdb..66c79397ade 100644
--- a/packages/cors-proxy/src/proxy/server.ts
+++ b/packages/cors-proxy/src/proxy/server.ts
@@ -27,6 +27,7 @@ export type ServerArgs = {
   port: number;
   verbose: boolean;
   hostsToUseHttp: string[];
+  allowedHosts: string[];
 };
 
 export const startServer = (args: ServerArgs): void => {
@@ -36,6 +37,7 @@ export const startServer = (args: ServerArgs): void => {
   console.log(`Port:                       ${args.port}`);
   console.log(`Verbose:                    ${args.verbose}`);
   console.log(`Hosts to proxy with HTTP:   ${args.hostsToUseHttp}`);
+  console.log(`Allow hosts:                ${args.allowedHosts}`);
   console.log("====================================================");
 
   const app: express.Express = express();
diff --git a/packages/cors-proxy/tests/ExpressCorsProxy.test.ts 
b/packages/cors-proxy/tests/ExpressCorsProxy.test.ts
new file mode 100644
index 00000000000..73352f7504e
--- /dev/null
+++ b/packages/cors-proxy/tests/ExpressCorsProxy.test.ts
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+const mockFetch = jest.fn();
+jest.mock("node-fetch", () => ({
+  __esModule: true,
+  default: mockFetch,
+}));
+
+import { ExpressCorsProxy } from "../src/proxy/ExpressCorsProxy";
+import { Request, Response } from "express";
+
+const getProxy = (allowedHosts: string[]) =>
+  new ExpressCorsProxy({
+    allowedOrigins: ["http://example.com";],
+    verbose: false,
+    hostsToUseHttp: [],
+    allowedHosts,
+  });
+
+const getMockFetchResponse = () =>
+  Promise.resolve({
+    status: 200,
+    headers: new Map([["content-type", "application/json"]]),
+  });
+
+const getMockResponse = (): Response =>
+  ({
+    header: () => {},
+    setHeader: () => {},
+    getHeaders: () => {},
+    status: () => {},
+    end: () => {},
+    write: () => {},
+    on: () => {},
+    once: () => {},
+    emit: () => {},
+  }) as any as Response;
+
+const getMockGetRequest = (url: string) =>
+  ({
+    header: (header: string) => {
+      if (header === "origin") {
+        return "http://example.com";;
+      }
+    },
+    headers: {
+      origin: "http://example.com";,
+    },
+    url,
+    method: "GET",
+  }) as any as Request;
+
+const getMockPostRequest = (targetUrl: string) =>
+  ({
+    header: (header: string) => {
+      if (header === "origin") {
+        return "http://example.com";;
+      }
+    },
+    headers: {
+      origin: "http://example.com";,
+      "target-url": targetUrl,
+    },
+    method: "POST",
+  }) as any as Request;
+
+describe("ExpressCorsProxy allowed hosts functionality", () => {
+  const mockWarn = (console.warn = jest.fn());
+  const mockNext = jest.fn();
+  const allowedRequests = [
+    ["http://";, "localhost:8081", "localhost,*.github.com"],
+    ["https://";, "localhost:4000", "localhost,*.github.com"],
+    ["http://";, "gist.github.com", "localhost,*.github.com"],
+    ["http://";, "www.github.com", "localhost,*.github.com"],
+    ["https://";, "www.github.com", "localhost,*.github.com"],
+    ["http://";, "test.target.example.com", 
"*.target.example.com,*.github.com"],
+    ["http://";, "test.target.example.com:9000", 
"*.target.example.com,*.github.com"],
+    [
+      "http://";,
+      "test.target.example.com:9000/path/to/something?search=test&sortBy=name",
+      "*.target.example.com,*.github.com",
+    ],
+    ["https://";, "test.target.example.com", 
"*.target.example.com,*.github.com"],
+    ["https://";, "test.target.example.com/graphql", 
"*.target.example.com,*.github.com"],
+    ["https://";, "test.target.example.com/openapi", 
"*.target.example.com,*.github.com"],
+    ["http://";, "gist.github.com", "*.target.example.com,*.github.com"],
+    ["http://";, "www.github.com", "*.target.example.com,*.github.com"],
+    ["https://";, "www.github.com", "*.target.example.com,*.github.com"],
+    [
+      "https://";,
+      "api.aaa.bbb.p1.openshiftapps.com:6443/version",
+      "*.target.example.com,*.github.com,*.openshiftapps.com",
+    ],
+  ];
+  const deniedRequests = [
+    ["http://";, "www.example.com"],
+    ["http://";, "www.example.com/graphql"],
+    ["http://";, "api.notvalid.com"],
+    ["http://";, "api.notvalid.com/openapi.json"],
+    ["http://";, "notvalid.com"],
+    ["http://";, "api.notvalid.com/www.github.com"],
+  ];
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+    mockFetch.mockImplementation(getMockFetchResponse);
+  });
+
+  describe("Test GET requests", () => {
+    it.each(allowedRequests)(
+      `should allow GET requests to %s%s with allowed hosts: %s`,
+      async (protocol, targetUrl, allowedHosts) => {
+        const proxy = getProxy(allowedHosts.split(","));
+
+        await proxy.handle(getMockGetRequest(`/${targetUrl}`), 
getMockResponse(), mockNext);
+
+        expect(mockWarn).not.toHaveBeenCalled();
+        expect(mockFetch).toHaveBeenCalledWith(
+          new URL(protocol + targetUrl),
+          expect.objectContaining({ method: "GET" })
+        );
+        expect(mockNext).not.toHaveBeenCalled();
+      }
+    );
+
+    it.each(deniedRequests)(
+      "should not allow requests to %s%s with allowed hosts: 
*.target.example.com,*.github.com",
+      async (protocol, targetUrl) => {
+        const proxy = getProxy(["*.target.example.com", "*.github.com"]);
+
+        await proxy.handle(getMockGetRequest(`/${targetUrl}`), 
getMockResponse(), mockNext);
+
+        expect(mockWarn).toHaveBeenCalledWith(expect.any(String), 
expect.stringContaining("not allowed"));
+        expect(mockFetch).not.toHaveBeenCalled();
+        expect(mockNext).toHaveBeenCalled();
+      }
+    );
+  });
+
+  describe("Test POST requests", () => {
+    it.each(allowedRequests)(
+      `should allow POST requests to %s%s with allowed hosts: %s`,
+      async (protocol, targetUrl, allowedHosts) => {
+        const proxy = getProxy(allowedHosts.split(","));
+
+        await proxy.handle(getMockPostRequest(protocol + targetUrl), 
getMockResponse(), mockNext);
+
+        expect(mockWarn).not.toHaveBeenCalled();
+        expect(mockFetch).toHaveBeenCalledWith(
+          new URL(protocol + targetUrl),
+          expect.objectContaining({ method: "POST" })
+        );
+        expect(mockNext).not.toHaveBeenCalled();
+      }
+    );
+
+    it.each(deniedRequests)(
+      "should not allow requests to %s%s with allowed hosts: 
*.target.example.com,*.github.com",
+      async (protocol, targetUrl) => {
+        const proxy = getProxy(["*.target.example.com", "*.github.com"]);
+
+        await proxy.handle(getMockPostRequest(protocol + targetUrl), 
getMockResponse(), mockNext);
+
+        expect(mockWarn).toHaveBeenCalledWith(expect.any(String), 
expect.stringContaining("not allowed"));
+        expect(mockFetch).not.toHaveBeenCalled();
+        expect(mockNext).toHaveBeenCalled();
+      }
+    );
+  });
+});
diff --git a/packages/cors-proxy/tests/index.test.ts 
b/packages/cors-proxy/tests/index.test.ts
index 393a5601236..aa20bf3f0cb 100644
--- a/packages/cors-proxy/tests/index.test.ts
+++ b/packages/cors-proxy/tests/index.test.ts
@@ -41,6 +41,20 @@ describe("index.ts test", () => {
     jest.resetAllMocks();
   });
 
+  it("Default values", () => {
+    setEnv({});
+
+    run();
+    expect(startServer).toHaveBeenCalledWith(
+      expect.objectContaining({
+        port: 8080,
+        verbose: false,
+        allowedHosts: ["localhost", "*.github.com"],
+        allowedOrigins: ["http://localhost:9001";],
+      })
+    );
+  });
+
   it("Custom port", () => {
     setEnv({
       CORS_PROXY_HTTP_PORT: "90",
@@ -53,6 +67,7 @@ describe("index.ts test", () => {
         port: 90,
         allowedOrigins: ["http://example.com";],
         verbose: false,
+        allowedHosts: ["localhost", "*.github.com"],
       })
     );
   });
@@ -68,10 +83,29 @@ describe("index.ts test", () => {
         port: 8080,
         allowedOrigins: ["http://example.com";],
         verbose: true,
+        allowedHosts: ["localhost", "*.github.com"],
       })
     );
   });
 
+  describe("Allowed hosts configuration", () => {
+    it.each(["*.target.example.com,*.github.com", "*"])("Custom allow hosts 
with: %s", (allowedHosts) => {
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: "http://example.com";,
+        CORS_PROXY_ALLOWED_HOSTS: allowedHosts,
+      });
+      run();
+      expect(startServer).toHaveBeenCalledWith(
+        expect.objectContaining({
+          port: 8080,
+          verbose: false,
+          allowedHosts: allowedHosts.split(","),
+          allowedOrigins: ["http://example.com";],
+        })
+      );
+    });
+  });
+
   describe("Allowed origins configuration", () => {
     it("Single allowed origin", () => {
       setEnv({
@@ -84,6 +118,7 @@ describe("index.ts test", () => {
           port: 8080,
           allowedOrigins: ["http://example.com";],
           verbose: false,
+          allowedHosts: ["localhost", "*.github.com"],
         })
       );
     });
@@ -99,6 +134,7 @@ describe("index.ts test", () => {
           port: 8080,
           allowedOrigins: ["http://example.com";, "https://other.example.com";, 
"http://localhost:9001";],
           verbose: false,
+          allowedHosts: ["localhost", "*.github.com"],
         })
       );
     });
@@ -121,15 +157,18 @@ describe("index.ts test", () => {
       }).toThrow(new Error("Invalid origin: empty origins are not allowed in 
CORS_PROXY_ALLOWED_ORIGINS."));
     });
 
-    it("Should throw an error when wildcard '*' is in the list", () => {
-      setEnv({
-        CORS_PROXY_ALLOWED_ORIGINS: "http://example.com,*";,
-      });
-
-      expect(() => {
-        run();
-      }).toThrow(new Error('Invalid origin: wildcard "*" is not allowed in 
CORS_PROXY_ALLOWED_ORIGINS.'));
-    });
+    it.each(["*,http://example.com";, "http://example.com,*";, "*"])(
+      "Should throw an error when wildcard '*' is in the list with 
CORS_PROXY_ALLOWED_ORIGINS: %s",
+      (allowedOrigins) => {
+        setEnv({
+          CORS_PROXY_ALLOWED_ORIGINS: allowedOrigins,
+        });
+
+        expect(() => {
+          run();
+        }).toThrow(new Error('Invalid origin: wildcard "*" is not allowed in 
CORS_PROXY_ALLOWED_ORIGINS.'));
+      }
+    );
 
     it("Should throw an error when there are empty origins in the list", () => 
{
       setEnv({
diff --git a/packages/cors-proxy/tests/server.test.ts 
b/packages/cors-proxy/tests/server.test.ts
index 77b35c3cd9c..5678134ede1 100644
--- a/packages/cors-proxy/tests/server.test.ts
+++ b/packages/cors-proxy/tests/server.test.ts
@@ -45,6 +45,7 @@ describe("CORS handler logic test", () => {
         port: 8080,
         verbose: false,
         hostsToUseHttp: [],
+        allowedHosts: ["localhost"],
       };
 
       startServer(args);
@@ -77,6 +78,7 @@ describe("CORS handler logic test", () => {
         port: 8080,
         verbose: false,
         hostsToUseHttp: [],
+        allowedHosts: ["localhost"],
       };
 
       startServer(args);
@@ -113,6 +115,7 @@ describe("CORS handler logic test", () => {
           port: 8080,
           verbose: false,
           hostsToUseHttp: [],
+          allowedHosts: ["localhost"],
         };
 
         startServer(args);
@@ -146,6 +149,40 @@ describe("CORS handler logic test", () => {
         port: 8080,
         verbose: false,
         hostsToUseHttp: [],
+        allowedHosts: ["localhost"],
+      };
+
+      startServer(args);
+
+      const req: any = {
+        headers: {
+          origin: "http://example.com";,
+        },
+        method: "GET",
+      };
+
+      const res: any = {
+        statusCode: 200,
+        setHeader: jest.fn(),
+        getHeader: jest.fn(),
+      };
+
+      const next = function () {
+        
expect(res.setHeader).toHaveBeenCalledWith("Access-Control-Allow-Origin", 
"http://example.com";);
+        done();
+      };
+
+      const corsMiddleware = corsMock.mock.results[0].value;
+      corsMiddleware(req, res, next);
+    });
+
+    it("should not allow requests with origin http://notvalid:9000";, (done) => 
{
+      const args: ServerArgs = {
+        allowedOrigins: ["http://localhost:9000";],
+        port: 8080,
+        verbose: false,
+        hostsToUseHttp: [],
+        allowedHosts: ["localhost"],
       };
 
       startServer(args);
diff --git a/packages/online-editor/package.json 
b/packages/online-editor/package.json
index 7bdc0d5a7ec..2443c665040 100644
--- a/packages/online-editor/package.json
+++ b/packages/online-editor/package.json
@@ -18,8 +18,8 @@
     "build:dev": "rimraf dist && webpack --config webpack.config.ts --env dev",
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack && pnpm 
test-e2e",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
-    "start": "concurrently 'pnpm start:cors-proxy' 'pnpm 
start:extended-services' 'pnpm start:kie-sandbox' 'pnpm 
start:kie-sandbox-accelerator-quarkus'",
-    "start:cors-proxy": "cross-env 
CORS_PROXY__origin=https://localhost:$(build-env onlineEditor.dev.port) 
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env 
kieSandboxAcceleratorQuarkus.dev.port)\" npm --prefix 
./node_modules/@kie-tools/cors-proxy run start",
+    "start": "concurrently --no-colors 'pnpm start:cors-proxy' 'pnpm 
start:extended-services' 'pnpm start:kie-sandbox' 'pnpm 
start:kie-sandbox-accelerator-quarkus'",
+    "start:cors-proxy": "cross-env 
CORS_PROXY__allowedOrigins=http://localhost:$(build-env onlineEditor.dev.port) 
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env 
kieSandboxAcceleratorQuarkus.dev.port) CORS_PROXY__allowedHosts=*\" npm 
--prefix ./node_modules/@kie-tools/cors-proxy run start",
     "start:extended-services": "cross-env 
EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\" npm --prefix 
./node_modules/@kie-tools/extended-services-java run start",
     "start:kie-sandbox": "cross-env EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\" 
webpack serve --host 0.0.0.0 --env dev",
     "start:kie-sandbox-accelerator-quarkus": "npm --prefix 
./node_modules/@kie-tools/kie-sandbox-accelerator-quarkus run start",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 77004101ddb..2d13f2056bd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1898,6 +1898,9 @@ importers:
       https-proxy-agent:
         specifier: ^7.0.6
         version: 7.0.6
+      minimatch:
+        specifier: ^3.0.5
+        version: 3.1.2
       node-fetch:
         specifier: ^3.3.2
         version: 3.3.2
@@ -1935,6 +1938,9 @@ importers:
       '@types/jest':
         specifier: ^29.5.12
         version: 29.5.12
+      '@types/minimatch':
+        specifier: ^3.0.5
+        version: 3.0.5
       '@types/node':
         specifier: ^22.14.1
         version: 22.18.8
@@ -60236,7 +60242,7 @@ snapshots:
       watchpack: 2.4.2
       webpack-sources: 3.2.3
     optionalDependencies:
-      webpack-cli: 4.10.0([email protected])([email protected])
+      webpack-cli: 4.10.0([email protected])
     transitivePeerDependencies:
       - '@swc/core'
       - esbuild


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to