fix: harden FeedbackRecords Envoy auth routing

This commit is contained in:
Bhagya Amarasinghe
2026-04-24 13:51:54 +05:30
parent 1cfadd968a
commit 6036a8c767
6 changed files with 25 additions and 12 deletions
@@ -213,14 +213,17 @@ describe("FeedbackRecords envoy auth route", () => {
});
const response = await GET(
createRequest("http://localhost/api/envoy-auth/feedback-records/v1/feedback-records", {
createRequest(
`http://localhost/api/envoy-auth/feedback-records/v1/feedback-records?tenant_id=${feedbackRecordDirectoryId}`,
{
headers: {
method: "GET",
path: `/v1/feedback-records?tenant_id=${feedbackRecordDirectoryId}`,
authorization: "Bearer header.payload.signature",
cookie: "next-auth.session-token=still-present",
},
})
}
)
);
expect(response.status).toBe(401);
@@ -237,13 +240,16 @@ describe("FeedbackRecords envoy auth route", () => {
});
const response = await GET(
createRequest("http://localhost/api/envoy-auth/feedback-records/v1/feedback-records", {
createRequest(
`http://localhost/api/envoy-auth/feedback-records/v1/feedback-records?tenant_id=${feedbackRecordDirectoryId}`,
{
headers: {
method: "GET",
path: `/v1/feedback-records?tenant_id=${feedbackRecordDirectoryId}`,
authorization: "Bearer header.payload.signature",
},
})
}
)
);
expect(response.status).toBe(403);
@@ -20,6 +20,7 @@ import { getFeedbackRecordTenant } from "@/modules/hub/service";
const FEEDBACK_RECORDS_V3_PREFIX = "/api/v3/feedbackRecords";
const FEEDBACK_RECORDS_SDK_PREFIX = "/v1/feedback-records";
const FEEDBACK_RECORDS_AUTH_PREFIX = "/api/envoy-auth/feedback-records";
const ZFeedbackRecordId = z.string().uuid();
const HEADERS_TO_REMOVE_ON_ALLOW = "x-api-key,cookie";
@@ -88,15 +89,23 @@ const parseOriginalRequestMetadata = (
request: NextRequest
): { method: string; url: URL } | { errorResponse: Response } => {
const originalMethod = request.headers.get("method")?.toUpperCase();
const originalPath = request.headers.get("path");
if (!originalMethod || !originalPath) {
if (!originalMethod) {
return {
errorResponse: buildStatusResponse(400, "Missing original request metadata"),
};
}
if (!request.nextUrl.pathname.startsWith(FEEDBACK_RECORDS_AUTH_PREFIX)) {
return {
errorResponse: buildStatusResponse(400, "Invalid FeedbackRecords auth request path"),
};
}
try {
const originalPathname = request.nextUrl.pathname.slice(FEEDBACK_RECORDS_AUTH_PREFIX.length) || "/";
const originalPath = `${originalPathname}${request.nextUrl.search}`;
return {
method: originalMethod,
url: new URL(originalPath, "http://feedback-records-gateway.local"),
+1 -1
View File
@@ -157,7 +157,7 @@ If `namespaceOverride` is provided, it will be used; otherwise, it defaults to `
{{- end }}
{{- define "formbricks.hubApiKey" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "formbricks.appSecretName" .)) }}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "formbricks.hubSecretName" .)) }}
{{- if and $secret (index $secret.data "HUB_API_KEY") }}
{{- index $secret.data "HUB_API_KEY" | b64dec -}}
{{- else }}
@@ -7,9 +7,9 @@
{{- $gatewayClassName := include "formbricks.envoy.gatewayClassName" . -}}
{{- $proxyName := include "formbricks.envoy.proxyName" . -}}
{{- $proxyServiceName := include "formbricks.envoy.proxyServiceName" . -}}
{{- $appSecretName := include "formbricks.appSecretName" . -}}
{{- $appServiceName := include "formbricks.name" . -}}
{{- $hubServiceName := include "formbricks.hubname" . -}}
{{- $hubSecretName := include "formbricks.hubSecretName" . -}}
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
@@ -303,7 +303,7 @@ spec:
overwrite: true
credential:
valueRef:
name: {{ $hubSecretName }}
name: {{ $appSecretName }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
-3
View File
@@ -5,7 +5,6 @@
{{- $redisPassword := include "formbricks.redisPassword" . }}
{{- $webappUrl := required "formbricks.webappUrl is required. Set it to your Formbricks instance URL (e.g., https://formbricks.example.com)" .Values.formbricks.webappUrl }}
{{- $hubApiKey := include "formbricks.hubApiKey" . }}
{{- $includeHubApiKeyInAppSecret := or (not .Values.hub.existingSecret) (eq .Values.hub.existingSecret (include "formbricks.appSecretName" .)) }}
---
apiVersion: v1
kind: Secret
@@ -30,10 +29,8 @@ data:
{{- else }}
DATABASE_URL: {{ .Values.postgresql.externalDatabaseUrl | b64enc }}
{{- end }}
{{- if $includeHubApiKeyInAppSecret }}
HUB_API_KEY: {{ $hubApiKey | b64enc }}
credential: {{ printf "Bearer %s" $hubApiKey | b64enc }}
{{- end }}
CRON_SECRET: {{ include "formbricks.cronSecret" . | b64enc }}
ENCRYPTION_KEY: {{ include "formbricks.encryptionKey" . | b64enc }}
NEXTAUTH_SECRET: {{ include "formbricks.nextAuthSecret" . | b64enc }}
+1
View File
@@ -573,6 +573,7 @@ hub:
# Optional override for the secret Hub reads from.
# Defaults to the generated app secret (<release>-app-secrets), which contains DATABASE_URL and HUB_API_KEY.
# If you set this, the custom secret must provide DATABASE_URL and HUB_API_KEY.
# The app secret still needs HUB_API_KEY as well because the web app talks to Hub directly.
existingSecret: ""
# Optional env vars (non-secret). Use existingSecret for secret values such as DATABASE_URL and HUB_API_KEY.