沉淀生产收口规约与清理证据(07-15-production-trust-closeout-cleanup)
这个提交包含在:
@@ -169,3 +169,128 @@ if (acknowledgementCount > 0) {
|
||||
throw new AppError({ code: "VALID_001", message: "参数校验失败", statusCode: 409 });
|
||||
}
|
||||
```
|
||||
|
||||
## Scenario: Safe Development Seed
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: changing or running `server/src/scripts/seed-dev.js`, its safety
|
||||
guard, development account defaults or the `seed:dev` npm command.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Command: `SEED_DEV_ALLOW=1 SEED_DEV_DATABASE_CONFIRM=<db> npm run seed:dev`.
|
||||
- Optional reset: `SEED_DEV_RESET_PASSWORDS=1`.
|
||||
- Target: `DATABASE_URL` parsed with the same `pg` semantics used by Prisma's
|
||||
PostgreSQL adapter.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- `NODE_ENV=production` is permanently refused.
|
||||
- The explicit allow switch and exact database-name confirmation are both
|
||||
required.
|
||||
- The effective PostgreSQL host, including query-string overrides, must be
|
||||
loopback; checking only the URI authority is insufficient.
|
||||
- Existing passwords are preserved by default. Newly created accounts and
|
||||
explicitly rotated accounts set `must_change_password=true`.
|
||||
- The guard and seed logs never print credentials, complete targets or account
|
||||
passwords.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Production -> `production_forbidden`.
|
||||
- Missing allow switch -> `explicit_allow_required`.
|
||||
- Invalid/non-PostgreSQL URL -> `database_url_invalid` or
|
||||
`database_protocol_invalid`.
|
||||
- Effective non-loopback host, including `?host=...` ->
|
||||
`database_host_not_local`.
|
||||
- Missing/mismatched confirmation -> `database_confirmation_mismatch`.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: loopback test database, exact confirmation, new accounts require a
|
||||
password change.
|
||||
- Base: rerun without reset preserves existing password hashes.
|
||||
- Bad: accept `postgresql://[email protected]/db?host=remote.internal` because only
|
||||
`URL.hostname` was checked.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Pure guard tests for production, missing allow, remote authority, host-query
|
||||
override, exact confirmation and redacted errors.
|
||||
- Unit tests for existing-password preservation, explicit rotation and new
|
||||
account first-login change.
|
||||
- Do not validate refusal paths by connecting to a real database.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```js
|
||||
if (new URL(env.DATABASE_URL).hostname === "127.0.0.1") allowSeed();
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```js
|
||||
const client = new Client({ connectionString: env.DATABASE_URL });
|
||||
if (!LOOPBACK_HOSTS.has(client.host)) refuse("database_host_not_local");
|
||||
```
|
||||
|
||||
## Scenario: Database-Free App Contract Tests
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: unit tests call the production `buildApp()` factory to verify health,
|
||||
readiness, static serving or other app-level contracts in CI without a DB.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Production: `buildApp()`.
|
||||
- Test seam: `buildApp({ prismaPlugin, startJobs })`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Omitted dependencies always use the production Prisma plugin and job starter.
|
||||
- Unit tests inject a `fastify-plugin`-wrapped Prisma decorator and a no-op job
|
||||
starter; they must not rely on ESM `vi.mock` intercepting a CJS `require`.
|
||||
- App-level test doubles expose only methods used by the tested requests.
|
||||
- `DATABASE_URL='' JWT_SECRET=''` must not make isolated app tests access a
|
||||
developer `.env` or local PostgreSQL instance.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Production call with missing DB target -> normal startup refusal.
|
||||
- Test call with injected Prisma plugin -> no production client construction.
|
||||
- Test double missing a method exercised by the request -> focused unit failure.
|
||||
- Injected dependencies leaking into `buildApp()` callers without options ->
|
||||
contract regression.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: health/static tests inject Prisma and pass with empty DB/JWT process
|
||||
variables after setting their own test JWT.
|
||||
- Base: API/Worker call `buildApp()` without options and retain production wiring.
|
||||
- Bad: a hoisted `vi.mock("../prismaClient")` appears green only because a local
|
||||
`.env` database is reachable.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Run health and static tests with `DATABASE_URL='' JWT_SECRET=''`.
|
||||
- Run the full `scripts/check-minimal.sh` under the same empty environment.
|
||||
- Keep the production default path covered by normal startup/smoke checks.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```js
|
||||
vi.mock("../../src/prismaClient", () => ({ createPrismaClient: fake }));
|
||||
await buildApp(); // CJS plugin may still construct the real client
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```js
|
||||
await buildApp({ prismaPlugin: testPrismaPlugin, startJobs: noOpStartJobs });
|
||||
```
|
||||
|
||||
@@ -263,3 +263,87 @@ const REQUIRED_MAIN_NAV_KEYS = [
|
||||
const REQUIRED_BACKUP_NAV_KEYS = ["weeklyReports", "announcements"];
|
||||
const REQUIRED_ADMIN_NAV_KEYS = ["systemSettings"];
|
||||
```
|
||||
|
||||
## Scenario: Immutable Deployment Provenance And Dual Build SHA
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: changing the trialrun deployment entry, Docker build, Compose
|
||||
wiring, `/health` or `/ready`, public bundle scanning or live readiness.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Provenance gate: `node deploy/trialrun/check-source-provenance.mjs`.
|
||||
- Standard release: `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`.
|
||||
- Build/runtime inputs: `BUILD_SHA=<full-commit>` and
|
||||
`VITE_BUILD_SHA=<12-char-commit>`.
|
||||
- Runtime outputs: `/health.data.buildSha`, `/ready.data.buildSha` and the
|
||||
frontend `html[data-build-sha]` marker.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Deployment rejects tracked and untracked dirty files before synchronization.
|
||||
- By default HEAD must be contained in its upstream. The explicit unpublished
|
||||
override is for controlled offline recovery and never relaxes clean-tree.
|
||||
- Standard deployment refreshes the configured upstream remote before the
|
||||
ancestor check; a stale local remote-tracking ref is not publication proof.
|
||||
- Unpublished override requires an allowlisted `DEPLOY_UNPUBLISHED_REASON` and
|
||||
must emit an `UNPUBLISHED-OVERRIDE` audit line.
|
||||
- Synchronization comes from `git archive <verified-commit>`, not the working
|
||||
tree.
|
||||
- Full `BUILD_SHA` is injected at build and runtime; `VITE_BUILD_SHA` is
|
||||
normalized before bundling so only 12 characters become public.
|
||||
- Neither build key is persisted in `deploy/trialrun/.env`; direct Compose use
|
||||
must explicitly provide both and must not publish `unknown`.
|
||||
- Deployment compares public `/ready` and the public bundle marker with the
|
||||
verified commit before reporting success.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Dirty tree -> `dirty_worktree`, deployment stops.
|
||||
- No upstream or commit absent from upstream -> stop unless the explicit
|
||||
unpublished override is approved.
|
||||
- Upstream refresh fails -> stop in standard mode; override mode requires an
|
||||
allowlisted reason and records `remoteVerified=false`.
|
||||
- Missing runtime/build SHA input -> Compose interpolation fails.
|
||||
- `/ready` SHA mismatch, bundle marker missing or full SHA exposed -> deployment
|
||||
fails.
|
||||
- Standalone readiness missing/mismatching observed SHA -> non-clean finding.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: clean published commit -> Git archive -> dual-SHA build -> matching
|
||||
backend and public bundle checks.
|
||||
- Base: local development build uses `unknown` but is never represented as a
|
||||
release.
|
||||
- Bad: rsync the current working tree or let `.env` override the image's SHA
|
||||
with `unknown`.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Temp-repo provenance tests for dirty, missing upstream, published and
|
||||
unpublished-override cases, including a stale remote-tracking ref after a
|
||||
forced remote update.
|
||||
- `node deploy/trialrun/validate-env-contract.js` and Compose config with both
|
||||
SHA inputs.
|
||||
- Synthetic 40-character build: bundle contains the matching 12-character SHA
|
||||
and not the full value.
|
||||
- Local-stub readiness test for expected/observed SHA propagation.
|
||||
- Public deployment still requires separate approval and post-deploy checks.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```bash
|
||||
rsync -az --delete ./ remote:/app
|
||||
docker compose up -d --build server
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```bash
|
||||
node deploy/trialrun/check-source-provenance.mjs
|
||||
BUILD_SHA=<verified-full-sha> VITE_BUILD_SHA=<matching-short-sha> \
|
||||
docker compose -f deploy/trialrun/docker-compose.yml build server
|
||||
```
|
||||
|
||||
@@ -36,6 +36,9 @@ Start from `docs/文档索引.md` and `docs/文档事实源状态矩阵.md`.
|
||||
- Use repo-relative `reportRef` / `logRef` when a path is inside the repo.
|
||||
- Do not write absolute local workspace paths into `summary.json`.
|
||||
- Parent summaries must include child report status and child finding counts.
|
||||
- Live-readiness summaries must distinguish the local `sourceCommit` from the
|
||||
public `observedBuildSha`; a missing or mismatched public build marker cannot
|
||||
produce a clean pass.
|
||||
- Parent `findingCount` must become non-zero when any child summary reports
|
||||
`PASS_WITH_FINDINGS`, `SKIP`, `PARTIAL`, `PAUSED`, `MISSING`, blocker-like
|
||||
status or child `findingCount > 0`.
|
||||
@@ -47,6 +50,8 @@ Start from `docs/文档索引.md` and `docs/文档事实源状态矩阵.md`.
|
||||
- Credential/readiness presence reports must use safe business labels, not raw
|
||||
env key names. For example, emit `adminCredentialReady: true` instead of a
|
||||
field named after a credential-value environment variable.
|
||||
- `check-pending-ocr.mjs` must reuse the adapter-backed Prisma client factory
|
||||
and close both Prisma and its external PostgreSQL pool.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
@@ -60,11 +65,15 @@ Start from `docs/文档索引.md` and `docs/文档事实源状态矩阵.md`.
|
||||
summary reflect the failure.
|
||||
- Secret-like field names in generated reports -> privacy finding, even when
|
||||
the value is only a boolean presence flag.
|
||||
- Public `/ready` has no usable build SHA -> `manual_or_config` finding.
|
||||
- Expected and observed public SHA differ -> `manual_or_config` finding or a
|
||||
deployment blocker; never a clean pass attributed to local HEAD.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: `summary.json` contains `reportRef`, `childReports.<name>.status`,
|
||||
`childReports.<name>.findingCount` and no absolute local path.
|
||||
`childReports.<name>.findingCount`, `sourceCommit`, `observedBuildSha` and no
|
||||
absolute local path.
|
||||
- Base: Missing runtime credentials produce `PASS_WITH_FINDINGS` or
|
||||
`manual_or_config`, not a clean pass.
|
||||
- Bad: Parent command exits 0 for a child `PASS_WITH_FINDINGS` and the parent
|
||||
@@ -81,6 +90,9 @@ Start from `docs/文档索引.md` and `docs/文档事实源状态矩阵.md`.
|
||||
- For live/readiness env reports, assert the JSON contains safe readiness
|
||||
labels and does not contain raw secret-like env key names.
|
||||
- Run the matching launch/readiness aggregator when it consumes the report.
|
||||
- Build a synthetic 40-character SHA and assert the public bundle contains only
|
||||
its 12-character marker; use a local HTTP stub to assert readiness records and
|
||||
matches the observed marker.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
@@ -107,6 +119,9 @@ Start from `docs/文档索引.md` and `docs/文档事实源状态矩阵.md`.
|
||||
```json
|
||||
{
|
||||
"status": "PASS_WITH_FINDINGS",
|
||||
"sourceCommit": "abcdef1234567890",
|
||||
"observedBuildSha": "abcdef123456",
|
||||
"buildShaMatches": true,
|
||||
"reportRef": "artifacts/qa-flow/run",
|
||||
"childReports": {
|
||||
"oaOnlySmokeReadiness": {
|
||||
|
||||
@@ -13,8 +13,9 @@ tasks after TRELLIS2.
|
||||
- Put goal, scope, out-of-scope, acceptance and test plan in `prd.md`.
|
||||
- Add `design.md` or `implement.md` for complex process, API, migration,
|
||||
permission, deployment or workflow-governance changes.
|
||||
- Curate `implement.jsonl` and `check.jsonl` with stable spec or research
|
||||
context only.
|
||||
- In sub-agent dispatch mode, curate `implement.jsonl` and `check.jsonl` with
|
||||
stable spec or research context only. In Codex inline mode they may contain
|
||||
no real entries because the main session reads specs directly.
|
||||
- Give a concrete implementation plan before coding and wait for approval.
|
||||
- Keep edits scoped to the current Trellis task.
|
||||
- Commit in Chinese and include the Trellis task name or task ID.
|
||||
@@ -60,3 +61,62 @@ rollback and future self-maintenance.
|
||||
- Do not delete, bulk rewrite or move historical `issues/*.csv` files.
|
||||
- New work may mention an old Issue CSV for traceability, but must not require
|
||||
a new CSV unless the user explicitly requests legacy/export evidence.
|
||||
|
||||
## Scenario: Codex Inline Context Manifests
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: creating, validating or finishing a Trellis task while
|
||||
`.trellis/config.yaml` sets `codex.dispatch_mode: inline`.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Config: `codex.dispatch_mode: inline | sub-agent`.
|
||||
- Context files: `<task>/implement.jsonl`, `<task>/check.jsonl`.
|
||||
- Gates: `node scripts/qa/check-trellis-governance.mjs` and
|
||||
`python3 ./.trellis/scripts/task.py validate <task>`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Inline mode may keep both JSONL files at zero real entries; the seed
|
||||
`_example` row does not count as injected context.
|
||||
- If an inline task contains real entries, each entry must still be valid JSON
|
||||
with non-empty `file` and `reason`; normal path and context warnings apply.
|
||||
- Sub-agent mode requires at least one real entry in each manifest.
|
||||
- Switching dispatch mode changes the validation policy, not historical task
|
||||
evidence and not the requirement to read specs before implementation.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Inline + zero real entries -> pass with `*_inline_optional`.
|
||||
- Inline + malformed real entry -> fail.
|
||||
- Sub-agent + zero real entries -> fail with `*_empty`.
|
||||
- Either mode + non-spec/non-research context -> warning for review.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: inline task uses the seed-only files and the main agent reads specs.
|
||||
- Base: inline task keeps curated entries for audit; they remain validated.
|
||||
- Bad: governance fabricates placeholder entries only to satisfy a rule meant
|
||||
for sub-agent context injection.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Fixture test for inline seed-only pass.
|
||||
- Fixture test for sub-agent seed-only failure.
|
||||
- Run both Trellis governance and `task.py validate` for the active task.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```text
|
||||
dispatch_mode=inline -> require at least one injected JSONL entry
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```text
|
||||
dispatch_mode=inline -> allow zero real entries; validate any real entries
|
||||
dispatch_mode=sub-agent -> require curated real entries
|
||||
```
|
||||
|
||||
@@ -155,3 +155,123 @@ return reply.send(stream);
|
||||
originals in normal OA attachment areas.
|
||||
- Customer original material, sensitive quotes, contract bodies or signed
|
||||
packages outside authorized business flows.
|
||||
|
||||
## Scenario: External Delivery Error Logging
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: logging SMTP, webhook, object-storage or other provider delivery
|
||||
failures whose native error objects may contain recipients or payloads.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Email log metadata: `errorCode`, optional `providerCode`, optional
|
||||
`smtpCommand`, optional numeric `smtpResponseCode`, request/business IDs and
|
||||
recipient count.
|
||||
- Forbidden input: raw provider `Error` objects in structured logs.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Log only explicitly allowlisted scalar metadata.
|
||||
- Do not log `response`, `rejected`, `rejectedErrors`, `envelope`, addresses,
|
||||
raw messages, headers, credentials or payloads.
|
||||
- Provider codes must match a bounded token format; SMTP commands must come
|
||||
from a fixed safe set; response codes must be bounded integers.
|
||||
- Delivery failure counts remain observable without exposing recipient data.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Known safe provider code/command/response code -> include normalized fields.
|
||||
- Unknown or free-form field -> omit it.
|
||||
- Error with rejected address or SMTP response text -> log generic category and
|
||||
safe numeric/token fields only.
|
||||
- Missing logger -> return the delivery result without throwing a logging
|
||||
error.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: record `EENVELOPE`, `RCPT TO`, `550`, request ID and failed count.
|
||||
- Base: plain `Error` becomes only `errorCode=email_delivery_failed`.
|
||||
- Bad: pass Nodemailer's raw `err` to Pino, which serializes rejected addresses.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Mock a provider error containing a rejected full address, response and
|
||||
envelope.
|
||||
- Assert serialized log context contains none of those values and retains only
|
||||
allowlisted metadata.
|
||||
- Cover disabled, configured, success and failure delivery paths.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```js
|
||||
logger.error({ err: providerError, recipient }, "delivery failed");
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```js
|
||||
logger.error({ ...buildSafeErrorLog(providerError), requestId, failed }, "delivery failed");
|
||||
```
|
||||
|
||||
## Scenario: Current Fact Source Sensitive Gate
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: adding, registering or changing a CURRENT fact source, README,
|
||||
deployment entry or environment template.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Gate: `node scripts/qa/check-sensitive-content.mjs`.
|
||||
- Registry: `docs/文档事实源状态矩阵.md` rows whose status is `CURRENT` and
|
||||
contract path is under `docs/`.
|
||||
- Output: `fileRef`, `line`, `category`; never the matched text.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Scan fixed execution/deployment entrypoints plus every CURRENT docs contract
|
||||
derived from the status matrix; do not maintain a partial duplicate docs list.
|
||||
- Detect secret assignments, credential URLs, full accounts, personal workspace
|
||||
paths, private keys and public IPv4 values.
|
||||
- Allow explicit placeholders, environment interpolation and loopback addresses.
|
||||
- Missing registry files remain a docs-audit concern; existing scanned files
|
||||
must not be silently excluded.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Any sensitive match -> `FAIL` with non-zero `findingCount`.
|
||||
- CURRENT doc added to the matrix -> automatically enters the scan set.
|
||||
- EVIDENCE/HISTORICAL issue row -> does not enter the CURRENT docs scan set.
|
||||
- Placeholder such as `<repo-root>` -> pass.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: all current docs and deploy entrypoints scan clean with metadata-only
|
||||
output.
|
||||
- Base: historical evidence stays outside this current-source blocking gate.
|
||||
- Bad: hard-code six docs while the matrix contains eighteen CURRENT docs.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Parser fixture with CURRENT doc, historical doc and CURRENT Issue row.
|
||||
- Assertion that representative current manuals/specs appear in the resolved
|
||||
default set.
|
||||
- Repository gate must report `findingCount=0` and the expected expanded file
|
||||
count after registry changes.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```js
|
||||
const files = ["docs/文档索引.md", "docs/产品设计规则.md"];
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```js
|
||||
const files = [...fixedEntrypoints, ...extractCurrentDocumentFiles(statusMatrix)];
|
||||
```
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1,53 @@
|
||||
# 生产可信度收口设计
|
||||
|
||||
## 目标架构
|
||||
|
||||
本任务不重写业务架构,只在现有入口增加可验证的安全与发布边界。实施按可独立回滚的工作包进行,每个工作包完成后运行聚焦测试,最终再跑全量门禁。
|
||||
|
||||
## 工作包
|
||||
|
||||
### WP1:恢复测试基线
|
||||
|
||||
- 使用 Vitest fake timers 或显式注入当前时间,修复公告测试时间炸弹。
|
||||
- 更新导航测试到当前批准名称,不在实现中恢复旧名称。
|
||||
- 将 `server npm test` 纳入最小/CI 可信门禁,避免静态绿灯掩盖全量失败。
|
||||
|
||||
### WP2:运行时与依赖安全
|
||||
|
||||
- 统一 Node 22。
|
||||
- 按研究摘要分三段升级依赖;每段运行认证、回调、邮件、Prisma 和 server 全量测试。
|
||||
- 生产依赖审计无 critical;直接可达 high 清零,其余项写明依赖路径和处理结论。
|
||||
|
||||
### WP3:Readiness 与 Seed 防误操作
|
||||
|
||||
- 给 readiness 子步骤增加结构化状态和 finding 传播。
|
||||
- 新增缺前置条件回归,保证 `SKIP` 不会成为 clean PASS。
|
||||
- 抽出可单测的 dev-seed safety guard;默认不覆盖既有密码,日志不输出口令。
|
||||
|
||||
### WP4:发布追溯与敏感治理
|
||||
|
||||
- 部署前检查 clean tree、commit/upstream,并把 build SHA 传入构建和版本响应。
|
||||
- 扩大当前事实源/README/部署入口的脱敏扫描,输出文件与类别而非匹配原文。
|
||||
- 脱敏当前文档中的完整账号、凭据、基础设施信息和绝对路径;不批量重写历史 CSV。
|
||||
|
||||
### WP5:第一批生成物清理与第二批候选
|
||||
|
||||
- 删除可重建且无跟踪引用的 build/test 临时目录。
|
||||
- 保留根级 `output/`、`artifacts/`,提交第二批候选清单,不删除 Git 跟踪兼容代码。
|
||||
|
||||
## 验证矩阵
|
||||
|
||||
- 后端:Prisma validate/generate check、全量 `npm test`、触达文件 `node --check`、认证/企微回调/邮件聚焦测试、生产依赖审计。
|
||||
- 前端:typecheck、build、Router 聚焦 smoke。
|
||||
- QA:readiness 四类状态场景、process/Trellis/docs gates、部署环境契约、shell syntax。
|
||||
- 治理:task validate、敏感扫描、`git diff --check`、只读 reviewer。
|
||||
|
||||
## 回滚
|
||||
|
||||
- 依赖段按 package/lockfile 和相关适配代码分别回滚,不使用 amend 或重写迁移。
|
||||
- readiness/seed/deploy 入口均保留旧业务行为之外的 fail-closed 变化;若验证失败,回滚对应工作包,不放宽安全边界。
|
||||
- 删除仅限可再生忽略目录;必要时由 build/test 命令重建。
|
||||
|
||||
## 部署边界
|
||||
|
||||
本任务完成只代表本地可信基线。公网部署、远端配置和带凭据复核需另行明确批准。
|
||||
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1,160 @@
|
||||
# 生产可信度收口与兼容清理
|
||||
|
||||
## Goal
|
||||
|
||||
将项目从“功能完整但发布可信度不足的内部试运行态”收口到可验证、可追溯、可安全继续试运行的工程基线:先修复安全依赖、全量测试、readiness 假绿、开发 seed 防误操作和发布追溯等 P0 问题,再以引用、运行时和验证证据为依据清理本地生成物、兼容层及确认不需要的内容,降低单人维护成本。
|
||||
|
||||
## Scope
|
||||
|
||||
- 后端测试、Node 运行时、生产依赖、认证、企微回调和邮件发送适配。
|
||||
- QA readiness 状态、报告聚合、敏感扫描和最小/CI 门禁。
|
||||
- 开发 seed 防误操作、部署 clean-tree 与 commit/build 追溯。
|
||||
- 当前事实源、运行手册和开发说明的必要脱敏。
|
||||
- 可重建本地生成物清理,以及第二批 Git 跟踪兼容/冗余候选清单。
|
||||
- Trellis inline 模式与项目治理门禁的一致性修正。
|
||||
|
||||
## What I Already Know
|
||||
|
||||
- 仓库最小门禁、Prisma schema、前端 typecheck/build、Trellis 治理和 `git diff --check` 当前通过。
|
||||
- 后端全量测试为 733/738 通过,5 个失败来自固定日期样例和旧菜单名断言;当前不是全绿发布基线。
|
||||
- 后端生产依赖审计报告 3 个 critical、18 个 high、37 个 moderate;认证 JWT 和企业微信 XML 解析链存在直接可达风险。
|
||||
- `run-live-smoke-readiness.sh` 会把部分 `SKIP` 子项聚合成 clean `PASS`,历史 Day 1-Day 4 的零 finding 不能直接作为最终启用证据。
|
||||
- `seed:dev` 没有 production fail-closed、显式允许开关或目标数据库保护,且会覆盖既有开发账号凭据并输出口令。
|
||||
- 部署脚本直接同步当前工作树,没有 clean-tree 校验和不可变提交标识;当前公网 bundle 不能可靠映射到唯一已记录提交。
|
||||
- OA 7 天真实试运行只有 Day 1-Day 4 证据,缺 Day 5-Day 7、人工闭环和 Day 7 Go/No-Go。
|
||||
- 当前有 3 个 `in_progress` Trellis task,其中一个已部署完成但未归档,一个已提交代码但验收项未勾选。
|
||||
- `docs/` 有 24 个未登记文档,现有敏感扫描未完整覆盖账号、内部标识、基础设施信息和完整路径。
|
||||
- 本地忽略目录中约有 151 MB `output/` 和 17 MB `artifacts/`;Git 当前没有跟踪这些生成物。
|
||||
- 用户已同意按审查建议开展,并允许删除部分兼容或确认不需要的内容。
|
||||
|
||||
## Assumptions (Temporary)
|
||||
|
||||
- 第一批以 P0 可信度修复为主,不同时扩大业务能力。
|
||||
- 删除必须分为两类:无争议本地生成物可按保留策略清理;Git 跟踪内容必须先形成候选清单和证据,再按批准批次删除。
|
||||
- 数据库 migration、历史 `issues/*.csv`、已归档 Trellis task 属于审计材料,除非项目规则另行调整,否则不删除或改写。
|
||||
- 冻结功能不等于可直接删代码;只有确认不再使用、无运行时入口、无数据/迁移依赖且回归通过时,才进入删除候选。
|
||||
- 本任务不自动部署、不 push、不写生产数据、不重置数据库、不执行企业微信或真实付款写入。
|
||||
|
||||
## Requirements (Evolving)
|
||||
|
||||
### P0 可信度修复
|
||||
|
||||
- 修复或升级认证、XML 解析、Fastify 及其关键运行时依赖,更新 lockfile,并对认证和企业微信回调做聚焦回归。
|
||||
- 修复 5 个后端测试漂移;固定时间语义并同步已批准的新菜单契约。
|
||||
- 让 readiness 父子报告正确传播 `SKIP/PARTIAL/MISSING/PASS_WITH_FINDINGS` 和 findingCount;补缺数据库、缺凭据、缺 OCR 样票回归。
|
||||
- 为 `seed:dev` 增加 production fail-closed、显式允许开关、数据库目标保护、一次性口令和日志脱敏。
|
||||
- 为部署增加 clean-tree 检查、提交 SHA/构建标识和不可变产物边界;不得在本任务内未经批准部署。
|
||||
- 扩大敏感信息扫描范围并脱敏当前事实源、运行手册和开发说明中的完整标识、凭据及路径。
|
||||
|
||||
### 安全清理
|
||||
|
||||
- 第一批只清理可重建且没有任务/事实源证据依赖的本地生成物;`output/`、`artifacts/` 等存在历史证据引用的目录先盘点、后决定,不整目录直接删除。
|
||||
- 对 Git 跟踪的兼容层、旧入口、占位资源、未使用模块和重复事实源只建立候选清单,记录引用、运行时、数据和回滚影响,本轮不直接删除。
|
||||
- 第二批删除必须基于候选清单另行批准;删除后同步修复测试、文档、CI、路由和配置引用,不保留静默断链。
|
||||
- 迁移、历史审计材料和仍承担回滚/兼容职责的内容默认保留。
|
||||
|
||||
### 后续收口
|
||||
|
||||
- 整理 3 个活动 task 的真实状态,但不补造历史证据。
|
||||
- P0 修复后另行决定是否启动新的连续 7 天真实试运行 task。
|
||||
|
||||
## Acceptance Criteria (Evolving)
|
||||
|
||||
- [x] `cd server && npm test` 为 738/738 或更新后的完整用例全绿。
|
||||
- [x] `npm audit --omit=dev` 无 critical;直接可达 high 清零,其余 high 有可复核的不可达/接受说明。
|
||||
- [x] readiness 缺前置条件时输出非 clean PASS,并在父报告中产生非零 findingCount。
|
||||
- [x] `seed:dev` 在 production、未显式允许或非允许数据库上拒绝执行,日志不输出口令。
|
||||
- [x] 部署入口拒绝脏工作树并生成可核对的提交/构建标识。
|
||||
- [x] 前端 typecheck/build、Prisma validate、全量后端测试、项目治理门禁和文档审计通过。
|
||||
- [x] CI、Dockerfile、开发 compose 和 package engines 统一到 Node 22 基线。
|
||||
- [x] `check-trellis-governance` 不再要求 inline planning task 维护仅供子代理注入的 JSONL,但仍校验非 inline/有条目时的内容合法性。
|
||||
- [x] 每个 Git 跟踪删除项都有“无引用/无运行时依赖/无数据破坏/验证通过”证据(本批未删除 Git 跟踪项,第二批仅形成候选清单)。
|
||||
- [x] 生成物清理不删除当前任务或事实源引用的必要脱敏摘要。
|
||||
- [x] 工作树最终只包含本任务预期变更,不包含敏感原始材料。
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- 代码、测试、lockfile、QA runner、治理和必要文档在同一任务内保持一致。
|
||||
- 权限、认证、workflow、migration 和删除类高风险变更完成只读 reviewer 复核。
|
||||
- 完成项目规定的最小门禁、全量测试、依赖审计和 `git diff --check`。
|
||||
- 所有删除均可从 Git 历史或明确重建步骤恢复,并记录回滚方式。
|
||||
- 不把本地验证误报成公网已部署或正式启用完成。
|
||||
|
||||
## Test Plan
|
||||
|
||||
```bash
|
||||
cd server && npm run prisma:validate
|
||||
cd server && npm run prisma:check-generated
|
||||
cd server && npm test
|
||||
cd server && npm audit --omit=dev
|
||||
cd client && npm run typecheck
|
||||
cd client && npm run build
|
||||
cd client && npm audit --omit=dev
|
||||
bash -n scripts/qa/run-live-smoke-readiness.sh
|
||||
bash -n deploy/trialrun/deploy.sh
|
||||
node deploy/trialrun/validate-env-contract.js
|
||||
node scripts/qa/check-process-contract.mjs --baseline --json
|
||||
node scripts/qa/audit-docs.mjs
|
||||
node scripts/qa/check-trellis-governance.mjs
|
||||
python3 ./.trellis/scripts/task.py validate 07-15-production-trust-closeout-cleanup
|
||||
git diff --check
|
||||
```
|
||||
|
||||
- 另运行新增的 readiness 缺数据库/缺凭据/缺样票单元或隔离脚本测试。
|
||||
- 另运行认证、企微回调、邮件和公告/导航聚焦 Vitest。
|
||||
- 本任务不运行公网带凭据 smoke、真实 OCR、部署、seed 或任何数据库写入命令。
|
||||
|
||||
## Verification Results
|
||||
|
||||
- `DATABASE_URL='' JWT_SECRET='' bash scripts/check-minimal.sh` 全绿:Prisma validate、静态检查、后端 153 个测试文件 / 786 个用例、前端 typecheck/build 和特性矩阵均通过,证明 ci-minimal 不依赖本机数据库或 `.env`。
|
||||
- `npm run prisma:check-generated` 通过;部署环境契约、Compose config、process/docs/Trellis/task/sensitive gates 和 `git diff --check` 通过。
|
||||
- 服务端生产依赖审计为 0 critical、0 high、6 moderate;剩余项来自 Prisma CLI 的静态服务链,以及 ExcelJS/Tencent SDK 的 UUID v3/v5/v6 传递链,当前无直接可达 high。客户端生产依赖为 0 漏洞。
|
||||
- 完整开发依赖快照仍有工具链风险:server 16 项、client 16 项;与生产运行依赖分开登记,后续单独升级构建/测试工具链。
|
||||
- 合成 40 位 SHA 构建验证:公网 bundle 只包含 12 位标识,不包含完整 SHA;readiness 记录并比较本地来源提交与公网观察 SHA。
|
||||
- 发布来源检查会先刷新 upstream remote-tracking ref;离线 override 必须提供 allowlist 原因码并在日志中醒目标记。
|
||||
- 敏感门禁由状态矩阵派生全部 CURRENT docs,当前扫描 28 个入口/事实源且 findingCount=0。
|
||||
- 第一批生成物已在最终构建后再次删除;第二批 Git 跟踪候选未删除,仍需另行批准。
|
||||
- 未执行部署、push、真实 OCR、seed、数据库写入、企业微信写入或付款操作。
|
||||
|
||||
## Technical Approach
|
||||
|
||||
- 先修复现有 5 个测试漂移,建立可比较的全绿基线,再升级依赖;任何升级导致的新失败都可明确归因。
|
||||
- 运行时统一到 Node 22 LTS;Node 20 已结束支持,Node 24 暂不引入以减少跨版本变量。
|
||||
- 依赖按三段升级:兼容补丁/小版本、OTel 0.x 版本族、Nodemailer 主版本;每段独立执行聚焦测试和生产依赖审计,不使用 `npm audit fix --force`。
|
||||
- readiness 采用结构化 step JSON 和父子状态聚合,不依赖日志字符串或仅依赖退出码判断 `SKIP`。
|
||||
- `seed:dev` 采用 production 永久拒绝、显式允许、目标数据库确认和本机数据库限制;默认不覆盖既有密码,只有额外显式重置开关才允许旋转开发账号密码,任何模式都不打印口令。
|
||||
- 部署入口在同步前校验 clean tree、当前 commit 和 upstream 状态,并把 commit/build 标识传入构建;本任务只实现和验证入口,不实际部署。
|
||||
- 文档敏感扫描只阻断当前事实源、运行手册、开发说明和部署入口;历史 Issue CSV 保持审计只读,不因新规则被批量改写。
|
||||
- 第一批只删除 `client/dist`、测试报告、coverage、CLI 临时快照等可重建且零跟踪引用的生成物;根级 `output/`、`artifacts/` 先保留并登记第二批候选。
|
||||
|
||||
## Decision (ADR-lite)
|
||||
|
||||
**Context**:P0 可信度修复已经跨越安全依赖、测试、QA runner、开发 seed、部署和文档治理;同时删除 Git 跟踪兼容代码会扩大回归面,并可能触及历史证据、运行时入口和数据迁移。
|
||||
|
||||
**Decision**:采用两批策略。第一批完成 P0 修复和无争议本地生成物清理,并产出 Git 跟踪兼容/冗余候选清单;第二批在候选清单经用户批准后另行实施删除。
|
||||
|
||||
**Consequences**:第一批风险更可控、验证链更清晰,不会因清理动作掩盖安全修复问题;代价是部分已识别冗余会暂时保留到第二批。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 未经单独批准的公网部署、生产配置修改、远端同步、真实数据写入或数据库重置。
|
||||
- 在本任务中补造缺失的 Day 5-Day 7、人工业务或历史 Go/No-Go 证据。
|
||||
- 删除 Prisma migrations、历史 Issue CSV、归档 Trellis task 或仍被生产数据依赖的 schema。
|
||||
- 一次性重写全部超大页面、路由或业务架构。
|
||||
- 未经候选清单确认就删除低频但仍可能使用的业务模块。
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- 工作流:`.trellis/workflow.md`
|
||||
- 治理规约:`.trellis/spec/hyb-oa/project-governance.md`
|
||||
- 证据规约:`.trellis/spec/hyb-oa/docs-and-evidence.md`
|
||||
- 安全隐私:`.trellis/spec/hyb-oa/security-privacy.md`
|
||||
- 后端规约:`.trellis/spec/hyb-oa/backend-fastify-prisma.md`
|
||||
- 部署规约:`.trellis/spec/hyb-oa/deployment-trialrun.md`
|
||||
- 关键入口:`scripts/qa/run-live-smoke-readiness.sh`、`scripts/qa/run-oa-real-use-daily.sh`、`server/src/scripts/seed-dev.js`、`deploy/trialrun/deploy.sh`
|
||||
- 删除验证使用项目实际命令,不照搬通用 skill 中与本仓库技术栈不匹配的脚本名。
|
||||
|
||||
## Research References
|
||||
|
||||
- `research/p0-technical-research.md`:Node/依赖升级、readiness、seed 和发布追溯的最小风险方案。
|
||||
- `research/cleanup-candidate-inventory.md`:生成物与第二批兼容/冗余候选的保护边界。
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# 清理候选与保护边界
|
||||
|
||||
## 第一批可清理生成物
|
||||
|
||||
以下目录均未被 Git 跟踪,可从现有命令重建;在验证结束后清理:
|
||||
|
||||
- `client/dist/`
|
||||
- `client/playwright-report/`
|
||||
- `client/test-results/`
|
||||
- `client/output/`
|
||||
- `server/coverage/`
|
||||
- `.playwright-cli/`
|
||||
|
||||
`node_modules/` 本轮保留,避免在多段依赖验证中反复安装。
|
||||
|
||||
### 2026-07-15 执行结果
|
||||
|
||||
- 已删除:`.playwright-cli/`、`client/dist/`、`client/output/`、`client/playwright-report/`、`client/test-results/`、`server/coverage/`。
|
||||
- 删除前合计约 7.4 MB;六个目录的 Git 跟踪文件数均为 0。
|
||||
- 重建入口:`cd client && npm run build`、Playwright 对应用例、`cd server && npm run test:coverage`。
|
||||
- 未删除:`node_modules/`、`server/generated/storage/`、`deploy/trialrun/screenshots/`、根级 `output/` 和 `artifacts/`。
|
||||
- 最终全量门禁曾重建 `client/dist/`,只读前端复核曾产生 `client/playwright-report/`;两者均在取证完成后再次删除,其余第一批目录也再次确认不存在。
|
||||
|
||||
## 第一批明确保护
|
||||
|
||||
- 根级 `output/`:约 151 MB、1754 个文件。
|
||||
- 根级 `artifacts/`:约 17 MB、1786 个文件。
|
||||
- 跟踪文件中约有 430 处 `output/` 或 `artifacts/` 引用;其中可能含部署、视觉、试运行或敏感材料证据。
|
||||
- 在完成“引用映射、摘要留存、敏感材料处置、保留周期”前,不整目录删除。
|
||||
|
||||
## 第二批 Git 跟踪候选(本轮只盘点)
|
||||
|
||||
| 候选 | 当前信号 | 删除前置 |
|
||||
| --- | --- | --- |
|
||||
| 旧 `Portal` 导航兼容 | 运行时代码已使用当前命名;旧词仍存在于 1 个视觉 E2E 和部署规约的 mock 兼容示例 | 更新视觉 fixture 与部署规约后跑导航、live smoke 和视觉回归 |
|
||||
| `client/src/design/tokens.ts` | Git 跟踪;除文件自身外未发现静态引用;颜色/间距已由 CSS/Tailwind 承担 | 再确认没有生成器或外部同步脚本消费;删除后 typecheck/build |
|
||||
| 1x1 PWA 占位图标 | 3 个文件均仅 68 bytes,实际尺寸 1x1;manifest 却声明 192/512/maskable | 推荐替换为真实图标;若选择删除,必须同步移除 manifest 安装声明并做 PWA 验证 |
|
||||
| Postman 开发环境文件 | 仅 `server/README.md` 引用 collection/environment;环境模板含固定开发凭据模式 | 确认不再使用 Postman;可选“删除两文件和 README 章节”或“保留 collection、把 environment 改为空占位模板” |
|
||||
| ERP 入口、路由与集成代码 | `client/src`、`server/src`、`scripts`、`deploy`、CI 中仍有约 79 个含 ERP 的文件,远非孤立死代码 | 单独做 schema/outbox/审计/feature flag/历史数据审计;不得在普通清理批次删除 |
|
||||
| 冻结的预算、差旅、薪酬、绩效等模块 | 部分隐藏或冻结,但代码/数据仍完整存在 | 逐模块确认真实使用、数据保留、权限、路由和迁移影响 |
|
||||
| 历史 Issue-first 流程兼容 | 新任务已 Trellis-only,但旧 QA gate 仍消费 Issue CSV | 先迁移 gate 与历史引用;历史 CSV 本身保持审计只读 |
|
||||
|
||||
## 永久保护项
|
||||
|
||||
- Prisma migrations 和迁移历史。
|
||||
- 历史 `issues/*.csv` 审计材料,除非另有治理任务改变项目规则。
|
||||
- 已归档 Trellis task。
|
||||
- 仍被事实源、回滚、生产数据、部署或外部系统消费的兼容代码。
|
||||
|
||||
## 第二批删除准入
|
||||
|
||||
每个候选必须同时满足:无静态引用、无动态注册/配置引用、无生产数据依赖、无迁移破坏、回滚方式明确、聚焦与全量验证通过,并再次获得用户批准。
|
||||
|
||||
## 第二批建议决策顺序
|
||||
|
||||
1. `client/src/design/tokens.ts`:最接近可直接删除,但仍需第二批批准。
|
||||
2. 旧 `Portal` fixture/spec 兼容:先统一测试契约,再删除旧词兼容。
|
||||
3. Postman:在“空模板保留”与“整套删除”之间二选一。
|
||||
4. PWA 图标:优先替换,不建议直接删除。
|
||||
5. ERP 与冻结业务模块:另建专项 task,不纳入轻量清理。
|
||||
@@ -0,0 +1,69 @@
|
||||
# P0 技术研究摘要
|
||||
|
||||
## 运行时基线
|
||||
|
||||
- Node 官方 release schedule 显示 Node 20 已于 2026-04-30 结束支持;Node 22 支持至 2027-04-30,Node 24 支持至 2028-04-30。
|
||||
- 当前本机使用 Node 22,前端 build、Prisma validate 和后端绝大多数测试已在该版本运行;CI、开发 compose 和试运行 Dockerfile 仍为 Node 20。
|
||||
- 推荐统一 Node 22,更新 CI、Dockerfile、开发 compose、package engines 和版本文件;Node 24 延后单独评估。
|
||||
|
||||
## 依赖升级分段
|
||||
|
||||
### A. 兼容补丁/小版本
|
||||
|
||||
- `@fastify/jwt` 10.0 -> 10.2;最新版依赖修复后的 `fast-jwt` 6.2.4。
|
||||
- Fastify 5.7 -> 5.10。
|
||||
- `fast-xml-parser` 5.3.4 -> 5.10。
|
||||
- Prisma / Prisma Client 7.3 -> 7.8。
|
||||
- AWS S3 SDK 更新到同一 v3 最新兼容线,以消除旧 XML 解析传递依赖。
|
||||
- React Router DOM 仅升 6.30.3 -> 6.30.4,不跨到 7.x。
|
||||
|
||||
### B. OTel 0.x 版本族
|
||||
|
||||
- SDK 0.213 -> 0.220,auto-instrumentations 0.71 -> 0.78。
|
||||
- 0.x 次版本可能包含破坏性变化,需单独验证 server bootstrap、traces disabled/enabled、metrics 和优雅退出。
|
||||
- 该升级用于消除 protobuf/grpc 等传递严重公告;不在第一批删除 OTel 代码。
|
||||
|
||||
### C. Nodemailer 主版本
|
||||
|
||||
- 当前 6.x,安全修复线为 9.x;项目只使用 `createTransport` 和文本 `sendMail` 基础接口。
|
||||
- 单独升级并补 transporter 配置、发送成功、发送异常和禁用邮件测试;不得用真实 SMTP 做自动验证。
|
||||
|
||||
## Readiness 状态设计
|
||||
|
||||
- `check-pending-ocr.mjs` 应输出机器可读 `PASS/SKIP/FAIL`,缺数据库时为 `SKIP` 且 findingCount 非零。
|
||||
- `run-live-smoke-readiness.sh` 为 `/ready`、public bundle、pending OCR、live smoke、live OCR 分别写 step JSON。
|
||||
- 缺凭据、缺样票或缺数据库属于 `manual_or_config`,最终为 `PASS_WITH_FINDINGS`;required step 失败才为 `FAIL/BLOCKED`。
|
||||
- `summary.json` 必须包含 child/step status、findingCount、repo-relative reportRef 和 commit,且不得含原始凭据名或完整路径。
|
||||
- 回归必须覆盖缺数据库、缺登录凭据、缺 OCR 样票和全前置条件就绪四类场景。
|
||||
|
||||
## Dev Seed 安全设计
|
||||
|
||||
- `NODE_ENV=production` 无条件拒绝。
|
||||
- 必须同时设置显式允许开关和目标数据库确认值;数据库必须为本机地址,确认值必须匹配 URL 中实际数据库名。
|
||||
- 默认创建缺失开发账号,但不覆盖已有账号密码;密码重置需要额外显式开关。
|
||||
- 继续支持本地/CI 可重复测试,但不在控制台、报告或文档输出任何口令。
|
||||
- 对 guard 做纯函数单元测试;禁止用真实数据库验证拒绝路径。
|
||||
|
||||
## 发布追溯设计
|
||||
|
||||
- 部署脚本在 rsync 前拒绝 dirty/untracked 工作树,记录完整 commit SHA 和分支。
|
||||
- 默认要求 HEAD 已包含在 upstream;如确有离线灾备场景,必须使用单独显式 override,不能静默部署未同步提交。
|
||||
- 构建接收 commit/build 参数,健康或版本元数据返回脱敏短 SHA;部署报告据此核对公网版本。
|
||||
- 本任务不执行公网部署,完成后另行获得批准。
|
||||
|
||||
## 结论
|
||||
|
||||
采用“基线测试 -> Node/兼容升级 -> OTel -> 邮件 -> readiness/seed -> 发布追溯”的顺序。每段可独立回滚 lockfile 和对应代码,避免安全升级与历史清理互相掩盖。
|
||||
|
||||
## 2026-07-15 实施与风险处置结果
|
||||
|
||||
- 统一 Node 22,关键生产依赖升级后全量后端为 153 个测试文件、786 个用例全绿;客户端 typecheck/build 全绿。空 `DATABASE_URL/JWT_SECRET` 的 CI 等价最小门禁同样通过。
|
||||
- 生产依赖审计:server 为 0 critical / 0 high / 6 moderate,client 为 0 漏洞。server 剩余中危分别位于 Prisma CLI 的 Hono 静态服务依赖,以及 ExcelJS/Tencent SDK 的 UUID v3/v5/v6 传递链;不采用会把 Prisma 回退到 6.x 或 SDK 回退版本的 `audit fix --force`。
|
||||
- 完整开发依赖审计 server/client 各 16 项,属于后续构建与测试工具链升级范围,不与本轮生产运行风险混报。
|
||||
- Pending OCR 改为复用 Prisma 7 adapter 工厂并关闭外部 pool;缺数据库仍为非 clean `SKIP`。
|
||||
- Readiness 现在同时记录 `sourceCommit`、`expectedBuildSha`、`observedBuildSha` 和匹配结论;缺失或不匹配不再 clean PASS。
|
||||
- Seed guard 使用 node-postgres 的实际解析结果校验目标,阻断 `?host=` 绕过;新建和显式轮换账号均强制首次改密。
|
||||
- 邮件失败日志只保留白名单化错误分类、provider code、SMTP command 和数字响应码,不再序列化 Nodemailer 原始错误对象。
|
||||
- 部署使用 clean/published Git archive,并在判断 published 前刷新 upstream;离线 override 需要 allowlist 原因码且输出醒目审计。完整 SHA 仅用于后端构建与运行时,前端在 Vite 构建期截断为 12 位,直接 Compose 缺任一 SHA 时拒绝解析。
|
||||
- 敏感扫描从状态矩阵派生全部 CURRENT docs,扫描范围由 16 个文件扩展到 28 个;遗漏的两处完整本地路径已脱敏。
|
||||
- 本任务只完成本地可信基线,未据此声称公网版本已更新或可测试。
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"id": "production-trust-closeout-cleanup",
|
||||
"name": "production-trust-closeout-cleanup",
|
||||
"title": "生产可信度收口与兼容清理",
|
||||
"description": "修复生产可信度阻断项,收口测试、安全依赖、readiness、开发 seed 与发布追溯,并以证据驱动方式清理生成物、兼容层和确认不需要的内容。",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": "server, client, scripts/qa, deploy/trialrun, docs, Trellis governance and workspace hygiene",
|
||||
"package": null,
|
||||
"priority": "P0",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-07-15",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
"server/package.json",
|
||||
"server/src/scripts/seed-dev.js",
|
||||
"scripts/qa/run-live-smoke-readiness.sh",
|
||||
"scripts/check-minimal.sh",
|
||||
"deploy/trialrun/deploy.sh",
|
||||
"docs/文档事实源状态矩阵.md"
|
||||
],
|
||||
"notes": "用户已批准两阶段方案;P0 实施与本地门禁完成,等待最终只读复核和提交计划确认。第二阶段 Git 跟踪候选仍未获删除批准。",
|
||||
"meta": {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户