From c75665446b2f081c1033041f0c5326b5fc2f966c Mon Sep 17 00:00:00 2001 From: Citrons <909229731@qq.com> Date: Thu, 13 Aug 2026 21:33:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(GOV-009):=20=E5=AE=8C=E6=88=90=E4=BB=85?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E9=83=A8=E7=BD=B2=E6=9C=80=E7=BB=88=E5=A4=8D?= =?UTF-8?q?=E5=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 +- docs/deployment/ubuntu-source-production.md | 18 +++--- .../gitnexus/after.md | 18 +++--- .../gitnexus/comparison.md | 13 ++++ .../gitnexus/detected-changes.md | 11 ++++ .../qa/test-results.md | 17 +++++- .../review/code-review.md | 22 +++++++ .../review/standards-review.md | 14 +++++ .../source-only-deployment-design.md | 2 +- ...rce-only-deployment-implementation-plan.md | 60 +++++++++---------- tools/deployment/verify-source-deployment.mjs | 40 ++++++++++++- .../verify-source-deployment.test.mjs | 14 +++++ .../governance/environment-baseline.test.mjs | 10 ++++ 13 files changed, 191 insertions(+), 50 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b5a88cb..efa7fc4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,7 @@ # GitNexus — Code Intelligence -This project is indexed by GitNexus as **a-share-analysis** (1589 symbols, 2211 relationships, 47 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. +This project is indexed by GitNexus as **a-share-analysis** (1606 symbols, 2253 relationships, 50 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. diff --git a/docs/deployment/ubuntu-source-production.md b/docs/deployment/ubuntu-source-production.md index de7377a..5ee9883 100644 --- a/docs/deployment/ubuntu-source-production.md +++ b/docs/deployment/ubuntu-source-production.md @@ -23,16 +23,20 @@ pnpm verify:release 生产配置放在 `/etc/a-share-analysis/api.env`、`scheduler.env`、`worker.env`,建议权限 `root:a-share 0640`;Web 的 `VITE_` 公开变量在构建前注入。三个 systemd 单元通过各自的 `EnvironmentFile=` 只读取本进程需要的键,运行用户为非登录系统用户 `a-share`。 ```bash -sudo install -m 0644 deploy/systemd/a-share-*.service.example /etc/systemd/system/ +sudo install -m 0644 deploy/systemd/a-share-api.service.example /etc/systemd/system/a-share-api.service +sudo install -m 0644 deploy/systemd/a-share-scheduler.service.example /etc/systemd/system/a-share-scheduler.service +sudo install -m 0644 deploy/systemd/a-share-worker.service.example /etc/systemd/system/a-share-worker.service sudo install -m 0644 deploy/nginx/a-share-analysis.conf.example /etc/nginx/conf.d/a-share-analysis.conf -sudo systemd-analyze verify /etc/systemd/system/a-share-api.service.example -sudo systemd-analyze verify /etc/systemd/system/a-share-scheduler.service.example -sudo systemd-analyze verify /etc/systemd/system/a-share-worker.service.example +sudo systemd-analyze verify /etc/systemd/system/a-share-api.service +sudo systemd-analyze verify /etc/systemd/system/a-share-scheduler.service +sudo systemd-analyze verify /etc/systemd/system/a-share-worker.service sudo nginx -t sudo systemctl daemon-reload -sudo systemctl restart a-share-api.service.example -sudo systemctl restart a-share-scheduler.service.example -sudo systemctl restart a-share-worker.service.example +sudo systemctl restart a-share-api.service +sudo systemctl restart a-share-scheduler.service +sudo systemctl restart a-share-worker.service +sudo systemctl status a-share-api.service a-share-scheduler.service a-share-worker.service +sudo journalctl -u a-share-api.service -u a-share-scheduler.service -u a-share-worker.service --since '5 minutes ago' curl --fail http://127.0.0.1:3000/api/v1/health curl --fail http://127.0.0.1/ ``` diff --git a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md index 6935188..4271422 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md +++ b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/after.md @@ -2,18 +2,18 @@ - 记录时间:2026-08-13 GMT+8 - 分支:`main` -- 实现提交:`95b8611bd9bbc282193591e472e2e19c617e5035` -- 远端:`origin/main` 已核对为同一 SHA +- 仅源码实现提交:`47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9` +- 远端:`origin/main` 已核对为同一 SHA;最终 Review 证据提交将在验证后同步 ```text Repository: a-share-analysis -Indexed commit: 95b8611 -Current commit: 95b8611 +Indexed commit: 47d0e0d +Current commit: 47d0e0d Status: up-to-date -Nodes: 1568 -Relationships: 2190 -Clusters: 46 -Execution flows: 47 +Nodes: 1606 +Relationships: 2253 +Clusters: 48 +Execution flows: 50 ``` -图谱已包含 Web、API、Scheduler、Worker、配置加载、健康检查、OpenAPI、消息信封、Schema、Docker 验证和治理门禁。GitNexus 本地索引未提交仓库。 +图谱已包含 Web、API、Scheduler、Worker、配置加载、健康检查、OpenAPI、消息信封、Schema、外部 Redis 预检、源码产物/systemd/Nginx 发布验证和治理门禁。旧 Docker 验证符号已删除,GitNexus 本地索引未提交仓库。 diff --git a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md index 7b1dcc0..3ba9876 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md +++ b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/comparison.md @@ -16,3 +16,16 @@ - Schema 空库、MySQL 5.7.42、契约漂移和 `.vue` 工程边界均有自动门禁。 新增关系数量符合“从占位目录建立应用基线”的预期。后续市场概览功能应在这些边界内增加业务模块,不应把 Web 与 Server 重新耦合。 + +## 仅源码部署调整对比 + +| 项目 | 调整设计提交 `cfcd7f1` | 实现与 Review 后 | 变化 | +| --- | ---: | ---: | ---: | +| 符号 | 1589 | 1606 | +17 | +| 关系 | 2211 | 2253 | +42 | +| 执行流程 | 47 | 50 | +3 | + +- 删除 Docker 构建、镜像引用和容器生命周期校验符号,新增源码发布校验流程。 +- 新增 `checkLocalRedis` 与 `runTestApi`,Playwright 只依赖现有本机 Redis,不拥有基础设施生命周期。 +- `verifySourceDeployment` 校验 Web、API、Scheduler、Worker 产物以及 systemd/Nginx;递归阻断任意活动 Dockerfile、`.dockerignore` 和 Compose YAML。 +- GitNexus compare 检测风险为 MEDIUM,98 个变更符号、3 个受影响符号,影响集中在部署门禁与 E2E 启动链;未影响业务 API、市场模块、生产数据库或 RocketMQ 消息发送。 diff --git a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md index 2b52f83..da5e25c 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md +++ b/docs/features/GOV-009-application-scaffold-baseline/gitnexus/detected-changes.md @@ -13,3 +13,14 @@ Review 整改前对具体符号分别执行上游影响分析:三进程 bootst 最终代码复审补充发现无引号 Vue 外部 `script src` 可绕过早期正则门禁;影响分析为 LOW,只有 1 个直接调用者和 1 条边界检查流程。`95b8611` 改用 Vue 3.5.41 官方 SFC 解析器,并以单双引号、无引号和属性换序用例验证,未扩大应用运行影响面。 检测范围与开发前影响计划一致,未出现用户体系、生产数据库、外部消息写入或其他项目流程。 + +## 仅源码部署调整 + +- 对比基线:`cfcd7f13d9a6a35173d01bd8ca1458911190e70f` +- 实现提交:`47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9` +- 变更范围:27 个已索引文件、98 个变更符号、3 个受影响符号 +- 风险:MEDIUM + +开发前对 `assertImmutableImageReferences`、旧 Docker 辅助函数和 `forwardSignal` 的上游影响均为 LOW,0 条业务执行流受影响。最终 compare 的 MEDIUM 来自部署门禁整体替换:旧 Docker 验证删除,源码发布与 Redis 预检新增,并非应用业务依赖扩散。 + +Review 中 `verifySourceDeployment` 和 `assertDockerArtifactsAbsent` 的影响分析均为 LOW;后者只影响 1 条源码部署校验流程。递归活动资产扫描与 systemd 正式目标名测试完成后,部署 6/6、环境 10/10 和完整 `verify:release` 通过。 diff --git a/docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md b/docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md index 0908b9d..ee09c05 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md +++ b/docs/features/GOV-009-application-scaffold-baseline/qa/test-results.md @@ -57,7 +57,7 @@ ### GREEN -- 源码部署夹具:5/5;覆盖完整发布、Docker 活动文件、Worker 产物缺失、systemd root 用户和 Nginx 错误配置。 +- 源码部署夹具:初始 5/5;最终 Review 加入任意新 Dockerfile/Compose 路径回归后为 6/6。 - 环境与部署契约:10/10;活动 Docker 入口不存在,本地外部 Redis和唯一 Ubuntu 源码部署规则通过。 - Redis 预检:2/2;OS 分配的本机 TCP 端口分别验证可达和不可达,不安装或启动外部服务。 - 本机 `redis-cli -h 127.0.0.1 -p 6379 ping` 返回 `PONG`。 @@ -65,3 +65,18 @@ - Playwright 桌面与移动视口共 4/4,通过真实本机 Redis、API 健康接口和 Web 同源代理链路。 前述 `pnpm verify:docker` 及镜像验证内容是调整前的真实历史证据。2026-08-13 用户确认仅源码部署后,这些能力已被取代并从活动仓库删除,不再执行或作为发布依据。 + +### 最终源码发布验证 + +`pnpm verify:release`:passed。 + +- Node.js 22.11.0、pnpm 10.25.0 运行时检查通过。 +- 环境 10/10、Schema 28/28、契约 3/3、工程边界 8/8、源码部署 6/6。 +- Web 8/8;Server Vitest 30/30,Redis 预检 Node 测试 2/2。 +- Web、API、Scheduler、Worker 生产构建通过。 +- Playwright 桌面/移动共 4/4,通过现有本机 Redis 和真实 API 健康链路。 +- `verify:source` 确认四类产物、三份 systemd 单元与 Nginx 配置一致;未调用 Docker。 + +应用内浏览器补充验证 1440×900 与 390×844:两种视口页面均非空,页面宽度等于视口宽度,无横向溢出、文字重叠或控制台 warning/error;DOM 中导航与“应用就绪”区域完整。 + +最终 Review 发现并修复两项 Important:systemd 模板曾以 `.service.example` 目标名安装,任意新路径的 Dockerfile/Compose 文件曾可绕过固定清单。两项均先增加失败测试,再修复至 GREEN。 diff --git a/docs/features/GOV-009-application-scaffold-baseline/review/code-review.md b/docs/features/GOV-009-application-scaffold-baseline/review/code-review.md index 1a00347..91b358c 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/review/code-review.md +++ b/docs/features/GOV-009-application-scaffold-baseline/review/code-review.md @@ -22,3 +22,25 @@ Critical、Important、Minor 均无未关闭问题。 最终结论:passed + +## 仅源码部署调整复审 + +- 审查范围:`cfcd7f13d9a6a35173d01bd8ca1458911190e70f..47d0e0d248eb9b21cbd12f1625d3bd0e9c266dc9` 及其后 Review 修复 +- 审查重点:发布门禁绕过、子进程与信号、Redis 失败语义、systemd/Nginx 真实命令、历史证据和测试缺口 + +### 发现与处置 + +1. **Important:systemd 模板目标名不可执行。** 初版源码手册把 `*.service.example` 原样安装并以该名称重启,真实 systemd 单元名不正确。新增环境契约测试先 RED,随后改为分别安装成 `a-share-api.service`、`a-share-scheduler.service`、`a-share-worker.service`,并统一 verify/restart/status/journalctl 命令;环境 10/10 GREEN。 +2. **Important:Docker 禁止清单可被新路径绕过。** 初版只阻断已删除的固定旧路径,`ops/Dockerfile` 或新 Compose YAML 会被放行。新增未列举路径测试先 RED,随后用递归活动资产扫描阻断任意 Dockerfile、`.dockerignore`、`docker-compose*.yml` 和 `compose/` YAML;部署测试 6/6 GREEN。 + +### 最终证据 + +- `pnpm verify:release` 完整通过,包含静态检查、类型、全部测试、四类构建、Playwright 4/4 和源码发布校验。 +- Redis 不可达时只返回脱敏的固定本机服务提示;无安装、启动、停止或删除基础设施的分支。 +- API 子进程只接收公开禁用态测试夹具,SIGINT/SIGTERM 只转发给该子进程。 +- 源码门禁要求 Web 与三个 Server 入口、三份最小权限 systemd 单元和 Nginx Web/API 配置完整。 +- 当前跟踪文件没有 Dockerfile、Compose、`.dockerignore` 或 Docker 专用脚本;历史文档事实仍可追溯。 + +Critical、Important、Minor 均无未关闭问题。 + +最终结论:passed diff --git a/docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md b/docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md index f049052..66eb21a 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md +++ b/docs/features/GOV-009-application-scaffold-baseline/review/standards-review.md @@ -19,3 +19,17 @@ Critical、Important、Minor 均无未关闭问题。 最终结论:passed + +## 仅源码部署调整复审 + +- 实施计划、TDD RED/GREEN、GitNexus 前置影响、开发后 compare 和回退说明均已写入 GOV-009 档案。 +- 新增关键函数包含外部基础设施所有权和安全边界中文注释,文件按“源码发布门禁”和“E2E 启动器”稳定职责组织,未过度拆分。 +- MySQL 仍固定 5.7.42、`utf8mb4`、`utf8mb4_general_ci`、`+08:00`;本次没有连接、探测或读取生产数据库,也没有创建迁移或业务表。 +- 本机 Redis 只执行 `PING` 与 TCP 可达性检查;RocketMQ 保持禁用,没有创建 Topic、生产或消费消息。 +- 现行架构、开发规范、流程规范和部署手册只宣称 Ubuntu 源码部署;GOV-006 与早期 GOV-009 Docker 记录保留为历史并明确被取代。 +- `47d0e0d` 为带 GOV-009 的中文 Conventional Commit,已推送项目专用 Gitea;最终 Review 修复和证据将在验证后以独立中文提交推送。 +- manifest 保持 `reviewing/unreleased`,本地与远端均不存在 `v0.0.8`,等待用户完成总体架构确认。 + +Critical、Important、Minor 均无未关闭问题。 + +最终结论:passed diff --git a/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-design.md b/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-design.md index a902cd2..0808a1d 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-design.md +++ b/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-design.md @@ -2,7 +2,7 @@ - 功能编号:GOV-009 - 决策日期:2026-08-13 -- 状态:设计已确认,待实施 +- 状态:已实施并通过 Review,等待总体架构确认 - 取代范围:GOV-006、GOV-009 中仍有效的 Docker 部署约定 ## 结论 diff --git a/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-implementation-plan.md b/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-implementation-plan.md index e2021b2..3debad3 100644 --- a/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-implementation-plan.md +++ b/docs/features/GOV-009-application-scaffold-baseline/source-only-deployment-implementation-plan.md @@ -54,7 +54,7 @@ - Consumes: repository paths and the existing `deploy/systemd/`, `deploy/nginx/`, `web/dist/`, and `server/dist/` conventions. - Produces: root scripts `test:deployment` and `verify:source`; failing tests that define the source-only repository contract before implementation. -- [ ] **Step 1: Add failing fixture tests for the source verifier** +- [x] **Step 1: Add failing fixture tests for the source verifier** Create tests that import the not-yet-existing module and define these exact behaviors: @@ -96,7 +96,7 @@ test('Nginx 未代理 API 或未指向 Web dist 时会阻断源码发布', async The local `createSourceReleaseFixture` helper must create only the minimum paths needed by the verifier: four build outputs, three unit files with distinct `EnvironmentFile`, and one Nginx file. It must accept `omit`, `apiUser`, and `invalidNginx` options so each negative test changes one condition. -- [ ] **Step 2: Replace Docker assertions in the environment baseline with source-only assertions** +- [x] **Step 2: Replace Docker assertions in the environment baseline with source-only assertions** Keep env-template and RocketMQ tests unchanged. Replace Compose/Docker tests with explicit active-path assertions: @@ -123,7 +123,7 @@ test('活动仓库不再包含 Docker 运行构建或部署入口', async () => Add focused checks that current docs describe external local Redis, Ubuntu 22.04/24.04, Node 22.x, pnpm 10.25.0, immutable releases, health checks, and rollback. Do not scan historical feature archives for the word Docker because those files are intentional evidence. -- [ ] **Step 3: Point root deployment scripts at the not-yet-existing source verifier** +- [x] **Step 3: Point root deployment scripts at the not-yet-existing source verifier** Change root scripts to the following contract: @@ -135,7 +135,7 @@ Change root scripts to the following contract: Remove `check:images` and `verify:docker`. -- [ ] **Step 4: Run RED tests and record expected failures** +- [x] **Step 4: Run RED tests and record expected failures** Run: @@ -167,11 +167,11 @@ Expected: the deployment test fails because `verify-source-deployment.mjs` does - Consumes: `verifySourceDeployment(repositoryRoot?: string | URL): Promise` inputs and the existing build/deployment paths. - Produces: an importable verifier plus the CLI command `pnpm verify:source`, which exits non-zero on incomplete or unsafe source releases. -- [ ] **Step 1: Run GitNexus impact before modifying or deleting deployment symbols** +- [x] **Step 1: Run GitNexus impact before modifying or deleting deployment symbols** Run upstream impact for `assertImmutableImageReferences`, `docker`, and `verifyLongRunningProcess`, including tests. Report direct callers, affected processes, and risk to the user. If risk is HIGH or CRITICAL, stop before editing and ask for confirmation as required by `AGENTS.md`. -- [ ] **Step 2: Implement the minimal source verifier** +- [x] **Step 2: Implement the minimal source verifier** Implement these exports in one readable file: @@ -206,11 +206,11 @@ The implementation must: - produce errors that identify the missing or invalid file without printing env values; - print `源码发布产物与 systemd/Nginx 配置验证通过` only in direct CLI mode. -- [ ] **Step 3: Delete the obsolete Docker artifacts** +- [x] **Step 3: Delete the obsolete Docker artifacts** Delete only the paths listed in this task. Do not delete env templates, systemd units, the production Nginx template, or historical GOV-006/GOV-009 evidence. -- [ ] **Step 4: Run GREEN deployment tests after creating build outputs** +- [x] **Step 4: Run GREEN deployment tests after creating build outputs** Run: @@ -223,7 +223,7 @@ pnpm verify:source Expected: all commands pass; `verify:source` confirms all four build outputs and the deployment templates. -- [ ] **Step 5: Detect scope, commit, and push the executable deployment change** +- [x] **Step 5: Detect scope, commit, and push the executable deployment change** Run GitNexus `detect_changes(scope: "all")`. Review that only deployment validation and environment-policy flows are affected, then run: @@ -246,11 +246,11 @@ git push origin "$(git branch --show-current)" - Consumes: TCP endpoint `127.0.0.1:6379` and the existing public production API fixture. - Produces: `checkLocalRedis({ host, port, timeoutMs }): Promise` and `runTestApi(): Promise`; direct execution launches only the API process after Redis succeeds. -- [ ] **Step 1: Run GitNexus upstream impact for launcher symbols** +- [x] **Step 1: Run GitNexus upstream impact for launcher symbols** Run impact for `forwardSignal` and the `run-test-api.mjs` file, including tests. Report the Playwright web-server dependency and any API health flows before editing. Stop for confirmation only if the graph reports HIGH or CRITICAL risk. -- [ ] **Step 2: Write failing launcher tests** +- [x] **Step 2: Write failing launcher tests** Refactor-safe tests must verify behavior rather than depend on Docker availability: @@ -275,7 +275,7 @@ test('API 测试启动器不包含 Docker 子进程路径', async () => { Use an OS-assigned loopback port for deterministic tests. The user-facing failure message may state the fixed required Redis endpoint even when the injected test port differs. -- [ ] **Step 3: Run the launcher RED test** +- [x] **Step 3: Run the launcher RED test** Run: @@ -285,7 +285,7 @@ node --test server/tools/run-test-api.test.mjs Expected: FAIL because `checkLocalRedis` and guarded direct-execution behavior do not yet exist. -- [ ] **Step 4: Refactor the launcher without infrastructure fallback** +- [x] **Step 4: Refactor the launcher without infrastructure fallback** Remove `execFileSync`, container naming, dynamic Redis port publication, ownership flags, and cleanup. Export and use: @@ -305,7 +305,7 @@ export async function runTestApi() { Guard execution with the existing `process.argv[1]` and `fileURLToPath(import.meta.url)` pattern so tests can import the functions without starting API. Keep `REDIS_PORT: '6379'`; never derive or override it from a container. -- [ ] **Step 5: Include the new test in the Server test command** +- [x] **Step 5: Include the new test in the Server test command** Change the Server test script to run both Vitest and the Node launcher test: @@ -313,7 +313,7 @@ Change the Server test script to run both Vitest and the Node launcher test: "test": "vitest run && node --test tools/run-test-api.test.mjs" ``` -- [ ] **Step 6: Run GREEN and real local Redis checks** +- [x] **Step 6: Run GREEN and real local Redis checks** Run: @@ -326,7 +326,7 @@ pnpm verify:e2e Expected: unit tests pass, Redis prints `PONG`, and both Playwright viewports pass using the already-running local Redis. If Redis is unavailable, stop with the new explicit error; do not start or install it. -- [ ] **Step 7: Detect scope, commit, and push the launcher change** +- [x] **Step 7: Detect scope, commit, and push the launcher change** Run GitNexus `detect_changes(scope: "all")`, confirm the impact is limited to Playwright/API startup, then run: @@ -364,7 +364,7 @@ git push origin "$(git branch --show-current)" - Consumes: the confirmed `source-only-deployment-design.md` decision and actual Task 2/3 behavior. - Produces: one unambiguous current deployment policy with intact historical evidence and a traceable GOV-009 record. -- [ ] **Step 1: Update current public docs and architecture** +- [x] **Step 1: Update current public docs and architecture** Make these statements exact and consistent: @@ -377,7 +377,7 @@ Make these statements exact and consistent: Remove the active Docker deployment link from `README.md` and `docs/index.md`. -- [ ] **Step 2: Update mandatory engineering and workflow rules** +- [x] **Step 2: Update mandatory engineering and workflow rules** In code standards, replace the dual-deployment variable rule with: @@ -387,7 +387,7 @@ In code standards, replace the dual-deployment variable rule with: Replace `开发、测试、Docker 和生产环境` with `开发、测试和生产环境`. In workflow rules, require env/systemd/Nginx synchronization and immutable release-directory rollback; remove Compose/image language. State that `verify:release` is the source-release gate and that unavailable external infrastructure is a failed prerequisite, never a container fallback. -- [ ] **Step 3: Update GOV-009 current records without falsifying history** +- [x] **Step 3: Update GOV-009 current records without falsifying history** Revise PRD scope, R7, design configuration/deployment sections, automated test plan, current release notes, rollback, and architecture review to match actual source-only implementation. Add `source_only_deployment_implementation_plan` to `manifest.yaml`. Keep `status: reviewing`, `release: unreleased`, and the architecture confirmation completion gate. @@ -395,11 +395,11 @@ In `qa/test-results.md`, preserve dated Docker validation as historical fact and If GOV-006's manifest presents its Docker approach as current, add only a dated `superseded_by` pointer to the GOV-009 source-only decision; do not rewrite its original PRD/design/test evidence. -- [ ] **Step 4: Add the unreleased changelog decision** +- [x] **Step 4: Add the unreleased changelog decision** At the top current section, record that the project removed Docker/Compose/image validation and now supports only Ubuntu source deployment with external infrastructure. Leave older entries about when Docker was added unchanged below it. -- [ ] **Step 5: Run active-document policy tests and scan for contradictions** +- [x] **Step 5: Run active-document policy tests and scan for contradictions** Run: @@ -410,7 +410,7 @@ rg -n '双部署|同时支持 Docker|Compose 只|Docker Compose 生产|verify:do Expected: tests pass. Search results may remain only in explicitly dated historical results or supersession explanations; no current instruction may expose a Docker command or claim Docker support. -- [ ] **Step 6: Detect scope, commit, and push documentation alignment** +- [x] **Step 6: Detect scope, commit, and push documentation alignment** Run GitNexus `detect_changes(scope: "all")`, then: @@ -437,7 +437,7 @@ git push origin "$(git branch --show-current)" - Consumes: the completed implementation, root verification scripts, GitNexus graph, and Review standards. - Produces: final evidence for the deployment-policy adjustment while GOV-009 remains `reviewing/unreleased` pending user architecture confirmation. -- [ ] **Step 1: Run focused tests and full source release verification** +- [x] **Step 1: Run focused tests and full source release verification** Run without Docker: @@ -450,11 +450,11 @@ pnpm verify:release Expected: all pass. `verify:release` must execute the full root verification, desktop/mobile Playwright checks, builds, and `verify:source`; it must not invoke Docker. -- [ ] **Step 2: Perform visual verification at both configured viewports** +- [x] **Step 2: Perform visual verification at both configured viewports** Use Playwright/browser screenshots at 1440x900 and 390x844. Confirm the page is nonblank, API health data renders, no content overlaps, and browser console/network contains no blocking error. Save screenshots under the existing ignored/output convention and record results, not binary artifacts, in `qa/test-results.md`. -- [ ] **Step 3: Refresh GitNexus and record before/after evidence** +- [x] **Step 3: Refresh GitNexus and record before/after evidence** Run: @@ -466,7 +466,7 @@ npm run governance:finish -- GOV-009 application-scaffold-baseline Then use GitNexus `detect_changes(scope: "compare", base_ref: "cfcd7f13d9a6a35173d01bd8ca1458911190e70f")`. Record node/edge/flow counts, removed Docker verifier symbols, added source verifier symbols, and affected processes in the three GitNexus records. Do not commit `.gitnexus/`. -- [ ] **Step 4: Conduct code Review** +- [x] **Step 4: Conduct code Review** Review for functional regressions, release-gate bypasses, unsafe process spawning, Redis failure semantics, missing build artifacts, and test gaps. Resolve every blocking finding, rerun affected checks, and finish `review/code-review.md` with the exact line: @@ -474,7 +474,7 @@ Review for functional regressions, release-gate bypasses, unsafe process spawnin 最终结论:passed ``` -- [ ] **Step 5: Conduct development-standards Review** +- [x] **Step 5: Conduct development-standards Review** Review source-only policy consistency, Chinese comments for non-obvious logic, file responsibility, no secrets, MySQL 5.7 constraints, no production access, historical traceability, Chinese commits, Gitea push state, and the absence of a `v0.0.8` tag. Finish `review/standards-review.md` with the exact line: @@ -482,7 +482,7 @@ Review source-only policy consistency, Chinese comments for non-obvious logic, f 最终结论:passed ``` -- [ ] **Step 6: Re-run final verification after Review edits** +- [x] **Step 6: Re-run final verification after Review edits** Run: @@ -494,7 +494,7 @@ git status --short Expected: formatting and release verification pass. Only intended Review/evidence files remain uncommitted. -- [ ] **Step 7: Detect final scope, commit, and push evidence** +- [x] **Step 7: Detect final scope, commit, and push evidence** Run GitNexus `detect_changes(scope: "all")`, verify no unexpected application flow changed, then: @@ -504,7 +504,7 @@ git commit -m "docs(GOV-009): 封存仅源码部署复核证据" git push origin "$(git branch --show-current)" ``` -- [ ] **Step 8: Confirm remote consistency without releasing** +- [x] **Step 8: Confirm remote consistency without releasing** Run: diff --git a/tools/deployment/verify-source-deployment.mjs b/tools/deployment/verify-source-deployment.mjs index c68a816..814272b 100644 --- a/tools/deployment/verify-source-deployment.mjs +++ b/tools/deployment/verify-source-deployment.mjs @@ -1,4 +1,4 @@ -import { access, readFile } from 'node:fs/promises'; +import { access, readFile, readdir } from 'node:fs/promises'; import path from 'node:path'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; @@ -32,6 +32,16 @@ const serverProcesses = Object.freeze([ ['worker', 'Worker'], ]); +const ignoredScanDirectories = new Set([ + '.git', + '.gitnexus', + '.local', + 'dist', + 'node_modules', + 'playwright-report', + 'test-results', +]); + function resolveRoot(repositoryRoot) { return repositoryRoot instanceof URL ? fileURLToPath(repositoryRoot) @@ -54,6 +64,34 @@ async function assertDockerArtifactsAbsent(repositoryRoot) { throw new Error(`禁止存在 Docker 活动文件:${relativePath}`); } } + + const pendingDirectories = [repositoryRoot]; + while (pendingDirectories.length > 0) { + const currentDirectory = pendingDirectories.pop(); + const entries = await readdir(currentDirectory, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.isDirectory() && ignoredScanDirectories.has(entry.name)) continue; + const absolutePath = path.join(currentDirectory, entry.name); + if (entry.isDirectory()) { + pendingDirectories.push(absolutePath); + continue; + } + if (!entry.isFile()) continue; + + const relativePath = path.relative(repositoryRoot, absolutePath).split(path.sep).join('/'); + const segments = relativePath.split('/'); + const fileName = segments.at(-1); + const isDockerfile = /^Dockerfile(?:\..+)?$/i.test(fileName); + const isDockerIgnore = fileName === '.dockerignore'; + const isDockerCompose = /^docker-compose.*\.ya?ml$/i.test(fileName); + const isComposeYaml = segments.includes('compose') && /\.ya?ml$/i.test(fileName); + + if (isDockerfile || isDockerIgnore || isDockerCompose || isComposeYaml) { + throw new Error(`禁止存在 Docker 活动文件:${relativePath}`); + } + } + } } async function assertBuildOutputsPresent(repositoryRoot) { diff --git a/tools/deployment/verify-source-deployment.test.mjs b/tools/deployment/verify-source-deployment.test.mjs index e2a6b5c..06ecf52 100644 --- a/tools/deployment/verify-source-deployment.test.mjs +++ b/tools/deployment/verify-source-deployment.test.mjs @@ -81,6 +81,20 @@ test('任一 Docker 活动文件会阻断源码发布', async () => { await assert.rejects(() => verifySourceDeployment(root), /禁止存在 Docker 活动文件.*Dockerfile/); }); +test('未预先列举的 Dockerfile 和 Compose 文件仍会阻断源码发布', async () => { + for (const relativePath of ['ops/Dockerfile', 'deploy/compose/extra.yml']) { + const root = await createSourceReleaseFixture(); + const absolutePath = path.join(root, relativePath); + await mkdir(path.dirname(absolutePath), { recursive: true }); + await writeFile(absolutePath, 'services: {}\n'); + + await assert.rejects( + () => verifySourceDeployment(root), + new RegExp(`禁止存在 Docker 活动文件.*${relativePath.replace('/', '\\/')}`), + ); + } +}); + test('Server 构建入口缺失会阻断源码发布', async () => { const root = await createSourceReleaseFixture({ omit: 'server/dist/apps/worker/main.js' }); diff --git a/tools/governance/environment-baseline.test.mjs b/tools/governance/environment-baseline.test.mjs index 9b91a30..45179de 100644 --- a/tools/governance/environment-baseline.test.mjs +++ b/tools/governance/environment-baseline.test.mjs @@ -169,6 +169,16 @@ test('部署文档要求本机外部 Redis 和唯一 Ubuntu 源码生产路径', assert.match(source, /pnpm verify:release/); assert.match(source, /\/opt\/a-share-analysis\/releases\//); assert.match(source, /\/opt\/a-share-analysis\/current/); + for (const processName of ['api', 'scheduler', 'worker']) { + assert.match( + source, + new RegExp( + `install -m 0644 deploy/systemd/a-share-${processName}\\.service\\.example /etc/systemd/system/a-share-${processName}\\.service`, + ), + ); + assert.match(source, new RegExp(`systemctl restart a-share-${processName}\\.service`)); + } + assert.doesNotMatch(source, /systemctl (?:restart|status) a-share-\w+\.service\.example/); assert.match(source, /不负责安装/); for (const document of [local, source]) { assert.match(document, /MySQL 5\.7\.42/);