fix(deploy): replace PDA H5 containers with static hosting

This commit is contained in:
2026-10-23 15:25:45 +08:00
parent 1759290f87
commit 554b0f119e
11 changed files with 65 additions and 186 deletions
+20 -47
View File
@@ -1,43 +1,28 @@
import test from 'node:test'
import { runInNewContext } from 'node:vm'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import { readFile, readdir } from 'node:fs/promises'
const read = path => readFile(new URL(path, import.meta.url), 'utf8')
test('H5 image copies only compiled assets and static nginx configuration', async () => {
const dockerfile = await read('../deploy/Dockerfile.h5')
const copies = dockerfile.split(/\r?\n/).filter(line => line.startsWith('COPY '))
assert.deepEqual(copies, ['COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf', 'COPY dist/build/h5/ /srv/pda-h5/'])
assert.match(dockerfile, /ARG NGINX_BASE_IMAGE=/)
assert.match(dockerfile, /FROM \$\{NGINX_BASE_IMAGE\}/)
assert.doesNotMatch(dockerfile, /RUN |npm|node_modules|COPY \. /)
const ignore = await read('../.dockerignore')
assert.ok(ignore.split(/\r?\n/).includes('**'))
assert.ok(ignore.includes('!dist/build/h5/**'))
assert.doesNotMatch(ignore, /!\.env|!node_modules|!src/)
test('PDA H5 has no container publishing entry', async () => {
const files = await readdir(new URL('../deploy/', import.meta.url))
assert.deepEqual(files.filter(name => /docker|compose/i.test(name)), [])
await assert.rejects(read('../.dockerignore'), { code: 'ENOENT' })
})
test('static server serves the domain root and returns genuine missing-resource errors', async () => {
const nginx = await read('../deploy/nginx.conf')
assert.match(nginx, /listen 80;/)
assert.ok(nginx.includes('location /'))
assert.match(nginx, /root \/srv\/pda-h5;/)
assert.match(nginx, /try_files \$uri \$uri\/ =404;/)
assert.match(nginx, /Cache-Control "no-store" always/)
assert.doesNotMatch(nginx, /pda-domestic|pda-overseas/)
assert.match(nginx, /location = \/healthz/)
assert.doesNotMatch(nginx, /proxy_pass|gateway-api|try_files[^;]*index\.html/)
})
test('TEST H5 deployment has a required image tag and internal-only dual health checks', async () => {
const compose = await read('../deploy/docker-compose.h5.test.yml')
assert.ok(compose.includes('${IMAGE_TAG:?IMAGE_TAG is required}'))
assert.match(compose, /context: \.\./)
assert.match(compose, /dockerfile: deploy\/Dockerfile\.h5/)
assert.match(compose, /container_name: pda-overseas-h5-test/)
assert.match(compose, /aliases:\s*\n\s*- pda-overseas-h5-test/)
assert.match(compose, /external: true/)
assert.match(compose, /name: firstleg-test-network/)
assert.match(compose, /expose:\s*\n\s*- "80"/)
assert.ok(compose.includes('http://127.0.0.1/healthz && wget -qO /dev/null http://127.0.0.1/'))
assert.doesNotMatch(compose, /\bports:|volumes:|API_UPSTREAM|privileged:|pid: host/)
test('host nginx serves uploaded files and proxies only the API prefix', async () => {
const nginx = await read('../deploy/nginx.conf.template')
assert.ok(nginx.includes('root ${PDA_SITE_ROOT};'))
const page = nginx.match(/location \/ \{([^{}]*)\}/)?.[1]
assert.ok(page)
assert.match(page, /try_files \$uri \$uri\/ =404;/)
assert.match(page, /Cache-Control "no-store" always/)
assert.doesNotMatch(page, /proxy_pass|try_files[^;]*index\.html/)
assert.match(nginx, /location \^~ \/gateway-api\//)
assert.ok(nginx.includes('proxy_pass ${PDA_GATEWAY_ORIGIN}/api/;'))
assert.equal((nginx.match(/proxy_pass/g) || []).length, 1)
assert.match(nginx, /proxy_set_header Authorization \$http_authorization;/)
assert.match(nginx, /client_max_body_size 55m;/)
assert.doesNotMatch(nginx, /29005|29006|\/srv\/pda-h5|gateway:9000/)
})
test('only H5 production overrides the toolchain asset base', async () => {
@@ -72,15 +57,3 @@ test('H5 proxy uses the shared gateway prefix and preserves API suffixes', async
assert.equal(proxy['/gateway-api'].rewrite(`/gateway-api${suffix}`), `/api${suffix}`)
}
})
test('gray H5 runs on an isolated network with same-origin Gateway API', async () => {
const compose = await read('../deploy/docker-compose.h5.production.yml')
const nginx = await read('../deploy/nginx.production.conf.template')
const docker = await read('../deploy/Dockerfile.h5.production')
assert.match(compose, /name: firstleg-production-network/)
assert.match(compose, /127\.0\.0\.1:/)
assert.doesNotMatch(compose, /test-network|gateway-overseas/)
assert.match(nginx, /location \^~ \/gateway-api\//)
assert.ok(nginx.includes('proxy_pass ${API_UPSTREAM}/api/;'))
assert.match(docker, /COPY deploy\/nginx.production.conf.template \/etc\/nginx\/templates\/default.conf.template/)
})