@wdyy/skills 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,8 +17,8 @@
17
17
  },
18
18
  {
19
19
  "name": "wdyy-logging-standard",
20
- "description": "为 NestJS 和 Vue 项目实现固定写入项目根目录 ./logs 的访问、应用、安全与审计 JSON 日志,记录来源 IP、时间、业务功能、操作主体与结果,并提供 W3C trace、敏感字段净化、前端异常上报、2MB 轮转、哈希链及可执行校验。Use when 编写或审查日志、错误处理、请求追踪、安全访问记录、安全事件、审计溯源及生产可观测性时。",
21
- "files": ["SKILL.md", "agents/openai.yaml", "reference/logging-rules.md", "scripts/validate-log-entry.mjs", "scripts/validate-log-entry.test.mjs", "templates/frontend-error-report.template.ts", "templates/logger.template.ts", "templates/nestjs-http-logging.middleware.template.ts", "templates/security-audit-logger.template.ts"]
20
+ "description": "为 NestJS 和 Vue 项目基于 Pino 生态实现固定写入项目根目录 ./logs 的请求、响应、操作审计与安全 JSON 日志,通过 nestjs-pino 与 pino-http 记录 HTTP 请求/响应,使用 pino-roll 2MB 轮转,并提供 W3C trace、敏感字段净化、前端异常上报与哈希链校验。Use when 编写或审查日志、错误处理、请求追踪、安全访问记录、安全事件、审计溯源及生产可观测性时。",
21
+ "files": ["SKILL.md", "agents/openai.yaml", "reference/logging-rules.md", "scripts/validate-log-entry.mjs", "scripts/validate-log-entry.test.mjs", "templates/frontend-error-report.template.ts", "templates/logger.template.ts", "templates/pino-logger.template.ts", "templates/nestjs-http-logging.middleware.template.ts", "templates/security-audit-logger.template.ts"]
22
22
  },
23
23
  {
24
24
  "name": "wdyy-ui",
@@ -1,39 +1,41 @@
1
1
  ---
2
2
  name: wdyy-logging-standard
3
- description: 为 NestJS 和 Vue 项目实现固定写入项目根目录 ./logs 的访问、应用、安全与审计 JSON 日志,记录来源 IP、时间、业务功能、操作主体与结果,并提供 W3C trace、敏感字段净化、前端异常上报、2MB 轮转、哈希链及可执行校验。Use when 编写或审查日志、错误处理、请求追踪、安全访问记录、安全事件、审计溯源及生产可观测性时。
3
+ description: 为 NestJS 和 Vue 项目基于 Pino 生态实现固定写入项目根目录 ./logs 的请求、响应、操作审计与安全 JSON 日志,通过 nestjs-pino 与 pino-http 记录 HTTP 请求/响应,使用 pino-roll 2MB 轮转,并提供 W3C trace、敏感字段净化、前端异常上报与哈希链校验。Use when 编写或审查日志、错误处理、请求追踪、安全访问记录、安全事件、审计溯源及生产可观测性时。
4
4
  ---
5
5
 
6
- # 企业安全日志与溯源规范
6
+ # 企业安全日志与溯源规范(Pino)
7
7
 
8
8
  ## Overview
9
9
 
10
- 建立可追踪、可审计、可验证完整性的结构化日志。净化秘密和敏感个人信息后,保留其余完整业务参数结构。
10
+ 使用成熟 Node.js 日志框架 Pino 建立可追踪、可审计、可验证完整性的结构化日志。净化秘密和敏感个人信息后,保留其余完整业务参数结构。
11
11
 
12
12
  ## 输入与确认项
13
13
 
14
14
  - 输入:服务名、实例标识、环境、HTTP 与业务上下文,以及经工程师确认的业务功能目录;应用从项目根目录启动。
15
+ - 依赖(安装前须核实最新稳定版):`pino`、`pino-http`、`nestjs-pino`、`pino-roll`;已核实版本为 `pino@10.3.1`、`pino-http@11.0.0`、`nestjs-pino@5.2.0`、`pino-roll@4.0.0`。
15
16
  - 实施前由工程师确认:项目特有敏感字段、可信代理链、业务功能编码与名称、动作、审计主体映射、留存责任人,以及外部不可变副本的平台与接入参数。
16
17
  - 未确认外部平台、地址、凭据时保持 `待确认`,不得虚构已接入、已备份或合规达标。
17
18
 
18
19
  ## 执行步骤
19
20
 
20
- 1. 阅读 [详细日志规则](reference/logging-rules.md),确定四类日志及事件清单。
21
- 2. [后端 logger 模板](templates/logger.template.ts) 接入统一日志模块;业务代码不得直接使用 `console.log`。
22
- 3. 建立显式业务功能目录,再将 [NestJS HTTP 中间件模板](templates/nestjs-http-logging.middleware.template.ts) 接入入口;每个 `method + route` 必须映射稳定的功能编码、名称和动作。
21
+ 1. 阅读 [详细日志规则](reference/logging-rules.md),确定 `request`、`response`、`security`、`audit` 四类日志及事件清单。
22
+ 2. 使用 [Pino logger 模板](templates/pino-logger.template.ts) 创建统一日志流:先以 `0700` 预创建 `./logs`,再用 `pino.transport` 接入 `pino-roll`,并在写入前经过哈希链 Transform;业务代码不得直接使用 `console.log`。
23
+ 3. 建立显式业务功能目录,再将 [nestjs-pino 集成模板](templates/nestjs-http-logging.middleware.template.ts) 接入入口;`pino-http` `req`/`res` 日志分别映射为 `request`/`response`,每个 `method + route` 必须映射稳定的功能编码、名称和动作。
23
24
  4. 将 [安全审计模板](templates/security-audit-logger.template.ts) 接入认证、授权、权限变更、敏感数据导出和配置变更路径。
24
- 5. 将 [前端异常模板](templates/frontend-error-report.template.ts) 接入 Axios、未处理异常和 Promise 拒绝。
25
+ 5. 将 [前端异常模板](templates/frontend-error-report.template.ts) 接入 Axios、未处理异常和 Promise 拒绝;前端不使用 Pino。
25
26
  6. 写盘或上报前统一递归净化;必须删除凭据、令牌、Cookie、连接串、身份证件、银行卡、病历与健康数据字段,项目确认的附加字段一并删除。
26
27
  7. 进入本 Skill 目录,执行 `node --test scripts/validate-log-entry.test.mjs`,再运行目标项目的完整测试。
27
28
 
28
29
  ## 核心合同
29
30
 
30
- - `logType` 仅为 `access`、`application`、`security`、`audit`。
31
+ - `logType` 仅为 `request`、`response`、`security`、`audit`;`access` 与 `application` 已废弃并会被校验器拒绝。
31
32
  - 通用字段包含 `timestamp`、`timestampEpochMs`、`timezone: +08:00`、`level`、`service`、`instanceId`、`env`、`logType`、`message`。
32
- - 访问日志还必须包含 `traceId`、`method`、`route`、`sourceIp`、`actorId`、`actorType`、`functionCode`、`functionName`、`action`、`statusCode`、`result`、`durationMs`。
33
+ - `request` 日志还必须包含 `traceId`、`spanId`、`method`、`route`、`sourceIp`、`actorId`、`actorType`、`functionCode`、`functionName`、`action` 及净化后的 `query`、`body`。
34
+ - `response` 日志还必须包含同一 `traceId`、`method`、`route`、`statusCode`、`result`、`durationMs`;100–399 映射 `success`,400–599 映射 `failure`。
33
35
  - 未认证请求使用 `actorId: anonymous` 与 `actorType: anonymous`;已认证主体仅记录不含直接身份信息的内部标识。
34
36
  - 安全与审计日志还必须包含事件、主体、动作、对象和结果;失败事件必须包含原因。请求触发时还必须包含同一 `traceId`、有效 `sourceIp`、`route`、`functionCode` 和 `functionName`。
35
37
  - 使用 W3C `traceparent`,兼容 `x-trace-id`;无效或全零上游值必须替换,不能阻断请求。
36
- - 仅写项目根目录 `./logs`,目录权限 `0700`、文件权限 `0600`,排他创建、串行追加、单文件 2MB 轮转并记录哈希链。
38
+ - 仅写项目根目录 `./logs`,目录权限 `0700` 且必须预先创建,文件权限 `0600`;单文件 2MB 轮转,文件名遵循 `filename.date.count.log`,禁止自动删除、移动或覆盖历史日志;每条落盘记录包含 `chainId`、`sequence`、`previousHash`、`entryHash`。
37
39
 
38
40
  ## 禁止事项
39
41
 
@@ -41,12 +43,13 @@ description: 为 NestJS 和 Vue 项目实现固定写入项目根目录 ./logs
41
43
  - 不得记录带查询串的原始 URL,不得按服务、日期或类型创建日志子目录。
42
44
  - 不得用 `unknown`、原始 URL、控制器名或猜测值代替有效来源 IP 及显式业务功能映射。
43
45
  - 不得以裁剪全部请求体代替字段级净化,也不得以“完整原始入参”为由绕过净化。
44
- - 日志初始化或写入失败必须显式失败,不得静默吞错。
46
+ - 日志初始化或写入失败必须显式失败,不得降级到 console 或静默吞错。
45
47
 
46
48
  ## Verification
47
49
 
48
- - [ ] 四类日志必填字段、成功失败映射与失败原因均有行为测试;未知功能、无效 IP 和不完整主体会显式失败。
50
+ - [ ] 四类日志必填字段、成功失败映射与失败原因均有行为测试;旧类别、未知功能、无效 IP 和不完整主体会显式失败。
49
51
  - [ ] 净化后保留非敏感业务结构,校验器拒绝任何绕过净化的禁止字段。
50
52
  - [ ] trace 可跨前后端和内部调用延续,无效输入被安全替换。
51
- - [ ] 真实写盘权限、同秒并发、2MB 轮转、单行 JSON 与哈希链篡改检测通过。
53
+ - [ ] 请求与响应日志共享同一 trace 与业务功能上下文;哈希链篡改检测通过。
54
+ - [ ] `pino-roll` 存储选项固定 2MB、`0600`、仅追加且禁止删除历史日志;`./logs` 以 `0700` 预创建。
52
55
  - [ ] 网络安全相关日志至少留存六个月;备份、访问审计、容量告警和外部不可变副本有经确认的生产证据。
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "wdyy-logging-standard"
3
3
  short_description: "Record IP, time, business function, trace, and audit logs"
4
- default_prompt: "Use $wdyy-logging-standard to implement secure access, application, security, and audit logs with explicit business-function mapping, actor and source-IP validation, trace propagation, and behavioral verification."
4
+ default_prompt: "Use $wdyy-logging-standard to implement Pino-based request, response, security, and audit logs with explicit business-function mapping, actor and source-IP validation, trace propagation, 2MB pino-roll rotation, and behavioral verification."
@@ -1,4 +1,11 @@
1
- # 日志详细规则
1
+ # 日志详细规则(Pino)
2
+
3
+ ## 框架与依赖
4
+
5
+ - 后端统一使用 `nestjs-pino` 接入 Pino:`pino-http` 的 `req` 日志映射为 `request`,`res` 日志映射为 `response`,二者由同一条 HTTP 日志链路产生并共享 trace 与业务功能上下文。
6
+ - 落盘与轮转使用 `pino-roll`:通过 `pino.transport` 创建,单文件达到 2MB 轮转,文件名遵循 `filename.date.count.log`。
7
+ - 安装前必须从官方渠道核实最新稳定版本;若版本不兼容或存在未修复高危漏洞,停止安装并报告,不得擅自降级或添加豁免。
8
+ - 前端 Vue 不使用 Pino,继续使用本 Skill 的前端异常上报模板。
2
9
 
3
10
  ## 分类与字段
4
11
 
@@ -6,11 +13,13 @@
6
13
 
7
14
  | 类型 | 用途 | 关键字段 |
8
15
  |---|---|---|
9
- | `access` | HTTP 安全访问与性能追踪 | traceId、method、route、sourceIp、actorId、actorType、functionCode、functionName、action、statusCoderesult、durationMs |
10
- | `application` | 业务状态、集成调用与异常 | traceId(有调用链时)、errorCodeparamsbody、response |
16
+ | `request` | HTTP 请求安全访问记录 | traceId、spanId、method、route、sourceIp、actorId、actorType、functionCode、functionName、action、querybody |
17
+ | `response` | HTTP 响应与性能追踪 | traceId、methodroutestatusCode、result、durationMs、response |
11
18
  | `security` | 认证、授权、攻击与策略事件 | eventId、eventType、actor、action、target、result、reason(失败时) |
12
19
  | `audit` | 管理操作和关键数据变更溯源 | eventId、eventType、actor、action、target、before、after、result、reason(失败时) |
13
20
 
21
+ `access` 与 `application` 已废弃:业务/集成/HTTP 异常归入 `response` 并携带 `errorCode` 与净化上下文;非 HTTP 关键事件按语义归入 `security` 或 `audit`。
22
+
14
23
  安全事件至少覆盖:登录成功/失败、访问拒绝、权限或角色变更、账户锁定/解锁、敏感数据查询或导出、日志访问、审计配置变更和完整性校验失败。审计事件至少覆盖关键业务新增、修改、删除、状态流转及管理配置变更。
15
24
 
16
25
  ## 安全访问记录
@@ -19,7 +28,7 @@
19
28
  - 功能信息必须来自工程师维护的显式目录,以 `method + route` 精确映射;不得从原始 URL、控制器名或日志组件推断。未登记、重复或格式错误的映射必须显式失败。
20
29
  - `actorId` 只记录内部不透明标识,`actorType` 记录主体类别。未认证请求固定记录 `anonymous/anonymous`,不得使用姓名、身份证号、工号等直接身份信息,也不得虚构用户。
21
30
  - `sourceIp` 必须是有效 IPv4 或 IPv6 地址。Express `request.ip` 只有在可信代理链已由工程师确认并正确配置时才可采用;不得直接信任任意 `X-Forwarded-For`,也不得写入 `unknown`。
22
- - 请求触发的 `security`、`audit` 事件必须沿用访问日志的 trace、IP、路由和功能上下文;后台事件不得伪造请求字段。
31
+ - 请求触发的 `security`、`audit` 事件必须沿用请求日志的 trace、IP、路由和功能上下文;后台事件不得伪造请求字段。
23
32
 
24
33
  ## 数据安全
25
34
 
@@ -27,7 +36,7 @@
27
36
  - 固定禁止密码、认证头、Cookie、会话标识、各类 token、API/客户端密钥、私钥、数据库连接信息、身份证件、银行卡、病历号、诊断和健康数据字段;字段名匹配忽略大小写及分隔符。
28
37
  - 由工程师补充项目特有敏感字段。除被删除字段外,嵌套对象、数组与其他业务参数必须保留完整结构;不得静默截断或只保留白名单摘要。
29
38
  - `route` 只记录框架路由模板,如 `/patients/:patientId`;不得记录原始 URL、查询串或片段。客户端 IP 仅在可信代理配置已确认后读取转发头。
30
- - 消息中的 CR/LF 必须编码,防止伪造日志行。前端错误消息与堆栈在上报前也必须清除常见凭据。
39
+ - 消息与文本值中的 CR/LF 必须由 JSON 序列化编码,防止伪造日志行。前端错误消息与堆栈在上报前也必须清除常见凭据。
31
40
 
32
41
  ## 追踪与时间
33
42
 
@@ -38,9 +47,9 @@
38
47
  ## 本地存储与完整性
39
48
 
40
49
  - 应用从项目根目录启动,仅可写 `./logs`,不得读取环境变量改写目录或创建子目录。
41
- - `./logs` 使用 `0700`,日志文件使用 `0600`。以 `wx` 排他创建 `yyyy-mm-dd_hh24-mm-ss.log`;冲突依次增加 `_1`、`_2`。
42
- - 单进程内串行追加;文件达到 2MB 前轮转到新文件,不移动、重命名或覆盖旧文件。
43
- - 每条落盘记录包含 chainIdsequencepreviousHashentryHash。校验器必须能发现内容、顺序或链路被篡改;哈希链是完整性证据,不替代外部不可变存储。
50
+ - 初始化 logger 前必须以 `0700` 预创建 `./logs`;`pino-roll` 不得负责创建目录。日志文件以 `0600` 创建、仅追加。
51
+ - `pino-roll` `size` 固定为 `2m`,轮转文件命名遵循 `filename.date.count.log`,保留既有文件;不得启用 `limit.removeOtherLogFiles` 或有限 `limit.count` 等会删除历史日志的策略。
52
+ - 每条落盘记录在进入 `pino-roll` 前经过哈希链 Transform,包含 `chainId`、`sequence`、`previousHash`、`entryHash`。校验器必须能发现内容、顺序或链路被篡改;哈希链是完整性证据,不替代外部不可变存储。
44
53
  - 日志目录不可创建、权限不可收紧或写入失败时,服务必须显式失败,不得降级到 console 或吞错。
45
54
 
46
55
  ## 留存与生产控制
@@ -1,21 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  import { createHash } from 'node:crypto';
3
3
  import { readFile } from 'node:fs/promises';
4
+ import { basename } from 'node:path';
4
5
  import {
5
6
  assertLogEntry,
7
+ assertPinoRollStorageOptions,
8
+ assertRolledLogFileName,
6
9
  findForbiddenLogFieldPath,
7
10
  } from '../templates/logger.template.ts';
8
11
 
9
12
  const argumentsList = process.argv.slice(2);
10
13
  const storedMode = argumentsList[0] === '--stored';
11
- const inputPath = storedMode ? argumentsList[1] : argumentsList[0];
12
-
13
- if (!inputPath || argumentsList.length !== (storedMode ? 2 : 1)) {
14
- throw new Error('Usage: validate-log-entry.mjs [--stored] <log-file>');
14
+ const storageOptionsMode = argumentsList[0] === '--storage-options';
15
+ let inputPath;
16
+ if (storedMode || storageOptionsMode) {
17
+ if (argumentsList.length !== 2 || !argumentsList[1]) {
18
+ throw new Error('Usage: validate-log-entry.mjs [--stored|--storage-options] <file>');
19
+ }
20
+ inputPath = argumentsList[1];
21
+ } else {
22
+ if (argumentsList.length !== 1 || !argumentsList[0] || argumentsList[0].startsWith('--')) {
23
+ throw new Error('Usage: validate-log-entry.mjs [--stored|--storage-options] <file>');
24
+ }
25
+ inputPath = argumentsList[0];
15
26
  }
16
27
 
17
28
  const source = await readFile(inputPath, 'utf8');
18
29
 
30
+ if (storageOptionsMode) {
31
+ assertPinoRollStorageOptions(JSON.parse(source));
32
+ process.stdout.write('valid pino-roll storage options\n');
33
+ process.exit(0);
34
+ }
35
+
19
36
  const validateEntry = (entry) => {
20
37
  assertLogEntry(entry);
21
38
  const forbiddenPath = findForbiddenLogFieldPath(entry);
@@ -30,6 +47,8 @@ if (!storedMode) {
30
47
  process.exit(0);
31
48
  }
32
49
 
50
+ assertRolledLogFileName(basename(inputPath));
51
+
33
52
  const lines = source.split('\n').filter((line) => line !== '');
34
53
  if (lines.length === 0) throw new Error('Stored log file is empty');
35
54