From 3b7eda947b13a5ba0d3462a8137432640b68a1b7 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Sat, 10 Oct 2026 14:49:12 +0800 Subject: [PATCH] ci: route manual Bug Server PR tests to CN PPE --- .github/scripts/bug-server-manual.cjs | 9 +++++++-- .github/scripts/bug-server-manual.test.cjs | 17 ++++++++++++++--- .github/workflows/bug-server-manual-report.yml | 1 + .github/workflows/bug-server-manual.yml | 6 ++++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/scripts/bug-server-manual.cjs b/.github/scripts/bug-server-manual.cjs index 46b2678af..c171aee24 100644 --- a/.github/scripts/bug-server-manual.cjs +++ b/.github/scripts/bug-server-manual.cjs @@ -16,7 +16,12 @@ function context(env) { // 复用既有 GitHub CI 公网入口;内网页面入口另由 bugserver 的 Host 白名单控制。 const host = env.BUG_SERVER_HOST || 'https://bug-server.zijieapi.com'; if (!new Set(['https://bug-server.zijieapi.com', 'https://bugserver.cn.goofy.app', 'https://g20b7465b2.gf-boe.bytedance.net']).has(host)) throw new Error('Unsupported Bug Server host'); - return { env, host, runId }; + const environment = env.BUG_SERVER_ENVIRONMENT || (host === 'https://g20b7465b2.gf-boe.bytedance.net' ? 'boe' : 'cn'); + if (!['cn', 'boe', 'ppe'].includes(environment) || (environment === 'boe') !== (host === 'https://g20b7465b2.gf-boe.bytedance.net') || + (environment === 'ppe' && host !== 'https://bug-server.zijieapi.com')) throw new Error('Unsupported Bug Server environment'); + // PPE 固定复用 CN 公网入口,分流头仅发给 CI,不传给 GitHub 或产物地址。 + const headers = environment === 'ppe' ? { 'x-use-ppe': '1', 'x-tt-env': 'ppe_bugserver_titan_auth' } : {}; + return { env, host, runId, headers }; } /** 每次重新构造 multipart;服务端 checkpoint 保证重试不重复创建 SCM/截图批次。 */ @@ -30,7 +35,7 @@ async function call(ctx, triggerType, fields = {}, filePath) { form.append(key, String(value)); } if (filePath) form.append('bundleFile', new Blob([await readFile(filePath)], { type: 'text/javascript' }), 'index.js'); - const response = await fetch(`${ctx.host}/api/ci/trigger`, { method: 'POST', body: form, + const response = await fetch(`${ctx.host}/api/ci/trigger`, { method: 'POST', body: form, headers: ctx.headers, signal: AbortSignal.timeout(75000), redirect: 'error' }); const result = await response.json(); if (!response.ok || result.code !== 0) { diff --git a/.github/scripts/bug-server-manual.test.cjs b/.github/scripts/bug-server-manual.test.cjs index 02d801d2c..ae93479f9 100644 --- a/.github/scripts/bug-server-manual.test.cjs +++ b/.github/scripts/bug-server-manual.test.cjs @@ -11,7 +11,9 @@ const env = { GITHUB_REPOSITORY: 'VisActor/VChart', GITHUB_RUN_ID: '99', TASK_ID test('控制脚本拒绝任意仓库、入口、任务编号和 run ID', () => { for (const patch of [{ GITHUB_REPOSITORY: 'evil/VChart' }, { TASK_ID: `${taskId}\nreused=true` }, - { GITHUB_RUN_ID: '0' }, { BUG_SERVER_TOKEN: '' }, { BUG_SERVER_HOST: 'https://evil.example' }]) assert.throws(() => context({ ...env, ...patch })); + { GITHUB_RUN_ID: '0' }, { BUG_SERVER_TOKEN: '' }, { BUG_SERVER_HOST: 'https://evil.example' }, + { BUG_SERVER_ENVIRONMENT: 'ppe_other' }, { BUG_SERVER_ENVIRONMENT: 'boe' }, + { BUG_SERVER_ENVIRONMENT: 'ppe', BUG_SERVER_HOST: 'https://g20b7465b2.gf-boe.bytedance.net' }]) assert.throws(() => context({ ...env, ...patch })); }); test('BOE 控制请求只发送到固定 BOE 地址,保留任务与服务 token 校验', async t => { @@ -22,6 +24,7 @@ test('BOE 控制请求只发送到固定 BOE 地址,保留任务与服务 toke assert.equal(options.redirect, 'error'); assert.equal(options.body.get('token'), 'test-project-token'); assert.equal(options.body.get('workflowRunId'), '123'); + assert.deepEqual(options.headers, {}); return new Response(JSON.stringify({ code: 0, data: {} })); }; await run('complete', { ...env, TASK_ID: undefined, REPORTED_RUN_ID: '123', BUG_SERVER_HOST: 'https://g20b7465b2.gf-boe.bytedance.net' }); @@ -35,8 +38,10 @@ test('prepare 使用服务端冻结 SHA,下载复用失败会退回构建', as t.after(() => rm(directory, { recursive: true, force: true })); const previousFetch = global.fetch; t.after(() => { global.fetch = previousFetch; }); + let ppe = false; global.fetch = async (url, options) => { if (new URL(url).origin === 'https://api.github.com') return new Response('{}', { status: 404 }); + assert.deepEqual(options.headers, ppe ? { 'x-use-ppe': '1', 'x-tt-env': 'ppe_bugserver_titan_auth' } : {}); assert.equal(options.body.get('triggerType'), 'manual-info'); assert.equal(options.body.get('manualTaskId'), taskId); assert.equal(options.body.get('workflowRunId'), '99'); @@ -45,6 +50,8 @@ test('prepare 使用服务端冻结 SHA,下载复用失败会退回构建', as }; await run('prepare', { ...env, RUNNER_TEMP: directory, GITHUB_OUTPUT: join(directory, 'outputs') }); assert.equal(await readFile(join(directory, 'outputs'), 'utf8'), `head_sha=${'a'.repeat(40)}\nhead_repository=contributor/VChart\nreused=false\n`); + ppe = true; + await run('prepare', { ...env, BUG_SERVER_ENVIRONMENT: 'ppe', RUNNER_TEMP: directory, GITHUB_OUTPUT: join(directory, 'ppe-outputs') }); }); test('submit 把可执行 JS 只当作上传数据,沿用 SCM/截图链路并保留差异结论', async t => { @@ -62,6 +69,7 @@ test('submit 把可执行 JS 只当作上传数据,沿用 SCM/截图链路并 if (new URL(address).origin === 'https://api.github.com') { assert.equal(options.headers.Authorization, 'Bearer test-github-token'); assert.equal(options.redirect, 'manual'); + assert.equal(options.headers['x-tt-env'], undefined); return new Response(null, { status: 302, headers: { location: 'https://artifact.example/signed.zip' } }); } if (new URL(address).origin === 'https://artifact.example') { @@ -69,6 +77,8 @@ test('submit 把可执行 JS 只当作上传数据,沿用 SCM/截图链路并 return new Response(bytes); } assert.equal(options.redirect, 'error'); + assert.equal(address, 'https://bug-server.zijieapi.com/api/ci/trigger'); + assert.deepEqual(options.headers, { 'x-use-ppe': '1', 'x-tt-env': 'ppe_bugserver_titan_auth' }); const form = options.body, type = form.get('triggerType'); operations.push(type); assert.equal(form.get('token'), 'test-project-token'); @@ -83,7 +93,7 @@ test('submit 把可执行 JS 只当作上传数据,沿用 SCM/截图链路并 assert.ok(data, `Unexpected operation ${type}`); return new Response(JSON.stringify({ code: 0, data })); }; - assert.equal(await run('submit', env), 1); + assert.equal(await run('submit', { ...env, BUG_SERVER_ENVIRONMENT: 'ppe' }), 1); assert.deepEqual(operations, ['manual-artifact', 'upload-file', 'scm-build', 'scm-version-info', 'photo-test', 'photo-result', 'manual-finish']); assert.ok(!operations.includes('performance-test')); }); @@ -95,9 +105,10 @@ test('独立完成回报只提供源 run ID,不从事件 payload 猜测被测 assert.equal(options.body.get('workflowRunId'), '123'); assert.equal(options.body.get('manualTaskId'), null); assert.equal(options.body.get('outcome'), null); + assert.deepEqual(options.headers, { 'x-use-ppe': '1', 'x-tt-env': 'ppe_bugserver_titan_auth' }); return new Response(JSON.stringify({ code: 0, data: { outcome: 'cancelled' } })); }; - assert.equal(await run('complete', { ...env, TASK_ID: undefined, REPORTED_RUN_ID: '123' }), 0); + assert.equal(await run('complete', { ...env, TASK_ID: undefined, REPORTED_RUN_ID: '123', BUG_SERVER_ENVIRONMENT: 'ppe' }), 0); }); test('可信上传前检查拒绝文件及父目录符号链接、空文件和超限文件', async t => { diff --git a/.github/workflows/bug-server-manual-report.yml b/.github/workflows/bug-server-manual-report.yml index 1addfdd9d..3fd71c3fc 100644 --- a/.github/workflows/bug-server-manual-report.yml +++ b/.github/workflows/bug-server-manual-report.yml @@ -26,6 +26,7 @@ jobs: env: # 只从源 run 的固定环境后缀选择回报地址,不接受任意 URL。 BUG_SERVER_HOST: ${{ endsWith(github.event.workflow_run.display_title, ':boe') && 'https://g20b7465b2.gf-boe.bytedance.net' || 'https://bug-server.zijieapi.com' }} + BUG_SERVER_ENVIRONMENT: ${{ endsWith(github.event.workflow_run.display_title, ':boe') && 'boe' || endsWith(github.event.workflow_run.display_title, ':ppe') && 'ppe' || 'cn' }} REPORTED_RUN_ID: ${{ github.event.workflow_run.id }} BUG_SERVER_TOKEN: ${{ secrets.BUG_SERVER_TOKEN }} run: node .github/scripts/bug-server-manual.cjs complete diff --git a/.github/workflows/bug-server-manual.yml b/.github/workflows/bug-server-manual.yml index 5f90ffe51..7e92ce53a 100644 --- a/.github/workflows/bug-server-manual.yml +++ b/.github/workflows/bug-server-manual.yml @@ -1,5 +1,5 @@ name: Bug Server Manual PR -run-name: bugserver-manual:${{ inputs.task_id }}${{ inputs.environment == 'boe' && ':boe' || '' }} +run-name: bugserver-manual:${{ inputs.task_id }}${{ inputs.environment == 'boe' && ':boe' || inputs.environment == 'ppe' && ':ppe' || '' }} on: workflow_dispatch: @@ -13,7 +13,7 @@ on: required: false default: cn type: choice - options: [cn, boe] + options: [cn, boe, ppe] permissions: contents: read @@ -45,6 +45,7 @@ jobs: env: TASK_ID: ${{ inputs.task_id }} BUG_SERVER_HOST: ${{ inputs.environment == 'boe' && 'https://g20b7465b2.gf-boe.bytedance.net' || 'https://bug-server.zijieapi.com' }} + BUG_SERVER_ENVIRONMENT: ${{ inputs.environment }} GH_TOKEN: ${{ github.token }} BUG_SERVER_TOKEN: ${{ secrets.BUG_SERVER_TOKEN }} run: node .github/scripts/bug-server-manual.cjs prepare @@ -124,6 +125,7 @@ jobs: env: TASK_ID: ${{ inputs.task_id }} BUG_SERVER_HOST: ${{ inputs.environment == 'boe' && 'https://g20b7465b2.gf-boe.bytedance.net' || 'https://bug-server.zijieapi.com' }} + BUG_SERVER_ENVIRONMENT: ${{ inputs.environment }} GH_TOKEN: ${{ github.token }} BUG_SERVER_TOKEN: ${{ secrets.BUG_SERVER_TOKEN }} run: node .github/scripts/bug-server-manual.cjs submit