chore: close production operations automation
This commit is contained in:
Generated
+48
@@ -23,6 +23,7 @@
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.2.4",
|
||||
"playwright": "1.59.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
},
|
||||
@@ -4312,6 +4313,21 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -5744,6 +5760,38 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.59.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
|
||||
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.59.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.59.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
|
||||
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.2.4",
|
||||
"playwright": "1.59.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,48 @@ powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\rotate-admin-pas
|
||||
curl http://192.168.3.90:8001/api/v1/system/readiness
|
||||
```
|
||||
|
||||
## 6.6 阶段 5 生产运维门禁
|
||||
|
||||
生产健康巡检:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-health-check.ps1
|
||||
```
|
||||
|
||||
备份与恢复演练:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-backup-drill.ps1
|
||||
```
|
||||
|
||||
依赖治理:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-dependency-governance.ps1
|
||||
```
|
||||
|
||||
安全基线:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-security-baseline.ps1
|
||||
```
|
||||
|
||||
生产阶段 1/2/3 关键 E2E 回归:
|
||||
|
||||
```powershell
|
||||
$env:AI_CONTRACT_ADMIN_PASSWORD = '<由管理员输入的实际密码>'
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-regression.ps1
|
||||
Remove-Item Env:\AI_CONTRACT_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
当前阶段 5 已完成闭环验证:
|
||||
|
||||
- 生产健康巡检:PASS
|
||||
- 备份恢复演练:PASS
|
||||
- 依赖治理:PASS
|
||||
- 安全基线:PASS
|
||||
- 生产阶段 1/2/3 关键 E2E:PASS
|
||||
|
||||
## 7. 生产部署建议(当前阶段)
|
||||
|
||||
当前试点服务器部署口径:
|
||||
|
||||
@@ -174,7 +174,39 @@ backend\.venv\Scripts\python.exe -m pytest -q backend/tests
|
||||
|
||||
---
|
||||
|
||||
## 六、常见故障处理
|
||||
## 六、生产回归口径
|
||||
|
||||
执行生产阶段 1/2/3 关键 E2E 回归:
|
||||
|
||||
```powershell
|
||||
$env:AI_CONTRACT_ADMIN_PASSWORD = '<由管理员输入的实际密码>'
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-regression.ps1
|
||||
Remove-Item Env:\AI_CONTRACT_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
默认产物目录:
|
||||
|
||||
```text
|
||||
project-docs/qa-artifacts/phase5-production-regression/<timestamp>/
|
||||
```
|
||||
|
||||
回归内容:
|
||||
|
||||
1. 阶段 1 生产关键 E2E。
|
||||
2. 阶段 2 生产关键 E2E。
|
||||
3. 阶段 3 生产关键 E2E。
|
||||
4. 每个阶段保留独立日志和产物目录。
|
||||
|
||||
门禁:
|
||||
|
||||
1. 管理员真实密码只允许在当前终端进程中临时存在。
|
||||
2. 密码不得写入脚本、文档、Git、`.env` 或日志。
|
||||
3. 任一阶段 E2E 失败时,本次生产回归失败。
|
||||
4. 依赖升级、服务重启、密钥轮换、部署变更后必须复跑生产健康巡检、安全基线和生产回归。
|
||||
|
||||
---
|
||||
|
||||
## 七、常见故障处理
|
||||
|
||||
查看容器状态:
|
||||
|
||||
@@ -205,3 +237,4 @@ docker compose -f docker-compose.server.yml up -d backend frontend
|
||||
```
|
||||
|
||||
重启后必须重新执行生产健康巡检。
|
||||
如 backend 被重新创建后前端出现 API 代理解析失败,应同时重启 frontend,并重新执行生产健康巡检、安全基线和生产回归。
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
| 阶段 2:深度开发与交付体验补强 | PASS | `project-docs/阶段2-深度开发与交付体验补强执行记录-2026-05-01.md` |
|
||||
| 阶段 3:试点交付准备 | PASS | `project-docs/阶段3-试点交付准备执行记录-2026-05-01.md` |
|
||||
| 阶段 4:试点运行监控与安全加固 | PASS | `project-docs/阶段4-试点运行监控与安全加固执行记录-2026-05-01.md` |
|
||||
| 阶段 5:生产运行、安全、监控、备份与依赖治理 | IN PROGRESS | `project-docs/阶段5-生产运行安全监控备份与依赖治理执行记录-2026-05-01.md` |
|
||||
| 阶段 5:生产运行、安全、监控、备份与依赖治理 | PASS | `project-docs/阶段5-生产运行安全监控备份与依赖治理执行记录-2026-05-01.md` |
|
||||
|
||||
阶段 1 已完成源码闭环与生产入口闭环,生产无人 E2E `18/18` 通过。阶段 2 已完成 Review 重试、Knowledge Base 文档重试、Review -> Chat -> Contract 上下文联动、首页交付工作台和阶段 2 自动化无人闭环,本地与生产 E2E 均 `7/7` 通过。阶段 3 已完成系统 readiness、试点交付准备页、默认账号说明、演示样本数据、依赖健康门禁和阶段 3 自动化无人闭环,本地与生产 E2E 均 `5/5` 通过。
|
||||
|
||||
当前后续重点为“生产运行、安全、监控、备份与依赖治理”:默认密码轮换已完成,阶段 5 Step 1 生产健康巡检、Step 2 备份恢复演练、Step 3 依赖治理、Step 4 安全基线均已 PASS,下一步进入生产回归闭环。
|
||||
当前后续重点为“生产运行、安全、监控、备份与依赖治理”:默认密码轮换已完成,阶段 5 Step 1 生产健康巡检、Step 2 备份恢复演练、Step 3 依赖治理、Step 4 安全基线、Step 5 生产回归均已 PASS,阶段 5 已形成生产运行治理闭环。
|
||||
|
||||
---
|
||||
|
||||
@@ -174,7 +174,7 @@ AI合同平台当前已经不是从零建设阶段。登录、合同审查、Rev
|
||||
|
||||
---
|
||||
|
||||
## 四、阶段 5 立即执行清单
|
||||
## 四、阶段 5 已执行清单
|
||||
|
||||
第一批先建立生产运行基线:
|
||||
|
||||
@@ -184,7 +184,7 @@ AI合同平台当前已经不是从零建设阶段。登录、合同审查、Rev
|
||||
4. 验证默认密码不可登录,管理员真实密码只通过运行时环境变量注入。
|
||||
5. 生成 `production-health-summary.json` 和 `production-health-summary.md`。
|
||||
|
||||
第二批进入治理演练:
|
||||
第二批治理演练:
|
||||
|
||||
1. 新增或完善备份恢复演练脚本。
|
||||
2. 运行前端 `npm audit --json` 和后端 `pip check`。
|
||||
@@ -192,6 +192,14 @@ AI合同平台当前已经不是从零建设阶段。登录、合同审查、Rev
|
||||
4. 复跑生产阶段 1/2/3 核心 E2E。
|
||||
5. 更新运维手册和阶段 5 执行记录。
|
||||
|
||||
当前结果:
|
||||
|
||||
1. 生产健康巡检 PASS:`project-docs/qa-artifacts/phase5-production-health/2026-05-01T09-10-20/`
|
||||
2. 备份恢复演练 PASS:`project-docs/qa-artifacts/phase5-backup-drill/2026-05-01T08-40-59/`
|
||||
3. 依赖治理 PASS:`project-docs/qa-artifacts/phase5-dependency-governance/2026-05-01T09-08-52/`
|
||||
4. 安全基线 PASS:`project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T09-10-28/`
|
||||
5. 生产回归 PASS:`project-docs/qa-artifacts/phase5-production-regression/2026-05-01T09-10-34/`
|
||||
|
||||
---
|
||||
|
||||
## 五、交付完成定义
|
||||
@@ -210,4 +218,4 @@ AI合同平台当前已经不是从零建设阶段。登录、合同审查、Rev
|
||||
|
||||
## 六、当前一句话结论
|
||||
|
||||
AI合同平台阶段 1、阶段 2 和阶段 3 均已完成闭环交付验证,阶段 4 已完成默认管理员密码轮换闭环,阶段 5 已启动并完成生产健康巡检、备份恢复演练、依赖治理和安全基线,下一步进入生产回归闭环。
|
||||
AI合同平台阶段 1、阶段 2、阶段 3、阶段 4、阶段 5 均已完成闭环交付验证。当前系统已具备主业务闭环、试点交付准备、默认管理员密码轮换、生产健康巡检、备份恢复演练、依赖治理、安全基线和生产关键 E2E 回归证据。
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
| Step 2:备份与恢复演练 | PASS | `scripts/run-backup-drill.ps1` 已实现并完成生产备份/隔离恢复验证 |
|
||||
| Step 3:依赖治理专项 | PASS | Next/PostCSS moderate 漏洞已清零,前后端依赖门禁通过 |
|
||||
| Step 4:安全基线检查 | PASS | 生产 `SECRET_KEY` 已改为远端 `.env` 注入,安全基线脚本 PASS |
|
||||
| Step 5:生产回归闭环 | PENDING | 下一步进入,复跑阶段 1/2/3 关键 E2E |
|
||||
| Step 5:生产回归闭环 | PASS | `scripts/run-production-regression.ps1` 已实现,生产阶段 1/2/3 关键 E2E 全部通过 |
|
||||
|
||||
阶段 5 当前判定:Step 1、Step 2、Step 3、Step 4 均已 PASS。
|
||||
阶段 5 当前判定:Step 1、Step 2、Step 3、Step 4、Step 5 均已 PASS,已形成生产运行治理闭环。
|
||||
|
||||
---
|
||||
|
||||
@@ -84,17 +84,43 @@ default-password-login.json
|
||||
|
||||
---
|
||||
|
||||
## 五、下一步
|
||||
## 五、Step 5 生产回归闭环
|
||||
|
||||
阶段 5 下一步进入 Step 5:生产回归闭环。
|
||||
新增脚本:
|
||||
|
||||
优先交付:
|
||||
```powershell
|
||||
scripts\run-production-regression.ps1
|
||||
```
|
||||
|
||||
1. 阶段 1 生产关键 E2E
|
||||
2. 阶段 2 生产关键 E2E
|
||||
3. 阶段 3 生产关键 E2E
|
||||
4. 生产健康巡检
|
||||
5. 最终阶段 5 闭环报告
|
||||
本次回归产物:
|
||||
|
||||
```text
|
||||
project-docs/qa-artifacts/phase5-production-regression/2026-05-01T09-10-34/
|
||||
```
|
||||
|
||||
最终复验产物:
|
||||
|
||||
```text
|
||||
project-docs/qa-artifacts/phase5-production-health/2026-05-01T09-10-20/
|
||||
project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T09-10-28/
|
||||
```
|
||||
|
||||
回归结果:
|
||||
|
||||
| 检查项 | 结果 | 说明 |
|
||||
|---|---|---|
|
||||
| 阶段 1 生产关键 E2E | PASS | 生产入口登录、合同审查、报告、合同生成等核心闭环通过 |
|
||||
| 阶段 2 生产关键 E2E | PASS | Review 重试、Knowledge Base 重试、Review -> Chat -> Contract 联动通过 |
|
||||
| 阶段 3 生产关键 E2E | PASS | Readiness、试点交付准备、默认账号说明、演示数据与生产门禁通过 |
|
||||
| 生产健康巡检复验 | PASS | 容器、端口、`/health`、readiness、关键页面、默认密码拒绝通过 |
|
||||
| 安全基线复验 | PASS | 强密钥、默认密码拒绝、member 权限边界、敏感文件扫描通过 |
|
||||
|
||||
执行口径:
|
||||
|
||||
1. 管理员真实密码只通过当前进程环境变量读取。
|
||||
2. 脚本、文档、Git、`.env` 均不保存管理员真实密码。
|
||||
3. 生产回归执行完成后应移除当前终端进程中的密码环境变量。
|
||||
4. 任何阶段 E2E 失败时,脚本退出失败并保留阶段级日志与产物目录。
|
||||
|
||||
---
|
||||
|
||||
@@ -167,7 +193,7 @@ scripts\run-dependency-governance.ps1
|
||||
本次依赖治理产物:
|
||||
|
||||
```text
|
||||
project-docs/qa-artifacts/phase5-dependency-governance/2026-05-01T08-46-29/
|
||||
project-docs/qa-artifacts/phase5-dependency-governance/2026-05-01T09-08-52/
|
||||
```
|
||||
|
||||
验证记录:
|
||||
@@ -203,7 +229,7 @@ scripts\run-security-baseline.ps1
|
||||
安全基线产物:
|
||||
|
||||
```text
|
||||
project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T08-55-24/
|
||||
project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T09-10-28/
|
||||
```
|
||||
|
||||
生产健康复验产物:
|
||||
|
||||
@@ -156,21 +156,25 @@ $env:AI_CONTRACT_ADMIN_PASSWORD = '<管理员实际密码>'
|
||||
|
||||
---
|
||||
|
||||
## 六、建议立即进入的第一步
|
||||
## 六、阶段闭环状态
|
||||
|
||||
优先执行 Step 1:生产健康巡检自动化。
|
||||
阶段 5 已完成闭环。后续运维应把生产健康巡检、安全基线和生产回归作为上线、重启、依赖升级和密钥轮换后的固定门禁。
|
||||
|
||||
理由:
|
||||
原因:
|
||||
|
||||
1. 风险低,不改业务逻辑。
|
||||
2. 可以先建立阶段 5 的观测基线。
|
||||
3. 后续备份、依赖治理、安全基线和回归都可以复用同一套健康产物。
|
||||
2. 可以快速确认生产入口、readiness、默认密码拒绝和关键页面状态。
|
||||
3. 可以在安全、依赖、部署变更后立即发现回归。
|
||||
|
||||
第一批文件建议:
|
||||
当前阶段 5 已交付文件:
|
||||
|
||||
1. `scripts/run-production-health-check.ps1`
|
||||
2. `project-docs/阶段5-生产运行安全监控备份与依赖治理执行记录-2026-05-01.md`
|
||||
3. `project-docs/运维手册-2026-05-01.md`
|
||||
2. `scripts/run-backup-drill.ps1`
|
||||
3. `scripts/run-dependency-governance.ps1`
|
||||
4. `scripts/run-security-baseline.ps1`
|
||||
5. `scripts/run-production-regression.ps1`
|
||||
6. `project-docs/阶段5-生产运行安全监控备份与依赖治理执行记录-2026-05-01.md`
|
||||
7. `project-docs/运维手册-2026-05-01.md`
|
||||
|
||||
当前执行状态:
|
||||
|
||||
@@ -182,14 +186,17 @@ $env:AI_CONTRACT_ADMIN_PASSWORD = '<管理员实际密码>'
|
||||
- 备份演练产物:`project-docs/qa-artifacts/phase5-backup-drill/2026-05-01T08-40-59/`
|
||||
- Step 3 已完成:`scripts/run-dependency-governance.ps1`
|
||||
- 依赖治理结果:PASS,`npm audit` 0 vulnerabilities,后端 `pip check` PASS
|
||||
- 依赖治理产物:`project-docs/qa-artifacts/phase5-dependency-governance/2026-05-01T08-46-29/`
|
||||
- 依赖治理产物:`project-docs/qa-artifacts/phase5-dependency-governance/2026-05-01T09-08-52/`
|
||||
- Step 4 已完成:`scripts/run-security-baseline.ps1`
|
||||
- 安全基线结果:PASS,生产 `SECRET_KEY` 已改为远端 `.env` 强密钥注入
|
||||
- 安全基线产物:`project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T08-55-24/`
|
||||
- 下一步:Step 5 生产回归闭环
|
||||
- 安全基线最终复验产物:`project-docs/qa-artifacts/phase5-security-baseline/2026-05-01T09-10-28/`
|
||||
- Step 5 已完成:`scripts/run-production-regression.ps1`
|
||||
- 生产回归结果:PASS,阶段 1/2/3 生产关键 E2E 全部通过
|
||||
- 生产回归产物:`project-docs/qa-artifacts/phase5-production-regression/2026-05-01T09-10-34/`
|
||||
- 阶段 5 最终状态:PASS,生产运行、安全、监控、备份、依赖治理与回归已闭环
|
||||
|
||||
---
|
||||
|
||||
## 七、一句话结论
|
||||
|
||||
阶段 5 的核心不是再证明“业务能跑”,而是证明“系统能长期、安全、可恢复地跑”。下一步直接进入生产健康巡检自动化,先把运行状态变成每日可复查的事实。
|
||||
阶段 5 的核心不是再证明“业务能跑”,而是证明“系统能长期、安全、可恢复地跑”。当前阶段 5 已完成闭环,后续应进入常态化巡检、告警接入和发布前门禁固化。
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
param(
|
||||
[string]$WebUrl = "http://192.168.3.90:3003",
|
||||
[string]$ApiUrl = "http://192.168.3.90:8001/api/v1",
|
||||
[string]$HealthUrl = "http://192.168.3.90:8001/health",
|
||||
[string]$ReadinessUrl = "http://192.168.3.90:8001/api/v1/system/readiness",
|
||||
[string]$ArtifactRoot = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||
$frontendDir = Join-Path $repoRoot "frontend"
|
||||
$timestamp = Get-Date -Format "yyyy-MM-ddTHH-mm-ss"
|
||||
if ([string]::IsNullOrWhiteSpace($ArtifactRoot)) {
|
||||
$ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase5-production-regression"
|
||||
}
|
||||
$artifactDir = Join-Path $ArtifactRoot $timestamp
|
||||
$summaryJson = Join-Path $artifactDir "production-regression-summary.json"
|
||||
$summaryMd = Join-Path $artifactDir "production-regression-summary.md"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $artifactDir | Out-Null
|
||||
|
||||
if (-not (Test-Path "$HOME\.Codex\skills\gstack\bin")) {
|
||||
throw "gstack is required for all AI-assisted work in this repo."
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($env:AI_CONTRACT_ADMIN_PASSWORD)) {
|
||||
throw "AI_CONTRACT_ADMIN_PASSWORD must be set for production regression. The value is read from the current process only."
|
||||
}
|
||||
|
||||
$checks = New-Object System.Collections.Generic.List[object]
|
||||
|
||||
function Add-Check {
|
||||
param(
|
||||
[string]$Key,
|
||||
[string]$Label,
|
||||
[ValidateSet("pass", "fail")]
|
||||
[string]$Status,
|
||||
[string]$Detail,
|
||||
[hashtable]$Meta = @{}
|
||||
)
|
||||
|
||||
$checks.Add([ordered]@{
|
||||
key = $Key
|
||||
label = $Label
|
||||
status = $Status
|
||||
required = $true
|
||||
detail = $Detail
|
||||
meta = $Meta
|
||||
}) | Out-Null
|
||||
}
|
||||
|
||||
function Save-Json {
|
||||
param(
|
||||
[string]$Path,
|
||||
[object]$Value
|
||||
)
|
||||
$Value | ConvertTo-Json -Depth 12 | Set-Content -Encoding UTF8 -Path $Path
|
||||
}
|
||||
|
||||
function Invoke-NodePhase {
|
||||
param(
|
||||
[string]$Phase,
|
||||
[string]$ScriptName
|
||||
)
|
||||
|
||||
$phaseArtifactDir = Join-Path $artifactDir $Phase
|
||||
New-Item -ItemType Directory -Force -Path $phaseArtifactDir | Out-Null
|
||||
$logPath = Join-Path $artifactDir "$Phase.log"
|
||||
|
||||
$previous = @{
|
||||
PHASE1_WEB_URL = $env:PHASE1_WEB_URL
|
||||
PHASE1_API_URL = $env:PHASE1_API_URL
|
||||
PHASE1_HEALTH_URL = $env:PHASE1_HEALTH_URL
|
||||
PHASE1_ARTIFACT_DIR = $env:PHASE1_ARTIFACT_DIR
|
||||
PHASE2_WEB_URL = $env:PHASE2_WEB_URL
|
||||
PHASE2_API_URL = $env:PHASE2_API_URL
|
||||
PHASE2_HEALTH_URL = $env:PHASE2_HEALTH_URL
|
||||
PHASE2_ARTIFACT_DIR = $env:PHASE2_ARTIFACT_DIR
|
||||
PHASE3_WEB_URL = $env:PHASE3_WEB_URL
|
||||
PHASE3_API_URL = $env:PHASE3_API_URL
|
||||
PHASE3_HEALTH_URL = $env:PHASE3_HEALTH_URL
|
||||
PHASE3_READINESS_URL = $env:PHASE3_READINESS_URL
|
||||
PHASE3_ARTIFACT_DIR = $env:PHASE3_ARTIFACT_DIR
|
||||
}
|
||||
|
||||
if ($Phase -eq "phase1") {
|
||||
$env:PHASE1_WEB_URL = $WebUrl
|
||||
$env:PHASE1_API_URL = $ApiUrl
|
||||
$env:PHASE1_HEALTH_URL = $HealthUrl
|
||||
$env:PHASE1_ARTIFACT_DIR = $phaseArtifactDir
|
||||
} elseif ($Phase -eq "phase2") {
|
||||
$env:PHASE2_WEB_URL = $WebUrl
|
||||
$env:PHASE2_API_URL = $ApiUrl
|
||||
$env:PHASE2_HEALTH_URL = $HealthUrl
|
||||
$env:PHASE2_ARTIFACT_DIR = $phaseArtifactDir
|
||||
} elseif ($Phase -eq "phase3") {
|
||||
$env:PHASE3_WEB_URL = $WebUrl
|
||||
$env:PHASE3_API_URL = $ApiUrl
|
||||
$env:PHASE3_HEALTH_URL = $HealthUrl
|
||||
$env:PHASE3_READINESS_URL = $ReadinessUrl
|
||||
$env:PHASE3_ARTIFACT_DIR = $phaseArtifactDir
|
||||
}
|
||||
|
||||
Push-Location $frontendDir
|
||||
$previousErrorActionPreference = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
try {
|
||||
$output = & node ".\scripts\$ScriptName" 2>&1
|
||||
$exitCode = $LASTEXITCODE
|
||||
} finally {
|
||||
$ErrorActionPreference = $previousErrorActionPreference
|
||||
Pop-Location
|
||||
foreach ($key in $previous.Keys) {
|
||||
Set-Item -Path "env:$key" -Value $previous[$key] -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
($output -join [Environment]::NewLine) | Set-Content -Encoding UTF8 -Path $logPath
|
||||
return [ordered]@{
|
||||
exit_code = $exitCode
|
||||
log = $logPath
|
||||
artifact_dir = $phaseArtifactDir
|
||||
}
|
||||
}
|
||||
|
||||
$phase1 = Invoke-NodePhase -Phase "phase1" -ScriptName "phase1-closed-loop-e2e.mjs"
|
||||
if ($phase1.exit_code -eq 0) {
|
||||
Add-Check -Key "phase1_production_e2e" -Label "phase1 production E2E" -Status "pass" -Detail "phase1 production E2E passed" -Meta @{ log = $phase1.log; artifact_dir = $phase1.artifact_dir }
|
||||
} else {
|
||||
Add-Check -Key "phase1_production_e2e" -Label "phase1 production E2E" -Status "fail" -Detail "phase1 production E2E failed" -Meta @{ log = $phase1.log; artifact_dir = $phase1.artifact_dir }
|
||||
}
|
||||
|
||||
$phase2 = Invoke-NodePhase -Phase "phase2" -ScriptName "phase2-closed-loop-e2e.mjs"
|
||||
if ($phase2.exit_code -eq 0) {
|
||||
Add-Check -Key "phase2_production_e2e" -Label "phase2 production E2E" -Status "pass" -Detail "phase2 production E2E passed" -Meta @{ log = $phase2.log; artifact_dir = $phase2.artifact_dir }
|
||||
} else {
|
||||
Add-Check -Key "phase2_production_e2e" -Label "phase2 production E2E" -Status "fail" -Detail "phase2 production E2E failed" -Meta @{ log = $phase2.log; artifact_dir = $phase2.artifact_dir }
|
||||
}
|
||||
|
||||
$phase3 = Invoke-NodePhase -Phase "phase3" -ScriptName "phase3-closed-loop-e2e.mjs"
|
||||
if ($phase3.exit_code -eq 0) {
|
||||
Add-Check -Key "phase3_production_e2e" -Label "phase3 production E2E" -Status "pass" -Detail "phase3 production E2E passed" -Meta @{ log = $phase3.log; artifact_dir = $phase3.artifact_dir }
|
||||
} else {
|
||||
Add-Check -Key "phase3_production_e2e" -Label "phase3 production E2E" -Status "fail" -Detail "phase3 production E2E failed" -Meta @{ log = $phase3.log; artifact_dir = $phase3.artifact_dir }
|
||||
}
|
||||
|
||||
$failedRequired = @($checks | Where-Object { $_.status -eq "fail" })
|
||||
$overallStatus = if ($failedRequired.Count -gt 0) { "FAIL" } else { "PASS" }
|
||||
|
||||
$summary = [ordered]@{
|
||||
name = "phase5-production-regression"
|
||||
status = $overallStatus
|
||||
generated_at = (Get-Date).ToUniversalTime().ToString("o")
|
||||
artifact_dir = $artifactDir
|
||||
targets = [ordered]@{
|
||||
web_url = $WebUrl
|
||||
api_url = $ApiUrl
|
||||
health_url = $HealthUrl
|
||||
readiness_url = $ReadinessUrl
|
||||
}
|
||||
checks = $checks
|
||||
totals = [ordered]@{
|
||||
total = $checks.Count
|
||||
failed_required = $failedRequired.Count
|
||||
}
|
||||
}
|
||||
Save-Json -Path $summaryJson -Value $summary
|
||||
|
||||
$markdown = New-Object System.Collections.Generic.List[string]
|
||||
$markdown.Add("# Phase 5 Production Regression") | Out-Null
|
||||
$markdown.Add("") | Out-Null
|
||||
$markdown.Add("- Status: $overallStatus") | Out-Null
|
||||
$markdown.Add("- Generated at: $($summary.generated_at)") | Out-Null
|
||||
$markdown.Add("- Artifact dir: $artifactDir") | Out-Null
|
||||
$markdown.Add("- Web URL: $WebUrl") | Out-Null
|
||||
$markdown.Add("- API URL: $ApiUrl") | Out-Null
|
||||
$markdown.Add("") | Out-Null
|
||||
$markdown.Add("| Check | Required | Status | Detail |") | Out-Null
|
||||
$markdown.Add("|---|---:|---|---|") | Out-Null
|
||||
foreach ($check in $checks) {
|
||||
$markdown.Add("| $($check.label) | $($check.required) | $($check.status.ToUpperInvariant()) | $($check.detail) |") | Out-Null
|
||||
}
|
||||
$markdown.Add("") | Out-Null
|
||||
$markdown.Add("Local artifacts:") | Out-Null
|
||||
$markdown.Add("") | Out-Null
|
||||
$markdown.Add('- `production-regression-summary.json`') | Out-Null
|
||||
$markdown.Add('- `phase1/`') | Out-Null
|
||||
$markdown.Add('- `phase2/`') | Out-Null
|
||||
$markdown.Add('- `phase3/`') | Out-Null
|
||||
$markdown.Add('- `phase*.log`') | Out-Null
|
||||
$markdown | Set-Content -Encoding UTF8 -Path $summaryMd
|
||||
|
||||
Write-Host "PHASE5_PRODUCTION_REGRESSION_$overallStatus $artifactDir"
|
||||
if ($overallStatus -eq "FAIL") {
|
||||
throw "Phase 5 production regression failed. See $summaryMd"
|
||||
}
|
||||
@@ -278,7 +278,13 @@ if ($trackedSensitive) {
|
||||
}
|
||||
|
||||
$secretScanPath = Join-Path $artifactDir "source-secret-scan.txt"
|
||||
$secretScan = git -C $repoRoot grep -n -I -E 'BEGIN (RSA|OPENSSH|PRIVATE) KEY|zmfCSR|AI_CONTRACT_ADMIN_PASSWORD[[:space:]]*=' -- backend frontend scripts docker-compose.server.yml 2>$null
|
||||
$secretPatterns = @(
|
||||
"BEGIN (RSA|OPENSSH|PRIVATE) KEY",
|
||||
("z" + "mfCSR"),
|
||||
("AI_CONTRACT_ADMIN_PASSWORD" + "[[:space:]]*=")
|
||||
)
|
||||
$secretRegex = $secretPatterns -join "|"
|
||||
$secretScan = git -C $repoRoot grep -n -I -E $secretRegex -- backend frontend scripts docker-compose.server.yml 2>$null
|
||||
if ($secretScan) {
|
||||
($secretScan | ForEach-Object { $_ }) | Set-Content -Encoding UTF8 -Path $secretScanPath
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user