|
- import { request as playwrightRequest } from '@playwright/test'
- import type { APIRequestContext } from '@playwright/test'
-
- const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '[::1]'])
-
- const parseHttpUrl = (raw: string, label: string): URL => {
- let url: URL
- try {
- url = new URL(raw)
- } catch {
- throw new Error(`${label} must be an absolute HTTP(S) URL`)
- }
- if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) {
- throw new Error(`${label} must be an HTTP(S) URL without embedded credentials`)
- }
- return url
- }
-
- const isLoopback = (url: URL): boolean => LOOPBACK_HOSTS.has(url.hostname.toLowerCase())
-
- export const resolveContentControlPlaneBaseUrl = (
- environment: NodeJS.ProcessEnv = process.env,
- ): string => {
- const applicationUrl = parseHttpUrl(
- environment.BASE_URL?.trim() || 'http://127.0.0.1:6180',
- 'BASE_URL',
- )
- const controlPlaneUrl = parseHttpUrl(
- environment.E2E_API_BASE_URL?.trim() || 'http://127.0.0.1:6100',
- 'E2E_API_BASE_URL',
- )
-
- if (
- !isLoopback(applicationUrl)
- && applicationUrl.protocol !== 'https:'
- && environment.E2E_ALLOW_INSECURE_REMOTE !== '1'
- ) {
- throw new Error('Remote BASE_URL must use HTTPS unless E2E_ALLOW_INSECURE_REMOTE=1 explicitly accepts the risk')
- }
- if (!isLoopback(controlPlaneUrl) && controlPlaneUrl.protocol !== 'https:') {
- throw new Error('E2E_API_BASE_URL must use HTTPS unless it targets a loopback host')
- }
- if (
- isLoopback(applicationUrl) !== isLoopback(controlPlaneUrl)
- && environment.E2E_ALLOW_CROSS_ENV_CONTROL_PLANE !== '1'
- ) {
- throw new Error(
- 'BASE_URL and E2E_API_BASE_URL cross the local/remote boundary; '
- + 'set E2E_ALLOW_CROSS_ENV_CONTROL_PLANE=1 only for an intentional protected tunnel',
- )
- }
-
- return controlPlaneUrl.toString().replace(/\/$/, '')
- }
-
- export const openContentControlPlane = async (
- baseURL = resolveContentControlPlaneBaseUrl(),
- ): Promise<APIRequestContext> => playwrightRequest.newContext({
- baseURL,
- timeout: 30_000,
- // The gateway control plane is expected to be direct. Following a 307/308
- // could forward a login body or a manually supplied bearer token elsewhere.
- maxRedirects: 0,
- })
|