Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

65 rader
2.2 KiB

  1. import { request as playwrightRequest } from '@playwright/test'
  2. import type { APIRequestContext } from '@playwright/test'
  3. const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '[::1]'])
  4. const parseHttpUrl = (raw: string, label: string): URL => {
  5. let url: URL
  6. try {
  7. url = new URL(raw)
  8. } catch {
  9. throw new Error(`${label} must be an absolute HTTP(S) URL`)
  10. }
  11. if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) {
  12. throw new Error(`${label} must be an HTTP(S) URL without embedded credentials`)
  13. }
  14. return url
  15. }
  16. const isLoopback = (url: URL): boolean => LOOPBACK_HOSTS.has(url.hostname.toLowerCase())
  17. export const resolveContentControlPlaneBaseUrl = (
  18. environment: NodeJS.ProcessEnv = process.env,
  19. ): string => {
  20. const applicationUrl = parseHttpUrl(
  21. environment.BASE_URL?.trim() || 'http://127.0.0.1:6180',
  22. 'BASE_URL',
  23. )
  24. const controlPlaneUrl = parseHttpUrl(
  25. environment.E2E_API_BASE_URL?.trim() || 'http://127.0.0.1:6100',
  26. 'E2E_API_BASE_URL',
  27. )
  28. if (
  29. !isLoopback(applicationUrl)
  30. && applicationUrl.protocol !== 'https:'
  31. && environment.E2E_ALLOW_INSECURE_REMOTE !== '1'
  32. ) {
  33. throw new Error('Remote BASE_URL must use HTTPS unless E2E_ALLOW_INSECURE_REMOTE=1 explicitly accepts the risk')
  34. }
  35. if (!isLoopback(controlPlaneUrl) && controlPlaneUrl.protocol !== 'https:') {
  36. throw new Error('E2E_API_BASE_URL must use HTTPS unless it targets a loopback host')
  37. }
  38. if (
  39. isLoopback(applicationUrl) !== isLoopback(controlPlaneUrl)
  40. && environment.E2E_ALLOW_CROSS_ENV_CONTROL_PLANE !== '1'
  41. ) {
  42. throw new Error(
  43. 'BASE_URL and E2E_API_BASE_URL cross the local/remote boundary; '
  44. + 'set E2E_ALLOW_CROSS_ENV_CONTROL_PLANE=1 only for an intentional protected tunnel',
  45. )
  46. }
  47. return controlPlaneUrl.toString().replace(/\/$/, '')
  48. }
  49. export const openContentControlPlane = async (
  50. baseURL = resolveContentControlPlaneBaseUrl(),
  51. ): Promise<APIRequestContext> => playwrightRequest.newContext({
  52. baseURL,
  53. timeout: 30_000,
  54. // The gateway control plane is expected to be direct. Following a 307/308
  55. // could forward a login body or a manually supplied bearer token elsewhere.
  56. maxRedirects: 0,
  57. })