feat: 增加NapCat设备画像检查
This commit is contained in:
parent
c2377f96ef
commit
7075d863c2
@ -15,6 +15,7 @@
|
|||||||
- 生成页面测试用例:内置“先写用例、可视化证据、事不过三”的测试闭环。
|
- 生成页面测试用例:内置“先写用例、可视化证据、事不过三”的测试闭环。
|
||||||
- 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。
|
- 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。
|
||||||
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
||||||
|
- 静态检查 NapCat 设备身份护栏:确认 API 仍保留 QQNT 可见 hostname、稳定 `02:42:*` MAC、QQNT `machine-info` 写入、持久化 runtime dir 和 `DB_TIMEZONE` 默认值。
|
||||||
- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。
|
- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。
|
||||||
- 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。
|
- 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。
|
||||||
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
||||||
@ -39,6 +40,7 @@ pnpm run obsidian-context -- --module ktWorkflow
|
|||||||
pnpm run obsidian-validate
|
pnpm run obsidian-validate
|
||||||
pnpm run obsidian-sync
|
pnpm run obsidian-sync
|
||||||
pnpm run workstream-closeout -- --title "发布闭环" --verification "Jenkins SUCCESS" --doc-sync "无需文档更新" --cleanup "cleanup-history dry-run deleted=0" --cleanup-final-deleted 0 --review "global-review findings=0" --superpowers-review "Superpowers reviewer completed; no Critical/Important findings" --problem "无新卡点" --solution "无新增稳定解法"
|
pnpm run workstream-closeout -- --title "发布闭环" --verification "Jenkins SUCCESS" --doc-sync "无需文档更新" --cleanup "cleanup-history dry-run deleted=0" --cleanup-final-deleted 0 --review "global-review findings=0" --superpowers-review "Superpowers reviewer completed; no Critical/Important findings" --problem "无新卡点" --solution "无新增稳定解法"
|
||||||
|
pnpm run napcat-device-profile-check
|
||||||
pnpm run cleanup-history -- --dry-run
|
pnpm run cleanup-history -- --dry-run
|
||||||
pnpm run cleanup-history -- --execute
|
pnpm run cleanup-history -- --execute
|
||||||
pnpm run deploy-observation -- --project api --job KT-Template/KT-Template-API/main --namespace kt-prod --deployment kt-template-online-api --container api --health-url http://127.0.0.1:48085/health/runtime --smoke "curl -fsS --max-time 8 http://127.0.0.1:48085/health/runtime"
|
pnpm run deploy-observation -- --project api --job KT-Template/KT-Template-API/main --namespace kt-prod --deployment kt-template-online-api --container api --health-url http://127.0.0.1:48085/health/runtime --smoke "curl -fsS --max-time 8 http://127.0.0.1:48085/health/runtime"
|
||||||
@ -93,6 +95,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
|||||||
| `kt_commit_plan` | 生成多仓库提交计划、建议 commit message 和检查项 |
|
| `kt_commit_plan` | 生成多仓库提交计划、建议 commit message 和检查项 |
|
||||||
| `kt_push_plan` | 生成多仓库推送计划和远程异常提醒 |
|
| `kt_push_plan` | 生成多仓库推送计划和远程异常提醒 |
|
||||||
| `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 |
|
| `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 |
|
||||||
|
| `kt_napcat_device_profile_check` | 静态检查 API NapCat 设备身份护栏,覆盖 hostname、MAC、`machine-info`、runtime dir 和 DB timezone |
|
||||||
| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 |
|
| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 |
|
||||||
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
||||||
| `kt_deploy_observation` | 生成或执行 API 发布后的部署观测,汇总 Jenkins SCM revision、K8s、Pod、`/health/runtime` 和任务 smoke 证据 |
|
| `kt_deploy_observation` | 生成或执行 API 发布后的部署观测,汇总 Jenkins SCM revision、K8s、Pod、`/health/runtime` 和任务 smoke 证据 |
|
||||||
@ -110,6 +113,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
|||||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `pnpm run admin-login` | 使用可见 Edge 打开 Admin 登录页,填写账号密码,拖动滑块,保存登录态和截图。默认账号来自初始化数据 `admin/123456`,生产或个人账号用 `KT_ADMIN_USERNAME` / `KT_ADMIN_PASSWORD` 或 CLI 参数覆盖。 |
|
| `pnpm run admin-login` | 使用可见 Edge 打开 Admin 登录页,填写账号密码,拖动滑块,保存登录态和截图。默认账号来自初始化数据 `admin/123456`,生产或个人账号用 `KT_ADMIN_USERNAME` / `KT_ADMIN_PASSWORD` 或 CLI 参数覆盖。 |
|
||||||
| `pnpm run global-review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,默认仅对变更文件做内容深扫,输出 JSON 复审报告,并校验 `TASKS.md` 最近记录只保留范围、关键词、验证字段、NapCat `latest` 漂移、QQBot 重型服务单测导入风险、QQBot 插件 registry/controller smoke 未 mock 具体插件实现风险、OneBot/QQ 登录态边界、NapCat 密码登录验证码 wait 阶段、日志窗口锚点、验证码状态早于日志 URL 的短轮询、验证码 pending 被状态轮询误清理、API Pod SSH 日志读取超时及清理前 pending 回归,以及普通处理中状态误吃旧验证码日志回归;明显测试占位 token 不报凭据风险,确认误报时优先升级 `src/tools/review.ts`,不要把误报沉积到上下文。 |
|
| `pnpm run global-review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,默认仅对变更文件做内容深扫,输出 JSON 复审报告,并校验 `TASKS.md` 最近记录只保留范围、关键词、验证字段、NapCat `latest` 漂移、QQBot 重型服务单测导入风险、QQBot 插件 registry/controller smoke 未 mock 具体插件实现风险、OneBot/QQ 登录态边界、NapCat 密码登录验证码 wait 阶段、日志窗口锚点、验证码状态早于日志 URL 的短轮询、验证码 pending 被状态轮询误清理、API Pod SSH 日志读取超时及清理前 pending 回归,以及普通处理中状态误吃旧验证码日志回归;明显测试占位 token 不报凭据风险,确认误报时优先升级 `src/tools/review.ts`,不要把误报沉积到上下文。 |
|
||||||
|
| `pnpm run napcat-device-profile-check` | 静态检查 API NapCat 设备身份护栏,防止回退到未知设备风险配置。 |
|
||||||
| `pnpm run deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 |
|
| `pnpm run deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 |
|
||||||
| `pnpm run obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 |
|
| `pnpm run obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 |
|
||||||
| `pnpm run obsidian-validate` | 校验 KT Obsidian vault 结构和链接;默认 warning 不让脚本失败,需要严格模式时传 `--fail-on-warnings`。 |
|
| `pnpm run obsidian-validate` | 校验 KT Obsidian vault 结构和链接;默认 warning 不让脚本失败,需要严格模式时传 `--fail-on-warnings`。 |
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
"cleanup-history": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --cleanup-history",
|
"cleanup-history": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --cleanup-history",
|
||||||
"deploy-observation": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --deploy-observation",
|
"deploy-observation": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --deploy-observation",
|
||||||
"global-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --global-review",
|
"global-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --global-review",
|
||||||
|
"napcat-device-profile-check": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-device-profile-check",
|
||||||
"obsidian-context": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-context",
|
"obsidian-context": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-context",
|
||||||
"obsidian-sync": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-sync",
|
"obsidian-sync": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-sync",
|
||||||
"obsidian-validate": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-validate",
|
"obsidian-validate": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-validate",
|
||||||
|
|||||||
@ -69,6 +69,7 @@ export const registeredToolNames = [
|
|||||||
'kt_commit_plan',
|
'kt_commit_plan',
|
||||||
'kt_push_plan',
|
'kt_push_plan',
|
||||||
'kt_business_test_plan',
|
'kt_business_test_plan',
|
||||||
|
'kt_napcat_device_profile_check',
|
||||||
'kt_blocker_resolution',
|
'kt_blocker_resolution',
|
||||||
'kt_remote_health_check',
|
'kt_remote_health_check',
|
||||||
'kt_deploy_observation',
|
'kt_deploy_observation',
|
||||||
|
|||||||
@ -12,7 +12,12 @@ import { buildWorkflowLoopAudit } from './tools/loop.js';
|
|||||||
import { readObsidianContext, syncObsidianWorkflow, validateObsidianVault } from './tools/obsidian.js';
|
import { readObsidianContext, syncObsidianWorkflow, validateObsidianVault } from './tools/obsidian.js';
|
||||||
import { buildGlobalCodeReview, defaultReviewProjects } from './tools/review.js';
|
import { buildGlobalCodeReview, defaultReviewProjects } from './tools/review.js';
|
||||||
import { appendTaskRecord, createCommitChecklist, prepareTask, readWorkflowContext } from './tools/task.js';
|
import { appendTaskRecord, createCommitChecklist, prepareTask, readWorkflowContext } from './tools/task.js';
|
||||||
import { buildBusinessTestPlan, createApiTestPlan, createPageTestCase } from './tools/testing.js';
|
import {
|
||||||
|
buildBusinessTestPlan,
|
||||||
|
buildNapcatDeviceProfileCheck,
|
||||||
|
createApiTestPlan,
|
||||||
|
createPageTestCase,
|
||||||
|
} from './tools/testing.js';
|
||||||
import { buildVerificationPlan } from './tools/verification.js';
|
import { buildVerificationPlan } from './tools/verification.js';
|
||||||
import { buildWorkstreamCloseout } from './tools/closeout.js';
|
import { buildWorkstreamCloseout } from './tools/closeout.js';
|
||||||
import { buildChangeDocSync } from './tools/docSync.js';
|
import { buildChangeDocSync } from './tools/docSync.js';
|
||||||
@ -365,6 +370,19 @@ export function registerTools(server: McpServer): void {
|
|||||||
async (input) => response(buildBusinessTestPlan(input)),
|
async (input) => response(buildBusinessTestPlan(input)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
'kt_napcat_device_profile_check',
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'静态检查 API NapCat 设备身份护栏:QQNT 可见 hostname、02:42 MAC、machine-info、runtime dir 和 DB_TIMEZONE。',
|
||||||
|
inputSchema: {
|
||||||
|
project: z.string().default('api'),
|
||||||
|
},
|
||||||
|
title: 'KT NapCat Device Profile Check',
|
||||||
|
},
|
||||||
|
async (input) => response(buildNapcatDeviceProfileCheck(input)),
|
||||||
|
);
|
||||||
|
|
||||||
server.registerTool(
|
server.registerTool(
|
||||||
'kt_blocker_resolution',
|
'kt_blocker_resolution',
|
||||||
{
|
{
|
||||||
|
|||||||
@ -35,7 +35,10 @@ import {
|
|||||||
findTaskRecordGovernanceFindings,
|
findTaskRecordGovernanceFindings,
|
||||||
isBenignCredentialReviewValue,
|
isBenignCredentialReviewValue,
|
||||||
} from "./tools/review.js";
|
} from "./tools/review.js";
|
||||||
import { buildBusinessTestPlan } from "./tools/testing.js";
|
import {
|
||||||
|
buildBusinessTestPlan,
|
||||||
|
buildNapcatDeviceProfileCheck,
|
||||||
|
} from "./tools/testing.js";
|
||||||
import { buildVerificationPlan } from "./tools/verification.js";
|
import { buildVerificationPlan } from "./tools/verification.js";
|
||||||
import { buildWorkstreamCloseout } from "./tools/closeout.js";
|
import { buildWorkstreamCloseout } from "./tools/closeout.js";
|
||||||
import {
|
import {
|
||||||
@ -1211,6 +1214,13 @@ export async function runSelfTest(): Promise<void> {
|
|||||||
throw new Error("DB sync plan safety self-check failed");
|
throw new Error("DB sync plan safety self-check failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const napcatDeviceProfileCheck = buildNapcatDeviceProfileCheck({
|
||||||
|
project: "api",
|
||||||
|
});
|
||||||
|
if ((napcatDeviceProfileCheck.ok as boolean) !== true) {
|
||||||
|
throw new Error("NapCat device profile guardrail self-check failed");
|
||||||
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
context: readWorkflowContext({ taskRecordCount: 2 }),
|
context: readWorkflowContext({ taskRecordCount: 2 }),
|
||||||
guardrails: buildGuardrails({
|
guardrails: buildGuardrails({
|
||||||
@ -1251,6 +1261,7 @@ export async function runSelfTest(): Promise<void> {
|
|||||||
businessTestPlan: buildBusinessTestPlan({
|
businessTestPlan: buildBusinessTestPlan({
|
||||||
flow: "system-log-visualization",
|
flow: "system-log-visualization",
|
||||||
}),
|
}),
|
||||||
|
napcatDeviceProfileCheck,
|
||||||
closeoutComplete,
|
closeoutComplete,
|
||||||
closeoutNeedsUpgrade,
|
closeoutNeedsUpgrade,
|
||||||
obsidianContext,
|
obsidianContext,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { readObsidianContext, syncObsidianWorkflow, validateObsidianVault } from
|
|||||||
import { buildGlobalCodeReview } from './tools/review.js';
|
import { buildGlobalCodeReview } from './tools/review.js';
|
||||||
import { registerTools } from './registerTools.js';
|
import { registerTools } from './registerTools.js';
|
||||||
import { runSelfTest } from './selfTest.js';
|
import { runSelfTest } from './selfTest.js';
|
||||||
|
import { buildNapcatDeviceProfileCheck } from './tools/testing.js';
|
||||||
|
|
||||||
if (process.argv.includes('--cleanup-history')) {
|
if (process.argv.includes('--cleanup-history')) {
|
||||||
console.log(JSON.stringify(cleanupHistoryArtifacts(parseCliCleanupArgs(process.argv)), null, 2));
|
console.log(JSON.stringify(cleanupHistoryArtifacts(parseCliCleanupArgs(process.argv)), null, 2));
|
||||||
@ -46,6 +47,8 @@ if (process.argv.includes('--cleanup-history')) {
|
|||||||
await runSelfTest();
|
await runSelfTest();
|
||||||
} else if (process.argv.includes('--workstream-closeout')) {
|
} else if (process.argv.includes('--workstream-closeout')) {
|
||||||
console.log(JSON.stringify(buildWorkstreamCloseout(parseWorkstreamCloseoutCliArgs(process.argv)), null, 2));
|
console.log(JSON.stringify(buildWorkstreamCloseout(parseWorkstreamCloseoutCliArgs(process.argv)), null, 2));
|
||||||
|
} else if (process.argv.includes('--napcat-device-profile-check')) {
|
||||||
|
console.log(JSON.stringify(buildNapcatDeviceProfileCheck({ project: 'api' }), null, 2));
|
||||||
} else {
|
} else {
|
||||||
const server = new McpServer({
|
const server = new McpServer({
|
||||||
name: 'kt-workflow',
|
name: 'kt-workflow',
|
||||||
|
|||||||
@ -1,5 +1,120 @@
|
|||||||
import type { ApiTestPlanInput, BusinessFlow, BusinessTestPlanInput, PageTestCaseInput, PageTestCaseResult } from '../types.js';
|
import { existsSync, readFileSync } from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ApiTestPlanInput,
|
||||||
|
BusinessFlow,
|
||||||
|
BusinessTestPlanInput,
|
||||||
|
NapcatDeviceProfileCheckInput,
|
||||||
|
PageTestCaseInput,
|
||||||
|
PageTestCaseResult,
|
||||||
|
} from '../types.js';
|
||||||
import { resolveProject } from '../core/workspace.js';
|
import { resolveProject } from '../core/workspace.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a project-relative source file for static NapCat device profile checks.
|
||||||
|
* @param projectPath - Absolute project path returned by `resolveProject()`.
|
||||||
|
* @param relativePath - File path inside the API project.
|
||||||
|
* @returns UTF-8 file content, or an empty string when the file is absent.
|
||||||
|
*/
|
||||||
|
function readProjectFile(projectPath: string, relativePath: string): string {
|
||||||
|
const filePath = path.join(projectPath, relativePath);
|
||||||
|
return existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a boolean static check with a human-readable recovery hint.
|
||||||
|
* @param name - Stable check identifier for reports and self-test output.
|
||||||
|
* @param passed - Whether the source text still contains the expected guardrail.
|
||||||
|
* @param evidence - Short description of the expected code-level evidence.
|
||||||
|
* @returns Check result consumed by `buildNapcatDeviceProfileCheck()`.
|
||||||
|
*/
|
||||||
|
function createNapcatCheck(
|
||||||
|
name: string,
|
||||||
|
passed: boolean,
|
||||||
|
evidence: string,
|
||||||
|
): Record<string, unknown> {
|
||||||
|
return {
|
||||||
|
evidence,
|
||||||
|
name,
|
||||||
|
passed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the API project still contains the NapCat device-profile guardrails needed to avoid unknown QQ devices.
|
||||||
|
* @param input - Project alias or path to scan; defaults to the API backend.
|
||||||
|
* @returns Static guardrail report covering hostname, MAC, machine-info, runtime dir, and DB timezone.
|
||||||
|
*/
|
||||||
|
export function buildNapcatDeviceProfileCheck(
|
||||||
|
input: NapcatDeviceProfileCheckInput = {},
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const project = resolveProject(input.project || 'api');
|
||||||
|
const deviceIdentity = readProjectFile(
|
||||||
|
project.path,
|
||||||
|
'src/modules/qqbot/napcat/infrastructure/integration/device/napcat-device-identity.service.ts',
|
||||||
|
);
|
||||||
|
const dockerOptions = readProjectFile(
|
||||||
|
project.path,
|
||||||
|
'src/modules/qqbot/napcat/infrastructure/integration/container/napcat-docker-device-options.ts',
|
||||||
|
);
|
||||||
|
const containerService = readProjectFile(
|
||||||
|
project.path,
|
||||||
|
'src/modules/qqbot/napcat/infrastructure/integration/container/qqbot-napcat-container.service.ts',
|
||||||
|
);
|
||||||
|
const appModule = readProjectFile(project.path, 'src/app.module.ts');
|
||||||
|
const runtimeConfig = readProjectFile(
|
||||||
|
project.path,
|
||||||
|
'src/runtime/config/runtime-config.service.ts',
|
||||||
|
);
|
||||||
|
const checks = [
|
||||||
|
createNapcatCheck(
|
||||||
|
'hostname-strategy',
|
||||||
|
deviceIdentity.includes('qqnt-visible-hostname-v1') &&
|
||||||
|
deviceIdentity.includes('pc-') &&
|
||||||
|
deviceIdentity.includes('hash.slice(0, 8)'),
|
||||||
|
'device identity uses qqnt-visible-hostname-v1 and pc-<8hex>',
|
||||||
|
),
|
||||||
|
createNapcatCheck(
|
||||||
|
'docker-bridge-mac-strategy',
|
||||||
|
deviceIdentity.includes('docker-bridge-mac-v1') &&
|
||||||
|
deviceIdentity.includes('02:42:'),
|
||||||
|
'device identity uses docker-bridge-mac-v1 and stable 02:42:* MACs',
|
||||||
|
),
|
||||||
|
createNapcatCheck(
|
||||||
|
'machine-info-options',
|
||||||
|
dockerOptions.includes('machineInfoPath') &&
|
||||||
|
dockerOptions.includes('macAddressHyphen'),
|
||||||
|
'docker device options carry machineInfoPath and hyphenated MAC',
|
||||||
|
),
|
||||||
|
createNapcatCheck(
|
||||||
|
'machine-info-script',
|
||||||
|
containerService.includes('MACHINE_INFO_PATH') &&
|
||||||
|
containerService.includes('NAPCAT_MAC_HYPHEN') &&
|
||||||
|
containerService.includes("tr 'A-Za-z' 'N-ZA-Mn-za-m'") &&
|
||||||
|
containerService.includes("printf '\\\\000\\\\000\\\\000\\\\021'"),
|
||||||
|
'remote create script writes QQNT machine-info using ROT13 MAC format',
|
||||||
|
),
|
||||||
|
createNapcatCheck(
|
||||||
|
'runtime-dir-mount',
|
||||||
|
containerService.includes('$DATA_DIR/runtime:/tmp/runtime-napcat'),
|
||||||
|
'remote create script persists XDG_RUNTIME_DIR under the account data dir',
|
||||||
|
),
|
||||||
|
createNapcatCheck(
|
||||||
|
'db-timezone',
|
||||||
|
appModule.includes('DB_TIMEZONE') &&
|
||||||
|
appModule.includes("'+08:00'") &&
|
||||||
|
runtimeConfig.includes('DB_TIMEZONE'),
|
||||||
|
'TypeORM and runtime config expose DB_TIMEZONE with +08:00 default',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
checks,
|
||||||
|
ok: checks.every((item) => item.passed === true),
|
||||||
|
project,
|
||||||
|
};
|
||||||
|
}
|
||||||
export function createPageTestCase(input: PageTestCaseInput): PageTestCaseResult {
|
export function createPageTestCase(input: PageTestCaseInput): PageTestCaseResult {
|
||||||
const project = resolveProject(input.project);
|
const project = resolveProject(input.project);
|
||||||
const title = input.title || `${project.label} 页面级测试`;
|
const title = input.title || `${project.label} 页面级测试`;
|
||||||
|
|||||||
@ -185,6 +185,10 @@ export interface BusinessTestPlanInput {
|
|||||||
flow?: BusinessFlow | 'all';
|
flow?: BusinessFlow | 'all';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NapcatDeviceProfileCheckInput {
|
||||||
|
project?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BlockerResolutionInput {
|
export interface BlockerResolutionInput {
|
||||||
attempts?: number;
|
attempts?: number;
|
||||||
command?: string;
|
command?: string;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user