|
23941
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
AI 模块单元测试
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
ai-unit-test:
name: AI 模块单元测试
runs-on: ubuntu-latest
if: |
needs.detect-changes.outputs.ai-modules == 'true' ||
needs.detect-changes.outputs.backend == 'true' ||
(github.event.inputs.run_ai_tests != 'false')
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: AI Agents 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agents --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Agent Skills 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agent-skills --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Review Queue 模块测试
run: |
cd backend
npx vitest run src/modules/ai-review-queue --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Copilot 模块测试
run: |
cd backend
npx vitest run src/modules/ai-copilot --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: Lead Scoring AI 模块测试
run: |
cd backend
npx vitest run src/modules/lead-scoring-ai --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI 状态机测试
run: |
cd backend
npx vitest run \
src/shared/state-machines/__tests__/ai-agent.machine.test.ts \
src/shared/state-machines/__tests__/ai-task.machine.test.ts \
src/shared/state-machines/__tests__/training-plan.machine.test.ts \
--reporter=verbose --passWithNoTests
- if: always()
name: 生成 AI 测试摘要
run: |
echo "## AI 模块测试结果" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| AI 模块 | 测试文件数 |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-----------|" >> $GITHUB_STEP_SUMMARY
echo "| ai-agents | 4 (service/controller/schema/permissions) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-agent-skills | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-review-queue | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-copilot | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| lead-scoring-ai | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| AI 状态机 | 3 (ai-agent/ai-task/training-plan) |" >> $GITHUB_STEP_SUMMARY
...
|
ai-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
20592
|
4
|
1777249786
|
1777249786
|
1777249501
|
1777249786
|
|
1
|
|
0
|
Edit
Delete
|
|
23940
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
状态机测试
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
state-machine-test:
name: 状态机测试
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行状态机测试
run: cd backend && npx vitest run src/shared/state-machines --reporter=verbose --passWithNoTests
...
|
state-machine-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249732
|
|
1
|
|
0
|
Edit
Delete
|
|
23939
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
前端单元测试
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
frontend-unit-test:
name: 前端单元测试
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 运行前端单元测试
run: pnpm --filter juhi-frontend run test:coverage
- name: 上传覆盖率
uses: actions/upload-artifact@v4
with:
name: frontend-coverage
path: frontend/coverage/lcov.info
retention-days: "7"
...
|
frontend-unit-test
|
["frontend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249736
|
|
1
|
|
0
|
Edit
Delete
|
|
23938
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
后端单元测试 (4/4)
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-unit-test:
name: 后端单元测试 (4/4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试(分片 ${{ matrix.shard }}/4)
run: pnpm --filter juhi-api run test:ci -- --shard=${{ matrix.shard }}/4
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- name: 上传覆盖率
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend-shard-${{ matrix.shard }}
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: backend-unit-shard-${{ matrix.shard }}
path: backend/test-results/
retention-days: "7"
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test
POSTGRES_USER: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
shard:
- 4
...
|
backend-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249732
|
|
1
|
|
0
|
Edit
Delete
|
|
23937
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
后端单元测试 (3/4)
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-unit-test:
name: 后端单元测试 (3/4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试(分片 ${{ matrix.shard }}/4)
run: pnpm --filter juhi-api run test:ci -- --shard=${{ matrix.shard }}/4
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- name: 上传覆盖率
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend-shard-${{ matrix.shard }}
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: backend-unit-shard-${{ matrix.shard }}
path: backend/test-results/
retention-days: "7"
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test
POSTGRES_USER: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
shard:
- 3
...
|
backend-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249732
|
|
1
|
|
0
|
Edit
Delete
|
|
23936
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
后端单元测试 (2/4)
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-unit-test:
name: 后端单元测试 (2/4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试(分片 ${{ matrix.shard }}/4)
run: pnpm --filter juhi-api run test:ci -- --shard=${{ matrix.shard }}/4
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- name: 上传覆盖率
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend-shard-${{ matrix.shard }}
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: backend-unit-shard-${{ matrix.shard }}
path: backend/test-results/
retention-days: "7"
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test
POSTGRES_USER: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
shard:
- 2
...
|
backend-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249731
|
|
1
|
|
0
|
Edit
Delete
|
|
23935
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
后端单元测试 (1/4)
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-unit-test:
name: 后端单元测试 (1/4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试(分片 ${{ matrix.shard }}/4)
run: pnpm --filter juhi-api run test:ci -- --shard=${{ matrix.shard }}/4
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- name: 上传覆盖率
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend-shard-${{ matrix.shard }}
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: backend-unit-shard-${{ matrix.shard }}
path: backend/test-results/
retention-days: "7"
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test
POSTGRES_USER: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
shard:
- 1
...
|
backend-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249501
|
1777249731
|
|
1
|
|
0
|
Edit
Delete
|
|
23934
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
共享包检查
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
shared-check:
name: 共享包检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.shared == 'true'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 构建 + 测试
run: |
pnpm --filter @juhi/shared run build
pnpm --filter @juhi/shared run test:coverage
- name: 验证导出
run: cd shared && node -e "import('./dist/index.js').then(m => console.log('shared 导出验证通过'))"
- name: 上传覆盖率
uses: actions/upload-artifact@v4
with:
name: shared-coverage
path: shared/coverage/lcov.info
retention-days: "7"
...
|
shared-check
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
20584
|
4
|
1777249734
|
1777249734
|
1777249501
|
1777249735
|
|
1
|
|
0
|
Edit
Delete
|
|
23933
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
前端静态检查
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
frontend-lint:
name: 前端静态检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.frontend == 'true'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: ESLint 检查
run: pnpm --filter juhi-frontend run lint
- name: 数组守卫检查
run: pnpm --filter juhi-frontend run check:array-guard
- name: TypeScript 类型检查
run: pnpm --filter juhi-frontend run type-check
...
|
frontend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
20583
|
4
|
1777249728
|
1777249728
|
1777249501
|
1777249734
|
|
1
|
|
0
|
Edit
Delete
|
|
23932
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
后端静态检查
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-lint:
name: 后端静态检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: ESLint 检查
run: pnpm --filter juhi-api run lint
- name: TypeScript 类型检查
run: pnpm --filter juhi-api run type-check
- name: Prisma Schema 验证
run: cd backend && npx prisma validate
- name: Prisma ↔ Zod Schema 一致性
run: pnpm --filter juhi-api run check:schema
continue-on-error: true
...
|
backend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
20582
|
4
|
1777249726
|
1777249726
|
1777249501
|
1777249727
|
|
1
|
|
0
|
Edit
Delete
|
|
23931
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
安装依赖
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 缓存依赖
uses: actions/cache/save@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
...
|
setup
|
null
|
["ubuntu-latest"]
|
20576
|
2
|
1777249688
|
1777249709
|
1777249501
|
1777249710
|
|
0
|
|
0
|
Edit
Delete
|
|
23930
|
17902
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
检测代码变更
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
detect-changes:
name: 检测代码变更
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: filter
uses: dorny/paths-filter@v3
with:
filters: |
backend:
- 'backend/**'
- 'shared/**'
frontend:
- 'frontend/**'
- 'shared/**'
shared:
- 'shared/**'
ai-modules:
- 'backend/src/modules/ai-agents/**'
- 'backend/src/modules/ai-agent-skills/**'
- 'backend/src/modules/ai-review-queue/**'
- 'backend/src/modules/ai-copilot/**'
- 'backend/src/modules/lead-scoring-ai/**'
- 'backend/src/shared/state-machines/machines/ai-*.ts'
- 'backend/src/shared/state-machines/machines/training-*.ts'
prisma:
- 'backend/prisma/**'
e2e:
- 'e2e/**'
outputs:
ai-modules: ${{ steps.filter.outputs.ai-modules }}
backend: ${{ steps.filter.outputs.backend }}
e2e: ${{ steps.filter.outputs.e2e }}
frontend: ${{ steps.filter.outputs.frontend }}
prisma: ${{ steps.filter.outputs.prisma }}
shared: ${{ steps.filter.outputs.shared }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
20575
|
1
|
1777249671
|
1777249688
|
1777249501
|
1777249688
|
|
0
|
|
0
|
Edit
Delete
|
|
23929
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
test-summary
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test-summary:
name: test-summary
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all test artifacts
uses: actions/download-artifact@v4
- name: Generate summary report
run: "echo \"## \U0001F9EA E2E 测试汇总\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -d \"playwright-report-pr\" ]; then\n echo \"### PR 快速验证\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 关键测试通过\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"business-flows-report\" ]; then\n echo \"### 业务流程测试\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 业务流程测试完成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"performance-report\" ]; then\n echo \"### 性能基准测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F4CA 性能测试报告已生成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"visual-regression-report\" ]; then\n echo \"### 视觉回归测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F3A8 视觉对比完成\" >> $GITHUB_STEP_SUMMARY\nfi\n"
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
20580
|
2
|
1777249720
|
1777249722
|
1777249500
|
1777249722
|
|
1
|
|
0
|
Edit
Delete
|
|
23928
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
visual-regression
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
visual-regression:
name: visual-regression
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'visual-regression')
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run visual regression tests
run: |
cd e2e
npx playwright test tests/visual-regression/ --reporter=html
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload visual diff results
uses: actions/upload-artifact@v4
with:
name: visual-regression-report
path: |
e2e/playwright-report/
e2e/test-results/
retention-days: "30"
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Update baseline screenshots
run: |
cd e2e
npx playwright test tests/visual-regression/ --update-snapshots
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add tests/visual-regression/**/*.png
git commit -m "chore: update visual regression baselines" || echo "No changes"
git push
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
visual-regression
|
null
|
["ubuntu-latest"]
|
20574
|
2
|
1777249594
|
1777249665
|
1777249500
|
1777249665
|
|
0
|
|
0
|
Edit
Delete
|
|
23927
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
performance-benchmarks
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
performance-benchmarks:
name: performance-benchmarks
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'performance')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: production
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run performance tests
run: |
cd e2e
npx playwright test \
tests/flows/complete-sales-flow.spec.ts \
tests/lead-to-cash.spec.ts \
--reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- name: Generate performance report
run: |
cd e2e
node scripts/generate-performance-report.js
- if: always()
name: Upload performance results
uses: actions/upload-artifact@v4
with:
name: performance-report
path: |
e2e/playwright-report/
e2e/performance-results.json
retention-days: "90"
- if: github.event_name == 'schedule'
name: Comment with performance results
uses: actions/github-script@v7
with:
script: "const fs = require('fs');\nconst results = JSON.parse(fs.readFileSync('e2e/performance-results.json', 'utf8'));\n\nconst comment = `\n## \U0001F4CA 每日性能基准测试报告\n\n- **页面加载时间**: ${results.pageLoadTime}ms\n- **首次内容绘制 (FCP)**: ${results.fcp}ms\n- **最大内容绘制 (LCP)**: ${results.lcp}ms\n- **首次输入延迟 (FID)**: ${results.fid}ms\n- **累积布局偏移 (CLS)**: ${results.cls}\n\n${results.passed ? '✅ 所有性能指标达标' : '⚠️ 部分指标未达标,请关注'}\n`;\n\n// 创建 Issue 或发送通知\n// ...\n"
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
performance-benchmarks
|
null
|
["ubuntu-latest"]
|
20573
|
4
|
1777249592
|
1777249592
|
1777249500
|
1777249593
|
|
0
|
|
0
|
Edit
Delete
|
|
23926
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
business-flows
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
business-flows:
name: business-flows
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'business-flows'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run business flow tests
run: |
cd e2e
npx playwright test tests/business-flows/ --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: business-flows-report
path: e2e/playwright-report/
retention-days: "30"
timeout-minutes: "45"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
business-flows
|
null
|
["ubuntu-latest"]
|
20572
|
4
|
1777249590
|
1777249590
|
1777249500
|
1777249591
|
|
0
|
|
0
|
Edit
Delete
|
|
23925
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
full-test-suite (webkit)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (webkit)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- webkit
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
20571
|
2
|
1777249572
|
1777249590
|
1777249500
|
1777249590
|
|
0
|
|
0
|
Edit
Delete
|
|
23924
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
full-test-suite (firefox)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (firefox)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- firefox
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
20570
|
2
|
1777249554
|
1777249571
|
1777249500
|
1777249571
|
|
0
|
|
0
|
Edit
Delete
|
|
23923
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
full-test-suite (chromium)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (chromium)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- chromium
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
20569
|
2
|
1777249536
|
1777249553
|
1777249500
|
1777249553
|
|
0
|
|
0
|
Edit
Delete
|
|
23922
|
17901
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
pr-validation
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
pr-validation:
name: pr-validation
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run critical E2E tests
run: |
cd e2e
npx playwright test \
tests/auth/login.spec.ts \
tests/navigation/full-menu-click.spec.ts \
tests/multi-tenant/data-isolation.spec.ts \
tests/form-interactions/ \
--reporter=html
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-pr
path: e2e/playwright-report/
retention-days: "7"
- if: always() && github.event_name == 'pull_request'
name: Comment PR with test results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const reportPath = 'e2e/playwright-report/index.html';
const testsPassed = !fs.existsSync('e2e/test-results/');
const comment = testsPassed
? '✅ E2E 测试通过!'
: '❌ E2E 测试失败,请查看报告';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
pr-validation
|
null
|
["ubuntu-latest"]
|
20568
|
4
|
1777249533
|
1777249533
|
1777249500
|
1777249533
|
|
0
|
|
0
|
Edit
Delete
|
|
23921
|
17900
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test","governance-audit"]...
|
["ubuntu-latest"]
|
20577
|
4
|
1777249712
|
1777249713
|
1777249499
|
1777249713
|
|
1
|
|
0
|
Edit
Delete
|
|
23920
|
17900
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
Governance Audit (HIGH=0 gate)
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
governance-audit:
name: Governance Audit (HIGH=0 gate)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend run audit:prisma-zod-contract
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report
continue-on-error: true
- if: always()
name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
'',
'**HIGH+CRITICAL 必须为 0;任何新增高危 finding 阻塞 PR 合并。**',
];
require('fs').appendFileSync(process.env.GITHUB_STEP_SUMMARY, lines.join('\n') + '\n');
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败' >> $GITHUB_STEP_SUMMARY
fi
- name: 校验 HIGH+CRITICAL 必须为 0
run: |
if [ ! -f reports/harness-dashboard.latest.json ]; then
echo "::error::治理门禁失败:harness-dashboard 未生成"
exit 1
fi
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const blocking = (s.high || 0) + (s.critical || 0);
if (blocking > 0) {
console.error('::error::治理门禁失败:HIGH+CRITICAL = ' + blocking + ',必须为 0');
console.error('详见 governance-audit-reports artifact 中的 harness-dashboard.latest.json');
process.exit(1);
}
console.log('治理门禁通过:HIGH+CRITICAL = 0');
"
permissions:
contents: read
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249499
|
1777249535
|
|
1
|
|
0
|
Edit
Delete
|
|
23919
|
17900
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1777249499
|
1777249535
|
|
1
|
|
0
|
Edit
Delete
|
|
23918
|
17900
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
20567
|
2
|
1777249517
|
1777249532
|
1777249499
|
1777249532
|
|
0
|
|
0
|
Edit
Delete
|
|
23917
|
17900
|
6
|
5
|
8b28a0af74c8801b122de4d42a95742e2302646a
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
20566
|
2
|
1777249500
|
1777249516
|
1777249499
|
1777249517
|
|
0
|
|
0
|
Edit
Delete
|
|
31052
|
23488
|
72
|
5
|
8ae98649e077fa188f8e9c1b0a11b78a2377c836
|
0
|
Runtime and UI acceptance
|
1
|
name: Governance
"on":
pull_request:
name: Governance
"on":
pull_request:
push:
branches:
- main
jobs:
runtime-acceptance:
name: Runtime and UI acceptance
runs-on: ubuntu-latest
env:
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/juhai_quotation_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
# 桶名须 juhai-quotation* 前缀(preflight 基座守卫,G15 同型)。
S3_ENDPOINT: http://127.0.0.1:9000
S3_BUCKET: juhai-quotation-ci
S3_ACCESS_KEY_ID: ci-access-key
S3_SECRET_ACCESS_KEY: ci-secret-key
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@9.15.9 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm prisma:generate
- name: Start object storage (MinIO)
run: |
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=ci-access-key \
-e MINIO_ROOT_PASSWORD=ci-secret-key \
minio/minio:latest server /data
for _ in $(seq 1 30); do
if curl -sf http://127.0.0.1:9000/minio/health/live >/dev/null; then
echo "MinIO is live."
exit 0
fi
sleep 2
done
echo "MinIO did not become live within 60s" >&2
docker logs minio >&2
exit 1
- name: Run real DB and Redis acceptance
run: pnpm check:runtime
- name: Install Playwright browser
run: pnpm --filter web exec playwright install --with-deps chromium
- name: Run UI acceptance
run: pnpm check:ui
- if: failure()
name: Upload acceptance evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: acceptance-evidence
path: |
reports/*.latest.json
apps/web/e2e-results.json
apps/web/test-results/**
retention-days: "7"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: juhai_quotation_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d juhai_quotation_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
...
|
runtime-acceptance
|
["static-governance"]
|
["ubuntu-latest"]
|
27161
|
2
|
1786965670
|
1786965698
|
1786965499
|
1786965698
|
|
1
|
|
0
|
Edit
Delete
|
|
31051
|
23488
|
72
|
5
|
8ae98649e077fa188f8e9c1b0a11b78a2377c836
|
0
|
Static governance
|
1
|
name: Governance
"on":
pull_request:
name: Governance
"on":
pull_request:
push:
branches:
- main
jobs:
static-governance:
name: Static governance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@9.15.9 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm prisma:generate
- name: Run static governance gate
run: pnpm check
...
|
static-governance
|
null
|
["ubuntu-latest"]
|
27160
|
1
|
1786965499
|
1786965668
|
1786965499
|
1786965668
|
|
0
|
|
0
|
Edit
Delete
|
|
35961
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Release candidate verification + manifest
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${{ github.run_attempt }}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35960
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35959
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; identity 目前无私包依赖,保持同一配置步骤以便后续 pin)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (255 tests, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (12 cases)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35958
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and prepare isolated ordinary-role databases
run: |
pnpm runtime:build:modules
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload runtime and UI evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/conformance-differential.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35957
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Port conformance (kernel / modules / clients)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35956
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35955
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Static governance (repo root, private packages)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/conformance-differential.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
35954
|
24546
|
116
|
5
|
8ade7e39d08cef28571d2225bcef0b757223d806
|
0
|
Public static checks (no private packages)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Public static checks (no private packages)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Governance checks (no private packages; contracts deps from public npm)
run: |
pnpm check:module-imports
pnpm check:fact-pii
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1790297893
|
1790297420
|
1790297893
|
|
0
|
|
0
|
Edit
Delete
|
|
36614
|
24843
|
121
|
5
|
8aa26b92675d489fea49c09e13bd9554d50b4d32
|
0
|
acceptance
|
1
|
name: Kernel V1.0 CI
"on":
push:
name: Kernel V1.0 CI
"on":
push:
branches: [main]
jobs:
acceptance:
name: acceptance
runs-on: ubuntu-latest
steps:
- name: Checkout fixed source
uses: https://gitea.com/actions/checkout@v4
with:
fetch-depth: "0"
persist-credentials: "false"
- name: Verify host runner and locked toolchain
run: |
set -eu
echo "Node executable: $(command -v node || true)"
node --version
node -e "if (Number(process.versions.node.split('.')[0]) < 22) { console.error('Node.js >=22 is required'); process.exit(1); }"
echo "Docker executable: $(command -v docker || true)"
docker version
docker image inspect postgres:16-alpine >/dev/null
corepack --version
corepack enable
corepack prepare pnpm@9.15.9 --activate
- name: Run isolated PostgreSQL acceptance
run: pnpm ci:local
env:
ERK_TEST_CONCURRENCY: "1"
permissions:
contents: read
...
|
acceptance
|
null
|
["ubuntu-latest"]
|
30977
|
1
|
1790820485
|
1790821280
|
1790773382
|
1790821280
|
|
0
|
|
0
|
Edit
Delete
|
|
32127
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: actions/download-artifact@v4
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: actions/download-artifact@v4
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: actions/download-artifact@v4
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: actions/download-artifact@v4
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${{ github.run_attempt }}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity"]...
|
["ubuntu-latest"]
|
27864
|
2
|
1789209693
|
1789209729
|
1789208470
|
1789209730
|
|
1
|
|
0
|
Edit
Delete
|
|
32126
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; identity 目前无私包依赖,保持同一配置步骤以便后续 pin)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (255 tests, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (12 cases)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
27858
|
4
|
1789209681
|
1789209681
|
1789208470
|
1789209681
|
|
1
|
|
0
|
Edit
Delete
|
|
32125
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: UI acceptance
run: pnpm runtime:check:ui
- if: always()
name: Upload runtime and UI evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/conformance-differential.latest.json
runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
27857
|
4
|
1789209679
|
1789209679
|
1789208470
|
1789209679
|
|
1
|
|
0
|
Edit
Delete
|
|
32124
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Port conformance (kernel / modules / clients)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
27856
|
4
|
1789209677
|
1789209677
|
1789208470
|
1789209677
|
|
1
|
|
0
|
Edit
Delete
|
|
32123
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
27855
|
4
|
1789209675
|
1789209675
|
1789208470
|
1789209675
|
|
1
|
|
0
|
Edit
Delete
|
|
32122
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Static governance (repo root, private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/conformance-differential.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
27852
|
2
|
1789209544
|
1789209634
|
1789208470
|
1789209634
|
|
0
|
|
0
|
Edit
Delete
|
|
32121
|
23891
|
116
|
5
|
8a95879f7501b2874d73cf1f36f07f7673695db3
|
0
|
Public static checks (no private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Public static checks (no private packages)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Governance checks (no private packages; contracts deps from public npm)
run: |
pnpm check:module-imports
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
27851
|
2
|
1789208471
|
1789209543
|
1789208470
|
1789209544
|
|
0
|
|
0
|
Edit
Delete
|
|
34715
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${{ github.run_attempt }}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
29589
|
2
|
1789974147
|
1789974177
|
1789974008
|
1789974177
|
|
1
|
|
0
|
Edit
Delete
|
|
34714
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
29588
|
4
|
1789974145
|
1789974145
|
1789974008
|
1789974145
|
|
1
|
|
0
|
Edit
Delete
|
|
34713
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; identity 目前无私包依赖,保持同一配置步骤以便后续 pin)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (255 tests, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (12 cases)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
29587
|
4
|
1789974143
|
1789974143
|
1789974008
|
1789974143
|
|
1
|
|
0
|
Edit
Delete
|
|
34712
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and prepare isolated ordinary-role databases
run: |
pnpm runtime:build:modules
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload runtime and UI evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/conformance-differential.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
29586
|
4
|
1789974141
|
1789974141
|
1789974008
|
1789974141
|
|
1
|
|
0
|
Edit
Delete
|
|
34711
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Port conformance (kernel / modules / clients)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
29585
|
4
|
1789974139
|
1789974139
|
1789974008
|
1789974139
|
|
1
|
|
0
|
Edit
Delete
|
|
34710
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
29584
|
4
|
1789974137
|
1789974137
|
1789974008
|
1789974137
|
|
1
|
|
0
|
Edit
Delete
|
|
34709
|
24324
|
116
|
5
|
8a852297e81e2df71e877aee5f01930d7797fbfb
|
0
|
Static governance (repo root, private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
CANDIDATE_TAG: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
GOV_REPORT_RUNNER: gitea-actions
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.GITEA_NPM_TOKEN }}
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/conformance-differential.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
29583
|
2
|
1789974044
|
1789974134
|
1789974008
|
1789974135
|
|
0
|
|
0
|
Edit
Delete
|