diff --git a/tradein-mvp/frontend/src/app/mera-public/__tests__/public-perimeter.test.ts b/tradein-mvp/frontend/src/app/mera-public/__tests__/public-perimeter.test.ts index a570b49b..202df462 100644 --- a/tradein-mvp/frontend/src/app/mera-public/__tests__/public-perimeter.test.ts +++ b/tradein-mvp/frontend/src/app/mera-public/__tests__/public-perimeter.test.ts @@ -55,6 +55,26 @@ describe("палитра v3 доезжает до CSS", () => { }); }); +/** + * Эффективный конфиг Caddy = корневой Caddyfile + всё, что он импортирует из + * caddy/sites/*.caddy. С #3059 site-блоки живут в отдельных файлах (переезд на + * Selectel: на новом хосте поднимаются только apps, на Beget остаются infra), + * а корневой файл держит глобальные опции и два import'а. Читать один + * Caddyfile здесь больше нельзя — проверка стала бы пустой и молча зелёной. + * + * Берём ВСЕ файлы из caddy/sites/ намеренно: `import caddy/sites/{$CADDY_SITES:*}` + * без переменной раскрывается в звёздочку, то есть это и есть конфиг по умолчанию. + */ +function readEffectiveCaddyConfig(repoRoot: string): string { + const sitesDir = path.join(repoRoot, "caddy", "sites"); + const siteFiles = readdirSync(sitesDir) + .filter((f) => f.endsWith(".caddy")) + .sort() + .map((f) => readFileSync(path.join(sitesDir, f), "utf8")); + return [readFileSync(path.join(repoRoot, "Caddyfile"), "utf8"), ...siteFiles].join(" +"); +} + describe("короткие адреса публичного домена", () => { /** * Дефект 15.08.2026: подвал v3 вёл «Главную» на `/mera-public`, а Caddy на @@ -62,7 +82,7 @@ describe("короткие адреса публичного домена", () = * голый путь падал в catch-all 404. Страница, которой нет в allowlist * Caddyfile, недоступна независимо от того, что она собралась. */ - const caddyfile = readFileSync(path.join(REPO_ROOT, "Caddyfile"), "utf8"); + const caddyfile = readEffectiveCaddyConfig(REPO_ROOT); const meraBlock = caddyfile.slice( caddyfile.indexOf("meraocenka.ru {"), caddyfile.indexOf("merahome.ru {"), diff --git a/tradein-mvp/frontend/src/components/auth/__tests__/RouteGuard.publicPaths.test.ts b/tradein-mvp/frontend/src/components/auth/__tests__/RouteGuard.publicPaths.test.ts index 21eedf8c..4dc18692 100644 --- a/tradein-mvp/frontend/src/components/auth/__tests__/RouteGuard.publicPaths.test.ts +++ b/tradein-mvp/frontend/src/components/auth/__tests__/RouteGuard.publicPaths.test.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { readFileSync, readdirSync } from "node:fs"; import path from "node:path"; import { describe, expect, it } from "vitest"; @@ -19,6 +19,26 @@ import { isPublicPath } from "../RouteGuard"; * ТОЧНЫМ совпадением. Наивное добавление его в префиксный список сделало бы * публичным всё приложение — `"/v2/admin".startsWith("/")` истинно. */ +/** + * Эффективный конфиг Caddy = корневой Caddyfile + всё, что он импортирует из + * caddy/sites/*.caddy. С #3059 site-блоки живут в отдельных файлах (переезд на + * Selectel: на новом хосте поднимаются только apps, на Beget остаются infra), + * а корневой файл держит глобальные опции и два import'а. Читать один + * Caddyfile здесь больше нельзя — проверка стала бы пустой и молча зелёной. + * + * Берём ВСЕ файлы из caddy/sites/ намеренно: `import caddy/sites/{$CADDY_SITES:*}` + * без переменной раскрывается в звёздочку, то есть это и есть конфиг по умолчанию. + */ +function readEffectiveCaddyConfig(repoRoot: string): string { + const sitesDir = path.join(repoRoot, "caddy", "sites"); + const siteFiles = readdirSync(sitesDir) + .filter((f) => f.endsWith(".caddy")) + .sort() + .map((f) => readFileSync(path.join(sitesDir, f), "utf8")); + return [readFileSync(path.join(repoRoot, "Caddyfile"), "utf8"), ...siteFiles].join(" +"); +} + describe("isPublicPath", () => { it("пропускает поддерево лэндинга (путь без basePath)", () => { expect(isPublicPath("/mera-public")).toBe(true); @@ -50,7 +70,7 @@ describe("isPublicPath", () => { it("совпадает с тем, что публичный домен реально раздаёт (Caddyfile)", () => { // __tests__ → auth → components → src → frontend → tradein-mvp → корень. const repoRoot = path.resolve(__dirname, "../../../../../.."); - const caddyfile = readFileSync(path.join(repoRoot, "Caddyfile"), "utf8"); + const caddyfile = readEffectiveCaddyConfig(repoRoot); const served = caddyfile .match(/@meraPages path ([^\n]+)/)?.[1] .split(/\s+/)