chore: add public brand hygiene gate
This commit is contained in:
parent
8b8c39a495
commit
2c5a70c3b3
@ -70,6 +70,7 @@ http://localhost:3001/settings
|
||||
pnpm dev
|
||||
pnpm lint
|
||||
pnpm check:logs
|
||||
pnpm check:brand
|
||||
pnpm check:artifacts
|
||||
pnpm check:quality
|
||||
pnpm exec tsc --noEmit --pretty false
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
```bash
|
||||
pnpm lint
|
||||
pnpm check:logs
|
||||
pnpm check:brand
|
||||
pnpm exec tsc --noEmit --pretty false
|
||||
git diff --check
|
||||
pnpm check:artifacts
|
||||
@ -22,7 +23,7 @@ pnpm check:quality
|
||||
|
||||
## CI
|
||||
|
||||
`.github/workflows/lint.yml` 是基础质量门禁,运行 `pnpm check:quality`,负责 lint、日志治理、类型检查、diff hygiene 和 tracked 污染物检查。
|
||||
`.github/workflows/lint.yml` 是基础质量门禁,运行 `pnpm check:quality`,负责 lint、日志治理、公开交付面品牌治理、类型检查、diff hygiene 和 tracked 污染物检查。
|
||||
|
||||
CI 和本地提交前检查复用同一个入口,避免规则漂移。
|
||||
|
||||
@ -46,6 +47,14 @@ logger.error("event failed", error);
|
||||
|
||||
`pnpm check:logs` 会检查已治理文件是否重新引入裸 console,并验证 token、API Key、URL、base64、password 等敏感值不会明文输出。
|
||||
|
||||
## 品牌与模板残留治理
|
||||
|
||||
```bash
|
||||
pnpm check:brand
|
||||
```
|
||||
|
||||
`pnpm check:brand` 只扫描 README、核心 docs、GitHub 模板、workflow 和 package metadata 等公开交付入口。历史方案文档和兼容性 runtime key 不在本门禁范围内,避免为了改名破坏旧用户数据或研发记录。
|
||||
|
||||
## 首页性能烟测
|
||||
|
||||
```bash
|
||||
|
||||
@ -13,7 +13,7 @@ SMOKE_BASE_URL=http://127.0.0.1:3001 pnpm smoke:routes
|
||||
|
||||
预期:
|
||||
|
||||
- `pnpm check:quality` 通过 lint、日志脱敏门禁、类型检查、diff hygiene 和 tracked 污染物检查。
|
||||
- `pnpm check:quality` 通过 lint、日志脱敏门禁、公开交付面品牌治理、类型检查、diff hygiene 和 tracked 污染物检查。
|
||||
- `pnpm smoke:routes` 验证 `/` 返回 200。
|
||||
- `/classic` 和 `/chat/test-id` 重定向到 `/`。
|
||||
- `/settings` 未登录重定向到 `/login?callbackUrl=%2Fsettings`。
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
"lint": "npx ultracite@latest check",
|
||||
"check:logs": "node scripts/check-log-hygiene.mjs && tsx scripts/check-log-redaction.ts",
|
||||
"check:artifacts": "node scripts/check-tracked-artifacts.mjs",
|
||||
"check:quality": "pnpm lint && pnpm check:logs && pnpm exec tsc --noEmit --pretty false && git diff --check && pnpm check:artifacts",
|
||||
"check:brand": "node scripts/check-brand-hygiene.mjs",
|
||||
"check:quality": "pnpm lint && pnpm check:logs && pnpm check:brand && pnpm exec tsc --noEmit --pretty false && git diff --check && pnpm check:artifacts",
|
||||
"smoke:routes": "node scripts/smoke-routes.mjs",
|
||||
"format": "npx ultracite@latest fix",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
|
||||
69
scripts/check-brand-hygiene.mjs
Normal file
69
scripts/check-brand-hygiene.mjs
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
const expectedPackageName = "yedir-ai";
|
||||
|
||||
const governedFiles = [
|
||||
"package.json",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"SECURITY.md",
|
||||
"CONTRIBUTING.md",
|
||||
"SUPPORT.md",
|
||||
"CODE_OF_CONDUCT.md",
|
||||
".env.example",
|
||||
"docs/architecture.md",
|
||||
"docs/deployment.md",
|
||||
"docs/operations.md",
|
||||
"docs/release-readiness.md",
|
||||
".github/CODEOWNERS",
|
||||
".github/PULL_REQUEST_TEMPLATE.md",
|
||||
".github/dependabot.yml",
|
||||
".github/ISSUE_TEMPLATE/bug_report.yml",
|
||||
".github/ISSUE_TEMPLATE/config.yml",
|
||||
".github/ISSUE_TEMPLATE/feature_request.yml",
|
||||
".github/workflows/lint.yml",
|
||||
".github/workflows/playwright.yml",
|
||||
];
|
||||
|
||||
const forbiddenPatterns = [
|
||||
{ pattern: /\bai-chatbot\b/i, reason: "legacy package/repository name" },
|
||||
{ pattern: /chat-sdk\.dev/i, reason: "template documentation URL" },
|
||||
{ pattern: /Next\.js AI Chatbot/i, reason: "template project name" },
|
||||
{ pattern: /Chat SDK/i, reason: "template positioning" },
|
||||
{ pattern: /Deploy Your Own/i, reason: "template deployment copy" },
|
||||
{ pattern: /Vercel templates?/i, reason: "template marketplace copy" },
|
||||
{ pattern: /build:skip-prerender/i, reason: "build bypass script" },
|
||||
{ pattern: /Build fallback/i, reason: "build bypass output" },
|
||||
{ pattern: /next build --no-lint/i, reason: "build bypass command" },
|
||||
];
|
||||
|
||||
const violations = [];
|
||||
|
||||
const packageJson = JSON.parse(readFileSync("package.json", "utf8"));
|
||||
if (packageJson.name !== expectedPackageName) {
|
||||
violations.push(
|
||||
`package.json: expected package name "${expectedPackageName}", received "${packageJson.name}"`
|
||||
);
|
||||
}
|
||||
|
||||
for (const file of governedFiles) {
|
||||
const source = readFileSync(file, "utf8");
|
||||
const lines = source.split(/\r?\n/);
|
||||
lines.forEach((line, index) => {
|
||||
for (const { pattern, reason } of forbiddenPatterns) {
|
||||
if (pattern.test(line)) {
|
||||
violations.push(`${file}:${index + 1}: ${reason}: ${line.trim()}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (violations.length > 0) {
|
||||
console.error("Brand hygiene check failed. Keep public delivery surfaces aligned with yedir-ai.");
|
||||
console.error(violations.join("\n"));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Brand hygiene check passed for ${governedFiles.length} files.`);
|
||||
Loading…
x
Reference in New Issue
Block a user