From 9ce70478b341c1539d4825b198344ff92004d985 Mon Sep 17 00:00:00 2001 From: 5rk7n <7523150+5rk7n@users.noreply.github.com> Date: Fri, 29 May 2026 14:54:39 +0000 Subject: [PATCH 1/5] test: add unit tests for getCallbackUrl Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- apps/api/src/services/oauth/provider.test.ts | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 apps/api/src/services/oauth/provider.test.ts diff --git a/apps/api/src/services/oauth/provider.test.ts b/apps/api/src/services/oauth/provider.test.ts new file mode 100644 index 00000000..be25bf37 --- /dev/null +++ b/apps/api/src/services/oauth/provider.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { getCallbackUrl } from "./provider.js"; + +describe("getCallbackUrl", () => { + const originalEnv = { ...process.env }; + + beforeEach(() => { + // Clear relevant environment variables before each test + delete process.env.PUBLIC_URL; + delete process.env.API_PORT; + }); + + afterEach(() => { + // Restore original environment + process.env = { ...originalEnv }; + }); + + it("uses PUBLIC_URL when it is set", () => { + process.env.PUBLIC_URL = "https://optio.example.com"; + + const url = getCallbackUrl("github"); + + expect(url).toBe("https://optio.example.com/api/auth/github/callback"); + }); + + it("falls back to localhost with API_PORT when PUBLIC_URL is not set", () => { + process.env.API_PORT = "8080"; + + const url = getCallbackUrl("google"); + + expect(url).toBe("http://localhost:8080/api/auth/google/callback"); + }); + + it("falls back to localhost:4000 when neither PUBLIC_URL nor API_PORT are set", () => { + const url = getCallbackUrl("oidc"); + + expect(url).toBe("http://localhost:4000/api/auth/oidc/callback"); + }); +}); From f782020567487dfb84331304afb4bfa91a987167 Mon Sep 17 00:00:00 2001 From: Sira Kantana Date: Sat, 30 May 2026 13:45:18 +0200 Subject: [PATCH 2/5] fix: publicApiUrl deployment variable --- helm/optio/templates/web-deployment.yaml | 3 +++ helm/optio/values.yaml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/helm/optio/templates/web-deployment.yaml b/helm/optio/templates/web-deployment.yaml index ace5927e..e153b8d1 100644 --- a/helm/optio/templates/web-deployment.yaml +++ b/helm/optio/templates/web-deployment.yaml @@ -79,6 +79,9 @@ spec: {{- if .Values.web.publicApiUrl }} - name: PUBLIC_API_URL value: {{ .Values.web.publicApiUrl | quote }} + {{- else if .Values.publicUrl }} + - name: PUBLIC_API_URL + value: "{{ trimSuffix "/" .Values.publicUrl }}/api" {{- else if and (eq .Values.api.service.type "NodePort") .Values.api.service.nodePort }} - name: PUBLIC_API_URL value: "http://localhost:{{ .Values.api.service.nodePort }}" diff --git a/helm/optio/values.yaml b/helm/optio/values.yaml index 5b4cacd2..b9bd91d4 100644 --- a/helm/optio/values.yaml +++ b/helm/optio/values.yaml @@ -96,6 +96,8 @@ web: maxReplicas: 4 targetCPUUtilizationPercentage: 70 targetMemoryUtilizationPercentage: "" + # Optional override for the public API URL (defaults to PUBLIC_URL with /api path) + publicApiUrl: "" # ────────────────────────────────────────────────────────────────────────────── # Optio Operations Assistant Pod From ed32568654a1734aab6172914c71388152c82982 Mon Sep 17 00:00:00 2001 From: Sira Kantana Date: Sat, 30 May 2026 14:04:25 +0200 Subject: [PATCH 3/5] fix: publicApiUrl variable used in api & test improvement --- apps/api/src/services/oauth/provider.test.ts | 19 ++++++++++++++++++- apps/api/src/services/oauth/provider.ts | 4 ++++ helm/optio/templates/api-deployment.yaml | 10 ++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/apps/api/src/services/oauth/provider.test.ts b/apps/api/src/services/oauth/provider.test.ts index be25bf37..0d74b0ae 100644 --- a/apps/api/src/services/oauth/provider.test.ts +++ b/apps/api/src/services/oauth/provider.test.ts @@ -7,6 +7,7 @@ describe("getCallbackUrl", () => { beforeEach(() => { // Clear relevant environment variables before each test delete process.env.PUBLIC_URL; + delete process.env.PUBLIC_API_URL; delete process.env.API_PORT; }); @@ -15,7 +16,23 @@ describe("getCallbackUrl", () => { process.env = { ...originalEnv }; }); - it("uses PUBLIC_URL when it is set", () => { + it("uses PUBLIC_API_URL when it is set", () => { + process.env.PUBLIC_API_URL = "https://api.example.com/api"; + + const url = getCallbackUrl("github"); + + expect(url).toBe("https://api.example.com/api/auth/github/callback"); + }); + + it("uses PUBLIC_API_URL and trims trailing slash", () => { + process.env.PUBLIC_API_URL = "https://api.example.com/api/"; + + const url = getCallbackUrl("github"); + + expect(url).toBe("https://api.example.com/api/auth/github/callback"); + }); + + it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { process.env.PUBLIC_URL = "https://optio.example.com"; const url = getCallbackUrl("github"); diff --git a/apps/api/src/services/oauth/provider.ts b/apps/api/src/services/oauth/provider.ts index b950e2ba..d3871097 100644 --- a/apps/api/src/services/oauth/provider.ts +++ b/apps/api/src/services/oauth/provider.ts @@ -21,6 +21,10 @@ export interface OAuthProvider { } export function getCallbackUrl(provider: string): string { + if (process.env.PUBLIC_API_URL) { + const base = process.env.PUBLIC_API_URL.replace(/\/$/, ""); + return `${base}/auth/${provider}/callback`; + } const base = process.env.PUBLIC_URL ?? `http://localhost:${process.env.API_PORT ?? 4000}`; return `${base}/api/auth/${provider}/callback`; } diff --git a/helm/optio/templates/api-deployment.yaml b/helm/optio/templates/api-deployment.yaml index b85ab7d6..c535ec80 100644 --- a/helm/optio/templates/api-deployment.yaml +++ b/helm/optio/templates/api-deployment.yaml @@ -92,6 +92,16 @@ spec: value: "0.0.0.0" - name: OPTIO_API_INTERNAL_URL value: "http://{{ .Release.Name }}-api:{{ .Values.api.port }}" + {{- if .Values.web.publicApiUrl }} + - name: PUBLIC_API_URL + value: {{ .Values.web.publicApiUrl | quote }} + {{- else if .Values.publicUrl }} + - name: PUBLIC_API_URL + value: "{{ trimSuffix "/" .Values.publicUrl }}/api" + {{- else if and (eq .Values.api.service.type "NodePort") .Values.api.service.nodePort }} + - name: PUBLIC_API_URL + value: "http://localhost:{{ .Values.api.service.nodePort }}" + {{- end }} - name: NODE_ENV value: "production" - name: LOG_LEVEL From 699a8c72761afc2e7e26e4d0e83b2f388ec471ef Mon Sep 17 00:00:00 2001 From: Sira Kantana Date: Sat, 30 May 2026 14:25:36 +0200 Subject: [PATCH 4/5] test: add oidc test case to getCallbackUrl --- apps/api/src/services/oauth/provider.test.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/api/src/services/oauth/provider.test.ts b/apps/api/src/services/oauth/provider.test.ts index 0d74b0ae..4c51d5dd 100644 --- a/apps/api/src/services/oauth/provider.test.ts +++ b/apps/api/src/services/oauth/provider.test.ts @@ -16,6 +16,16 @@ describe("getCallbackUrl", () => { process.env = { ...originalEnv }; }); + it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { + process.env.PUBLIC_URL = "https://optio.example.com"; + + const githubUrl = getCallbackUrl("github"); + const oidcUrl = getCallbackUrl("oidc"); + + expect(githubUrl).toBe("https://optio.example.com/api/auth/github/callback"); + expect(oidcUrl).toBe("https://optio.example.com/api/auth/oidc/callback"); + }); + it("uses PUBLIC_API_URL when it is set", () => { process.env.PUBLIC_API_URL = "https://api.example.com/api"; @@ -32,14 +42,6 @@ describe("getCallbackUrl", () => { expect(url).toBe("https://api.example.com/api/auth/github/callback"); }); - it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { - process.env.PUBLIC_URL = "https://optio.example.com"; - - const url = getCallbackUrl("github"); - - expect(url).toBe("https://optio.example.com/api/auth/github/callback"); - }); - it("falls back to localhost with API_PORT when PUBLIC_URL is not set", () => { process.env.API_PORT = "8080"; From 3f977ec906153cfebd239cb3df6b8aff1fcf70c1 Mon Sep 17 00:00:00 2001 From: Sira Kantana Date: Sat, 30 May 2026 14:33:00 +0200 Subject: [PATCH 5/5] test: optimize provider tests using describe.each --- apps/api/src/services/oauth/provider.test.ts | 68 +++++++++----------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/apps/api/src/services/oauth/provider.test.ts b/apps/api/src/services/oauth/provider.test.ts index 4c51d5dd..907e08c4 100644 --- a/apps/api/src/services/oauth/provider.test.ts +++ b/apps/api/src/services/oauth/provider.test.ts @@ -16,43 +16,35 @@ describe("getCallbackUrl", () => { process.env = { ...originalEnv }; }); - it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { - process.env.PUBLIC_URL = "https://optio.example.com"; - - const githubUrl = getCallbackUrl("github"); - const oidcUrl = getCallbackUrl("oidc"); - - expect(githubUrl).toBe("https://optio.example.com/api/auth/github/callback"); - expect(oidcUrl).toBe("https://optio.example.com/api/auth/oidc/callback"); - }); - - it("uses PUBLIC_API_URL when it is set", () => { - process.env.PUBLIC_API_URL = "https://api.example.com/api"; - - const url = getCallbackUrl("github"); - - expect(url).toBe("https://api.example.com/api/auth/github/callback"); - }); - - it("uses PUBLIC_API_URL and trims trailing slash", () => { - process.env.PUBLIC_API_URL = "https://api.example.com/api/"; - - const url = getCallbackUrl("github"); - - expect(url).toBe("https://api.example.com/api/auth/github/callback"); - }); - - it("falls back to localhost with API_PORT when PUBLIC_URL is not set", () => { - process.env.API_PORT = "8080"; - - const url = getCallbackUrl("google"); - - expect(url).toBe("http://localhost:8080/api/auth/google/callback"); - }); - - it("falls back to localhost:4000 when neither PUBLIC_URL nor API_PORT are set", () => { - const url = getCallbackUrl("oidc"); - - expect(url).toBe("http://localhost:4000/api/auth/oidc/callback"); + describe.each(["github", "google", "oidc"])("with provider %s", (provider) => { + it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { + process.env.PUBLIC_URL = "https://optio.example.com"; + expect(getCallbackUrl(provider)).toBe( + `https://optio.example.com/api/auth/${provider}/callback`, + ); + }); + + it("uses PUBLIC_API_URL when it is set", () => { + process.env.PUBLIC_API_URL = "https://optio-api.example.com/api"; + expect(getCallbackUrl(provider)).toBe( + `https://optio-api.example.com/api/auth/${provider}/callback`, + ); + }); + + it("uses PUBLIC_API_URL and trims trailing slash", () => { + process.env.PUBLIC_API_URL = "https://optio-api.example.com/api/"; + expect(getCallbackUrl(provider)).toBe( + `https://optio-api.example.com/api/auth/${provider}/callback`, + ); + }); + + it("falls back to localhost with API_PORT when PUBLIC_URL is not set", () => { + process.env.API_PORT = "8080"; + expect(getCallbackUrl(provider)).toBe(`http://localhost:8080/api/auth/${provider}/callback`); + }); + + it("falls back to localhost:4000 when neither PUBLIC_URL nor API_PORT are set", () => { + expect(getCallbackUrl(provider)).toBe(`http://localhost:4000/api/auth/${provider}/callback`); + }); }); });