From 90e2f25e86c09f2d402017fcf12e1f92a15e285e Mon Sep 17 00:00:00 2001 From: loong10k <20489781+loong10k@users.noreply.github.com> Date: Sun, 20 Sep 2026 05:25:48 +0800 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20=E5=8A=A0=E5=9B=BA=E5=A4=96=E9=83=A8?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E5=90=8C=E6=AD=A5=20PR=20=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/skills-sync.yml | 4 ++-- .../.openspec.yaml | 3 +++ .../design.md | 13 +++++++++++ .../proposal.md | 23 +++++++++++++++++++ .../2026-09-20-harden-skills-sync-pr/tasks.md | 9 ++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 openspec/changes/archive/2026-09-20-harden-skills-sync-pr/.openspec.yaml create mode 100644 openspec/changes/archive/2026-09-20-harden-skills-sync-pr/design.md create mode 100644 openspec/changes/archive/2026-09-20-harden-skills-sync-pr/proposal.md create mode 100644 openspec/changes/archive/2026-09-20-harden-skills-sync-pr/tasks.md diff --git a/.github/workflows/skills-sync.yml b/.github/workflows/skills-sync.yml index b9985f1..41f0b87 100644 --- a/.github/workflows/skills-sync.yml +++ b/.github/workflows/skills-sync.yml @@ -59,6 +59,7 @@ jobs: fi git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git fetch origin refs/heads/chore/skills-sync:refs/remotes/origin/chore/skills-sync || true git checkout -B chore/skills-sync git add skills/ skills.lock.json git commit -m "chore: sync vendored skills from codeguard-skills ${REQUESTED_REF:-current-lock}" @@ -74,5 +75,4 @@ jobs: gh pr create \ --title "chore: sync vendored Codeguard skills ${REQUESTED_REF:-current-lock}" \ --body "Automated refresh of the checksummed skill snapshot from skills.lock.json. Requested release: ${REQUESTED_REF:-current lock}; expected commit: ${REQUESTED_SHA:-already pinned}. Externally managed skills come from full-stack-skills/codeguard-skills; plugin-local exceptions must be declared in plugin-local-skills.json." \ - --head chore/skills-sync --base main \ - --label skills-sync + --head chore/skills-sync --base main diff --git a/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/.openspec.yaml b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/.openspec.yaml new file mode 100644 index 0000000..c00284d --- /dev/null +++ b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/.openspec.yaml @@ -0,0 +1,3 @@ +schema: spec-driven +created: 2026-09-20 +skip_specs: true diff --git a/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/design.md b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/design.md new file mode 100644 index 0000000..a1ce58f --- /dev/null +++ b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/design.md @@ -0,0 +1,13 @@ +## Context + +真实 release 验证显示同步内容与锁校验成功,但复用固定同步分支时 lease 信息缺失,或 PR label 不存在,导致升级链在最后阶段失败。 + +## Decisions + +- 显式 fetch refs/heads/chore/skills-sync 到远端跟踪引用,然后继续使用 force-with-lease,不降级为无保护的 force。 +- 删除硬编码 label 参数;分支和 PR 标题仍可清楚识别同步来源。 +- 保留单一同步分支,避免并发 release 产生无限分支。 + +## Verification + +使用静态 workflow 断言、YAML 解析、OpenSpec strict validation,并以 Dreamina/Maya 的真实 immutable release 重新触发端到端同步。 diff --git a/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/proposal.md b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/proposal.md new file mode 100644 index 0000000..3ab2288 --- /dev/null +++ b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/proposal.md @@ -0,0 +1,23 @@ +## Why + +技能同步工作流在远端已存在 chore/skills-sync 分支时没有获取 lease 基线,导致 force-with-lease 以 stale info 失败;仓库缺少 skills-sync label 时,PR 创建也会失败。 + +## What Changes + +- 在重建同步分支前获取远端分支引用,保留安全的 force-with-lease 语义。 +- PR 创建不再依赖预先存在的 label。 +- 保持 ref、peeled SHA、vendor hash 校验与 PR 审核边界不变。 + +## Capabilities + +### New Capabilities + +None. This is an infrastructure-only workflow correction and skip_specs: true is set. + +### Modified Capabilities + +None. + +## Impact + +仅影响 .github/workflows/skills-sync.yml 和本 OpenSpec 记录;不直接修改技能快照、插件版本或运行时行为。 diff --git a/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/tasks.md b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/tasks.md new file mode 100644 index 0000000..5079cd4 --- /dev/null +++ b/openspec/changes/archive/2026-09-20-harden-skills-sync-pr/tasks.md @@ -0,0 +1,9 @@ +## 1. Workflow correction + +- [x] 1.1 Fetch the remote sync branch before rebuilding it. +- [x] 1.2 Remove the hard dependency on a pre-existing PR label. + +## 2. Validation + +- [x] 2.1 Check workflow syntax and required immutable-ref guards. +- [x] 2.2 Run strict OpenSpec validation and archive the change. From 898775c67f60f5e43e86fa3beff5ed3c7aa64c9e Mon Sep 17 00:00:00 2001 From: loong10k <20489781+loong10k@users.noreply.github.com> Date: Sun, 20 Sep 2026 08:08:51 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix:=20=E5=9B=BA=E5=AE=9A=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=AE=88=E5=8D=AB=E4=B8=8D=E5=8F=AF=E5=8F=98=E5=88=86=E5=8F=91?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/plugins/marketplace.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 4fdcc2b..fdfd340 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -9,7 +9,7 @@ "source": { "source": "url", "url": "https://github.com/partme-ai/partme-codeguard-plugin.git", - "ref": "main" + "ref": "v0.5.4" }, "policy": { "installation": "AVAILABLE", @@ -18,11 +18,11 @@ "category": "Developer Tools", "version": "0.5.4", "description": "Cross-language code lint enforcement for AI coding assistants (ZCode, Claude Code, Codex CLI, Kimi Code): Java, Rust, TypeScript, Python. PostToolUse hook auto-runs the native linter on every AI-written file and blocks on failure in strict mode.", - "icon": "https://raw.githubusercontent.com/partme-ai/partme-codeguard-plugin/main/assets/official-logo.png", + "icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.5.4/assets/official-logo.png", "interface": { "displayName": "代码规范守卫", "shortDescription": "Make AI-written code pass lint on first try", - "logo": "https://raw.githubusercontent.com/partme-ai/partme-codeguard-plugin/main/assets/official-logo.png" + "logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.5.4/assets/official-logo.png" } } ] From 01eb47ac2f5b5ca55c63c5480a69c7e75dda4c9d Mon Sep 17 00:00:00 2001 From: loong10k <20489781+loong10k@users.noreply.github.com> Date: Tue, 22 Sep 2026 00:41:04 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20CVE=20=E9=80=9A=E7=94=A8=E5=85=9C?= =?UTF-8?q?=E5=BA=95=E6=8E=A5=E7=BA=BF=20+=20markdown=20=E9=97=A8=E7=A6=81?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=88=E4=B8=A4=E4=BB=BD=20OpenSpec=20chan?= =?UTF-8?q?ge=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wire-cve-universal-fallback: - 生态标识三套命名空间合并为 ECOSYSTEM_SCANNERS 权威映射(别名 java/trivy) - 无原生扫描器的语言自动落 universal(trivy)兜底;原生工具缺失不顶替 - --severity 统一「阈值及以上」;maven 改按 CVSS 档位下界(HIGH⇒7,修复旧映射吞 MEDIUM) - 新增退出码 3=参数错误,未声明生态在任何扫描前拒绝 repair-markdown-gate-and-doc-sync: - markdown lint 补 glob、format 补 npx/--fix、probe 改 --format+stdin=DEVNULL(修假绿) - markdown/yaml 声明 requiresConfig:未接入→未验证跳过,不再被默认规则全仓报错 - 配置模板补 MD060;docs/LANGUAGES.md 恢复可复现(6 步流程入生成器) - tests 增 cve 子集(35 条)与文档同步子集(双向漂移拦截),全量 141/141 --- .markdownlint-cli2.jsonc | 27 +++ README.md | 17 +- README.zh-CN.md | 13 +- bin/codeguard | 5 +- docs/LANGUAGES.md | 53 ++--- linters/markdown/.markdownlint-cli2.jsonc | 1 + .../.openspec.yaml | 2 + .../design.md | 87 ++++++++ .../proposal.md | 48 +++++ .../specs/language-gate-commands/spec.md | 56 +++++ .../specs/language-registry-doc-sync/spec.md | 51 +++++ .../tasks.md | 55 +++++ .../.openspec.yaml | 2 + .../design.md | 64 ++++++ .../proposal.md | 36 ++++ .../specs/cve-dependency-scan/spec.md | 95 +++++++++ .../tasks.md | 48 +++++ scripts/cve_check.py | 180 ++++++++++++---- scripts/detect_lang.py | 4 +- scripts/gen_language_docs.py | 25 ++- scripts/languages.json | 30 ++- tests/run_all.py | 197 +++++++++++++++++- 22 files changed, 1006 insertions(+), 90 deletions(-) create mode 100644 .markdownlint-cli2.jsonc create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/.openspec.yaml create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/design.md create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/proposal.md create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-gate-commands/spec.md create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-registry-doc-sync/spec.md create mode 100644 openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/tasks.md create mode 100644 openspec/changes/2026-09-21-wire-cve-universal-fallback/.openspec.yaml create mode 100644 openspec/changes/2026-09-21-wire-cve-universal-fallback/design.md create mode 100644 openspec/changes/2026-09-21-wire-cve-universal-fallback/proposal.md create mode 100644 openspec/changes/2026-09-21-wire-cve-universal-fallback/specs/cve-dependency-scan/spec.md create mode 100644 openspec/changes/2026-09-21-wire-cve-universal-fallback/tasks.md diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..fb7113d --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,27 @@ +// codestyle-check (codeguard): markdownlint 宽松配置 +// 定位:AI 产出的报告/文档不应用代码级规则拦截;本配置只保留真正影响可读性的规则。 +// 使用方法:拷贝到项目根 .markdownlint-cli2.jsonc + +{ + "config": { + // ===== 关闭(报告/文档类高频误报)===== + "MD013": false, // line-length:报告行宽不设限 + "MD022": false, // headings 应前后空行 + "MD031": false, // fenced code blocks 前后空行 + "MD032": false, // lists 前后空行 + "MD040": false, // fenced code blocks 语言标注 + "MD041": false, // 首行必须是标题(附录/片段常不满足) + "MD033": false, // 行内 HTML(报告常用表格/详情标签) + "MD036": false, // 不用强调代替标题 + "MD034": false, // 不带空格的裸 URL + "MD038": false, // 行内代码中的反引号 + "MD047": false, // 文件末尾单换行(工具生成文件常缺) + "MD060": false, // 表格列样式(新规则;报告表格不按它排版,同 MD013 理由) + + // ===== 保留(真实影响可读性)===== + "MD009": { "br_spaces": 0 }, // 行尾空格 + "MD010": { "code_blocks": false }, // 硬 tab + "MD012": { "maximum": 3 }, // 连续空行上限 + "MD004": { "style": "dash" }, // 无序列表符号一致 + } +} diff --git a/README.md b/README.md index 2611b1e..071089c 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,15 @@ AI code that passes lint on first try | Status | Languages | |---|---| | **Stable** (53, auto-enforced) | Java, Rust, TypeScript/JavaScript, Python, Go, C#, Kotlin, Swift, PHP, Ruby, Scala, Shell, Dockerfile, YAML, Elixir, CSS/SCSS, Markdown, SQL, TOML, HTML, Protobuf, Terraform/OpenTofu, Nix, Dart, Solidity, Ansible-playbooks, Perl, Groovy, Clojure, PowerShell, Zig, Nim, Crystal, Julia (format-only), Pascal (format-only), Elm, Lua, Luau, C++ (clang-tidy), Objective-C, CUDA, GraphQL, Protobuf digest, VB.NET, Erlang, R, CFML — and more; see LANGUAGES.md | + +> **Markdown / YAML opt-in semantics**: both declare `requiresConfig` — without a root linter config +> (e.g. `.markdownlint-cli2.jsonc` / `.yamllint`) the project counts as not opted in: safely skipped, +> never blocked, never swept by tool default rules. The markdown gate is advisory (reported in skipped, non-blocking). +> Its lint command previously lacked a glob and always exited with a usage error; it now returns real results. +> `codeguard init` copies the lenient config template. | **Planned** (4, no independent CLI linter) | Metal, ArkTS (HarmonyOS), COBOL, Liquid (Shopify theme-check 已列为工具,待接通) | -## Governance skills (Git & Security) (Git & Security) + +## Governance skills (Git & Security) Beyond linting, codeguard ships standalone governance skills sourced from the team's engineering-standards wiki: @@ -150,12 +157,16 @@ ln -s $PWD/bin/codeguard /usr/local/bin/codeguard codeguard check # multi-language lint gate codeguard fix # auto-fix lint issues -codeguard cve # CVE dependency scan (Maven/npm/Python/Rust orchestration) +codeguard cve # CVE dependency scan (Maven/npm/Python/Rust + universal trivy fallback) codeguard cve --fix # scan + auto-fix (npm audit fix) -codeguard cve --severity MEDIUM # gate threshold down to medium +codeguard cve --severity MEDIUM # threshold-and-above: MEDIUM+HIGH+CRITICAL fail +codeguard cve --ecosystem java # alias for maven; unknown values exit 3 before any scan codeguard detect # detect project languages ``` +CVE exit codes: `0` pass, `1` unverifiable (tool missing / nothing scannable), `2` findings, `3` usage error. +Ecosystems without a native scanner fall back to `trivy fs --scanners vuln` when detected; native tools are never replaced by the fallback. Severity means threshold-and-above on every scanner (maven maps to CVSS band floors: HIGH⇒7). + Maven CVE scanning uses OWASP dependency-check (pom snippet in `linters/maven/dependency-check-pom-snippet.xml`; build fails at `CVSS>=7`). **A finding must be fixed, not filed away**: every report ships with the fix command diff --git a/README.zh-CN.md b/README.zh-CN.md index adc832b..b9a8157 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -79,6 +79,11 @@ AI 一次写出就过 lint 的代码 | 状态 | 语言 | |---|---| | **Stable**(53 种,默认强制) | Java、Rust、TypeScript/JavaScript、Python、Go、C#、Kotlin、Swift、PHP、Ruby、Scala、Shell、Dockerfile、YAML、Elixir、CSS/SCSS、Markdown、SQL、TOML、HTML、Protobuf、Terraform/OpenTofu、Nix、Dart、Solidity、Ansible、Perl、Groovy、Clojure、PowerShell、Zig、Nim、Crystal、Julia(仅格式化)、Pascal(仅格式化)、Elm、Lua、Luau、C++(clang-tidy)、Objective-C、CUDA、GraphQL、VB.NET、Erlang、R、CFML 等,详见 LANGUAGES.md | + +> **Markdown / YAML 接入语义**:二者声明了 `requiresConfig`——项目根没有对应 linter 配置 +> (如 `.markdownlint-cli2.jsonc` / `.yamllint`)时视为**未接入**,安全跳过、不阻塞提交, +> 不会被工具默认规则全仓报错。Markdown 门禁为 advisory(告警进 skipped,不拦截); +> 此前其 lint 命令缺 glob、恒以用法错误退出,现已返回真实结论。`codeguard init` 会拷入宽松配置模板。 | **Planned**(4 种,无独立 CLI linter) | Metal、ArkTS(HarmonyOS)、COBOL、Liquid(theme-check 待接通) | ## 外部技能来源 @@ -136,12 +141,16 @@ ln -s $PWD/bin/codeguard /usr/local/bin/codeguard codeguard check # 跑多语言 lint 门禁 codeguard fix # 自动修复 lint 问题 -codeguard cve # CVE 依赖漏洞扫描(Maven/npm/Python/Rust 编排) +codeguard cve # CVE 依赖漏洞扫描(Maven/npm/Python/Rust + universal trivy 兜底) codeguard cve --fix # 扫描并自动修复(npm audit fix) -codeguard cve --severity MEDIUM # 门禁阈值调到中危 +codeguard cve --severity MEDIUM # 「该级别及以上」:MEDIUM/HIGH/CRITICAL 都算失败 +codeguard cve --ecosystem java # maven 的别名;未声明生态在任何扫描前退出码 3 拒绝 codeguard detect # 检测项目语言 ``` +CVE 退出码:`0` 通过 / `1` 无法验证(工具缺失或无可扫描生态) / `2` 存在漏洞 / `3` 参数错误。 +未被原生扫描器覆盖的语言自动落 `trivy fs --scanners vuln` 通用兜底;原生工具缺失时保持「无法验证」,不用兜底顶替。`--severity` 在所有扫描器上都是「阈值及以上」(maven 按 CVSS 档位下界换算:HIGH⇒7)。 + Maven 项目 CVE 扫描使用 OWASP dependency-check(pom 配置模板见 `linters/maven/dependency-check-pom-snippet.xml`;`CVSS>=7 构建失败`)。 **检查出来了得修**:报告会附带每个生态的修复命令(升级依赖 / 登记误报),npm 支持 `audit fix` 自动修复。 diff --git a/bin/codeguard b/bin/codeguard index 4aeb696..3a14d63 100755 --- a/bin/codeguard +++ b/bin/codeguard @@ -4,7 +4,10 @@ # 用法: # codeguard check [--lang LANG] [--timeout N] [path] # 跑代码规范 lint(多语言) # codeguard fix [--lang LANG] [path] # 自动修复 lint 问题 -# codeguard cve [--json] [--severity S] [path] # CVE 依赖漏洞扫描(多生态编排) +# codeguard cve [--ecosystem E] [--severity S] [--fix] [--json] [path] +# # CVE 依赖漏洞扫描 +# # 生态: maven(别名 java) / node / python / rust / universal(别名 trivy) +# # 退出码: 0 通过 / 1 无法验证 / 2 存在漏洞 / 3 参数错误 # codeguard dockerfile [--json] [path] # Dockerfile 安全风险检查(hadolint + trivy config) # codeguard detect [path] # 检测项目语言 # diff --git a/docs/LANGUAGES.md b/docs/LANGUAGES.md index 064e9ac..4a0fc1e 100644 --- a/docs/LANGUAGES.md +++ b/docs/LANGUAGES.md @@ -1,7 +1,7 @@ # partme-codeguard-plugin 支持的语言 > 覆盖 **55 种编程语言**(注册表 57 条,含 Dockerfile/Ansible 等文件类型条目)。所有语言均可被 `detect_lang` 识别;其中 **53 条**已接入 linter 强制门禁(Stable / Beta),其余列入路线图(Planned,钩子检测到后安全跳过)。 - +> > 本文档由 `scripts/languages.json` 注册表自动生成(`scripts/gen_language_docs.py`);新增/调整语言请改注册表后重新生成。 @@ -11,57 +11,57 @@ |---|---|---|---|---| | Java | `.java` | `mvn -q javadoc:jar -DskipTests` | `mvn -q spotless:apply` | — | | Rust | `.rs` | `cargo clippy --all-targets -- -D warnings` | `cargo fmt` | — | -| TypeScript / JavaScript | `.ts` `.tsx` `.js` `.jsx` `.mjs` `.cjs` | `npx eslint . --max-warnings 0` | `npx eslint . --fix` | 项目需安装 eslint | +| TypeScript / JavaScript | `.ts` `.tsx` `.js` `.jsx` `.mjs` `.cjs` | `npx --no-install eslint . --max-warnings 0` | `npx eslint . --fix` | 项目需安装 eslint | | Python | `.py` | `ruff check .` | `ruff check . --fix` | pip install ruff | | Go | `.go` | `go vet ./...` | `gofmt -w .` | 内置于 Go 工具链;聚合 lint 可装 golangci-lint | | C# | `.cs` | `dotnet format --verify-no-changes` | `dotnet format` | .NET SDK 6+ | | Kotlin | `.kt` `.kts` | `./gradlew detekt` | `./gradlew ktlintFormat` | 项目需配置 detekt / ktlint 插件 | | Swift | `.swift` | `swiftlint` | `swiftlint --fix` | brew install swiftlint | -| PHP | `.php` | `php -l` | `php-cs-fixer fix` | composer require --dev php-cs-fixer | +| PHP | `.php` | `php -l {file}` | `php-cs-fixer fix` | composer require --dev php-cs-fixer | | Ruby | `.rb` | `rubocop` | `rubocop -A` | gem install rubocop | -| Scala | `.scala` `.sc` | `scalafmt --check` | `scalafmt` | coursier install scalafmt | -| Shell | `.sh` `.bash` `.zsh` | `shellcheck` | `shfmt -w .` | brew install shellcheck shfmt | -| Dockerfile | (文件名匹配) | `hadolint` | `hadolint` | brew install hadolint | +| Scala | `.scala` `.sc` | `scalafmt --check .` | `scalafmt` | coursier install scalafmt | +| Shell | `.sh` `.bash` `.zsh` | `shellcheck {file}` | `shfmt -w .` | brew install shellcheck shfmt | +| Dockerfile | (文件名匹配) | `hadolint {file}` | `hadolint` | brew install hadolint | | YAML | `.yml` `.yaml` | `yamllint .` | `yamllint .` | pip install yamllint | | Elixir | `.ex` `.exs` | `mix credo --strict` | `mix format` | 项目需配置 credo 依赖 | -| CSS / SCSS / Sass / LESS | `.css` `.scss` `.sass` `.less` | `npx stylelint **/*.css` | `npx stylelint **/*.css --fix` | npm install --save-dev stylelint stylelint-config-standard | -| C | `.c` `.h` | `clang-tidy --quiet` | `clang-format -i` | clang-tidy + clang-format | -| C++ | `.cpp` `.hpp` `.cc` | `clang-tidy --quiet` | `clang-format -i` | clang-tidy + clang-format | -| Objective-C | `.m` `.mm` | `clang-tidy --quiet` | `clang-format -i` | clang-tidy + clang-format | +| CSS / SCSS / Sass / LESS | `.css` `.scss` `.sass` `.less` | `npx --no-install stylelint **/*.css` | `npx stylelint **/*.css --fix` | npm install --save-dev stylelint stylelint-config-standard | +| C | `.c` `.h` | `clang-tidy --quiet {file}` | `clang-format -i {file}` | clang-tidy + clang-format | +| C++ | `.cpp` `.hpp` `.cc` | `clang-tidy --quiet {file}` | `clang-format -i {file}` | clang-tidy + clang-format | +| Objective-C | `.m` `.mm` | `clang-tidy --quiet {file}` | `clang-format -i {file}` | clang-tidy + clang-format | | Dart / Flutter | `.dart` | `dart analyze` | `dart format .` | Dart SDK 内置 | -| Vue | `.vue` | `npx eslint --ext .vue .` | `npx eslint --ext .vue . --fix` | eslint-plugin-vue | -| Svelte | `.svelte` | `npx eslint .` | `npx eslint . --fix` | eslint-plugin-svelte | -| Astro | `.astro` | `npx eslint .` | `npx eslint . --fix` | eslint-plugin-astro | +| Vue | `.vue` | `npx --no-install eslint --ext .vue .` | `npx eslint --ext .vue . --fix` | eslint-plugin-vue | +| Svelte | `.svelte` | `npx --no-install eslint .` | `npx eslint . --fix` | eslint-plugin-svelte | +| Astro | `.astro` | `npx --no-install eslint .` | `npx eslint . --fix` | eslint-plugin-astro | | Solidity | `.sol` | `solhint **/*.sol` | `prettier --plugin=prettier-plugin-solidity --write` | npm install -g solhint prettier prettier-plugin-solidity | | Terraform / OpenTofu | `.tf` `.tfvars` `.tofu` | `tflint` | `terraform fmt` | brew install tflint | -| Nix | `.nix` | `deadnix` | `nixpkgs-fmt` | nix-env -iA nixpkgs.nixpkgs-fmt nixpkgs.deadnix | -| HTML | `.html` `.htm` | `npx htmlhint` | `prettier --write` | npm install -g htmlhint | -| SQL | `.sql` | `sqlfluff lint` | `sqlfluff fix` | pip install sqlfluff | -| GraphQL | `.graphql` `.gql` | `npx eslint --ext .graphql .` | `npx eslint --ext .graphql . --fix` | graphql-eslint | +| Nix | `.nix` | `deadnix {file}` | `nixpkgs-fmt {file}` | nix-env -iA nixpkgs.nixpkgs-fmt nixpkgs.deadnix | +| HTML | `.html` `.htm` | `npx --no-install htmlhint {file}` | `prettier --write` | npm install -g htmlhint | +| SQL | `.sql` | `sqlfluff lint {file}` | `sqlfluff fix` | pip install sqlfluff | +| GraphQL | `.graphql` `.gql` | `npx --no-install eslint --ext .graphql .` | `npx eslint --ext .graphql . --fix` | graphql-eslint | | Protobuf | `.proto` | `buf lint` | `buf format` | brew install bufbuild/buf/buf | -| Markdown | `.md` `.markdown` | `npx markdownlint-cli2 **/*.md` | `markdownlint-cli2 --fix` | npm install -g markdownlint-cli2 | -| TOML | `.toml` | `taplo lint` | `taplo format` | cargo install taplo-cli --locked | +| Markdown | `.md` `.markdown` | `npx --no-install markdownlint-cli2 **/*.md #node_modules` | `npx --no-install markdownlint-cli2 **/*.md #node_modules --fix` | npm install -g markdownlint-cli2 | +| TOML | `.toml` | `taplo lint .` | `taplo format` | cargo install taplo-cli --locked | | Haskell | `.hs` `.lhs` | `hlint .` | `fourmolu -i .` | brew install hlint fourmolu | | OCaml | `.ml` `.mli` | `ocamlformat --check .` | `ocamlformat -i .` | opam install ocamlformat | | F# | `.fs` `.fsi` `.fsx` | `dotnet fantomas --check` | `dotnet fantomas` | dotnet tool install -g fantomas | -| Perl | `.pl` `.pm` `.t` | `perlcritic` | `perltidy -b` | cpanm Perl::Critic Perl::Tidy | -| Groovy | `.groovy` | `npm-groovy-lint` | `npm-groovy-lint --fix` | npm install -g npm-groovy-lint | +| Perl | `.pl` `.pm` `.t` | `perlcritic {file}` | `perltidy -b {file}` | cpanm Perl::Critic Perl::Tidy | +| Groovy | `.groovy` | `npm-groovy-lint {file}` | `npm-groovy-lint --fix` | npm install -g npm-groovy-lint | | Clojure | `.clj` `.cljs` `.cljc` `.edn` | `clj-kondo --lint src` | `cljstyle` | brew install clj-kondo cljstyle | | PowerShell | `.ps1` `.psm1` | `pwsh -NoProfile -Command Invoke-ScriptAnalyzer -Path . -Severity Error` | `pwsh -NoProfile -Command Invoke-Formatter` | Install-Module PSScriptAnalyzer | -| Zig | `.zig` | `zig fmt --check` | `zig fmt` | 内置于 Zig 工具链 | +| Zig | `.zig` | `zig fmt --check .` | `zig fmt` | 内置于 Zig 工具链 | | Nim | `.nim` | `nim check src` | `nimpretty -r .` | nimpretty 内置于 Nim | | Crystal | `.cr` | `ameba` | `crystal tool format` | brew install crystal-ameba | | Julia | `.jl` | — | `julia -e using JuliaFormatter; format('.')` | julia -e 'using Pkg; Pkg.add("JuliaFormatter")' | | Elm | `.elm` | `elm-review` | `elm-format --yes` | npm install -g elm-review elm-format | | Lua | `.lua` | `luacheck .` | `stylua .` | luarocks install luacheck; cargo install stylua | -| Luau | `.luau` | `luau-analyze` | `stylua --syntax luau .` | luau-lsp / luau-analyze | +| Luau | `.luau` | `luau-analyze {file}` | `stylua --syntax luau .` | luau-lsp / luau-analyze | | Pascal / Delphi | `.pas` `.dpr` `.dpk` `.lpr` | — | `ptop -b .` | pasfmt | | R | `.r` | `Rscript -e lintr::lint_dir('.')` | `styler :: style_dir` | Rscript -e 'install.packages(c("lintr","styler"))' | -| CFML (ColdFusion) | `.cfc` `.cfm` `.cfs` | `cflint` | — | brew install cflint | -| Visual Basic .NET | `.vb` | `dotnet format` | `dotnet format` | .NET SDK 6+ | +| CFML (ColdFusion) | `.cfc` `.cfm` `.cfs` | `cflint {file}` | — | brew install cflint | +| Visual Basic .NET | `.vb` | `dotnet format --verify-no-changes` | `dotnet format` | .NET SDK 6+ | | Erlang | `.erl` `.hrl` | `elvis rock` | `erlfmt` | rebar3 plugins / escript | | Liquid (Shopify) | `.liquid` | `theme-check .` | — | gem install theme-check | -| CUDA | `.cu` `.cuh` | `clang-tidy --quiet` | `clang-format -i` | CUDA Toolkit + clangd | +| CUDA | `.cu` `.cuh` | `clang-tidy --quiet {file}` | `clang-format -i {file}` | CUDA Toolkit + clangd | ## Planned(已识别,linter 在路线图上)(4 种) @@ -87,3 +87,4 @@ 4. 更新插件 `skills.lock.json` 的 ref 和技能清单,运行 `python3 scripts/vendor/skill_vendor.py update`。 5. 重跑 `python3 scripts/gen_language_docs.py` 同步本文档。 6. 执行 vendor 离线/在线检查,并用 `python3 scripts/detect_lang.py <项目>` 冒烟验证。 + diff --git a/linters/markdown/.markdownlint-cli2.jsonc b/linters/markdown/.markdownlint-cli2.jsonc index 3da386b..fb7113d 100644 --- a/linters/markdown/.markdownlint-cli2.jsonc +++ b/linters/markdown/.markdownlint-cli2.jsonc @@ -16,6 +16,7 @@ "MD034": false, // 不带空格的裸 URL "MD038": false, // 行内代码中的反引号 "MD047": false, // 文件末尾单换行(工具生成文件常缺) + "MD060": false, // 表格列样式(新规则;报告表格不按它排版,同 MD013 理由) // ===== 保留(真实影响可读性)===== "MD009": { "br_spaces": 0 }, // 行尾空格 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/.openspec.yaml b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/.openspec.yaml new file mode 100644 index 0000000..563fab5 --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-21 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/design.md b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/design.md new file mode 100644 index 0000000..c9b453e --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/design.md @@ -0,0 +1,87 @@ +## Context + +markdown 门禁的红与仓库内容无关。`scripts/languages.json` 中 markdown 的 `lint` 是 +`["npx","--no-install","markdownlint-cli2"]`,而 markdownlint-cli2 v0.23.3 在无参数调用下打印用法并以 **exit 2** 结束: + +``` +$ npx --no-install markdownlint-cli2 ; echo $? +2 +``` + +即 markdown 从未检查过任何文件,却每次都被上报为「lint 失败」。同一语言的另外两个命令也不成立: +`probe` 为 `... markdownlint-cli2 --version`,`--version` 不被识别而**被当成 glob**(输出 `Finding: --version`), +扫 0 文件后成功退出;`format` 为 `["markdownlint-cli2","--fix"]`,既无包管理器前缀也无 glob, +而该二进制并未全局安装。 + +模板侧:`linters/markdown/.markdownlint-cli2.jsonc` 的禁用清单写于 `MD060` 出现之前。 +加上显式 glob 后全仓为 2651 条,套用模板降到 1087 条,其中 **1005 条是 `MD060/table-column-style` 一条新规则**; +把 MD060 也关掉后降到 80 条。 + +`docs/LANGUAGES.md` 的漂移是排查中偶然发现的:文档自称由注册表生成,但实测与注册表有 **31 处命令不一致** +(表格落后于注册表,例如文档写 `php -l` 而注册表已是 `php -l {file}`), +而「新增语言的流程」一段又**领先于生成器**(文档里的 6 步版本包含外部技能仓与 vendor 流程,生成器只产出旧的 5 步版本)。 +因此重跑生成器会**同时修正表格、破坏段落**——这就是为什么不能直接重新生成。 + +## Goals / Non-Goals + +**Goals:** + +- 让 markdown 门禁真正执行检查,并让「未接入」回到「未验证、不阻塞」的既有语义。 +- 让注册表到文档的生成关系变成真的可复现,从而使注册表可以被安全修改。 +- 让上述两类不一致都有检查可检出,而不是依赖人工发现。 + +**Non-Goals:** + +- 不修改 `skills/**` 下 80 条 markdown 问题。那是外部锁定内容,须在上游 `codeguard-skills` 修复并发版。 +- 不改动 `post_tool_lint` 的全仓格式化行为(见 Risks,属独立问题)。 +- 不引入 linter 版本固定或依赖锁(本变更只让命令能跑,不解决规则集随时间漂移)。 +- 不改动 markdown / yaml 之外语言的门禁行为。 + +## Decisions + +**修命令而不修调用方。** +门禁调用约定是「注册表声明什么就执行什么」,`{file}` 占位符与 glob 都由注册表表达。若改为在调用方补 glob, +则每个调用点都要知道每种工具的参数习惯——那正是注册表要消除的重复。markdown 的 glob 属于该语言自己的约定, +放回注册表。同理 `format` 补 `npx --no-install`:与 eslint、stylelint 等条目已在用的写法一致。 + +**给 markdown / yaml 声明 `requiresConfig`,并据此重新表述既有断言。** +现有测试断言的措辞是「无 requiresConfig 视为已接入」——它记录的是**未声明时不做限制**这一默认行为,而不是 +「任何语言都不得声明前置条件」。本变更不推翻该默认,只是让 markdown / yaml 不再落在默认里。 +这两个语言的共同点是:工具默认规则包含大量风格偏好(行宽、表格列样式),在没有项目配置的情况下用默认值全仓报错, +等于用别人的审美否决本仓内容。这与 `codeguard init` 的设计一致——配置本来就是「拷贝即用」的可选项。 + +**MD060 加进模板,而不是改门禁去忽略它。** +模板注释已写明「AI 产出的报告/文档不应用代码级规则拦截」,`MD060`(表格列样式)正属该类。 +把它加进模板的禁用清单,是延续模板既有意图;若改为在门禁层面忽略,则用户项目里同样的问题仍会复现。 + +**生成器覆盖全部内容,而不是给手工段打标记。** +两条路都能满足可复现:把 6 步段落搬进生成器,或在文档里标注该段手工维护并由生成器原样保留。 +选前者:该段落描述的是「新增语言的流程」,其权威来源就是本仓流程本身,放进生成器后修改只需改一处; +而「保留区段」方案会让生成器继续与文档存在第二种关系,正是本次漂移的成因。 + +**漂移检查放进 `tests/run_all.py`,双向比对。** +现有测试入口已被 CI 调用,无需新增命令。检查按语言行的 `lint`/`format` 逐字段比对, +因此「文档落后」与「文档被手工前移」都会失败——后者尤其重要,它正是本次漂移中「段落领先于生成器」的那一半。 + +## Risks / Trade-offs + +- **markdown 门禁的结论会首次变成真实结果**:此前恒为「用法错误」,此后已接入 markdown 的仓会得到真实 lint 结论, + 可能立刻显示大量问题(本仓在修完自有 2 条后仍剩 80 条,全部来自锁定的 `skills/**`,需上游发版才能清零)。 + 这是本变更的预期收益,但必须让使用者预期到,否则会被读成「这次改动弄坏了 markdown」。 +- **`requiresConfig` 会改变所有仓的 markdown / yaml 判定**:未配置的仓从「被默认规则全仓报错」变为「未验证跳过」。 + 这消除了误报,但也意味着未配置的仓不再获得任何 markdown 覆盖——是「不误报」与「不遗漏」之间的取舍,取了前者。 +- **`npx --no-install` 仍会解析到较新版本**,规则集继续随时间漂移(本次的 MD060 即由此而来)。 + 固定版本需引入依赖锁,属独立变更;本变更只保证命令能跑、且新规则可通过模板禁用清单追补。 +- **`docs/LANGUAGES.md` 重新生成会一次性产生 31 处命令修正**,diff 较大。这些修正是把陈旧表格对齐到注册表, + 不是新增内容;但审阅时需要逐条确认对齐方向正确(注册表为较新一侧)。 +- **本仓 markdown 门禁在本次变更后仍不会转绿**(80 条在上游)。若有流程把「门禁绿」当作完成信号,需注意这一点。 + +## Verification + +- `openspec validate --strict` 通过。 +- `python3 tests/run_all.py` 全绿,且包含新增的漂移检查。 +- 单项验证:`npx --no-install markdownlint-cli2 "**/*.md"` 在仓根返回真实 lint 结论(非用法错误)。 +- 可复现性:注册表未变更时重跑 `python3 scripts/gen_language_docs.py` 无差异(`git diff` 为空)。 +- 双向前移检测:手工改动文档任一命令后漂移检查失败;恢复后通过。 +- 未接入语义:在一个没有 markdownlint 配置的临时项目上跑门禁,markdown 归为未验证且不阻塞。 +- 端到端转绿的唯一路径已明确:上游 `codeguard-skills` 修 80 条 → 发 tag → 插件重 vendor。 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/proposal.md b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/proposal.md new file mode 100644 index 0000000..95edec9 --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/proposal.md @@ -0,0 +1,48 @@ +## Why + +`markdown` 门禁从未工作过:注册表里 markdown 的 `lint` 命令是 +`npx --no-install markdownlint-cli2`,而 markdownlint-cli2 v0.23.3 不接受无参数调用, +于是每一次门禁都以「用法错误」退出(exit 2)——它与仓库内容无关,是**结构性红**。 +同时这条命令的 `probe` 把一个无效 flag 当成路径处理、`format` 引用未全局安装的二进制, +三者合起来意味着 markdown 的「工具可用性 / 检查 / 自动修复」三个环节都没有真正跑通过。 + +叠加两层后果:仓内 markdown 配置模板写于 `MD060` 规则出现之前,其禁用清单没有它, +因此一旦命令被修好,全仓会立刻被这条新规则淹没;而 `markdown` / `yaml` 未声明 `requiresConfig`, +使「项目未接入」被当成「已接入」,用工具**默认**规则扫全仓——这也是聚合工作区根目录永久红的原因。 + +排查过程中还发现一条独立的缺陷:`docs/LANGUAGES.md` 自称「由注册表自动生成」, +但实际**双向漂移**——表格落后于注册表(31 处命令不一致),而「新增语言的流程」一段又领先于生成器 +(文档里的 6 步版本包含外部技能仓与 vendor 流程,生成器只会产出旧的 5 步版本)。 +后果是**重跑生成器会同时修正与破坏**,在当前状态下并不安全。 + +## What Changes + +- 修正 markdown 的命令三处:`lint` 补 glob、`format` 补包管理器前缀与 glob、`probe` 改用真实可用性查询。 +- 给 `markdown` / `yaml` 声明 `requiresConfig`,使「项目未接入」回到「未验证、不阻塞」的既有语义。 +- 仓内 markdown 配置模板补上 `MD060` 禁用项,与模板既有的「AI 产出文档不应用代码级规则拦截」定位一致。 +- 让生成器覆盖文档的全部内容,然后重跑一次,使 `docs/LANGUAGES.md` 同时正确且可复现。 +- 增加漂移检查,使文档与注册表任一方向的不一致都可见。 + +## Capabilities + +### New Capabilities + +- `language-gate-commands`: 注册表声明的 lint / format / probe 命令的可执行性要求,以及语言声明配置前置条件的能力。 +- `language-registry-doc-sync`: 注册表到 `docs/LANGUAGES.md` 的可复现生成、命令逐字段一致性,以及漂移可检出。 + +### Modified Capabilities + +None. 本仓 `openspec/specs/` 当前为空。 + +## Impact + +- `scripts/languages.json`:markdown 的 `lint` / `format` / `probe`,`markdown` 与 `yaml` 的 `requiresConfig`。 +- `linters/markdown/.markdownlint-cli2.jsonc`:新增 `MD060` 禁用项(会随 `codeguard init` 复制到用户项目)。 +- `scripts/gen_language_docs.py`:覆盖「新增语言的流程」等区段,使文档可复现。 +- `docs/LANGUAGES.md`:重新生成一次;`README.md`、`docs/LANGUAGES.md` 本次已就地修掉的自有 markdown 问题。 +- `tests/run_all.py`:`无 requiresConfig 视为已接入` 这条断言的含义需重新表述——它描述的是「未声明时不做限制」, + 而不是「不得声明」;同时新增文档/注册表漂移断言。 +- **行为变更**:markdown 门禁从「永远因用法错误而红」变为「真正按配置检查」。已接入 markdown 的仓将首次得到真实结论; + 未接入的仓转为未验证。这一改动会影响所有使用 codeguard 的仓,需在发布说明中明示。 +- 上游 `full-stack-skills/codeguard-skills` 需修掉 `skills/**` 下 80 条 markdown 问题并发新 tag,插件重 vendor 后 + 才能让本仓 markdown 门禁转绿;本变更不直接修改锁定技能内容。 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-gate-commands/spec.md b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-gate-commands/spec.md new file mode 100644 index 0000000..79dc779 --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-gate-commands/spec.md @@ -0,0 +1,56 @@ +## Purpose + +定义语言注册表中每个条目所声明命令的可执行性要求:`lint` / `format` / `probe` 必须能以声明的方式真正运行,需要路径或文件参数时必须以显式占位符或 glob 表达;并定义语言声明配置前置条件的能力,使「项目未接入」与「检查失败」不再混为一谈。 + +## ADDED Requirements + +### Requirement: Declared commands must be runnable as written + +注册表声明的 `lint` / `format` / `probe` 命令 SHALL 能按声明形式直接执行;需要文件或路径参数的 SHALL 以 `{file}` 占位符或显式 glob 表达,不得依赖调用方补全。 + +#### Scenario: 缺少必需参数 + +- **WHEN** 某语言的 `lint` 命令在无参数调用下返回工具用法错误(而非 lint 结论) +- **THEN** 门禁不得把它作为「lint 失败」上报,因为该结果与仓库内容无关 + +#### Scenario: markdown 的 lint 命令 + +- **WHEN** 门禁在已接入 markdown 的项目上运行 +- **THEN** markdownlint 实际检查文件并以 lint 结论作为退出码,而不是返回用法错误 + +### Requirement: Probe must not confirm availability through a misinterpreted argument + +`probe` 命令 SHALL 使用目标工具真实支持的可用性查询方式。当命令中的 flag 不被工具识别、因而被解释为路径或 glob 参数时,SHALL NOT 据此判定工具可用。 + +#### Scenario: 无效 flag 被当成路径 + +- **WHEN** probe 命令包含该工具不认识的 flag,导致其被当作文件或 glob 处理并仍然成功退出 +- **THEN** 该探测结果不得被用作「工具已安装且可用」的证据 + +### Requirement: Auto-fix command must be executable and scoped + +`format` 命令 SHALL 可通过注册表声明的入口直接执行,包括在工具未全局安装时经包管理器解析;且 SHALL 明确其作用范围是单文件还是整个项目,不得使调用方无从判断影响面。 + +#### Scenario: 工具未全局安装 + +- **WHEN** `format` 命令引用一个未全局安装的工具 +- **THEN** 自动修复 SHALL 经包管理器解析执行,而不是以 command not found 失败 + +### Requirement: Languages may declare a configuration prerequisite + +注册表 SHALL 允许为语言声明 `requiresConfig`。对以风格偏好为主、其默认规则会大面积误报的工具(如 markdown、yaml),SHALL 声明该前置条件。 + +#### Scenario: 已声明前置条件且项目未接入 + +- **WHEN** 项目缺少该语言声明的配置文件 +- **THEN** 该语言判定为未接入 / 未验证,安全跳过且不阻塞提交,并在结果中说明未验证的原因 + +#### Scenario: 已声明前置条件且项目已接入 + +- **WHEN** 项目存在该语言声明的配置文件 +- **THEN** 门禁按该配置正常检查,结论作为 lint 结果上报 + +#### Scenario: 未声明前置条件的语言不受影响 + +- **WHEN** 某语言未声明 `requiresConfig` +- **THEN** 其行为与现状一致,不被本要求改变 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-registry-doc-sync/spec.md b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-registry-doc-sync/spec.md new file mode 100644 index 0000000..04e6046 --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/specs/language-registry-doc-sync/spec.md @@ -0,0 +1,51 @@ +## Purpose + +定义 `docs/LANGUAGES.md` 与注册表之间的可复现关系:文档的全部内容都应由注册表与生成器产生,重跑生成器在注册表未变更时不得产生差异,且任一方向的不一致都必须可被检出,而不是静默存在。 + +## ADDED Requirements + +### Requirement: Documentation must be fully reproducible from the registry + +`docs/LANGUAGES.md` SHALL 能由注册表与生成器完全复现。生成器 SHALL 覆盖文档的全部内容;若存在有意手工维护的区段,该区段 SHALL 在文档中明确标注,且 SHALL 由生成器原样保留。 + +#### Scenario: 注册表未变更时重跑生成器 + +- **WHEN** 注册表自上次生成以来未发生变更 +- **THEN** 重跑生成器不产生任何差异 + +#### Scenario: 手工维护区段被保留 + +- **WHEN** 文档中存在已声明为手工维护的区段 +- **THEN** 重跑生成器后该区段内容保持不变 + +### Requirement: Documented commands must match the registry field by field + +文档中每个语言条目的 `lint` 与 `format` 命令 SHALL 与注册表逐字段一致,包括占位符与参数顺序。 + +#### Scenario: 表格行与注册表不一致 + +- **WHEN** 任一语言行的命令文本与注册表对应字段不同 +- **THEN** 校验报告该行,并指出两侧的实际取值 + +### Requirement: Drift must be detectable in both directions + +文档与注册表之间的不一致 SHALL 有检查手段可检出,且该检查 SHALL 同时覆盖「文档落后于注册表」与「文档领先于注册表」两种方向。 + +#### Scenario: 文档落后 + +- **WHEN** 注册表已更新而文档未重新生成 +- **THEN** 漂移检查失败并列出不一致条目 + +#### Scenario: 文档被手工前移 + +- **WHEN** 文档被手工修改,其内容为生成器无法产生 +- **THEN** 漂移检查同样失败,使该修改必须回落到注册表或生成器 + +### Requirement: Drift check must run in the existing gate + +漂移检查 SHALL 纳入既有的测试入口,与其余回归一起执行,无需额外的独立命令。 + +#### Scenario: 常规回归被执行 + +- **WHEN** 运行既有测试入口 +- **THEN** 文档与注册表的漂移检查包含在其中,且失败会以非零状态体现 diff --git a/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/tasks.md b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/tasks.md new file mode 100644 index 0000000..4c3ce5e --- /dev/null +++ b/openspec/changes/2026-09-21-repair-markdown-gate-and-doc-sync/tasks.md @@ -0,0 +1,55 @@ +## 1. 本仓自有 markdown 问题(已完成,无需上游) + +- [x] 1.1 `README.md` 表格与后续标题之间补空行(MD058)。 +- [x] 1.2 `README.md` 去掉标题重复后缀 `(Git & Security) (Git & Security)`。 +- [x] 1.3 `docs/LANGUAGES.md` 把两条说明合并为同一引用块(MD028)——就地修,不重新生成,以免丢失手工维护内容。 +- [x] 1.4 修 `scripts/gen_language_docs.py` 中的同一根因,使未来重新生成不再复发 MD028。 + +## 2. markdown 命令修复 + +- [x] 2.1 `scripts/languages.json` 的 markdown `lint` 补显式 glob。 +- [x] 2.2 `scripts/languages.json` 的 markdown `format` 补包管理器前缀与 glob(与 eslint/stylelint 条目写法一致)。 +- [x] 2.3 `scripts/languages.json` 的 markdown `probe` 改用工具真实支持的可用性查询方式。 +- [x] 2.4 `linters/markdown/.markdownlint-cli2.jsonc` 增加 `MD060` 禁用项,延续模板既有的「AI 产出文档不应用代码级规则拦截」定位。 +- [x] 2.5 确认仓根 `.markdownlint-cli2.jsonc` 与模板保持一致(本仓已按 `codeguard init` 的方式拷入)。 +- [x] 2.6 验证修好后命令返回真实 lint 结论而非用法错误。 + +## 3. 配置前置条件(requiresConfig) + +- [x] 3.1 `scripts/languages.json` 为 markdown 声明 `requiresConfig`。 +- [x] 3.2 `scripts/languages.json` 为 yaml 声明 `requiresConfig`。 +- [x] 3.3 重新表述 `tests/run_all.py` 中「无 requiresConfig 视为已接入」这条断言——它记录的是「未声明时不做限制」,不是「不得声明」。 +- [x] 3.4 新增用例:未接入 → 未验证且不阻塞;已接入 → 正常检查。 +- [x] 3.5 新增用例:未声明前置条件的语言行为不变(防回归)。 + +## 4. 生成器可复现 + +- [x] 4.1 把「新增语言的流程」的 6 步版本(含外部技能仓与 vendor 流程)搬进 `gen_language_docs.py`。 +- [x] 4.2 重跑生成器,逐条确认 31 处表格修正的方向正确(注册表为较新一侧)。 +- [x] 4.3 确认注册表未变更时重跑生成器无差异。 + +## 5. 漂移检查 + +- [x] 5.1 `tests/run_all.py` 增加文档与注册表的逐字段比对(按语言行的 `lint` / `format`)。 +- [x] 5.2 覆盖双向:文档落后于注册表、以及文档被手工前移(生成器无法产生的内容)。 +- [x] 5.3 确认检查在既有测试入口内执行,无需额外命令。 + +## 6. 文档与会话提示 + +- [x] 6.1 `README.md` / `README.zh-CN.md` 说明 markdown 门禁的行为变更:此前恒为用法错误,此后返回真实结论。 +- [x] 6.2 说明 `requiresConfig` 语义:未配置的仓转为「未验证跳过」,不再被默认规则全仓报错。 +- [x] 6.3 明确记录:本仓 markdown 门禁转绿依赖上游修复,本次变更后仍不会绿。 + +## 7. 上游收口(跨仓,本变更不修改锁定内容) + +- [x] 7.1 在 `full-stack-skills/codeguard-skills` 修 `skills/**` 下 80 条 markdown:66 `MD029/ol-prefix`、13 `MD056/table-column-count`、1 `MD037`。 +- [ ] 7.2 发布不可变 tag。 +- [ ] 7.3 插件侧更新 `skills.lock.json` 的 ref 并重跑 vendor。 +- [ ] 7.4 确认本仓 markdown 门禁转绿(此时 `npx --no-install markdownlint-cli2 "**/*.md"` 应为 0 问题)。 + +## 8. 发布 + +- [ ] 8.1 运行 `python3 scripts/vendor/skill_vendor.py check --offline` 与在线 `check`。 +- [ ] 8.2 按 AGENTS.md 执行 `node scripts/bump-plugin.mjs codeguard minor`(含行为变更)。 +- [ ] 8.3 同步市场仓 `full-stack-plugins` 的 catalog 版本并重新生成三平台清单。 +- [ ] 8.4 提交并推送插件仓与市场仓。 diff --git a/openspec/changes/2026-09-21-wire-cve-universal-fallback/.openspec.yaml b/openspec/changes/2026-09-21-wire-cve-universal-fallback/.openspec.yaml new file mode 100644 index 0000000..563fab5 --- /dev/null +++ b/openspec/changes/2026-09-21-wire-cve-universal-fallback/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-21 diff --git a/openspec/changes/2026-09-21-wire-cve-universal-fallback/design.md b/openspec/changes/2026-09-21-wire-cve-universal-fallback/design.md new file mode 100644 index 0000000..a0de112 --- /dev/null +++ b/openspec/changes/2026-09-21-wire-cve-universal-fallback/design.md @@ -0,0 +1,64 @@ +## Context + +`scripts/cve_check.py` 当前有 4 个原生扫描器(maven/node/python/rust)和 1 个已实现但无调用者的通用扫描器 `scan_trivy`。生态标识散落在四处、彼此不一致: + +| 位置 | 使用的标识 | +| --- | --- | +| `--ecosystem` 帮助文案 | `java` / `node` / `python` / `rust` | +| 扫描前置条件表 `ECOSYSTEM_PRECHECK` | `maven` / `node` / `python` / `rust` | +| 派发表 `ECOSYSTEM_SCANNERS` | `java` / `node` / `python` / `rust` | +| `main()` 派发比较 | `maven` / `node` / `python` / `rust` | +| 扫描器返回值 `ecosystem` 字段 | `maven` / `node` / `python` / `rust` / `universal` | + +由此产生两个已确认缺陷:文档化的 `--ecosystem java` 因前置条件表查不到而放行、随后被派发的 `else` 分支静默丢弃,最终报成「无可扫描生态(或对应工具未安装)」;`ECOSYSTEM_SCANNERS` 全仓无引用,其 `java` 键与派发的 `maven` 键错位,是半途重构的残留。 + +`scan_trivy` 另有一处未暴露的缺陷:严重级别参数构造为 `f"{threshold},CRITICAL"`。在阈值为 `HIGH`(默认)或 `CRITICAL` 时恰好正确,但 `--severity LOW` 会产出 `LOW,CRITICAL`、`--severity MEDIUM` 会产出 `MEDIUM,CRITICAL`,丢掉中间的 `MEDIUM`/`HIGH`。同文件已有的 `_severity_over()` 是按「阈值及以上」正确展开的,可直接复用其语义。 + +既有退出码约定:`0` 通过、`2` 策略失败(存在漏洞)、`1` 无法验证 / 无可扫描生态。 + +## Goals / Non-Goals + +**Goals:** + +- 让已披露的通用兜底真实可用,使无原生扫描器的生态获得 CVE 结论。 +- 用单一权威映射消除生态标识的三套命名空间,从根本上阻止同类漂移再次发生。 +- 让 `--severity` 在所有扫描器上表达同一个「阈值及以上」语义。 +- 让参数错误、无法验证、存在漏洞三种结局在退出码层面互不混淆。 + +**Non-Goals:** + +- 不为有原生扫描器的生态追加通用扫描(补扫)。这会改变既有用户的扫描结果并引入第二份漏洞数据库,不属于本变更。 +- 不在原生工具缺失时改用通用扫描器顶替。原生工具与通用扫描器的覆盖范围与漏洞来源不同,静默替换会改变结论含义。 +- 不新增扫描器或生态,不改变 trivy 作为可选外部工具的定位。 +- 不改动 `codeguard check` / `fix` / `dockerfile` 的行为与门禁语义。 + +## Decisions + +**通用兜底的触发条件是「无原生扫描器可用」,而不是「原生工具缺失」。** +原生工具未安装时结论保持「无法验证」不变。若改为用 trivy 顶替,同一份 `package.json` 会因工具不同而给出不同结论,而结论背后的漏洞源发生了静默替换——这比报「无法验证」更危险。已在 spec 中以独立场景固定该边界。 + +**通用兜底是替换而非追加。** +`--ecosystem` 的既有语义是替换(`ecosystems = [args.ecosystem]`),保持它。自动检测路径下,原生扫描器可用时通用扫描器不运行,避免同一依赖被两份数据库重复报告、以及由此产生的「修了 trivy 报告但 npm audit 仍报」的来回。 + +**复活 `ECOSYSTEM_SCANNERS` 作为唯一权威映射,而不是删除它。** +删除只能移除症状——前置条件表与派发仍会各自维护标识,下次新增生态必然重演本次漂移。改为一张表同时承载规范标识、别名、前置条件标志文件与扫描器入口,前置条件判定与派发都从它派生,标识不一致在本文件内即不可表达。这也顺带修掉 `--ecosystem java`:`java` 成为 `maven` 的显式别名而非隐藏陷阱。 + +**参数错误引入独立退出码 3,不复用 1 或 2。** +CI 里常见的写法是 `codeguard cve; if [ $? -eq 2 ]; then echo "vulns found"; fi`。若用 argparse 的 `choices` 直接拒绝,argparse 以退出码 2 结束,一次拼写错误就会被读成安全告警;若复用 1,则与「工具未安装」混淆,掩盖真实的环境问题。3 是唯一不会误导既有两个判据的选择,且对既有 `rc != 0` 调用方是纯增量。检查必须在任何扫描器启动前完成,避免先花钱跑扫描再报参数错。 + +**严重级别展开复用同文件既有语义。** +`_severity_over()` 已实现「阈值及以上」的展开,通用扫描器改为向其取值并拼接为 trivy 的 `--severity` 列表,与依赖检查器所用的数值阈值保持同一 intent。同时为该表达式补一条覆盖 `LOW`/`MEDIUM` 的用例——这正是原实现只在默认值上正确、因而从未暴露的原因。 + +## Risks / Trade-offs + +- **trivy 首次运行需要下载漏洞数据库**,`run()` 现有 1800s 超时对冷启动应当足够,但首次运行明显变慢。缓解:保持其可选外部工具的定位,未安装即「无法验证」。 +- **通用兜底的结论与原生扫描器不可直接比较**(不同数据库、不同严重级别口径)。缓解:结果中以独立生态标识 `universal` 报告,不并入原生生态。 +- **新增退出码 3 需要同步文档**。若漏改 `bin/codeguard` 用法注释与 README 的退出码说明,会出现「代码有 3、文档只有 0/1/2」的新漂移。已列入任务清单。 +- **本变更会改变无原生扫描器生态的既有结论**:此前一律「无可扫描生态」(退出 1),此后可能得到「存在漏洞」(退出 2)。依赖退出 1 来判定「没事」的调用方需要知道这一点。这是本变更的预期收益,但应在发布说明中明示。 + +## Verification + +- `openspec validate --strict` 通过。 +- 单元/集成:`tests/run_all.py` 全绿,且新增覆盖 `--ecosystem java` 别名、未声明标识退出码 3、`--severity LOW` 展开为全四级、无原生扫描器生态走通用兜底、trivy 未安装报「无法验证」五个用例。 +- 端到端:在一个 Go 或 PHP 项目上跑 `codeguard cve`,确认不再输出「无可扫描生态」。 +- 回归:java/node/python/rust 四个生态的既有结论与退出码不变。 diff --git a/openspec/changes/2026-09-21-wire-cve-universal-fallback/proposal.md b/openspec/changes/2026-09-21-wire-cve-universal-fallback/proposal.md new file mode 100644 index 0000000..dabd183 --- /dev/null +++ b/openspec/changes/2026-09-21-wire-cve-universal-fallback/proposal.md @@ -0,0 +1,36 @@ +## Why + +`codeguard cve` 对外承诺「通用兜底 → trivy fs --scanners vuln(装了 trivy 就能扫一切锁文件)」, +但该兜底从未接入派发路径:`scan_trivy` 已完整实现却无调用者,实际可扫生态只有 +java/node/python/rust 四个,53 个 stable 语言中其余生态(Go/PHP/Ruby/Swift/Kotlin/C# 等) +拿不到任何 CVE 结论。同时生态标识存在三套命名空间(`--ecosystem` 帮助写 java、 +前置条件表用 maven、派发表又用 java),导致文档化的 `--ecosystem java` 本身就被静默跳过, +并被报成「无可扫描生态(或对应工具未安装)」——把产品缺口说成环境问题。 + +## What Changes + +- 接通通用兜底扫描器:无原生扫描器可用的生态改由它给出结论。 +- 明确通用兜底是**替换而非补扫**:原生扫描器可用时不并行运行,避免同一依赖被两份不同漏洞源重复报告。 +- 统一生态标识:命令行入参、前置条件判定、结果字段共用一份权威映射,并接受已声明别名(如 `java` → `maven`)。 +- 未声明的生态标识在任何扫描器启动前拒绝,且退出状态与「存在漏洞」「无法验证」都可区分。 +- 修正通用扫描器的严重级别语义:`--severity` 表示「该级别及以上」,不再产出 `LOW,CRITICAL` 这类丢档子集。 +- 明确结果三分类(通过 / 存在漏洞 / 无法验证)的优先级与输出位置。 + +## Capabilities + +### New Capabilities + +- `cve-dependency-scan`: `codeguard cve` 的生态覆盖范围、兜底触发条件、生态标识规范、严重级别阈值语义,以及通过/存在漏洞/无法验证三分类的判定与退出状态。 + +### Modified Capabilities + +None. 本仓 `openspec/specs/` 当前为空,此为该能力的首个规格。 + +## Impact + +- `scripts/cve_check.py`:派发逻辑、生态标识映射、`scan_trivy` 严重级别参数、`main()` 的结果分类与退出码。 +- `bin/codeguard` 头部用法注释、`README.md` / `README.zh-CN.md`、`docs/LANGUAGES.md` 中的 CVE 覆盖说明。 +- `skills/codeguard-cve/SKILL.md`:当前只列出四个原生生态,需补通用兜底及其触发条件。 +- 新增一个退出码(用法错误),对既有 `rc != 0` 调用方无影响;不改动 0/1/2 的既有语义。 +- 不引入新依赖;trivy 为可选外部工具,未安装时按「无法验证」处理。 +- 不改动 `.github/workflows/`、技能快照或 vendor 边界。 diff --git a/openspec/changes/2026-09-21-wire-cve-universal-fallback/specs/cve-dependency-scan/spec.md b/openspec/changes/2026-09-21-wire-cve-universal-fallback/specs/cve-dependency-scan/spec.md new file mode 100644 index 0000000..43a940d --- /dev/null +++ b/openspec/changes/2026-09-21-wire-cve-universal-fallback/specs/cve-dependency-scan/spec.md @@ -0,0 +1,95 @@ +## Purpose + +定义 `codeguard cve` 的生态覆盖边界:哪些生态必须给出可验证结论、无原生扫描器时如何兜底、生态标识如何被接受与报告、严重级别阈值如何统一作用于每个扫描器,以及「通过 / 存在漏洞 / 无法验证」三类结果如何判定与退出。 + +## ADDED Requirements + +### Requirement: Universal fallback for ecosystems without a native scanner + +当项目被识别到的语言不属于任何已有原生扫描器的生态时,系统 SHALL 使用通用扫描器给出结论,而不是报告「无可扫描生态」。 + +#### Scenario: 检测到无原生扫描器的生态 + +- **WHEN** 项目被识别为无原生扫描器的语言(例如 Go、PHP、Ruby),且未显式指定 `--ecosystem` +- **THEN** 通用扫描器运行,结果以独立的生态标识报告,且 `--severity` 阈值对其生效 + +#### Scenario: 通用扫描器未安装 + +- **WHEN** 走通用兜底但通用扫描器未安装 +- **THEN** 该生态结果标记为「无法验证」并给出安装提示,退出状态为「无法验证」而非「存在漏洞」 + +#### Scenario: 无任何可扫描内容 + +- **WHEN** 既无原生生态可扫,也无通用兜底可扫的内容 +- **THEN** 报告「无可扫描生态」,退出状态为「无法验证」,且该信息不得与生态标识非法混用同一文案 + +### Requirement: Native scanner precedence and explicit selection + +当项目属于已有原生扫描器的生态时,系统 SHALL 只使用该原生扫描器;通用兜底 SHALL NOT 与之并行运行。显式选择生态时,选择 SHALL 为替换而非追加。 + +#### Scenario: 原生扫描器优先 + +- **WHEN** 项目被识别为 java、node、python 或 rust +- **THEN** 只运行对应原生扫描器,通用扫描器不运行,结果中不出现重复生态 + +#### Scenario: 显式指定通用扫描 + +- **WHEN** 用户显式指定 `--ecosystem universal` +- **THEN** 只运行通用扫描器,不追加原生扫描器 + +#### Scenario: 原生工具缺失 + +- **WHEN** 原生生态已识别但对应扫描工具未安装 +- **THEN** 结果保持「无法验证」,不回退到通用扫描器替代原生生态 + +### Requirement: Ecosystem identifier canonicalization + +命令行接受的生态标识、扫描前置条件判定使用的标识、结果中报告的标识,SHALL 来自同一份权威映射,不得由多处各自维护。 + +#### Scenario: 别名被接受 + +- **WHEN** 用户传入已声明的别名(例如以 `java` 指代 `maven`) +- **THEN** 归一化到规范标识后正常扫描,结果中报告规范标识 + +#### Scenario: 未知标识被拒绝 + +- **WHEN** 用户传入未声明的生态标识 +- **THEN** 在任何扫描器启动前拒绝,错误信息列出全部可接受标识及其别名,且输出中不得出现「无可扫描生态」或「存在漏洞」 + +#### Scenario: 参数错误状态可区分 + +- **WHEN** 因生态标识非法而拒绝执行 +- **THEN** 退出状态既不等于「存在漏洞」(2)也不等于「无法验证」(1),使调用方不会把拼写错误误判为安全告警 + +### Requirement: Severity threshold means threshold-and-above + +`--severity` 指定的阈值 SHALL 被解释为「该级别及以上」,且 SHALL 以等价形式传达给每个扫描器。 + +#### Scenario: 降低阈值 + +- **WHEN** 用户传入 `--severity LOW` 或 `--severity MEDIUM` +- **THEN** 通用扫描器收到包含全部更高级别的完整严重级别集合,而不是只含该级别与最高级别的子集 + +#### Scenario: 默认与最高阈值无回归 + +- **WHEN** 阈值为默认的 `HIGH`,或为 `CRITICAL` +- **THEN** 实际下发给扫描器的级别集合与阈值语义一致 + +### Requirement: Result classification + +每个被扫描的生态 SHALL 恰好落入「通过」「存在漏洞」「无法验证」三类之一,三者在文本与 JSON 输出中均可区分,「无法验证」SHALL NOT 被计入「存在漏洞」。 + +#### Scenario: 三类结果混合 + +- **WHEN** 一次运行中同时存在通过、存在漏洞与无法验证的生态 +- **THEN** 摘要分别列出三类,退出状态以「存在漏洞」优先于「无法验证」 + +#### Scenario: 存在无法验证的生态 + +- **WHEN** 无生态存在漏洞,但至少一个生态无法验证 +- **THEN** 退出状态为「无法验证」,且输出明确声明该结果不能视为通过 + +#### Scenario: 全部通过 + +- **WHEN** 所有被扫描生态均通过且无无法验证的生态 +- **THEN** 退出状态为通过 diff --git a/openspec/changes/2026-09-21-wire-cve-universal-fallback/tasks.md b/openspec/changes/2026-09-21-wire-cve-universal-fallback/tasks.md new file mode 100644 index 0000000..01e6720 --- /dev/null +++ b/openspec/changes/2026-09-21-wire-cve-universal-fallback/tasks.md @@ -0,0 +1,48 @@ +## 1. 生态标识统一(先做,其余改动都建立在它之上) + +- [x] 1.1 用一张权威映射替换现有 `ECOSYSTEM_SCANNERS`,逐项承载:规范标识、别名、扫描前置条件标志文件、扫描器入口。 +- [x] 1.2 让前置条件判定与 `main()` 派发都从该映射派生,删除 `ECOSYSTEM_PRECHECK` 与派发 `if/elif` 中重复维护的标识。 +- [x] 1.3 为 `maven` 声明别名 `java`,使文档化的 `--ecosystem java` 真正可用。 +- [x] 1.4 在派发前校验 `--ecosystem` 取值,未声明值在任何扫描器启动前拒绝,错误信息列出全部规范标识与别名。 + +## 2. 接通通用兜底 + +- [x] 2.1 自动检测路径:语言被识别但无原生生态映射时,改走通用扫描器,不再落入 `else: continue`。 +- [x] 2.2 `--ecosystem universal`(及别名)显式选择时只运行通用扫描器,保持「替换而非追加」语义。 +- [x] 2.3 确认原生扫描器可用时通用扫描器不运行;原生工具缺失时结果仍为「无法验证」,不回退。 +- [x] 2.4 结果分类:`universal` 作为独立生态标识报告,不与原生生态合并。 + +## 3. 严重级别语义修正 + +- [x] 3.1 复用同文件既有的「阈值及以上」展开逻辑,替换 `f"{threshold},CRITICAL"` 的两元素构造。 +- [x] 3.2 核对 maven 路径所用的数值阈值与其余扫描器的级别集合表达同一 intent。 + +## 4. 结果分类与退出状态 + +- [x] 4.1 引入退出码 3 表示参数错误,确认与「存在漏洞」(2)「无法验证」(1)不重叠。 +- [x] 4.2 修正「无可扫描生态」文案,使其不再被用于描述生态标识非法。 +- [x] 4.3 校验「存在漏洞」优先于「无法验证」的退出状态优先级与既有行为一致。 + +## 5. 测试 + +- [x] 5.1 `--ecosystem java` 归一化为 `maven` 并正常扫描(回归本变更修复的静默跳过)。 +- [x] 5.2 未声明生态标识退出码为 3,且输出不含「无可扫描生态」「存在漏洞」。 +- [x] 5.3 `--severity LOW` 与 `--severity MEDIUM` 展开为全部更高级别(回归被丢弃的档位)。 +- [x] 5.4 无原生扫描器的生态走通用兜底并产出结论。 +- [x] 5.5 通用扫描器未安装时该生态为「无法验证」,退出状态不为「存在漏洞」。 +- [x] 5.6 java/node/python/rust 既有结论与退出码无回归。 +- [x] 5.7 `tests/run_all.py` 全绿。 + +## 6. 文档与技能同步 + +- [x] 6.1 更新 `bin/codeguard` 头部用法注释中的生态标识与退出码说明。 +- [x] 6.2 更新 `README.md` / `README.zh-CN.md` 的 CVE 覆盖范围与退出码表。 +- [x] 6.3 更新 `skills/codeguard-cve/SKILL.md`:补通用兜底及其触发条件,并说明原生工具缺失时不替换。 +- [x] 6.4 如 `docs/LANGUAGES.md` 含 CVE 覆盖描述则一并同步。 + +## 7. 发布 + +- [ ] 7.1 运行 `python3 scripts/vendor/skill_vendor.py check --offline` 与在线 `check`(技能目录若有改动)。 +- [ ] 7.2 按 AGENTS.md 执行 `node scripts/bump-plugin.mjs codeguard minor`(新增能力,非破坏性)。 +- [ ] 7.3 同步市场仓 `full-stack-plugins` 的 catalog 版本并重新生成三平台市场清单。 +- [ ] 7.4 提交并推送插件仓与市场仓。 diff --git a/scripts/cve_check.py b/scripts/cve_check.py index 7b0e224..95f9163 100644 --- a/scripts/cve_check.py +++ b/scripts/cve_check.py @@ -26,6 +26,26 @@ SEVERITY_ORDER = {"LOW": 0, "MEDIUM": 1, "HIGH": 2, "CRITICAL": 3} +# CVSS v3 档位下界(LOW 0.1–3.9 / MEDIUM 4.0–6.9 / HIGH 7.0–8.9 / CRITICAL 9.0–10)。 +# maven 的 failBuildOnCVSS 是数值语义,与其余扫描器的「级别集合」必须表达同一 intent: +# --severity HIGH ⇒ 恰好在 CVSS>=7 失败,而不是旧映射 SEVERITY_ORDER+1 产生的 >=3 +# (那会把全部 MEDIUM 也算进 HIGH,比其他扫描器激进一整档)。 +CVSS_BAND_FLOOR = {"LOW": 0, "MEDIUM": 4, "HIGH": 7, "CRITICAL": 9} + + +def severities_at_and_above(threshold: str) -> list[str]: + """「阈值及以上」的级别集合,标签序从低到高(trivy 的 --severity 逗号列表用)""" + floor = SEVERITY_ORDER[threshold.upper()] + return [s for s in ("LOW", "MEDIUM", "HIGH", "CRITICAL") if SEVERITY_ORDER[s] >= floor] + +# 退出码:0 通过 / 1 无法验证 / 2 存在漏洞 / 3 参数错误。 +# 3 必须独立:CI 常用 -eq 2 判定安全告警,而 argparse 默认的参数错误退出码正是 2, +# 复用会把一次拼写错误读成漏洞告警;复用 1 又会把「用错了参数」掩盖成「环境缺工具」。 +EXIT_PASS = 0 +EXIT_UNVERIFIED = 1 +EXIT_FINDINGS = 2 +EXIT_USAGE = 3 + def run(cmd: list[str], cwd: Path, timeout: int = 600) -> tuple[int, str, str]: try: @@ -101,7 +121,7 @@ def scan_cargo(root: Path) -> dict: def scan_trivy(root: Path, threshold: str) -> dict: rc, out, err = run( ["trivy", "fs", "--scanners", "vuln", - "--severity", f"{threshold},CRITICAL" if threshold != "CRITICAL" else "CRITICAL", + "--severity", ",".join(severities_at_and_above(threshold)), "."], cwd=root, timeout=1800, ) @@ -114,26 +134,103 @@ def scan_trivy(root: Path, threshold: str) -> dict: "fix_hint": "按报告升级受影响依赖版本"} +# 各扫描器的调用约定不同(阈值形式、是否支持自动修复),适配成统一入口: +# (root, severity, allow_fix) -> result。差异与生态标识放在一起,不再散落在派发分支里。 +def _scan_maven_ecosystem(root: Path, severity: str, allow_fix: bool) -> dict: + # failBuildOnCVSS 按数值档位(HIGH⇒7),与其余扫描器的「阈值及以上」同一 intent + return scan_maven(root, CVSS_BAND_FLOOR[severity]) + + +def _scan_node_ecosystem(root: Path, severity: str, allow_fix: bool) -> dict: + result = scan_node(root, severity, allow_fix) + if allow_fix and result.get("failed"): + print("[codeguard-cve] npm audit fix ...") + run(["npm", "audit", "fix"], cwd=root, timeout=900) + result["after_fix"] = scan_node(root, severity, False) + return result + + +def _scan_pip_ecosystem(root: Path, severity: str, allow_fix: bool) -> dict: + return scan_pip(root) + + +def _scan_cargo_ecosystem(root: Path, severity: str, allow_fix: bool) -> dict: + return scan_cargo(root) + + +def _scan_trivy_ecosystem(root: Path, severity: str, allow_fix: bool) -> dict: + return scan_trivy(root, severity) + + +# 唯一权威映射:规范标识 → 别名 / 映射语言 / 前置条件标志文件 / 扫描入口。 +# 命令行入参、语言检测映射、前置条件判定与结果报告全部从这里派生, +# 标识不一致在该文件内不再可表达。 +# languages 为空的生态(universal)只能显式选择,不会被语言检测自动选中。 ECOSYSTEM_SCANNERS = { - "java": scan_maven, - "node": scan_node, - "python": scan_pip, - "rust": scan_cargo, + "maven": { + "aliases": ("java",), + "languages": ("java",), + "markers": ("pom.xml",), + "scan": _scan_maven_ecosystem, + }, + "node": { + "aliases": (), + "languages": ("typescript",), + "markers": ("package.json", "package-lock.json", "npm-shrinkwrap.json"), + "scan": _scan_node_ecosystem, + }, + "python": { + "aliases": (), + "languages": ("python",), + "markers": ("requirements.txt", "requirements-dev.txt", "pyproject.toml", "Pipfile.lock"), + "scan": _scan_pip_ecosystem, + }, + "rust": { + "aliases": (), + "languages": ("rust",), + "markers": ("Cargo.lock",), + "scan": _scan_cargo_ecosystem, + }, + "universal": { + "aliases": ("trivy",), + "languages": (), + "markers": (), + "scan": _scan_trivy_ecosystem, + }, } -# 扫描前置条件:缺少标志文件说明项目不属于该生态(或依赖未锁定), -# 运行扫描器只会得到环境错误——归类为「无法验证」而非「有漏洞」。 -ECOSYSTEM_PRECHECK = { - "maven": ["pom.xml"], - "node": ["package.json", "package-lock.json", "npm-shrinkwrap.json"], - "python": ["requirements.txt", "requirements-dev.txt", "pyproject.toml", "Pipfile.lock"], - "rust": ["Cargo.lock"], -} + +def canonical_ecosystem(value: str) -> str | None: + """生态标识归一化:接受规范标识与其别名;未声明返回 None""" + key = value.strip().lower() + if key in ECOSYSTEM_SCANNERS: + return key + for canonical, spec in ECOSYSTEM_SCANNERS.items(): + if key in spec["aliases"]: + return canonical + return None + + +def ecosystem_choices() -> str: + """全部可接受标识(含别名),供错误信息与 --help 共用""" + parts = [] + for canonical, spec in ECOSYSTEM_SCANNERS.items(): + aliases = spec["aliases"] + parts.append(f"{canonical}(别名 {'/'.join(aliases)})" if aliases else canonical) + return "、".join(parts) + + +def language_ecosystem_map() -> dict[str, str]: + """语言 id → 规范生态标识,从权威映射派生""" + return {lang: canonical + for canonical, spec in ECOSYSTEM_SCANNERS.items() + for lang in spec["languages"]} def precheck(root: Path, eco: str) -> tuple[bool, str]: - """返回 (可扫描, 说明)""" - markers = ECOSYSTEM_PRECHECK.get(eco, []) + """返回 (可扫描, 说明)。缺少标志文件说明项目不属于该生态(或依赖未锁定), + 运行扫描器只会得到环境错误——归类为「无法验证」而非「有漏洞」。""" + markers = ECOSYSTEM_SCANNERS.get(eco, {}).get("markers", ()) if not markers: return True, "" if any((root / m).exists() for m in markers): @@ -143,7 +240,7 @@ def precheck(root: Path, eco: str) -> tuple[bool, str]: def main() -> int: ap = argparse.ArgumentParser(prog="codeguard cve") - ap.add_argument("--ecosystem", help="只扫指定生态(java/node/python/rust)") + ap.add_argument("--ecosystem", help=f"只扫指定生态({ecosystem_choices()})") ap.add_argument("--fix", action="store_true", help="允许自动修复(当前 npm audit fix)") ap.add_argument("--severity", default="HIGH", choices=list(SEVERITY_ORDER)) ap.add_argument("--json", action="store_true", dest="as_json") @@ -151,46 +248,47 @@ def main() -> int: args = ap.parse_args() root = find_project_root(args.path) or Path(args.path).resolve() - langs = detect_languages(root) - eco_map = {"java": "maven", "typescript": "node", "python": "python", "rust": "rust"} - ecosystems = sorted({eco_map[l] for l in langs if l in eco_map}) + + # 参数错误必须先于任何扫描器启动被拒绝:否则会先花掉一次真实扫描再报错。 + # 退出码用独立的 EXIT_USAGE,避免被调用方读成「存在漏洞」或「无法验证」。 if args.ecosystem: # 显式指定优先:不依赖语言检测结果 - ecosystems = [args.ecosystem] + canonical = canonical_ecosystem(args.ecosystem) + if canonical is None: + print(f"[codeguard-cve] 未知生态 {args.ecosystem!r};可接受:{ecosystem_choices()}", + file=sys.stderr) + return EXIT_USAGE + ecosystems = [canonical] + else: + langs = detect_languages(root) + eco_map = language_ecosystem_map() + ecosystems = sorted({eco_map[l] for l in langs if l in eco_map}) + if langs and not ecosystems: + # 识别到了语言但都不属于原生生态(go/php/ruby…)→ 通用兜底给出结论, + # 而不是报「无可扫描生态」。原生生态存在时不并行兜底(替换而非追加); + # 一个语言都没识别到的目录不算「无原生扫描器的语言」,仍报无可扫描。 + ecosystems = ["universal"] print(f"[codeguard-cve] project: {root}") print(f"[codeguard-cve] ecosystems: {ecosystems or '(none detected)'}") results = [] for eco in ecosystems: - ok, why = precheck(root, eco) - if not ok: + spec = ECOSYSTEM_SCANNERS[eco] + scannable, why = precheck(root, eco) + if not scannable: results.append({"ecosystem": eco, "tool": eco, "exit": 127, "summary_tail": f"无法验证: {why}", "fix_hint": "确认项目类型后重试"}) print(f" {eco:8s} SKIP({why})") continue - if eco == "maven": - r = scan_maven(root, SEVERITY_ORDER[args.severity] + 1) # fail on >= threshold - elif eco == "node": - r = scan_node(root, args.severity, args.fix) - if args.fix and r.get("failed"): - print("[codeguard-cve] npm audit fix ...") - frc, _, _ = run(["npm", "audit", "fix"], cwd=root, timeout=900) - r2 = scan_node(root, args.severity, False) - r["after_fix"] = r2 - elif eco == "python": - r = scan_pip(root) - elif eco == "rust": - r = scan_cargo(root) - else: - continue + r = spec["scan"](root, args.severity, args.fix) results.append(r) status = "PASS" if r["exit"] == 0 else f"FAILED(exit={r['exit']})" print(f" {eco:8s} {r['tool']:28s} {status}") if not results: print("[codeguard-cve] 无可扫描生态(或对应工具未安装)") - return 1 + return EXIT_UNVERIFIED failed = [r for r in results if r["exit"] not in (0, 127) or r.get("failed")] unverifiable = [r for r in results if r["exit"] == 127] @@ -206,12 +304,12 @@ def main() -> int: if failed: n = len(failed) print(f"\n[codeguard-cve] {n} 个生态存在漏洞——检查出来了就得修,禁止带洞提交") - return 2 + return EXIT_FINDINGS if unverifiable: print("\n[codeguard-cve] ⚠️ 存在无法验证的生态(工具缺失)——不能视为通过") - return 1 + return EXIT_UNVERIFIED print("[codeguard-cve] ✅ 所有生态 CVE 检查通过") - return 0 + return EXIT_PASS if __name__ == "__main__": diff --git a/scripts/detect_lang.py b/scripts/detect_lang.py index ac35f88..531de60 100755 --- a/scripts/detect_lang.py +++ b/scripts/detect_lang.py @@ -230,7 +230,9 @@ def _cached(key: tuple, fn): def _run_probe_cmd(probe: list, timeout: int) -> tuple[bool, str]: import subprocess try: - proc = subprocess.run(probe, capture_output=True, text=True, timeout=timeout) + # stdin=DEVNULL:探活命令绝不消费宿主 stdin;--format 类探活靠 EOF 立即返回 + proc = subprocess.run(probe, capture_output=True, text=True, timeout=timeout, + stdin=subprocess.DEVNULL) except subprocess.TimeoutExpired: return False, f"探活超时: {' '.join(probe)}" except OSError as exc: diff --git a/scripts/gen_language_docs.py b/scripts/gen_language_docs.py index 513e315..77c664a 100755 --- a/scripts/gen_language_docs.py +++ b/scripts/gen_language_docs.py @@ -30,19 +30,20 @@ def cmd_str(lang: dict, key: str) -> str: return "`" + " ".join(cmd) + "`" -def main() -> int: - data = json.loads(REGISTRY.read_text(encoding="utf-8")) - langs = data["languages"] - +def build_lines(langs: list) -> list: + """由注册表产出文档全部内容(含「新增语言的流程」——该段与注册表同源演进, + 不再允许文档单方面领先于生成器:两向漂移都由 tests/run_all.py 的同步检查拦截)""" unique = len({l["id"] for l in langs}) - len([l for l in langs if l["id"] in ("dockerfile", "ansible")]) lines: list[str] = [] lines.append("# partme-codeguard-plugin 支持的语言\n") lines.append( f"> 覆盖 **{unique} 种编程语言**(注册表 {len(langs)} 条,含 Dockerfile/Ansible 等文件类型条目)。" f"所有语言均可被 `detect_lang` 识别;其中 **{sum(1 for l in langs if l['status'] != 'planned')} 条**已接入 linter 强制门禁" - "(Stable / Beta),其余列入路线图(Planned,钩子检测到后安全跳过)。\n" + "(Stable / Beta),其余列入路线图(Planned,钩子检测到后安全跳过)。" ) + # 两条说明同属一个引用块:中间留空行会被 markdownlint 判为 MD028(引用块内空行) lines.append( + ">\n" "> 本文档由 `scripts/languages.json` 注册表自动生成(`scripts/gen_language_docs.py`);" "新增/调整语言请改注册表后重新生成。\n" ) @@ -77,11 +78,17 @@ def main() -> int: lines.append("## 新增语言的流程\n") lines.append("1. `scripts/languages.json` 注册表加一条语言定义(id/extensions/markers/lint/format/status)。") lines.append("2. `linters//` 放配置模板。") - lines.append("3. `skills/codeguard-/SKILL.md` 写规范速查(frontmatter `name` == 目录名)。") - lines.append("4. 重跑 `python3 scripts/gen_language_docs.py` 同步本文档。") - lines.append("5. `python3 scripts/detect_lang.py <项目>` 冒烟验证。\n") + lines.append("3. 在外部 `full-stack-skills/codeguard-skills` 新增或更新 `skills/codeguard-/`,完成 lint、TRACE 评估并发布不可变 tag。") + lines.append("4. 更新插件 `skills.lock.json` 的 ref 和技能清单,运行 `python3 scripts/vendor/skill_vendor.py update`。") + lines.append("5. 重跑 `python3 scripts/gen_language_docs.py` 同步本文档。") + lines.append("6. 执行 vendor 离线/在线检查,并用 `python3 scripts/detect_lang.py <项目>` 冒烟验证。\n") + return lines - DOC.write_text("\n".join(lines) + "\n", encoding="utf-8") + +def main() -> int: + data = json.loads(REGISTRY.read_text(encoding="utf-8")) + langs = data["languages"] + DOC.write_text("\n".join(build_lines(langs)) + "\n", encoding="utf-8") print(f"[gen-language-docs] 生成 {DOC}({len(langs)} 语言)") return 0 diff --git a/scripts/languages.json b/scripts/languages.json index 1326a15..21995b7 100644 --- a/scripts/languages.json +++ b/scripts/languages.json @@ -378,7 +378,12 @@ "yamllint", "." ], - "install_hint": "pip install yamllint" + "install_hint": "pip install yamllint", + "requiresConfig": [ + ".yamllint", + ".yamllint.yaml", + ".yamllint.yml" + ] }, { "id": "elixir", @@ -863,10 +868,16 @@ "lint": [ "npx", "--no-install", - "markdownlint-cli2" + "markdownlint-cli2", + "**/*.md", + "#node_modules" ], "format": [ + "npx", + "--no-install", "markdownlint-cli2", + "**/*.md", + "#node_modules", "--fix" ], "install_hint": "npm install -g markdownlint-cli2", @@ -874,7 +885,18 @@ "npx", "--no-install", "markdownlint-cli2", - "--version" + "--format" + ], + "requiresConfig": [ + ".markdownlint-cli2.jsonc", + ".markdownlint-cli2.json", + ".markdownlint-cli2.yaml", + ".markdownlint-cli2.yml", + ".markdownlint.jsonc", + ".markdownlint.json", + ".markdownlint.yaml", + ".markdownlint.yml", + ".markdownlint.ini" ] }, { @@ -1448,4 +1470,4 @@ "install_hint": "playbook 检查由 ansible-lint 承接(yaml 通道);语义级检查待集成" } ] -} \ No newline at end of file +} diff --git a/tests/run_all.py b/tests/run_all.py index a134d77..235525e 100644 --- a/tests/run_all.py +++ b/tests/run_all.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 """codeguard 测试集:语言规则结构审计 + 对话级钩子触发模拟 + 报告结构断言。 -三个子集(可单独跑,缺省全跑): +可按子集单独跑(缺省全跑): python3 tests/run_all.py # 全量 python3 tests/run_all.py langs # 语言注册表结构审计(纯结构,不依赖工具安装) python3 tests/run_all.py hooks # 钩子级模拟(构造临时 git 仓,按宿主协议 stdin JSON 触发) python3 tests/run_all.py unit # 纯函数单测(glob/requiresConfig、{file} 兜底、多 cd 边界、综述≠细节) + python3 tests/run_all.py cve # CVE 生态标识、别名归一化与参数校验退出码 钩子模拟的原理 = 完全复刻宿主行为:把 ZCode/Claude 会发给钩子的 JSON payload 通过 stdin 喂给真实钩子脚本,断言退出码与输出协议(exit 0 JSON / exit 2 stderr)。 @@ -251,9 +252,9 @@ def test_hooks(): def test_unit(): print("\n[3] 纯函数单测") - from detect_lang import project_uses_linter, probe_toolchain import gate_lib import pre_tool_git_guard as guard + from detect_lang import probe_toolchain, project_uses_linter # requiresConfig glob 支持 tmp = Path(tempfile.mkdtemp()) @@ -293,6 +294,42 @@ def test_unit(): ok("无 git 段返回空", guard.resolve_project_roots("ls -la && echo done") == []) ok("is_guarded 词法匹配不误伤 echo", not guard.is_guarded('echo "git push 是危险命令"')) ok("is_guarded 命中真实 git push", guard.is_guarded("cd r && git push origin main")) + + # ── C2-3.4:requiresConfig 语义 —— 未接入→未验证不阻塞;已接入→真实检查 ── + import detect_lang as _dl + from gate_lib import run_gate as _run_gate + cfg_md = _dl.LANG_COMMANDS["markdown"] + cfg_yaml = _dl.LANG_COMMANDS["yaml"] + ok("markdown 已声明 requiresConfig", bool(cfg_md.get("requiresConfig"))) + ok("yaml 已声明 requiresConfig", bool(cfg_yaml.get("requiresConfig"))) + ok("markdown 探活可用(--format + stdin=DEVNULL)", _dl.probe_toolchain(cfg_md)[0]) + bare = Path(tempfile.mkdtemp()) + _dl._TOOL_CACHE.clear() + # 前面 {file} 用例遗留的 monkeypatch 会让 requiresConfig 分支永不可达——先还原真身 + gate_lib.detect_languages = lambda root: ["markdown", "yaml"] + gate_lib.project_uses_linter = _dl.project_uses_linter + gate_lib.probe_toolchain = _dl.probe_toolchain + try: + f1, s1 = _run_gate(bare, {}) + ok("未接入→未验证且不阻塞", not f1 and any("未接入" in x for x in s1), + f"failures={f1} skipped={s1}") + (bare / ".markdownlint-cli2.jsonc").write_text("{}") + (bare / "bad.md").write_text("text \n") # 行尾空格 → MD009,配置在→真跑 + _dl._TOOL_CACHE.clear() + f2, s2 = _run_gate(bare, {}) + ok("已接入→markdown 真跑(advisory 告警进 skipped)", + not f2 and any(x.startswith("markdown") and "告警" in x for x in s2), + f"failures={f2} skipped={s2}") + ok("已接入→yaml 仍未接入(无 .yamllint 配置)", + any(x.startswith("yaml") and "未接入" in x for x in s2)) + finally: + _dl._TOOL_CACHE.clear() + shutil.rmtree(bare, ignore_errors=True) + + # ── C2-3.5:未声明前置条件的语言不受影响(typescript 原有声明保持)── + ok("typescript 仍声明 requiresConfig(行为不变对照)", + bool(_dl.LANG_COMMANDS["typescript"].get("requiresConfig"))) + shutil.rmtree(tmp) @@ -462,7 +499,6 @@ def test_field_regressions(): def test_perf(): print("\n[5] 性能与健壮性(缓存/去重/兜底/冷却)") - import io as _io # ── 探活去重:eslint 系 4 语言只真探 1 次 ── import detect_lang as dl @@ -535,6 +571,7 @@ def counting_run(cmd, *a, **kw): # ── 通知冷却:同语言 60s 内只弹一次 ── import importlib + import post_tool_lint as ptl importlib.reload(ptl) tmp_state = Path(tempfile.mkdtemp()) / ".session_state.json" @@ -547,6 +584,158 @@ def counting_run(cmd, *a, **kw): _sh2.rmtree(repo, ignore_errors=True) +# ══════════════════════ 子集 6:CVE 生态标识与参数校验 ══════════════════════ + +def run_cve(args: list[str], cwd: Path): + """按 CLI 契约调用 codeguard cve:返回 (exit, stdout, stderr)""" + env = {**os.environ, "PYTHONIOENCODING": "utf-8"} + return subprocess.run( + [sys.executable, str(PLUGIN / "scripts" / "cve_check.py"), *args], + capture_output=True, text=True, cwd=cwd, timeout=120, env=env, check=False, + ) + + +def test_cve(): + print("\n[6] CVE 生态标识与参数校验") + import cve_check as cve + + tmp = Path(tempfile.mkdtemp()) + + # 权威映射结构:每条自带全部要素;别名不得与规范标识冲突或彼此重复 + ok("映射条目含全部要素", + all({"aliases", "languages", "markers", "scan"} <= set(spec) + for spec in cve.ECOSYSTEM_SCANNERS.values())) + aliases = [a for spec in cve.ECOSYSTEM_SCANNERS.values() for a in spec["aliases"]] + conflicts = [a for a in aliases if a in cve.ECOSYSTEM_SCANNERS] + ok("别名不冲突且不重复", not conflicts and len(aliases) == len(set(aliases)), + f"{conflicts} {aliases}") + + # 1.3:文档化的 java 必须归一到 maven(修复前它被派发 else 静默丢弃) + ok("java 归一到 maven", cve.canonical_ecosystem("java") == "maven") + ok("trivy 归一到 universal", cve.canonical_ecosystem("trivy") == "universal") + ok("规范标识自身可解析", cve.canonical_ecosystem("python") == "python") + ok("大小写不敏感", cve.canonical_ecosystem("JAVA") == "maven") + ok("未声明标识返回 None", cve.canonical_ecosystem("go") is None) + ok("可接受值含别名", "java" in cve.ecosystem_choices() and "trivy" in cve.ecosystem_choices()) + + # 1.2:前置条件从权威映射派生,独立死表已移除 + ok("死表 ECOSYSTEM_PRECHECK 已移除", not hasattr(cve, "ECOSYSTEM_PRECHECK")) + ok("缺标志文件→不可扫描", cve.precheck(tmp, "rust")[0] is False) + (tmp / "Cargo.lock").write_text("") + ok("有标志文件→可扫描", cve.precheck(tmp, "rust")[0] is True) + ok("无前置条件生态直接可扫描", cve.precheck(tmp, "universal")[0] is True) + ok("语言映射值均为规范标识", + all(v in cve.ECOSYSTEM_SCANNERS for v in cve.language_ecosystem_map().values())) + + # 5.2:未知生态在扫描前拒绝,退出码 3,且不混用其他结论文案 + r = run_cve(["--ecosystem", "go", str(tmp)], tmp) + out = r.stdout + r.stderr + ok("未知生态退出码=3", r.returncode == 3, f"rc={r.returncode}") + ok("退出码与「存在漏洞」「无法验证」不重叠", r.returncode not in (1, 2)) + ok("错误信息列出可接受值", "可接受" in out and "java" in out) + ok("不误报「无可扫描生态」", "无可扫描生态" not in out) + ok("不误报存在漏洞", "存在漏洞" not in out and "有漏洞" not in out) + + # 5.1:--ecosystem java 真正进入 maven 派发 + r = run_cve(["--ecosystem", "java", str(tmp)], tmp) + ok("java 别名进入 maven 派发", "ecosystems: ['maven']" in r.stdout, r.stdout.strip()[:120]) + ok("java 未被当成未知生态", r.returncode != 3) + + # ── C1-5.3:severity 展开为「阈值及以上」(回归被丢弃的档位)── + ok("LOW 展开为全部四级", cve.severities_at_and_above("LOW") == ["LOW", "MEDIUM", "HIGH", "CRITICAL"]) + ok("MEDIUM 不再丢 HIGH", cve.severities_at_and_above("MEDIUM") == ["MEDIUM", "HIGH", "CRITICAL"]) + ok("HIGH 默认两档", cve.severities_at_and_above("HIGH") == ["HIGH", "CRITICAL"]) + ok("CRITICAL 单档", cve.severities_at_and_above("CRITICAL") == ["CRITICAL"]) + captured = {} + orig_run = cve.run + cve.run = lambda cmd, cwd, timeout=600: (captured.update(cmd=cmd), (0, "", ""))[1] + try: + cve.scan_trivy(tmp, "MEDIUM") + finally: + cve.run = orig_run + ok("trivy 收到完整级别集合", + captured.get("cmd", []).count("MEDIUM,HIGH,CRITICAL") == 1, str(captured.get("cmd"))) + + # ── C1-3.2:maven 数值阈值与其余扫描器同一 intent(HIGH⇒CVSS 7,不是旧映射的 3)── + seen = {} + orig_mv = cve.scan_maven + cve.scan_maven = lambda root, th, _s=seen: (_s.update(th=th), {"ecosystem": "maven", "tool": "fake", "exit": 0})[1] + try: + cve._scan_maven_ecosystem(tmp, "HIGH", False) + ok("HIGH ⇒ failBuildOnCVSS=7", seen.get("th") == 7, f"th={seen.get('th')}") + cve._scan_maven_ecosystem(tmp, "MEDIUM", False) + ok("MEDIUM ⇒ failBuildOnCVSS=4", seen.get("th") == 4, f"th={seen.get('th')}") + finally: + cve.scan_maven = orig_mv + + # ── C1-5.6:四个原生生态派发不回归(mock 扫描器,不依赖真实工具/网络)── + for eco, marker in (("maven", "pom.xml"), ("node", "package.json"), + ("python", "pyproject.toml"), ("rust", "Cargo.lock")): + d = Path(tempfile.mkdtemp()) + (d / marker).write_text("") + calls = [] + orig_scan = cve.ECOSYSTEM_SCANNERS[eco]["scan"] + cve.ECOSYSTEM_SCANNERS[eco]["scan"] = ( + lambda root, sev, fix, _c=calls, _e=eco: (_c.append(sev), {"ecosystem": _e, "tool": "fake", "exit": 0})[1]) + old_argv = sys.argv + try: + sys.argv = ["cve_check.py", "--ecosystem", eco, str(d)] + rc = cve.main() + finally: + sys.argv = old_argv + cve.ECOSYSTEM_SCANNERS[eco]["scan"] = orig_scan + ok(f"{eco} 原生派发且 severity 透传", rc == 0 and calls == ["HIGH"], f"rc={rc} calls={calls}") + + # ── C1-4.3:存在漏洞优先于无法验证 ── + d = Path(tempfile.mkdtemp()) + (d / "package.json").write_text("{}") + (d / "Cargo.lock").write_text("") + orig_node = cve.ECOSYSTEM_SCANNERS["node"]["scan"] + orig_rust = cve.ECOSYSTEM_SCANNERS["rust"]["scan"] + cve.ECOSYSTEM_SCANNERS["node"]["scan"] = lambda root, sev, fix: {"ecosystem": "node", "tool": "fake", "exit": 1, "failed": True} + cve.ECOSYSTEM_SCANNERS["rust"]["scan"] = lambda root, sev, fix: {"ecosystem": "rust", "tool": "fake", "exit": 127} + try: + sys.argv = ["cve_check.py", str(d)] + rc_mixed = cve.main() + finally: + sys.argv = ["cve_check.py"] + cve.ECOSYSTEM_SCANNERS["node"]["scan"] = orig_node + cve.ECOSYSTEM_SCANNERS["rust"]["scan"] = orig_rust + ok("漏洞(2) 优先于无法验证(1)", rc_mixed == 2, f"rc={rc_mixed}") + + # ── C1-5.4/5.5:无原生扫描器的语言自动落兜底;trivy 缺失=无法验证而非漏洞 ── + d = Path(tempfile.mkdtemp()) + (d / "go.mod").write_text("module x\n\ngo 1.21\n") + (d / "main.go").write_text("package main\n") + r = run_cve([str(d)], d) + out = r.stdout + r.stderr + ok("go 项目自动走 universal 兜底", "ecosystems: ['universal']" in r.stdout, r.stdout.strip()[:120]) + ok("trivy 缺失 → 无法验证(1) 而非漏洞(2)", r.returncode == 1, f"rc={r.returncode}") + ok("兜底路径不误报「有漏洞」", "有漏洞" not in out) + + shutil.rmtree(tmp) + + +# ══════════════════════ 子集 7:文档与注册表可复现同步 ══════════════════════ + +def test_doc_sync(): + print("\n[7] 文档与注册表可复现同步") + import gen_language_docs as gen + + reg = json.loads((PLUGIN / "scripts" / "languages.json").read_text(encoding="utf-8")) + expected = "\n".join(gen.build_lines(reg["languages"])) + "\n" + actual = (PLUGIN / "docs" / "LANGUAGES.md").read_text(encoding="utf-8") + if expected == actual: + ok("docs/LANGUAGES.md 与注册表完全可复现(双向一致)", True) + else: + import difflib + diff = [ln for ln in difflib.unified_diff( + actual.splitlines(), expected.splitlines(), + "docs/LANGUAGES.md", "registry-generated", n=0, lineterm="")] + ok("docs/LANGUAGES.md 与注册表完全可复现(双向一致)", False, + f"{len(diff)} 行差异,首 6 行: {diff[:6]}") + + def main(): which = sys.argv[1] if len(sys.argv) > 1 else "all" print(f"codeguard 测试集 plugin={PLUGIN.name}") @@ -556,6 +745,8 @@ def main(): if which in ("all", "edges"): test_edges() if which in ("all", "perf"): test_perf() if which in ("all", "field"): test_field_regressions() + if which in ("all", "cve"): test_cve() + if which in ("all", "doc"): test_doc_sync() print(f"\n═══ 结果: {len(PASS)} 通过 / {len(FAIL)} 失败 / {len(SKIP)} 跳过 ═══") if FAIL: print("失败项:", *FAIL, sep="\n - ") From a95dbf29ad765035e044424c778f24bb40a606fb Mon Sep 17 00:00:00 2001 From: loong10k <20489781+loong10k@users.noreply.github.com> Date: Tue, 22 Sep 2026 00:41:04 +0800 Subject: [PATCH 4/7] =?UTF-8?q?chore(ci):=20=E6=8C=89=E6=9D=A5=E6=BA=90?= =?UTF-8?q?=E7=BB=84=E7=BB=87=E9=80=89=E7=94=A8=E5=90=8C=E6=AD=A5=E4=BB=A4?= =?UTF-8?q?=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/skills-sync.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/skills-sync.yml b/.github/workflows/skills-sync.yml index 41f0b87..56ba5ea 100644 --- a/.github/workflows/skills-sync.yml +++ b/.github/workflows/skills-sync.yml @@ -24,13 +24,13 @@ jobs: sync: runs-on: ubuntu-latest env: - GH_TOKEN: ${{ secrets.SKILLS_SYNC_TOKEN || secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.FULL_STACK_SKILLS_SYNC_TOKEN || secrets.GITHUB_TOKEN }} REQUESTED_REF: ${{ github.event.client_payload.ref || inputs.ref }} REQUESTED_SHA: ${{ github.event.client_payload.sha || inputs.sha }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - token: ${{ secrets.SKILLS_SYNC_TOKEN || secrets.GITHUB_TOKEN }} + token: ${{ secrets.FULL_STACK_SKILLS_SYNC_TOKEN || secrets.GITHUB_TOKEN }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" From c1468d07a0ae6fff50a01d2de93511a3c6ee6af3 Mon Sep 17 00:00:00 2001 From: loong10k <20489781+loong10k@users.noreply.github.com> Date: Tue, 22 Sep 2026 00:41:04 +0800 Subject: [PATCH 5/7] =?UTF-8?q?chore:=20vendor=20=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E5=BF=AB=E7=85=A7=E8=87=B3=20codeguard-skills=20v0.1.2?= =?UTF-8?q?=EF=BC=8880=20=E5=A4=84=20markdown=20=E4=BF=AE=E5=A4=8D=20+=20C?= =?UTF-8?q?VE=20=E5=85=9C=E5=BA=95=E8=AF=AD=E4=B9=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- skills.lock.json | 124 +++++++++--------- skills/codeguard-ansible/SKILL.md | 2 +- skills/codeguard-arkts/SKILL.md | 2 +- skills/codeguard-astro/SKILL.md | 2 +- skills/codeguard-c/SKILL.md | 4 +- skills/codeguard-cfml/SKILL.md | 4 +- skills/codeguard-clojure/SKILL.md | 2 +- skills/codeguard-cobol/SKILL.md | 2 +- skills/codeguard-cpp/SKILL.md | 4 +- skills/codeguard-crystal/SKILL.md | 2 +- skills/codeguard-csharp/SKILL.md | 2 +- skills/codeguard-css/SKILL.md | 2 +- skills/codeguard-cuda/SKILL.md | 4 +- skills/codeguard-cve/SKILL.md | 12 +- skills/codeguard-dart/SKILL.md | 2 +- skills/codeguard-dockerfile/SKILL.md | 4 +- skills/codeguard-elixir/SKILL.md | 2 +- skills/codeguard-elm/SKILL.md | 2 +- skills/codeguard-erlang/SKILL.md | 2 +- skills/codeguard-fix/SKILL.md | 8 +- skills/codeguard-fsharp/SKILL.md | 2 +- .../references/branch-models-comparison.md | 2 +- skills/codeguard-go/SKILL.md | 4 +- skills/codeguard-graphql/SKILL.md | 2 +- skills/codeguard-groovy/SKILL.md | 4 +- skills/codeguard-haskell/SKILL.md | 2 +- skills/codeguard-html/SKILL.md | 4 +- skills/codeguard-java/SKILL.md | 4 +- skills/codeguard-julia/SKILL.md | 2 +- skills/codeguard-kotlin/SKILL.md | 2 +- skills/codeguard-liquid/SKILL.md | 2 +- skills/codeguard-lua/SKILL.md | 2 +- skills/codeguard-luau/SKILL.md | 4 +- skills/codeguard-markdown/SKILL.md | 2 +- skills/codeguard-metal/SKILL.md | 2 +- skills/codeguard-nim/SKILL.md | 2 +- skills/codeguard-nix/SKILL.md | 4 +- skills/codeguard-objc/SKILL.md | 4 +- skills/codeguard-ocaml/SKILL.md | 2 +- skills/codeguard-pascal/SKILL.md | 2 +- skills/codeguard-perl/SKILL.md | 2 +- skills/codeguard-php/SKILL.md | 4 +- skills/codeguard-powershell/SKILL.md | 2 +- skills/codeguard-protobuf/SKILL.md | 2 +- skills/codeguard-python/SKILL.md | 4 +- skills/codeguard-r/SKILL.md | 2 +- skills/codeguard-ruby/SKILL.md | 2 +- skills/codeguard-rust/SKILL.md | 4 +- skills/codeguard-scala/SKILL.md | 2 +- skills/codeguard-shell/SKILL.md | 4 +- skills/codeguard-solidity/SKILL.md | 2 +- skills/codeguard-sql/SKILL.md | 4 +- skills/codeguard-svelte/SKILL.md | 2 +- skills/codeguard-swift/SKILL.md | 2 +- skills/codeguard-terraform/SKILL.md | 2 +- skills/codeguard-toml/SKILL.md | 2 +- skills/codeguard-typescript/SKILL.md | 4 +- skills/codeguard-vbnet/SKILL.md | 2 +- skills/codeguard-vue/SKILL.md | 2 +- skills/codeguard-yaml/SKILL.md | 2 +- skills/codeguard-zig/SKILL.md | 2 +- 61 files changed, 150 insertions(+), 146 deletions(-) diff --git a/skills.lock.json b/skills.lock.json index 05b5de2..a99c3a6 100644 --- a/skills.lock.json +++ b/skills.lock.json @@ -4,8 +4,8 @@ { "package": "codeguard-skills", "repo": "https://github.com/full-stack-skills/codeguard-skills.git", - "ref": "v0.1.1", - "sha": "5f20f995c82f07233682517c1c39686887e709f1", + "ref": "v0.1.2", + "sha": "2c0c8071f96de48dc53e11de2499c083c100e44c", "skills": [ "codeguard", "codeguard-ansible", @@ -79,73 +79,73 @@ "dest": "skills/", "sha256": { "codeguard": "9c6810ccf82c2add76506ee16c28f6809fd6285472d5a8d7107ca354e6fe1d8e", - "codeguard-ansible": "321fb22fab46de40e1076696429be69f813c661f608093986f0ac9f4b5e4bcc5", - "codeguard-arkts": "8f34880d447157e4044e616d5d4dc807c62e205863057a140965554e323644aa", - "codeguard-astro": "0765d95090f2ebb211dcdd83ebfd7ca2722ed857839a745064863d0424daeb79", - "codeguard-c": "2edd282530e1234ac6c1759f1b6e824d9f2023e5c692bef82a431c877dffc33e", - "codeguard-cfml": "3200617aa543f76e7d2f6e426c7ba34b0bfc96b4c90a97d14ba46c6e15be37c3", + "codeguard-ansible": "b4d78a74ea3ce4d98c9a53a9c45e488a24f418397b554590dffc34d3ca3b1337", + "codeguard-arkts": "ae1e5c637b77f0fcd247eb47d3700ab621e2ca857d3b57785dad1ab3daaaa4c7", + "codeguard-astro": "15a7a31cac804070b825ab1677ed8cef2e7626e062ebf9112acf71f7ef86ceb4", + "codeguard-c": "1c9e6b74ea93c6b57902c4938e2107403dae81aeebcf533dbede44f66992eac6", + "codeguard-cfml": "e4d00cfd229c5e5fcdd808ceb23d5183a8a95f61c365e95937c076aa28273ffa", "codeguard-check": "b0de6755927aab088e65f9c104ba3b5b42a31f2bb5e16e3c34a22721059723a4", - "codeguard-clojure": "01ea221b68bb8a65ca698881e72b708cb13f17369ed430e55d9ee9ada02bd140", - "codeguard-cobol": "62839eeb99efa7bceb82b6f741f861125d290cba7559c4ba6287bdb7384044ec", - "codeguard-cpp": "683c1b041b3df5c9c6fbe4a36e7bdd0c1c559f4e6fd2252cfac2186bd15f8b1c", - "codeguard-crystal": "636eeeeb6acc843f54895a6c62a913c330621670402c4a786fd422dc42611b6f", - "codeguard-csharp": "e9eeb68fc67532ffe448b8782c08c9f89490e1abcfe8bcc0116bcfaa1f928a71", - "codeguard-css": "4bdac4b30b12b7a1fbf47e6270a1814eb7041ae4f80b3e95b7ce3e37f0bc5dd3", - "codeguard-cuda": "f2a7e320ddafa0652973249954c11992be42ba69b56d5465b22ecb8d2aea9caa", - "codeguard-cve": "e0d6c35df5bf0d14d894b529946ca3b745bc5c990d540afc8c0e07bf1513ee2e", - "codeguard-dart": "990f700a1836bad992a330c4a9df86ff0c53b7cadd944ef55d7ed56ec6fa0298", + "codeguard-clojure": "6328245808d55dd11efa20e83711dce4b39c7b0f793dcde3a23cad9a3742ed8a", + "codeguard-cobol": "129b220e75e7429dfd593fff3b48fa97436370dbf892baee14bdf27c48e78bf8", + "codeguard-cpp": "e7cb2f9d2aac5279f53a26f92819376b1efd74964260a7fa01beeae4e46bd038", + "codeguard-crystal": "a73d4f07d136b81f09f2337f655eff2160b3f37ad0e3ec4d8599825ccaf0bc33", + "codeguard-csharp": "0d81c07a32d8bfc1e9b55a293a99d5e7733ee5636ba6640c323921f053f08427", + "codeguard-css": "5e38b1113fcd87d180928bdf400d9a109b5a4c88491e5d15ce8fc43851ce446b", + "codeguard-cuda": "9ee291bba0ac014140fa638a028ca5f77c09a28b49792e8c1fa96fd46e727859", + "codeguard-cve": "9db89a123c2da9228bc770618ea53eaa944ab76f87dc5a1c1ee4ce595a4b7482", + "codeguard-dart": "d40b0e9bd4810cc47101fb66d9c66ee0b816e07b75bfd1a3614c34d2c5eb1d93", "codeguard-detect": "56a6509aa250f6a508c088c421f98de623d94f15bb12f8c5067005d7d095842f", - "codeguard-dockerfile": "7df3ef6e1499c16a7ca2834ee36eadfa3ad3fcf624d684e16a380484b11bfedc", - "codeguard-elixir": "59b07b04d08d16f55260502c31188d37222ba310e02290a7ffbcae235a8321c7", - "codeguard-elm": "d6e4a06e7cc690a2e770c7a07cbaea510ce4dc8c341ffaa1789b954c1636f000", - "codeguard-erlang": "7b4dd925490da8a1626500a938da2500f1d3f02caa62eda4b1ebd5dda7c808f5", - "codeguard-fix": "5254cca09983c6e91615f8380ac6c9ccf93c5d19eb6ab83d8301787ce5638f68", - "codeguard-fsharp": "3bb354aa6343cf46bff10f2c407b1dbb75b7611ece359008e9991cea2aad3486", - "codeguard-git-branch": "adf2e584b5bf3e3758bc317f0e7364aac634cc1daada23aaf9aac9d605c15fc3", + "codeguard-dockerfile": "b95aafae842b8d474da7ddfe0c20c070080b35519c4d18b244dbb028f3f98ce0", + "codeguard-elixir": "bbac0b5691c678b2f944cb28061f05f99cd6683ce1099ced7416508aea638d72", + "codeguard-elm": "16cb94dba06adc95e6740687afcfe904297aa84ca2e7884e48c265df1f584da1", + "codeguard-erlang": "0ad262c45a3d1782c7cf18c702e973899a6f8798b54c4ddec94c868a569745cd", + "codeguard-fix": "f65ceabeda84f5c51ecac111cad059be86503be2335a48623cb2c09104c2d92e", + "codeguard-fsharp": "a8ea7769eb6b88d85b65b88e5f3aa36250a682047e8222dffb3e5737d7f3de00", + "codeguard-git-branch": "cf8c7814b2f7a0326470d87db18d37feb933f2d71c4152e57ba6f368c24f5e37", "codeguard-git-commit": "f930708f666b40361a5e82d11834bb2f9862368213ce5397d2393f342316165a", - "codeguard-go": "311729dc475a0c1035dfaec7e7b5efb61db8cb28682353c684102b1bbc16a231", - "codeguard-graphql": "8e65b3cd006c1b4e0bb073020986706010f40292bcbc8c8523ee4bf45276b69d", - "codeguard-groovy": "07e98c60fa1521a7a6eca02296779ec26870dda4b9abf4bc428909b506a5955e", - "codeguard-haskell": "45fcdd8bb87f06523e54896e8235fcbaebc6c899944f302fb2155270f2c54aa8", - "codeguard-html": "d109669f615f31c7351468aa657523399820728fabac0261d318e1e3be56b991", + "codeguard-go": "c45b4a657acaf67f922a7145492d5273d7e5b70fa58deb3c886ee338aa015d36", + "codeguard-graphql": "053e66e72304fb736f7115a6dad844ee3718613d09939a3abf06791848aecba4", + "codeguard-groovy": "5c80ca5d19ca3a39b6f3879a20317542334878ae7767cbf84ec87a669f66fdd9", + "codeguard-haskell": "e6ae6d01e2f7c7a31edd7b97381b612f76e235d73ae1f88b9704b2540a83a923", + "codeguard-html": "9cf8f6cb8d9411fc942a24efa507a19ef304d2db4587d1f742c48e3f9ee9abe3", "codeguard-init": "e76b00dea455c3354b67b060d7ef2f3ac15c6af7c2f0eed8fb944b3c26e7aea1", - "codeguard-java": "d46c8f58465ee6e6e1607534589498ebb0e2dd9d35bc189621efc75c37d50576", - "codeguard-julia": "42a1ffdaf61eea8d5dba4935269e020d91559eac7a9ede6cc5ecf39b41a3be5a", - "codeguard-kotlin": "d2fa6decd0507c4d9a76072688d77286f06b9424d26cf84851b860823ff0b759", - "codeguard-liquid": "9e9e27817a3ff625e43fb1fa72a3d4f3e9bc27fe3bf85f27ea51775ee3227202", - "codeguard-lua": "aec0ccecd991c02cac9a1a9e664ca84a193d240134d2722bc3ec00d22ec49aad", - "codeguard-luau": "038dc75d4d22cb13f847b18dbbb53aeda1af66d5d4399feba7cd3bc3151c5015", - "codeguard-markdown": "52c6cf08ef574bb86e62947b12689df08a540178f3bf10481150889b0d262799", - "codeguard-metal": "b530035d00dd23700957d975539e977135156e8b115a4ae688beca5f3dc31c45", - "codeguard-nim": "56a6290ed2383046bbd4ffc5c530c94ef1bd624b36761ef686c1a96828d05cf4", - "codeguard-nix": "9da0ae77ed82ee6ee20ecbc693fe955f6d3fd1492e2740411f40ea70e805fcda", - "codeguard-objc": "ab4f4cec6025dab69f590fe45aade41b2d61892f37621ee8d78216e19d4780a6", - "codeguard-ocaml": "cb50bc5b596719b5d28370d276c8759d252d0234495ebd2ec2b0a4f78b2b2bb9", - "codeguard-pascal": "e66dfd7e2f7e247fe53f058847eeefadc1688de7787a423b581214c5df073742", - "codeguard-perl": "7b5da7bee5b75d1cb7b4e254d3adb4e0388cc099c42ca50a878ead8c8a29ebc0", - "codeguard-php": "8a25b0a0ee50d8f670909f6eaf7617166836cea7ae5b10d2a84a61c62f6aff53", - "codeguard-powershell": "054e15c4eb4938bdf4dfa19e7b43bc1c2fc8f5560d99814c9d3c3d86737224a9", - "codeguard-protobuf": "5af019aa6f79c1e29aadacbff8428c57c3da68c9d3978460e7bb3efaa65ee1aa", - "codeguard-python": "d57035df55799c6a7cf5c9657511e18fa425c65a5bb998cca41f358b0799730a", - "codeguard-r": "35934b0c7c66ee9214fbdab84e985f18cb0d55c9b9e927ec7874e5deb80dae76", - "codeguard-ruby": "3efb0d280f7621d86cda26854d857a8a821ceeceb10dd9c605292e6be079eca7", - "codeguard-rust": "e541235142cfb27778ed1d14c67fd168f1d790ff9c4decb13611c55dcc44dfc9", - "codeguard-scala": "8e2960daebee289ec13aa4c9610c96edef0d9217ea250ce58b4c02eec5294b8d", + "codeguard-java": "3832f00a0a26badf80de805b0b1276109343bb711ffce60e63fad127b848843c", + "codeguard-julia": "0b4a32b0bf402ae3bbd5ce79a81144bf33f6e8f5d75feab5f1aba81e7b27b6a7", + "codeguard-kotlin": "0b7ac4c541d9d5dcdfead174d19f012427202e894f07d34254b568af9664c25f", + "codeguard-liquid": "d95db9bc6f7c180f85b62a0b6a4163c29056cbcb9c0d734e68e7c6a6190c586e", + "codeguard-lua": "950ff2e34fdeb5521f6c7a5d9a9928362a1d6ffbf9742130172b667fa4bff13d", + "codeguard-luau": "c988eb250e9b543be6b979852c7acc9e3093dec6929d1d3bd30da6a10269d91e", + "codeguard-markdown": "d4af5e6e63ddfb7664f376861ecc4ccf9ab76e8d70780120267761eb4c72fb62", + "codeguard-metal": "15c7bd82c506297fe7519b21812d1c26a8cb8385a91c43c2f47752ac5c9a8b67", + "codeguard-nim": "55fe4ead57cc373cd7641b6f68595b5ab53fcb673ead7d77e9ee48e6793b1ed8", + "codeguard-nix": "fb982830a842ca705b8b2e24d2eac85cbd36f526008e6f2954d697391f422359", + "codeguard-objc": "63b6369f9fc9d00bd5f8628a6f8e5127a9e1be3a0f9d03b57a9378b0d9e5b84d", + "codeguard-ocaml": "ce45d7e4559f7db3c3f287120d210b6f88d2cb7bb1d75ad7a7dba74d0e6e2d23", + "codeguard-pascal": "13a999918191e6ad3134ef2c997f46c9ea997272f4ec914c6b2b31343ec0cd6a", + "codeguard-perl": "61fb37f073eaedfce6fce46ef4564d97a3eddbbc75b25e926fcb28ce15348d34", + "codeguard-php": "b9139ab6b11499884d743880578bc01b108edd43498accfd40c2c86c98f8d4fd", + "codeguard-powershell": "573187f67123cb4ad9c04b4017351cfd69add325fc6afb5489f81dfcc3e0246f", + "codeguard-protobuf": "2096b8c0b97df8ac007e757e4052543b98a88cc2fec40a4eab712c68205de5b1", + "codeguard-python": "3893b3b90acb45f0e96ab94a3a1407ceb6c15b1a3f8f5708f3db63fa38d78aa2", + "codeguard-r": "1df4b652585676c78bacdc0170937f7ee4dac4e137bd358c7079a6deba7dd4b5", + "codeguard-ruby": "0645355f9b1a122baa79725e4a5cf4365555447bf8728ab6c5b444292655994b", + "codeguard-rust": "455c337fa1d6395983a80d185f951c15e3e9bd7ed12ea4638f53bcb824495f82", + "codeguard-scala": "52fe5b0ec76311db87142ffedb37b3b1110c851a380c927c8d0de7a4c811fafa", "codeguard-security-api": "8ee9900353bf58b80f25868829d84b047ccc6e1d8a28d53e2b88c3e822b5fbe1", "codeguard-security-code": "7d7d82cc21f75b1ff4bbcab92b14607e652980a833ebc4a6357f28ceaba8c22d", "codeguard-security-data": "185432d5dd2106506afe4f355108778ef9661ebf3e0ec253c35129b5d373cb38", - "codeguard-shell": "f746fb9ed4578f395d094d7555769e603ee8f1a31cf2ddad73e212b16daf10a2", - "codeguard-solidity": "1f9fab7a1fdde294c5cc38c2f5b8ce3b3ba16a6810f1e8958f18546ceca1ab3b", - "codeguard-sql": "32cfd608166900b7a78972b544e2445bd74413abdd996f14b24417f916ec9f15", - "codeguard-svelte": "74ac0580db7b7584197cf3361960b4ba71170ca1c9ff710ab81a0cfd03be9dff", - "codeguard-swift": "460ebb12c33798a6a5317739cd42b1d45cec54cd29b8f0a2dfbcc426ca1251a9", - "codeguard-terraform": "810acbc8ecfdf2f4aeaed46db5dd31a3bf3325bbc43c5ab1c75440670abe1e9b", - "codeguard-toml": "cef4c5699da7ec26521f9b82339cb91b6c943c0694eeafb3b260bbcb1c404b75", - "codeguard-typescript": "f69a7fa09b41905435b340413105581706fe53e1d03df428b65bfca1d260abda", - "codeguard-vbnet": "91a2cb590246641287c84e49c2eac85d7369b17cf7786d5b6fee97cc4ac44576", - "codeguard-vue": "281f2ad90860c663050a5deae0fe8aaab140b3b4c829a8f54ee7870ae9ac6027", - "codeguard-yaml": "f58dd6027424b7d4928707d36155dbfff9acbe5080080cda18f126883f101f31", - "codeguard-zig": "abd8ed9cb8c5f1981b297289c23ddb704eb8abcab41ea34643603baa056bb32f" + "codeguard-shell": "413477839e8748bd32d38646d00828470a7f2b168dedc2f2f4917cdfe053225a", + "codeguard-solidity": "8750aa66c12b02ce4c7a7096bf9c9fabe034cc7aeb8f6a0e5e4a0f94ffb97d54", + "codeguard-sql": "f4bc3f1b3e6f737b895f2cb018edfe68de386536b200879e0459b218ea336887", + "codeguard-svelte": "fbd6d282527f209c507229336fcc0c834ec03481a4835beaeff0bb071c19da5e", + "codeguard-swift": "b96e08a9442ca22ed6252f73622f267e38b5d9d8f08b85f401768c1220a8e255", + "codeguard-terraform": "bad531ce883507dd92fdd77c388b7f5d456507bfdd86dfb002e0bb2b410651e8", + "codeguard-toml": "93e66e8d97a15f436bb097438e04f011c49404c680a1d29d3f497eec6b8d7bab", + "codeguard-typescript": "c86714abd36b2e46b52ab4071d1936ceeb8f76f178d2497b05e498a8c82581bf", + "codeguard-vbnet": "d1f62359f13d2f581b446e39a7fecd34db4f8a085644a3ab5b906d5c55c35f55", + "codeguard-vue": "0df651c06a4a3b468027b1c3ad913c2808682c90890ddd109a9fe5632d064b9c", + "codeguard-yaml": "66b65f6aec5114d2a726726c03c39234fc13bd06ebb398277d22325a3e35af13", + "codeguard-zig": "329fdce6062c1b6e6d2889b1b36c0d50e6b29e384bb9794a3bc879d8df7c3d6a" } } ] diff --git a/skills/codeguard-ansible/SKILL.md b/skills/codeguard-ansible/SKILL.md index 1f0bc95..23e41d9 100644 --- a/skills/codeguard-ansible/SKILL.md +++ b/skills/codeguard-ansible/SKILL.md @@ -138,7 +138,7 @@ Ansible Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 当前条目标记为 planned;不得把 YAML 通道的结果冒充 Ansible 语义门禁。 +7. **领域陷阱** — 当前条目标记为 planned;不得把 YAML 通道的结果冒充 Ansible 语义门禁。 ## 信息不足时 diff --git a/skills/codeguard-arkts/SKILL.md b/skills/codeguard-arkts/SKILL.md index ad52943..cf6ee88 100644 --- a/skills/codeguard-arkts/SKILL.md +++ b/skills/codeguard-arkts/SKILL.md @@ -138,7 +138,7 @@ ArkTS (HarmonyOS) Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 当前条目标记为 planned;需要 HarmonyOS/DevEco 官方诊断证据后才能升级。 +7. **领域陷阱** — 当前条目标记为 planned;需要 HarmonyOS/DevEco 官方诊断证据后才能升级。 ## 信息不足时 diff --git a/skills/codeguard-astro/SKILL.md b/skills/codeguard-astro/SKILL.md index 7a7e970..7c50385 100644 --- a/skills/codeguard-astro/SKILL.md +++ b/skills/codeguard-astro/SKILL.md @@ -148,7 +148,7 @@ Astro Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Astro 文件需要专用 parser;只检查脚本区不能代表整个组件通过。 +7. **领域陷阱** — Astro 文件需要专用 parser;只检查脚本区不能代表整个组件通过。 ## 信息不足时 diff --git a/skills/codeguard-c/SKILL.md b/skills/codeguard-c/SKILL.md index 86db68c..efcae2f 100644 --- a/skills/codeguard-c/SKILL.md +++ b/skills/codeguard-c/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `clang-tidy --quiet '{file}'` | | format/fix | `clang-format -i '{file}'` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.c'"'"' -o -name '"'"'*.h'"'"' | xargs -r clang-tidy --quiet'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.c'"'"' -o -name '"'"'*.h'"'"' \| xargs -r clang-tidy --quiet'` | ## 标准 Workflow @@ -148,7 +148,7 @@ C Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — clang-tidy 需要可靠的编译参数;复杂项目优先提供 `compile_commands.json`。 +7. **领域陷阱** — clang-tidy 需要可靠的编译参数;复杂项目优先提供 `compile_commands.json`。 ## 信息不足时 diff --git a/skills/codeguard-cfml/SKILL.md b/skills/codeguard-cfml/SKILL.md index 98bd796..3b85eab 100644 --- a/skills/codeguard-cfml/SKILL.md +++ b/skills/codeguard-cfml/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `cflint '{file}'` | | format/fix | `未接入` | -| 项目级 gate | `bash -c 'find . \( -name '"'"'*.cfc'"'"' -o -name '"'"'*.cfm'"'"' \) -type f -print0 | xargs -0 -r cflint'` | +| 项目级 gate | `bash -c 'find . \( -name '"'"'*.cfc'"'"' -o -name '"'"'*.cfm'"'"' \) -type f -print0 \| xargs -0 -r cflint'` | ## 标准 Workflow @@ -148,7 +148,7 @@ CFML (ColdFusion) Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — CFML 方言与引擎差异会影响 CFLint 结果;需注明 Adobe CF 或 Lucee。 +7. **领域陷阱** — CFML 方言与引擎差异会影响 CFLint 结果;需注明 Adobe CF 或 Lucee。 ## 信息不足时 diff --git a/skills/codeguard-clojure/SKILL.md b/skills/codeguard-clojure/SKILL.md index 6cb9e22..dac67da 100644 --- a/skills/codeguard-clojure/SKILL.md +++ b/skills/codeguard-clojure/SKILL.md @@ -148,7 +148,7 @@ Clojure Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — clj-kondo cache 与 classpath 会影响宏分析;宏项目需提供导出配置。 +7. **领域陷阱** — clj-kondo cache 与 classpath 会影响宏分析;宏项目需提供导出配置。 ## 信息不足时 diff --git a/skills/codeguard-cobol/SKILL.md b/skills/codeguard-cobol/SKILL.md index 2f4e62e..d98321e 100644 --- a/skills/codeguard-cobol/SKILL.md +++ b/skills/codeguard-cobol/SKILL.md @@ -138,7 +138,7 @@ COBOL Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 当前条目标记为 planned;依赖具体编译器/IDE,不能虚构通用 CLI。 +7. **领域陷阱** — 当前条目标记为 planned;依赖具体编译器/IDE,不能虚构通用 CLI。 ## 信息不足时 diff --git a/skills/codeguard-cpp/SKILL.md b/skills/codeguard-cpp/SKILL.md index a4fca16..e5c8c42 100644 --- a/skills/codeguard-cpp/SKILL.md +++ b/skills/codeguard-cpp/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `clang-tidy --quiet '{file}'` | | format/fix | `clang-format -i '{file}'` | -| 项目级 gate | `bash -c 'find . \( -name '"'"'*.cpp'"'"' -o -name '"'"'*.hpp'"'"' -o -name '"'"'*.cc'"'"' \) -type f -print0 | xargs -0 -r clang-tidy --quiet'` | +| 项目级 gate | `bash -c 'find . \( -name '"'"'*.cpp'"'"' -o -name '"'"'*.hpp'"'"' -o -name '"'"'*.cc'"'"' \) -type f -print0 \| xargs -0 -r clang-tidy --quiet'` | ## 标准 Workflow @@ -148,7 +148,7 @@ C++ Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 模板、宏和条件编译高度依赖真实编译数据库;不要凭单文件默认参数宣布通过。 +7. **领域陷阱** — 模板、宏和条件编译高度依赖真实编译数据库;不要凭单文件默认参数宣布通过。 ## 信息不足时 diff --git a/skills/codeguard-crystal/SKILL.md b/skills/codeguard-crystal/SKILL.md index 3cb97d2..08026d8 100644 --- a/skills/codeguard-crystal/SKILL.md +++ b/skills/codeguard-crystal/SKILL.md @@ -148,7 +148,7 @@ Crystal Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Ameba 配置和 Crystal 版本需匹配;格式化不替代 `crystal spec`。 +7. **领域陷阱** — Ameba 配置和 Crystal 版本需匹配;格式化不替代 `crystal spec`。 ## 信息不足时 diff --git a/skills/codeguard-csharp/SKILL.md b/skills/codeguard-csharp/SKILL.md index b7602d4..63135f5 100644 --- a/skills/codeguard-csharp/SKILL.md +++ b/skills/codeguard-csharp/SKILL.md @@ -148,7 +148,7 @@ C# Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 +7. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 ## 信息不足时 diff --git a/skills/codeguard-css/SKILL.md b/skills/codeguard-css/SKILL.md index 049bb86..49dc82c 100644 --- a/skills/codeguard-css/SKILL.md +++ b/skills/codeguard-css/SKILL.md @@ -148,7 +148,7 @@ CSS / SCSS / Sass / LESS Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Stylelint glob 必须覆盖 SCSS/Sass/LESS 时显式扩展,默认 `**/*.css` 不会自动覆盖全部预处理器。 +7. **领域陷阱** — Stylelint glob 必须覆盖 SCSS/Sass/LESS 时显式扩展,默认 `**/*.css` 不会自动覆盖全部预处理器。 ## 信息不足时 diff --git a/skills/codeguard-cuda/SKILL.md b/skills/codeguard-cuda/SKILL.md index c73dda9..4123ab7 100644 --- a/skills/codeguard-cuda/SKILL.md +++ b/skills/codeguard-cuda/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `clang-tidy --quiet '{file}'` | | format/fix | `clang-format -i '{file}'` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.cu'"'"' | xargs -r clang-tidy --quiet'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.cu'"'"' \| xargs -r clang-tidy --quiet'` | ## 标准 Workflow @@ -148,7 +148,7 @@ CUDA Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — CUDA 文件同时受主机编译器与 nvcc 约束;clang-tidy 不能替代真实 CUDA 构建。 +7. **领域陷阱** — CUDA 文件同时受主机编译器与 nvcc 约束;clang-tidy 不能替代真实 CUDA 构建。 ## 信息不足时 diff --git a/skills/codeguard-cve/SKILL.md b/skills/codeguard-cve/SKILL.md index 3dec6c4..4bbb27d 100644 --- a/skills/codeguard-cve/SKILL.md +++ b/skills/codeguard-cve/SKILL.md @@ -1,7 +1,7 @@ --- name: codeguard-cve license: Apache-2.0 -description: 编排 Maven、Node、Python 和 Rust 依赖的 CVE 扫描与门禁;当用户要求扫漏洞、依赖安全检查、发布前审查、解释 HIGH/CRITICAL 发现或设计抑制策略时使用。必须保留工具、阈值、依赖路径与复扫证据。 +description: 编排 Maven、Node、Python 和 Rust 依赖的 CVE 扫描与门禁;未被原生扫描器覆盖的语言自动落 trivy 通用兜底(原生工具缺失时保持无法验证,不用兜底顶替);当用户要求扫漏洞、依赖安全检查、发布前审查、解释 HIGH/CRITICAL 发现或设计抑制策略时使用。必须保留工具、阈值、依赖路径与复扫证据。 compatibility: 需要目标生态的锁文件、扫描工具及可用漏洞数据源;默认不升级依赖、不自动接受抑制。 --- @@ -11,15 +11,19 @@ compatibility: 需要目标生态的锁文件、扫描工具及可用漏洞数 ### ✅ Strengths 1. 自动检测生态,编排对应扫描工具 -2. 阈值门禁(`--severity MEDIUM/HIGH/CRITICAL`) -3. `--fix` 自动修复(npm audit fix);其余生态输出修复指引 -4. 三态退出码:0=通过 / 1=无法验证(工具缺失)/ 2=发现漏洞 +2. 识别到语言但无原生生态映射 → 自动落 `universal`(trivy fs --scanners vuln);原生生态存在时不并行兜底 +3. `--severity` 为「该级别及以上」,在所有扫描器上同一语义(maven 按 CVSS 档位下界换算,HIGH⇒7) +4. 退出码:0 通过 / 1 无法验证 / 2 存在漏洞 / 3 参数错误(未声明 --ecosystem 在任何扫描前拒绝) +5. 阈值门禁(`--severity MEDIUM/HIGH/CRITICAL`) +6. `--fix` 自动修复(npm audit fix);其余生态输出修复指引 +7. 三态退出码:0=通过 / 1=无法验证(工具缺失)/ 2=发现漏洞 ### ⚠️ Prerequisites 1. Maven:mvn + 网络(首跑下载 NVD 库,建议申请 NVD_API_KEY) 2. Node:npm + package-lock.json 3. Python:pip-audit(`pip install pip-audit`) 4. Rust:cargo-audit(`cargo install cargo-audit`) +5. 通用兜底:trivy(`brew install trivy`)——仅在检测到无原生扫描器的语言(Go/PHP/Ruby 等)时触发 ### ❌ Out of Scope 1. 镜像内 OS 包 CVE → trivy image(可后续接入) diff --git a/skills/codeguard-dart/SKILL.md b/skills/codeguard-dart/SKILL.md index 52a9b5a..1bb459d 100644 --- a/skills/codeguard-dart/SKILL.md +++ b/skills/codeguard-dart/SKILL.md @@ -148,7 +148,7 @@ Dart / Flutter Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `dart analyze` 与 Flutter widget/integration tests 是不同证据层级。 +7. **领域陷阱** — `dart analyze` 与 Flutter widget/integration tests 是不同证据层级。 ## 信息不足时 diff --git a/skills/codeguard-dockerfile/SKILL.md b/skills/codeguard-dockerfile/SKILL.md index 5f2d74a..5be86ba 100644 --- a/skills/codeguard-dockerfile/SKILL.md +++ b/skills/codeguard-dockerfile/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `hadolint '{file}'` | | format/fix | `hadolint` | -| 项目级 gate | `bash -c 'find . \( -name '"'"'Dockerfile'"'"' -o -name '"'"'Dockerfile.*'"'"' -o -name '"'"'Containerfile'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -print0 | xargs -0 -r hadolint'` | +| 项目级 gate | `bash -c 'find . \( -name '"'"'Dockerfile'"'"' -o -name '"'"'Dockerfile.*'"'"' -o -name '"'"'Containerfile'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -print0 \| xargs -0 -r hadolint'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Dockerfile Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Hadolint 通过不证明镜像安全;仍需检查基础镜像摘要、SBOM 与漏洞扫描结果。 +7. **领域陷阱** — Hadolint 通过不证明镜像安全;仍需检查基础镜像摘要、SBOM 与漏洞扫描结果。 ## 信息不足时 diff --git a/skills/codeguard-elixir/SKILL.md b/skills/codeguard-elixir/SKILL.md index 481ee9a..f930a97 100644 --- a/skills/codeguard-elixir/SKILL.md +++ b/skills/codeguard-elixir/SKILL.md @@ -148,7 +148,7 @@ Elixir Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 +7. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 ## 信息不足时 diff --git a/skills/codeguard-elm/SKILL.md b/skills/codeguard-elm/SKILL.md index db97422..1ea51bc 100644 --- a/skills/codeguard-elm/SKILL.md +++ b/skills/codeguard-elm/SKILL.md @@ -148,7 +148,7 @@ Elm Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — elm-review 依赖项目 review 配置;未初始化时应报告不可验证。 +7. **领域陷阱** — elm-review 依赖项目 review 配置;未初始化时应报告不可验证。 ## 信息不足时 diff --git a/skills/codeguard-erlang/SKILL.md b/skills/codeguard-erlang/SKILL.md index 449a239..7559767 100644 --- a/skills/codeguard-erlang/SKILL.md +++ b/skills/codeguard-erlang/SKILL.md @@ -148,7 +148,7 @@ Erlang Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Elvis 与 erlfmt 依赖 rebar 项目上下文;OTP 版本也会改变可用语法。 +7. **领域陷阱** — Elvis 与 erlfmt 依赖 rebar 项目上下文;OTP 版本也会改变可用语法。 ## 信息不足时 diff --git a/skills/codeguard-fix/SKILL.md b/skills/codeguard-fix/SKILL.md index dc3e4bf..60a3be8 100644 --- a/skills/codeguard-fix/SKILL.md +++ b/skills/codeguard-fix/SKILL.md @@ -105,10 +105,10 @@ Codeguard fix 结果 ## 更常见的 Gotchas -3. **formatter 可以重写全文件**:小问题也可产生大 diff,需限定范围。 -4. **锁文件漂移**:某些工具会触发依赖解析,不应在格式修复中接受未授权的 lockfile 改动。 -5. **生成代码**:应修源模板并重新生成,不直接编辑产物。 -6. **语义性 autofix**:unused/import 修复可改变副作用,必须查看规则类型与测试。 +1. **formatter 可以重写全文件**:小问题也可产生大 diff,需限定范围。 +2. **锁文件漂移**:某些工具会触发依赖解析,不应在格式修复中接受未授权的 lockfile 改动。 +3. **生成代码**:应修源模板并重新生成,不直接编辑产物。 +4. **语义性 autofix**:unused/import 修复可改变副作用,必须查看规则类型与测试。 ## 按需加载资源 diff --git a/skills/codeguard-fsharp/SKILL.md b/skills/codeguard-fsharp/SKILL.md index c4da746..518bcc2 100644 --- a/skills/codeguard-fsharp/SKILL.md +++ b/skills/codeguard-fsharp/SKILL.md @@ -148,7 +148,7 @@ F# Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Fantomas 主要处理格式,不替代编译器、测试与 analyzers。 +7. **领域陷阱** — Fantomas 主要处理格式,不替代编译器、测试与 analyzers。 ## 信息不足时 diff --git a/skills/codeguard-git-branch/references/branch-models-comparison.md b/skills/codeguard-git-branch/references/branch-models-comparison.md index 5f5c3c1..4c63013 100644 --- a/skills/codeguard-git-branch/references/branch-models-comparison.md +++ b/skills/codeguard-git-branch/references/branch-models-comparison.md @@ -7,7 +7,7 @@ | 维度 | Gitflow | Gitflow+(团队) | GitLab 分支规范(团队变体) | GitHub Flow | GitLab Flow | Trunk-Based | OneFlow | Release Flow | |---|---|---|---|---|---|---|---|---| | 长期分支 | master, develop | master, develop, test | 主干(默认分支)+ env/* | main | main + 环境/发布分支 | trunk/main | main | main + release/v* | -| 临时分支 | feature, release, hotfix | feature, fix, hotfix | feature/*, *-stable | feature(短命) | feature(短命) | <2 天短命分支(或直推) | feature, release(可选), hotfix | feature(短命) | +| 临时分支 | feature, release, hotfix | feature, fix, hotfix | feature/*,*-stable | feature(短命) | feature(短命) | <2 天短命分支(或直推) | feature, release(可选), hotfix | feature(短命) | | 发布方式 | release → master → tag | test 回归 → release → master → tag | *-stable 分支 → PROD | 合并 main 即部署 | 环境晋升 / release 分支 | 每次提交可发布(feature flag) | main 打 tag | release/v* 维护 | | 热修复 | master→hotfix→master+develop | master→hotfix→master(+develop) | feature 修复走 MR | main 直修 | cherry-pick 下游 | trunk 直修(flag 关闭) | main→hotfix→main | main 修 + cherry-pick 回 release | | 合并方向门禁 | 严格 | 严格 | feature/*→主干 | feature→main | 上游→下游 | 全部→trunk | feature→main | 开发在 main,release 只收 cherry-pick | diff --git a/skills/codeguard-go/SKILL.md b/skills/codeguard-go/SKILL.md index b3a7917..0740cf2 100644 --- a/skills/codeguard-go/SKILL.md +++ b/skills/codeguard-go/SKILL.md @@ -148,8 +148,8 @@ Go Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `gofmt` 只处理格式;`go vet` 与 `go test` 仍需独立运行。 -2. **领域陷阱** — 多模块仓库可能包含多个 `go.mod`,从错误根目录执行会漏检。 +7. **领域陷阱** — `gofmt` 只处理格式;`go vet` 与 `go test` 仍需独立运行。 +8. **领域陷阱** — 多模块仓库可能包含多个 `go.mod`,从错误根目录执行会漏检。 ## 信息不足时 diff --git a/skills/codeguard-graphql/SKILL.md b/skills/codeguard-graphql/SKILL.md index 14bfd0c..c124311 100644 --- a/skills/codeguard-graphql/SKILL.md +++ b/skills/codeguard-graphql/SKILL.md @@ -148,7 +148,7 @@ GraphQL Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — GraphQL lint 依赖 schema;无 schema 时只能验证有限的文档规则。 +7. **领域陷阱** — GraphQL lint 依赖 schema;无 schema 时只能验证有限的文档规则。 ## 信息不足时 diff --git a/skills/codeguard-groovy/SKILL.md b/skills/codeguard-groovy/SKILL.md index b035ef1..e895122 100644 --- a/skills/codeguard-groovy/SKILL.md +++ b/skills/codeguard-groovy/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `npm-groovy-lint '{file}'` | | format/fix | `npm-groovy-lint --fix` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.groovy'"'"' -type f -not -path '"'"'*/node_modules/*'"'"' -print0 | xargs -0 -r npm-groovy-lint --no-insight'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.groovy'"'"' -type f -not -path '"'"'*/node_modules/*'"'"' -print0 \| xargs -0 -r npm-groovy-lint --no-insight'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Groovy Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Groovy 动态特性使静态 lint 覆盖有限;Gradle/Jenkins DSL 需结合宿主验证。 +7. **领域陷阱** — Groovy 动态特性使静态 lint 覆盖有限;Gradle/Jenkins DSL 需结合宿主验证。 ## 信息不足时 diff --git a/skills/codeguard-haskell/SKILL.md b/skills/codeguard-haskell/SKILL.md index 8f0d711..02af3c0 100644 --- a/skills/codeguard-haskell/SKILL.md +++ b/skills/codeguard-haskell/SKILL.md @@ -148,7 +148,7 @@ Haskell Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — HLint 建议不总是语义等价;涉及 strictness 或性能时禁止盲目批量应用。 +7. **领域陷阱** — HLint 建议不总是语义等价;涉及 strictness 或性能时禁止盲目批量应用。 ## 信息不足时 diff --git a/skills/codeguard-html/SKILL.md b/skills/codeguard-html/SKILL.md index 7cbff70..d7afbed 100644 --- a/skills/codeguard-html/SKILL.md +++ b/skills/codeguard-html/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `npx --no-install htmlhint --version` | | lint | `npx --no-install htmlhint '{file}'` | | format/fix | `prettier --write` | -| 项目级 gate | `bash -c 'find . \( -name '"'"'*.html'"'"' -o -name '"'"'*.htm'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -exec grep -L '"'"'<%'"'"' {} + | xargs -0 -r npx --no-install htmlhint'` | +| 项目级 gate | `bash -c 'find . \( -name '"'"'*.html'"'"' -o -name '"'"'*.htm'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -exec grep -L '"'"'<%'"'"' {} + \| xargs -0 -r npx --no-install htmlhint'` | ## 标准 Workflow @@ -148,7 +148,7 @@ HTML Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 模板文件可能包含服务端语法;HTMLHint 解析失败时先确认是否应交给模板专用工具。 +7. **领域陷阱** — 模板文件可能包含服务端语法;HTMLHint 解析失败时先确认是否应交给模板专用工具。 ## 信息不足时 diff --git a/skills/codeguard-java/SKILL.md b/skills/codeguard-java/SKILL.md index 30fc36d..d0a480e 100644 --- a/skills/codeguard-java/SKILL.md +++ b/skills/codeguard-java/SKILL.md @@ -148,8 +148,8 @@ Java Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `mvn compile` 不执行 Javadoc 门禁;发布链失败时必须单独运行 `mvn javadoc:jar`。 -2. **领域陷阱** — JDK 版本会改变 doclint 严格度;本地和 CI 必须使用同一主版本。 +7. **领域陷阱** — `mvn compile` 不执行 Javadoc 门禁;发布链失败时必须单独运行 `mvn javadoc:jar`。 +8. **领域陷阱** — JDK 版本会改变 doclint 严格度;本地和 CI 必须使用同一主版本。 ## 信息不足时 diff --git a/skills/codeguard-julia/SKILL.md b/skills/codeguard-julia/SKILL.md index 4b4169a..5ebf465 100644 --- a/skills/codeguard-julia/SKILL.md +++ b/skills/codeguard-julia/SKILL.md @@ -148,7 +148,7 @@ Julia Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 只有 formatter 时必须明确标为 format-only,不能把它当作语义 lint 通过。 +7. **领域陷阱** — 只有 formatter 时必须明确标为 format-only,不能把它当作语义 lint 通过。 ## 信息不足时 diff --git a/skills/codeguard-kotlin/SKILL.md b/skills/codeguard-kotlin/SKILL.md index ac5f234..20f9882 100644 --- a/skills/codeguard-kotlin/SKILL.md +++ b/skills/codeguard-kotlin/SKILL.md @@ -148,7 +148,7 @@ Kotlin Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Detekt 与 ktlint 是不同门禁;Gradle wrapper 版本和插件配置必须以项目为准。 +7. **领域陷阱** — Detekt 与 ktlint 是不同门禁;Gradle wrapper 版本和插件配置必须以项目为准。 ## 信息不足时 diff --git a/skills/codeguard-liquid/SKILL.md b/skills/codeguard-liquid/SKILL.md index 1503b12..ccef77c 100644 --- a/skills/codeguard-liquid/SKILL.md +++ b/skills/codeguard-liquid/SKILL.md @@ -148,7 +148,7 @@ Liquid (Shopify) Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Shopify Theme Check 面向 Shopify Liquid;其他 Liquid 方言需单独确认。 +7. **领域陷阱** — Shopify Theme Check 面向 Shopify Liquid;其他 Liquid 方言需单独确认。 ## 信息不足时 diff --git a/skills/codeguard-lua/SKILL.md b/skills/codeguard-lua/SKILL.md index 8740118..7e9d228 100644 --- a/skills/codeguard-lua/SKILL.md +++ b/skills/codeguard-lua/SKILL.md @@ -148,7 +148,7 @@ Lua Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Lua 版本和宿主环境差异大;Luacheck globals 必须与运行时一致。 +7. **领域陷阱** — Lua 版本和宿主环境差异大;Luacheck globals 必须与运行时一致。 ## 信息不足时 diff --git a/skills/codeguard-luau/SKILL.md b/skills/codeguard-luau/SKILL.md index 0015ebe..3bf04f9 100644 --- a/skills/codeguard-luau/SKILL.md +++ b/skills/codeguard-luau/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `luau-analyze '{file}'` | | format/fix | `stylua --syntax luau .` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.luau'"'"' -type f -print0 | xargs -0 -r luau-analyze'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.luau'"'"' -type f -print0 \| xargs -0 -r luau-analyze'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Luau Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Luau 与标准 Lua 类型/语法不同,禁止用普通 Lua linter 代替。 +7. **领域陷阱** — Luau 与标准 Lua 类型/语法不同,禁止用普通 Lua linter 代替。 ## 信息不足时 diff --git a/skills/codeguard-markdown/SKILL.md b/skills/codeguard-markdown/SKILL.md index e9b2cbc..b436166 100644 --- a/skills/codeguard-markdown/SKILL.md +++ b/skills/codeguard-markdown/SKILL.md @@ -148,7 +148,7 @@ Markdown Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Markdown 方言和文档生成器规则不同;先读取 `.markdownlint*` 与站点配置。 +7. **领域陷阱** — Markdown 方言和文档生成器规则不同;先读取 `.markdownlint*` 与站点配置。 ## 信息不足时 diff --git a/skills/codeguard-metal/SKILL.md b/skills/codeguard-metal/SKILL.md index e0bd03b..f77f21d 100644 --- a/skills/codeguard-metal/SKILL.md +++ b/skills/codeguard-metal/SKILL.md @@ -138,7 +138,7 @@ Metal Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 当前条目标记为 planned;需要 Xcode/metal 编译链证据后才能升级。 +7. **领域陷阱** — 当前条目标记为 planned;需要 Xcode/metal 编译链证据后才能升级。 ## 信息不足时 diff --git a/skills/codeguard-nim/SKILL.md b/skills/codeguard-nim/SKILL.md index 926d4bb..16396c5 100644 --- a/skills/codeguard-nim/SKILL.md +++ b/skills/codeguard-nim/SKILL.md @@ -148,7 +148,7 @@ Nim Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `nim check` 仍依赖项目 defines 与搜索路径;单文件默认上下文可能误报。 +7. **领域陷阱** — `nim check` 仍依赖项目 defines 与搜索路径;单文件默认上下文可能误报。 ## 信息不足时 diff --git a/skills/codeguard-nix/SKILL.md b/skills/codeguard-nix/SKILL.md index 3eedbda..8932f64 100644 --- a/skills/codeguard-nix/SKILL.md +++ b/skills/codeguard-nix/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `deadnix '{file}'` | | format/fix | `nixpkgs-fmt '{file}'` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.nix'"'"' -type f -print0 | xargs -0 -r deadnix'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.nix'"'"' -type f -print0 \| xargs -0 -r deadnix'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Nix Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — deadnix 发现未使用表达式,nixpkgs-fmt 只格式化;仍需执行 flake/check 或真实构建。 +7. **领域陷阱** — deadnix 发现未使用表达式,nixpkgs-fmt 只格式化;仍需执行 flake/check 或真实构建。 ## 信息不足时 diff --git a/skills/codeguard-objc/SKILL.md b/skills/codeguard-objc/SKILL.md index 2bcb0f2..0caca34 100644 --- a/skills/codeguard-objc/SKILL.md +++ b/skills/codeguard-objc/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `clang-tidy --quiet '{file}'` | | format/fix | `clang-format -i '{file}'` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.m'"'"' -o -name '"'"'*.mm'"'"' | xargs -r clang-tidy --quiet'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.m'"'"' -o -name '"'"'*.mm'"'"' \| xargs -r clang-tidy --quiet'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Objective-C Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Objective-C++ 的 `.mm` 文件必须使用匹配的 SDK 与编译参数,单独 clang-tidy 结果可能失真。 +7. **领域陷阱** — Objective-C++ 的 `.mm` 文件必须使用匹配的 SDK 与编译参数,单独 clang-tidy 结果可能失真。 ## 信息不足时 diff --git a/skills/codeguard-ocaml/SKILL.md b/skills/codeguard-ocaml/SKILL.md index 4a7cada..450b451 100644 --- a/skills/codeguard-ocaml/SKILL.md +++ b/skills/codeguard-ocaml/SKILL.md @@ -148,7 +148,7 @@ OCaml Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — ocamlformat 版本是格式契约的一部分;不同版本可能产生大面积无意义 diff。 +7. **领域陷阱** — ocamlformat 版本是格式契约的一部分;不同版本可能产生大面积无意义 diff。 ## 信息不足时 diff --git a/skills/codeguard-pascal/SKILL.md b/skills/codeguard-pascal/SKILL.md index 4ada04e..1a79722 100644 --- a/skills/codeguard-pascal/SKILL.md +++ b/skills/codeguard-pascal/SKILL.md @@ -148,7 +148,7 @@ Pascal / Delphi Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 只有格式化能力时不得声称完成静态检查;仍需编译器或 IDE 诊断。 +7. **领域陷阱** — 只有格式化能力时不得声称完成静态检查;仍需编译器或 IDE 诊断。 ## 信息不足时 diff --git a/skills/codeguard-perl/SKILL.md b/skills/codeguard-perl/SKILL.md index a279252..35f3b63 100644 --- a/skills/codeguard-perl/SKILL.md +++ b/skills/codeguard-perl/SKILL.md @@ -148,7 +148,7 @@ Perl Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Perl::Critic profile 决定严重级别;必须读取项目 `.perlcriticrc`。 +7. **领域陷阱** — Perl::Critic profile 决定严重级别;必须读取项目 `.perlcriticrc`。 ## 信息不足时 diff --git a/skills/codeguard-php/SKILL.md b/skills/codeguard-php/SKILL.md index 793cf35..2424ee1 100644 --- a/skills/codeguard-php/SKILL.md +++ b/skills/codeguard-php/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `php -l '{file}'` | | format/fix | `php-cs-fixer fix` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.php'"'"' -type f -not -path '"'"'*/vendor/*'"'"' -print0 | xargs -0 -n1 php -l'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.php'"'"' -type f -not -path '"'"'*/vendor/*'"'"' -print0 \| xargs -0 -n1 php -l'` | ## 标准 Workflow @@ -148,7 +148,7 @@ PHP Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `php -l` 只验证语法,不覆盖类型、风格或框架规则;不要把语法通过写成质量全绿。 +7. **领域陷阱** — `php -l` 只验证语法,不覆盖类型、风格或框架规则;不要把语法通过写成质量全绿。 ## 信息不足时 diff --git a/skills/codeguard-powershell/SKILL.md b/skills/codeguard-powershell/SKILL.md index 926196d..066d3b1 100644 --- a/skills/codeguard-powershell/SKILL.md +++ b/skills/codeguard-powershell/SKILL.md @@ -148,7 +148,7 @@ PowerShell Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Windows PowerShell 与 PowerShell 7 规则/模块不同,先确认目标运行时。 +7. **领域陷阱** — Windows PowerShell 与 PowerShell 7 规则/模块不同,先确认目标运行时。 ## 信息不足时 diff --git a/skills/codeguard-protobuf/SKILL.md b/skills/codeguard-protobuf/SKILL.md index 28c59f9..11a54d3 100644 --- a/skills/codeguard-protobuf/SKILL.md +++ b/skills/codeguard-protobuf/SKILL.md @@ -148,7 +148,7 @@ Protobuf Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Buf lint 通过后仍应检查 breaking changes;风格合规不等于 wire compatibility。 +7. **领域陷阱** — Buf lint 通过后仍应检查 breaking changes;风格合规不等于 wire compatibility。 ## 信息不足时 diff --git a/skills/codeguard-python/SKILL.md b/skills/codeguard-python/SKILL.md index f8036d2..f87b2c2 100644 --- a/skills/codeguard-python/SKILL.md +++ b/skills/codeguard-python/SKILL.md @@ -148,8 +148,8 @@ Python Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Ruff 的 `check --fix` 与 `format` 职责不同;需要格式化时两者应分别执行。 -2. **领域陷阱** — 先读取 `pyproject.toml` 的 target-version 与 per-file-ignores,不能用全局默认覆盖项目契约。 +7. **领域陷阱** — Ruff 的 `check --fix` 与 `format` 职责不同;需要格式化时两者应分别执行。 +8. **领域陷阱** — 先读取 `pyproject.toml` 的 target-version 与 per-file-ignores,不能用全局默认覆盖项目契约。 ## 信息不足时 diff --git a/skills/codeguard-r/SKILL.md b/skills/codeguard-r/SKILL.md index 97bacac..c5af0b2 100644 --- a/skills/codeguard-r/SKILL.md +++ b/skills/codeguard-r/SKILL.md @@ -148,7 +148,7 @@ R Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — R 包项目与普通脚本目录的 lint 范围不同;包项目还需 R CMD check。 +7. **领域陷阱** — R 包项目与普通脚本目录的 lint 范围不同;包项目还需 R CMD check。 ## 信息不足时 diff --git a/skills/codeguard-ruby/SKILL.md b/skills/codeguard-ruby/SKILL.md index 1472cb0..0801c3d 100644 --- a/skills/codeguard-ruby/SKILL.md +++ b/skills/codeguard-ruby/SKILL.md @@ -148,7 +148,7 @@ Ruby Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 +7. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 ## 信息不足时 diff --git a/skills/codeguard-rust/SKILL.md b/skills/codeguard-rust/SKILL.md index e6e1456..15f8b73 100644 --- a/skills/codeguard-rust/SKILL.md +++ b/skills/codeguard-rust/SKILL.md @@ -148,8 +148,8 @@ Rust Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `cargo fmt` 通过不代表 Clippy 通过;格式和语义 lint 是两条独立门禁。 -2. **领域陷阱** — Workspace 必须从根 `Cargo.toml` 执行,否则可能漏掉成员 crate。 +7. **领域陷阱** — `cargo fmt` 通过不代表 Clippy 通过;格式和语义 lint 是两条独立门禁。 +8. **领域陷阱** — Workspace 必须从根 `Cargo.toml` 执行,否则可能漏掉成员 crate。 ## 信息不足时 diff --git a/skills/codeguard-scala/SKILL.md b/skills/codeguard-scala/SKILL.md index 5cbab55..279bf93 100644 --- a/skills/codeguard-scala/SKILL.md +++ b/skills/codeguard-scala/SKILL.md @@ -148,7 +148,7 @@ Scala Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 +7. **项目配置优先** — 工具默认值不能覆盖仓库已提交的规则和版本约束。 ## 信息不足时 diff --git a/skills/codeguard-shell/SKILL.md b/skills/codeguard-shell/SKILL.md index aec74b7..ecbffd8 100644 --- a/skills/codeguard-shell/SKILL.md +++ b/skills/codeguard-shell/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `shellcheck '{file}'` | | format/fix | `shfmt -w .` | -| 项目级 gate | `bash -c 'find . \( -name '"'"'*.sh'"'"' -o -name '"'"'*.bash'"'"' -o -name '"'"'*.zsh'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -print0 | xargs -0 shellcheck --severity=warning'` | +| 项目级 gate | `bash -c 'find . \( -name '"'"'*.sh'"'"' -o -name '"'"'*.bash'"'"' -o -name '"'"'*.zsh'"'"' \) -type f -not -path '"'"'*/node_modules/*'"'"' -print0 \| xargs -0 shellcheck --severity=warning'` | ## 标准 Workflow @@ -148,7 +148,7 @@ Shell Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — ShellCheck 必须匹配脚本 shebang;bash、sh、zsh 的语义不能混用。 +7. **领域陷阱** — ShellCheck 必须匹配脚本 shebang;bash、sh、zsh 的语义不能混用。 ## 信息不足时 diff --git a/skills/codeguard-solidity/SKILL.md b/skills/codeguard-solidity/SKILL.md index aa6664a..09dcb79 100644 --- a/skills/codeguard-solidity/SKILL.md +++ b/skills/codeguard-solidity/SKILL.md @@ -148,7 +148,7 @@ Solidity Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Solhint 是风格/静态检查,不替代 Slither、Foundry 测试或合约审计。 +7. **领域陷阱** — Solhint 是风格/静态检查,不替代 Slither、Foundry 测试或合约审计。 ## 信息不足时 diff --git a/skills/codeguard-sql/SKILL.md b/skills/codeguard-sql/SKILL.md index 5eb991c..93b030c 100644 --- a/skills/codeguard-sql/SKILL.md +++ b/skills/codeguard-sql/SKILL.md @@ -79,7 +79,7 @@ compatibility: 需要本地项目、对应语言工具链和仓库既有 lint | 探测命令 | `使用命令查找与项目配置检查` | | lint | `sqlfluff lint '{file}'` | | format/fix | `sqlfluff fix` | -| 项目级 gate | `bash -c 'find . -name '"'"'*.sql'"'"' -type f -not -path '"'"'*/node_modules/*'"'"' -print0 | xargs -0 -r sqlfluff lint'` | +| 项目级 gate | `bash -c 'find . -name '"'"'*.sql'"'"' -type f -not -path '"'"'*/node_modules/*'"'"' -print0 \| xargs -0 -r sqlfluff lint'` | ## 标准 Workflow @@ -148,7 +148,7 @@ SQL Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — SQLFluff 必须设置正确 dialect;未指定方言的通过结果不能用于数据库兼容性结论。 +7. **领域陷阱** — SQLFluff 必须设置正确 dialect;未指定方言的通过结果不能用于数据库兼容性结论。 ## 信息不足时 diff --git a/skills/codeguard-svelte/SKILL.md b/skills/codeguard-svelte/SKILL.md index 0a0ab31..8854eb8 100644 --- a/skills/codeguard-svelte/SKILL.md +++ b/skills/codeguard-svelte/SKILL.md @@ -148,7 +148,7 @@ Svelte Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Svelte parser 与 ESLint 主版本需要兼容;解析失败不能降级为跳过。 +7. **领域陷阱** — Svelte parser 与 ESLint 主版本需要兼容;解析失败不能降级为跳过。 ## 信息不足时 diff --git a/skills/codeguard-swift/SKILL.md b/skills/codeguard-swift/SKILL.md index 0b4acee..1d4c826 100644 --- a/skills/codeguard-swift/SKILL.md +++ b/skills/codeguard-swift/SKILL.md @@ -148,7 +148,7 @@ Swift Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — SwiftLint 的规则来自仓库配置;不得用个人全局配置覆盖团队 `.swiftlint.yml`。 +7. **领域陷阱** — SwiftLint 的规则来自仓库配置;不得用个人全局配置覆盖团队 `.swiftlint.yml`。 ## 信息不足时 diff --git a/skills/codeguard-terraform/SKILL.md b/skills/codeguard-terraform/SKILL.md index 201e47b..79d3378 100644 --- a/skills/codeguard-terraform/SKILL.md +++ b/skills/codeguard-terraform/SKILL.md @@ -148,7 +148,7 @@ Terraform / OpenTofu Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — `terraform fmt`、`terraform validate` 与 TFLint 是三类门禁,不能互相替代。 +7. **领域陷阱** — `terraform fmt`、`terraform validate` 与 TFLint 是三类门禁,不能互相替代。 ## 信息不足时 diff --git a/skills/codeguard-toml/SKILL.md b/skills/codeguard-toml/SKILL.md index c130c04..cf036c2 100644 --- a/skills/codeguard-toml/SKILL.md +++ b/skills/codeguard-toml/SKILL.md @@ -148,7 +148,7 @@ TOML Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Taplo 格式化会重排布局;先确认生成文件和锁文件是否允许修改。 +7. **领域陷阱** — Taplo 格式化会重排布局;先确认生成文件和锁文件是否允许修改。 ## 信息不足时 diff --git a/skills/codeguard-typescript/SKILL.md b/skills/codeguard-typescript/SKILL.md index bc258eb..97487c7 100644 --- a/skills/codeguard-typescript/SKILL.md +++ b/skills/codeguard-typescript/SKILL.md @@ -148,8 +148,8 @@ TypeScript / JavaScript Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — 坚持 `npx --no-install`,避免检查过程静默下载与改变依赖树。 -2. **领域陷阱** — ESLint flat config 与旧 `.eslintrc` 的解析规则不同,先确认项目实际采用哪一套。 +7. **领域陷阱** — 坚持 `npx --no-install`,避免检查过程静默下载与改变依赖树。 +8. **领域陷阱** — ESLint flat config 与旧 `.eslintrc` 的解析规则不同,先确认项目实际采用哪一套。 ## 信息不足时 diff --git a/skills/codeguard-vbnet/SKILL.md b/skills/codeguard-vbnet/SKILL.md index d48ae01..44342ad 100644 --- a/skills/codeguard-vbnet/SKILL.md +++ b/skills/codeguard-vbnet/SKILL.md @@ -148,7 +148,7 @@ Visual Basic .NET Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — dotnet format 需要解析 solution/project;只有散落 `.vb` 文件时不可宣布通过。 +7. **领域陷阱** — dotnet format 需要解析 solution/project;只有散落 `.vb` 文件时不可宣布通过。 ## 信息不足时 diff --git a/skills/codeguard-vue/SKILL.md b/skills/codeguard-vue/SKILL.md index e3117c8..3f0f572 100644 --- a/skills/codeguard-vue/SKILL.md +++ b/skills/codeguard-vue/SKILL.md @@ -148,7 +148,7 @@ Vue Codeguard 结果 4. **占位符不是字面参数** — `{file}` 必须替换为真实、已授权路径。 5. **自动修复可能扩大 diff** — 修复后先审查 diff,再运行回归门禁。 6. **生成与 vendor 目录需显式策略** — 不得随意全仓扫描或修改第三方内容。 -1. **领域陷阱** — Vue SFC 需要匹配 Vue 版本的 parser/plugin;普通 ESLint 配置可能跳过 `