diff --git a/.gitea/workflows/staging_code_pull.yml b/.gitea/workflows/staging_code_pull.yml index bddb527b..4155f37a 100644 --- a/.gitea/workflows/staging_code_pull.yml +++ b/.gitea/workflows/staging_code_pull.yml @@ -181,6 +181,29 @@ jobs: # 배포 후 상태 확인 (실패 시 로그 출력을 위함) sleep 10 + + check_container_http() { + name="$1" + port="$2" + max="${FRONTEND_HEALTH_MAX_ATTEMPTS:-60}" + i=1 + while [ "${i}" -le "${max}" ]; do + if docker exec "${name}" node -e "fetch('http://127.0.0.1:${port}/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" >/dev/null 2>&1; then + echo "Frontend ready: ${name}:${port}" + return 0 + fi + echo "Waiting for frontend: ${name}:${port} (${i}/${max})" + i=$((i + 1)) + sleep 2 + done + echo "ERROR: frontend not ready: ${name}:${port}" >&2 + docker logs "${name}" --tail 200 >&2 || true + return 1 + } + + check_container_http baron_adminfront 5173 + check_container_http baron_devfront 5173 + check_container_http baron_orgfront 5175 echo "===== INIT-RP LOGS =====" docker compose -f staging_pull_compose.yaml logs init-rp || true diff --git a/devfront/vite.config.ts b/devfront/vite.config.ts index 6bbde0af..470594c9 100644 --- a/devfront/vite.config.ts +++ b/devfront/vite.config.ts @@ -1,11 +1,50 @@ import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; +const buildOutDir = + process.env.DEVFRONT_BUILD_OUT_DIR ?? "/tmp/baron-sso-devfront-dist"; + +const defaultAllowedHosts = [ + "sdev.hmac.kr", + "localhost", + "172.16.10.176", + "127.0.0.1", +]; + +function hostFromUrl(value: string | undefined) { + if (!value) return undefined; + try { + return new URL(value).hostname; + } catch { + return value; + } +} + +const allowedHosts = Array.from( + new Set( + [ + ...defaultAllowedHosts, + hostFromUrl(process.env.DEVFRONT_URL), + ...(process.env.DEVFRONT_ALLOWED_HOSTS ?? "") + .split(",") + .map((host) => host.trim()) + .filter(Boolean), + ].filter((host): host is string => Boolean(host)), + ), +); + export default defineConfig({ plugins: [react()], + cacheDir: + process.env.DEVFRONT_VITE_CACHE_DIR ?? + "/tmp/baron-sso-devfront-vite-cache", + build: { + outDir: buildOutDir, + emptyOutDir: true, + }, server: { host: "127.0.0.1", - allowedHosts: ["sdev.hmac.kr", "localhost", "172.16.10.176", "127.0.0.1"], + allowedHosts, proxy: { "/api": { target: process.env.API_PROXY_TARGET || "http://localhost:3000", @@ -16,7 +55,7 @@ export default defineConfig({ preview: { host: "127.0.0.1", port: 5173, - allowedHosts: ["sdev.hmac.kr", "localhost", "172.16.10.176", "127.0.0.1"], + allowedHosts, proxy: { "/api": { target: process.env.API_PROXY_TARGET || "http://localhost:3000", diff --git a/docker/staging_pull_compose.template.yaml b/docker/staging_pull_compose.template.yaml index 2ed6b07c..44335644 100644 --- a/docker/staging_pull_compose.template.yaml +++ b/docker/staging_pull_compose.template.yaml @@ -438,6 +438,12 @@ services: - /app/node_modules networks: - baron_net + healthcheck: + test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:5173/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] + interval: 10s + timeout: 5s + retries: 12 + start_period: 90s devfront: build: @@ -456,6 +462,12 @@ services: - /app/node_modules networks: - baron_net + healthcheck: + test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:5173/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] + interval: 10s + timeout: 5s + retries: 12 + start_period: 90s orgfront: build: @@ -475,6 +487,12 @@ services: - /app/node_modules networks: - baron_net + healthcheck: + test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:5175/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] + interval: 10s + timeout: 5s + retries: 12 + start_period: 90s userfront: build: diff --git a/orgfront/vite.config.ts b/orgfront/vite.config.ts index db34855c..2f6c447a 100644 --- a/orgfront/vite.config.ts +++ b/orgfront/vite.config.ts @@ -1,8 +1,12 @@ import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; +const buildOutDir = + process.env.ORGFRONT_BUILD_OUT_DIR ?? "/tmp/baron-sso-orgfront-dist"; + const defaultAllowedHosts = [ "baron-orgchart.hmac.kr", + "sorg.hmac.kr", "sdev.hmac.kr", "localhost", "172.16.10.176", @@ -33,6 +37,13 @@ const allowedHosts = Array.from( export default defineConfig({ plugins: [react()], + cacheDir: + process.env.ORGFRONT_VITE_CACHE_DIR ?? + "/tmp/baron-sso-orgfront-vite-cache", + build: { + outDir: buildOutDir, + emptyOutDir: true, + }, server: { host: "0.0.0.0", port: 5175, diff --git a/test/staging_frontend_deploy_policy_test.sh b/test/staging_frontend_deploy_policy_test.sh new file mode 100644 index 00000000..31a52caa --- /dev/null +++ b/test/staging_frontend_deploy_policy_test.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env sh +set -eu + +assert_contains() { + file="$1" + pattern="$2" + if ! grep -Fq "$pattern" "$file"; then + echo "missing pattern in $file: $pattern" >&2 + exit 1 + fi +} + +assert_not_contains() { + file="$1" + pattern="$2" + if grep -Fq "$pattern" "$file"; then + echo "forbidden pattern in $file: $pattern" >&2 + exit 1 + fi +} + +staging_pull=".gitea/workflows/staging_code_pull.yml" +pull_compose="docker/staging_pull_compose.template.yaml" +devfront_vite="devfront/vite.config.ts" +orgfront_vite="orgfront/vite.config.ts" + +for file in \ + "$staging_pull" \ + "$pull_compose" \ + "$devfront_vite" \ + "$orgfront_vite" +do + if [ ! -f "$file" ]; then + echo "missing expected file: $file" >&2 + exit 1 + fi +done + +for workflow in "$staging_pull"; do + assert_contains "$workflow" 'ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}' + assert_contains "$workflow" 'DEVFRONT_URL=${{ vars.DEVFRONT_URL }}' + assert_contains "$workflow" 'ORGFRONT_URL=${{ vars.ORGFRONT_URL }}' + assert_contains "$workflow" 'KRATOS_ALLOWED_RETURN_URLS_JSON=${{ vars.KRATOS_ALLOWED_RETURN_URLS_JSON }}' + assert_contains "$workflow" 'KRATOS_ALLOWED_RETURN_URLS_EXTRA=${{ vars.KRATOS_ALLOWED_RETURN_URLS_EXTRA }}' +done + +assert_contains "$staging_pull" 'bash scripts/render_ory_config.sh' +assert_contains "$staging_pull" 'chmod -R 777 config/.generated/ory' +assert_contains "$staging_pull" 'docker compose -f staging_pull_compose.yaml build --pull' + +assert_contains "$pull_compose" "baron_devfront" +assert_contains "$pull_compose" "baron_orgfront" +assert_contains "$pull_compose" "http://127.0.0.1:5173/" +assert_contains "$pull_compose" "http://127.0.0.1:5175/" + +assert_contains "$devfront_vite" "/tmp/baron-sso-devfront-dist" +assert_contains "$devfront_vite" "/tmp/baron-sso-devfront-vite-cache" +assert_contains "$devfront_vite" "hostFromUrl(process.env.DEVFRONT_URL)" +assert_contains "$devfront_vite" "process.env.DEVFRONT_ALLOWED_HOSTS" +assert_contains "$orgfront_vite" "/tmp/baron-sso-orgfront-dist" +assert_contains "$orgfront_vite" "/tmp/baron-sso-orgfront-vite-cache" +assert_contains "$orgfront_vite" '"sorg.hmac.kr"' + +echo "staging frontend deploy policy checks passed"