diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..78f1fccf --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# 来源补丁保留原始字节与固定摘要,不自动调整上下文空白。 +grammars/*/source.patch -whitespace diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c099c62f..b1bf99b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: run: | cargo test -p codeguard-runtime --features wasm-precheck --test process_contract cargo test -p codeguard-runtime --features wasm-precheck --test wasm_grammar_load --test dart_upstream_corpus - cargo test -p codeguard-cli --features wasm-precheck --test syntax_worker_candidate --test typescript_syntax_fallback_candidate --test java_syntax_fallback_candidate + cargo test -p codeguard-cli --features wasm-precheck --test syntax_worker_candidate --test grammar_probe_cli --test grammar_route --test check_all_grammar_candidates --test zig_lint_cli --test typescript_syntax_fallback_candidate --test java_syntax_fallback_candidate - name: Run test suite run: cargo test --workspace --all-targets diff --git a/README.md b/README.md index c358d78b..61bcba32 100644 --- a/README.md +++ b/README.md @@ -94,12 +94,18 @@ cargo build --locked -p codeguard-cli Version output includes `cli_version`, `target`, and protocol information. Discovery and init preview return observations and unknowns. Dry-run creates neither `AGENTS.md` nor a project data directory. Add Cargo `--offline` only when dependencies are cached. -The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with twenty-three pinned grammar candidates: ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin, and Dart. Java and TypeScript/TSX have narrow single-file fallback paths; `lint python` can provide bounded suspected syntax positions when Ruff is unavailable or no project Ruff configuration is declared. Native Ruff results take priority. It is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed. +The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with thirty-two pinned grammar candidates: ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin, Dart, Erlang, Pascal, CFML, CFQuery, CFScript, COBOL, Scala, Swift and VB.NET. Java and TypeScript/TSX have narrow single-file fallback paths; `lint python` can provide bounded suspected syntax positions when Ruff is unavailable or no project Ruff configuration is declared. Native Ruff results take priority. It is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed. -The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has twenty-three unqualified asset candidates (ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin, Dart) and zero released syntax capabilities. C, C++, C#, Go, JavaScript, Lua, Luau and Rust are byte-pinned CodeGraph assets that load in the Rust worker but have no public lint route or release qualification. ArkTS, Nix and Terraform are also pinned Rust-loadable candidates with narrow valid/invalid fixtures and no public lint route or release qualification; see the [limited acceptance record](tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The two dependency grammars retain their source bytes and use a byte-pinned legacy `dylink` metadata conversion for Rust loading; they have no public lint route or release qualification. Zig uses a byte-pinned import adaptation so the corrected CodeGraph grammar can load in Rust; it has no public `lint zig` route or release qualification yet. [Zig's limited acceptance record](tests/acceptance/zig-grammar-candidate.md) distinguishes this from released syntax support. Python has a source-build-only, unqualified CLI fallback path; its report remains incomplete and cannot approve delivery. R, Ruby, PHP and Kotlin have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow worker samples; PHP covers mixed HTML/PHP, and all four remain unqualified. The original CodeGraph Dart WASM cannot be instantiated by Rust, but CodeGuard now pins a reproducible Zig rebuild with the real scanner and a byte-pinned WASI import adaptation. Its narrow Rust and worker fixtures pass, while public lint and release remain unqualified; see the [Dart rebuild record](tests/acceptance/dart-grammar-rebuild-candidate.md). The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB source asset also exceeds the current Rust loader's 8 MiB limit. +The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has thirty-two unqualified asset candidates (ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin, Dart, Erlang, Pascal, CFML, CFQuery, CFScript, COBOL, Scala, Swift, VB.NET) and zero released syntax capabilities. C, C++, C#, Go, JavaScript, Lua, Luau and Rust are byte-pinned CodeGraph assets that load in the Rust worker but have no language-qualified standalone lint route or release qualification. ArkTS, Nix and Terraform are also pinned Rust-loadable candidates with narrow valid/invalid fixtures and no language-qualified standalone lint route or release qualification; see the [limited acceptance record](tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The two dependency grammars retain their source bytes and use a byte-pinned legacy `dylink` metadata conversion for Rust loading; they have no language-qualified standalone lint route or release qualification. Zig uses a byte-pinned import adaptation so the corrected CodeGraph grammar can load in Rust; it has a narrow `lint zig` native-first candidate route but no release qualification. [Zig's limited acceptance record](tests/acceptance/zig-grammar-candidate.md) distinguishes this from released syntax support. Python has a source-build-only, unqualified CLI fallback path; its report remains incomplete and cannot approve delivery. R, Ruby, PHP and Kotlin have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow worker samples; PHP covers mixed HTML/PHP, and all four remain unqualified. The original CodeGraph Dart WASM cannot be instantiated by Rust, but CodeGuard now pins a reproducible Zig rebuild with the real scanner and a byte-pinned WASI import adaptation. Its narrow Rust and worker fixtures pass, while public lint and release remain unqualified; see the [Dart rebuild record](tests/acceptance/dart-grammar-rebuild-candidate.md). Erlang now has pinned CodeGraph bytes, the upstream 0.19 license, ABI 14 and narrow Rust worker tests; it remains unqualified without native comparison or public lint. See the [Erlang candidate record](tests/acceptance/erlang-grammar-candidate.md). Pascal now has pinned CodeGraph bytes and its original Isopod dependency commit and license; ABI 14 and narrow worker tests pass, but native comparison and public lint remain open. See the [Pascal candidate record](tests/acceptance/pascal-grammar-candidate.md). The remaining CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET assets also load in the Rust worker, bringing the candidate inventory to 32/32 with zero released syntax capabilities. CFQuery misses `SELECT FROM`, VB.NET misparses a valid unindented method, and COBOL has a high load cost; see the [seven-asset acceptance record](tests/acceptance/final-seven-grammar-candidates.md). The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB asset now fits the bounded 20 MiB loader input, but its cold-load and memory budgets remain unqualified. ### npm installation and one-off use +In a source build with `--features wasm-precheck`, `codeguard grammar probe --format=json` can explicitly run any of the 32 pinned candidates in an isolated worker. It always exits 3 with `status=incomplete`, `native.status=not_run`, and `delivery_decision=not_evaluated`; a completed parse also has `precheck.status=incomplete`. Input or worker failures use the same [closed JSON schema](schemas/grammar-probe-v0.1.schema.json). Recovery anchors are suspected observations only. This diagnostic command does not yet connect all grammars to native-first `lint/check` or to the published npm package. + +The same source build now runs a bounded candidate pass from `codeguard check all . --format=json` after existing native checks. Its `syntax_candidates` field in [check feedback 0.33.0](schemas/check-feedback.schema.json) distinguishes TSX, JavaScript, CFScript and explicitly embedded CFQuery, preserving native blockers and skipped work. Python files covered by a completed Ruff scan of identical source bytes skip duplicate WASM and count under `native_preferred_count`; files without matching native syntax evidence retain candidate prechecks. Four bounded integration fixtures collectively invoked all 32 pinned grammars through this command. Every observation remains unqualified and the command exits 3; 64 files/64 fragments/90 seconds bound the candidate pass. This is not yet a language-qualified native fallback or part of published npm `0.1.2`. See [acceptance evidence](tests/acceptance/check-all-32-grammar-candidates.md). + +The source-built Unix CLI also has a narrow Zig route: `codeguard lint zig FILE --zig-tool /absolute/path/to/zig --format=json`. An explicitly supplied tool reporting Zig 0.16.0 and retaining the same byte digest runs native `ast-check` first; its source positions are retained without exposing source snippets. Without an explicit tool, the pinned Zig WASM provides an unqualified observation. Both paths remain incomplete because `ast-check` covers only local AST errors, not full lint, build or tests. See the [Zig feedback schema](schemas/zig-lint-feedback-v0.1.schema.json). + On Apple Silicon macOS, the published `0.1.2` package was verified with a fresh npm cache: ```bash diff --git a/README.zh-CN.md b/README.zh-CN.md index c2ec623b..8d552499 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -94,12 +94,18 @@ cargo build --locked -p codeguard-cli 版本输出包含 `cli_version`、`target` 和协议信息。发现与 init 预览返回观察及未知项。Dry-run 不创建 `AGENTS.md` 或项目数据目录。仅在依赖已缓存时为 Cargo 添加 `--offline`。 -工作区要求 `std`。可选 `wasm-precheck` 构建特性已有二十三份固定 grammar 候选资产与有界 Rust worker。Java 和 TypeScript/TSX 有局部单文件兜底;`lint python` 在 Ruff 不可用或项目未声明 Ruff 配置时可报告有界疑似语法位置,原生 Ruff 结果优先。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。 +工作区要求 `std`。可选 `wasm-precheck` 构建特性已有三十二份固定 grammar 候选资产与有界 Rust worker。Java 和 TypeScript/TSX 有局部单文件兜底;`lint python` 在 Ruff 不可用或项目未声明 Ruff 配置时可报告有界疑似语法位置,原生 Ruff 结果优先。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。 -当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前有二十三份未验收资产候选、零项已发行语法能力。C、C++、C#、Go、JavaScript、Lua、Luau、Rust、ArkTS、Nix、Terraform、R、Ruby、PHP、Kotlin 等已固定字节并由 Rust worker 做窄范围验证,但没有公开 lint 路由或发行验收。Objective-C 与 Solidity 的依赖包原始字节、许可证和固定散列的 `dylink` 元数据转换已入库;Zig 的新版语法也有固定导入适配。CodeGraph 原 Dart WASM 无法由 Rust 直接加载;CodeGuard 现以固定源码和真实外部 scanner 经 Zig 重建,并固定适配前后字节,150 例上游语料错误分类与预期一致,但仍未做 Dart 原生工具对照或发布验收,见[Dart 重建局部验收](tests/acceptance/dart-grammar-rebuild-candidate.md)。Python 已有仅限源码可选构建的 CLI 候选兜底,结果保持不完整,不能批准交付。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。 +当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前有三十二份未验收资产候选、零项已发行语法能力。C、C++、C#、Go、JavaScript、Lua、Luau、Rust、ArkTS、Nix、Terraform、R、Ruby、PHP、Kotlin、Erlang、Pascal、CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 等已固定字节并由 Rust worker 做窄范围验证,但没有逐语言验收的独立 lint 路由或发行验收。Objective-C 与 Solidity 的依赖包原始字节、许可证和固定散列的 `dylink` 元数据转换已入库;Zig 的新版语法也有固定导入适配。CodeGraph 原 Dart WASM 无法由 Rust 直接加载;CodeGuard 现以固定源码和真实外部 scanner 经 Zig 重建,并固定适配前后字节,150 例上游语料错误分类与预期一致,但仍未做 Dart 原生工具对照或发布验收,见[Dart 重建局部验收](tests/acceptance/dart-grammar-rebuild-candidate.md)。Erlang 已固定 CodeGraph 字节、上游 0.19 许可证和 ABI 14,Rust/隔离 worker 窄范围样例通过,但原生对照与公开 lint 尚缺,见[Erlang 候选局部验收](tests/acceptance/erlang-grammar-candidate.md)。Pascal 已固定 CodeGraph 字节、原始 Isopod 依赖提交和许可证,ABI 14 及窄范围 worker 样例通过;原生对照和公开 lint 尚缺,见[Pascal 候选局部验收](tests/acceptance/pascal-grammar-candidate.md)。其余七份 CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET 来源 WASM 也已固定并由 Rust worker 加载,累计 32/32 份候选、0 项已发行。CFQuery 漏掉 `SELECT FROM`,VB.NET 对合法未缩进方法体误报,COBOL 成本高;都不能发布为 lint,见[七份局部验收](tests/acceptance/final-seven-grammar-candidates.md)。Python 已有仅限源码可选构建的 CLI 候选兜底,结果保持不完整,不能批准交付。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 的 16.4 MB 固定资产现可在 20 MiB 输入限额下加载,但冷启动和内存预算尚未验收。 ### npm 安装与一次性调用 +源码以 `--features wasm-precheck` 构建后,可显式运行 `codeguard grammar probe --format=json`,由隔离 worker 调用 32 份固定候选中的任意一份。命令始终以退出码 3 返回,并标记 `status=incomplete`、`native.status=not_run`、`delivery_decision=not_evaluated`;解析完成时还标记 `precheck.status=incomplete`。输入或 worker 失败也遵守同一份[封闭 JSON Schema](schemas/grammar-probe-v0.1.schema.json)。恢复锚点只是疑似观察。此诊断入口尚未把全部语种接入原生优先的 `lint/check`,也尚未进入已发布 npm 包。 + +同一源码构建现在会在既有原生检查之后,从 `codeguard check all . --format=json` 执行有界候选初检。[检查反馈 0.33.0](schemas/check-feedback.schema.json)中的 `syntax_candidates` 区分 TSX、JavaScript、CFScript 和明确嵌入的 CFQuery,同时保留原生阻塞与未执行范围。Ruff 已对相同源码完成原生扫描的 Python 文件跳过重复 WASM,并计入 `native_preferred_count`;其余未确认语法能力的文件仍运行候选初检。四个有界集成样例经此入口合计调用了 32 种固定 grammar。观察仍未验收,命令保持退出码 3;候选阶段限 64 文件、64 片段、90 秒。这尚非逐语言验收的原生兜底,也未进入已发布 npm `0.1.2`;见[验收记录](tests/acceptance/check-all-32-grammar-candidates.md)。 + +源码构建的 Unix CLI 还提供局部 Zig 入口:`codeguard lint zig FILE --zig-tool /absolute/path/to/zig --format=json`。显式提供且报告 Zig 0.16.0、执行前后字节摘要一致的工具优先运行原生 `ast-check`,仅输出诊断位置,不回显源码;未显式提供工具时,固定 Zig WASM 给出未验收候选观察。两条路径都保持未完成,因为 `ast-check` 仅覆盖局部 AST 错误,不等于完整 lint、构建或测试。见 [Zig 报告 Schema](schemas/zig-lint-feedback-v0.1.schema.json)。 + 已在 Apple Silicon macOS 上通过全新 npm 缓存验证公开 `0.1.2` 包: ```bash diff --git a/crates/codeguard-adapters/src/grammar_asset_manifest.rs b/crates/codeguard-adapters/src/grammar_asset_manifest.rs index 5169eea2..ceb4cca7 100644 --- a/crates/codeguard-adapters/src/grammar_asset_manifest.rs +++ b/crates/codeguard-adapters/src/grammar_asset_manifest.rs @@ -27,6 +27,13 @@ const RUBY_COMMIT: &str = "71bd32fb7607035768799732addba884a37a6210"; const PHP_COMMIT: &str = "5b5627faaa290d89eb3d01b9bf47c3bb9e797dea"; const KOTLIN_COMMIT: &str = "e1a2d5ad1f61f5740677183cd4125bb071cd2f30"; const DART_COMMIT: &str = "d4d8f3e337d8be23be27ffc35a0aef972343cd54"; +const ERLANG_COMMIT: &str = "836aa2b6c3af2c7cef3f84049b0ed6d44485a870"; +const PASCAL_COMMIT: &str = "042119eca2e18a60e56317fb06ee3ba5c32cb447"; +const CFML_COMMIT: &str = "5279bde9b31d54efa68efb77a4b18ee9508518e4"; +const COBOL_COMMIT: &str = "e99dbdc3d800d5fa2796476efd60af91f6b43d93"; +const SCALA_COMMIT: &str = "b931fcc338390925eb893d70ad070033f5856ccf"; +const SWIFT_COMMIT: &str = "31d17fe7e818a2048c808b5c6fdc2dc792f4f5b5"; +const VBNET_COMMIT: &str = "538b7087bf80e86004531b392fe1186379c0a2b5"; /// 代码来源、许可和每份候选 grammar 的固定身份。 #[derive(Clone, Debug, Deserialize, Eq, PartialEq)] @@ -158,6 +165,22 @@ fn verify_bundled_asset(asset: &GrammarAsset) -> Result<&'static [u8], String> { include_bytes!("../../../grammars/c/parser.wasm").as_slice(), include_bytes!("../../../grammars/c/LICENSE").as_slice(), ), + "cfml" => ( + include_bytes!("../../../grammars/cfml/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfml/LICENSE").as_slice(), + ), + "cfquery" => ( + include_bytes!("../../../grammars/cfquery/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfquery/LICENSE").as_slice(), + ), + "cfscript" => ( + include_bytes!("../../../grammars/cfscript/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfscript/LICENSE").as_slice(), + ), + "cobol" => ( + include_bytes!("../../../grammars/cobol/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cobol/LICENSE").as_slice(), + ), "cpp" => ( include_bytes!("../../../grammars/cpp/parser.wasm").as_slice(), include_bytes!("../../../grammars/cpp/LICENSE").as_slice(), @@ -206,6 +229,26 @@ fn verify_bundled_asset(asset: &GrammarAsset) -> Result<&'static [u8], String> { include_bytes!("../../../grammars/dart/parser.wasm").as_slice(), include_bytes!("../../../grammars/dart/LICENSE").as_slice(), ), + "erlang" => ( + include_bytes!("../../../grammars/erlang/parser.wasm").as_slice(), + include_bytes!("../../../grammars/erlang/LICENSE").as_slice(), + ), + "pascal" => ( + include_bytes!("../../../grammars/pascal/parser.wasm").as_slice(), + include_bytes!("../../../grammars/pascal/LICENSE").as_slice(), + ), + "scala" => ( + include_bytes!("../../../grammars/scala/parser.wasm").as_slice(), + include_bytes!("../../../grammars/scala/LICENSE").as_slice(), + ), + "swift" => ( + include_bytes!("../../../grammars/swift/parser.wasm").as_slice(), + include_bytes!("../../../grammars/swift/LICENSE").as_slice(), + ), + "vbnet" => ( + include_bytes!("../../../grammars/vbnet/parser.wasm").as_slice(), + include_bytes!("../../../grammars/vbnet/LICENSE").as_slice(), + ), "java" => ( include_bytes!("../../../grammars/java/parser.wasm").as_slice(), include_bytes!("../../../grammars/java/LICENSE").as_slice(), @@ -258,6 +301,18 @@ fn verify_bundled_asset(asset: &GrammarAsset) -> Result<&'static [u8], String> { return Err("Dart grammar 重建来源适配关系不符".into()); } } + if asset.language == "vbnet" + && digest(include_bytes!("../../../grammars/vbnet/source.patch")) + != "33963ebe3ba60929fb58d90efd54f206f98a54ea13ae325d784732c828b7b93a" + { + return Err("VB.NET grammar 来源补丁字节不符".into()); + } + if asset.language == "cobol" + && digest(include_bytes!("../../../grammars/cobol/source.patch")) + != "04fe11a51243ddf7d31e0b6378068c725a51463534218c43c7021761c69701e5" + { + return Err("COBOL grammar 来源补丁字节不符".into()); + } if matches!(asset.language.as_str(), "objc" | "solidity") { let source = if asset.language == "objc" { include_bytes!("../../../grammars/objc/source.wasm").as_slice() @@ -287,7 +342,7 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result Result Result Result Result ( + "https://github.com/cfmleditor/tree-sitter-cfml", + CFML_COMMIT, + "v0.26.29", + "cfml/parser.wasm", + "17aeb294c58dd47045b470fc082ccceac3100c8e548b13764d4f3987a062322f", + 2700518, + "cfml/LICENSE", + "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + ), + "cfquery" => ( + "https://github.com/cfmleditor/tree-sitter-cfml", + CFML_COMMIT, + "v0.26.29", + "cfquery/parser.wasm", + "9d4eaaec46eec7e6400d4b8d6c85fac7dfe33867ed5b4e5c218dfa7851c32558", + 2411407, + "cfquery/LICENSE", + "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + ), + "cfscript" => ( + "https://github.com/cfmleditor/tree-sitter-cfml", + CFML_COMMIT, + "v0.26.29", + "cfscript/parser.wasm", + "e381db5d2b8a7744fc7d8e51b0a14ff03f86c8ff497cdfe32d1da467f19d4096", + 2162812, + "cfscript/LICENSE", + "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + ), + "cobol" => ( + "https://github.com/yutaro-sakamoto/tree-sitter-cobol", + COBOL_COMMIT, + "CodeGraph-patched-e99dbdc", + "cobol/parser.wasm", + "65b98799f92e831d8b5ed8cd811464c71fac31c4beabf66990a545a4f65e02f1", + 16355286, + "cobol/LICENSE", + "d724405ce238a22c0d35769c5a36b386ad5958192efe8bbb304fb2896254575f", + ), "cpp" => ( "https://github.com/tree-sitter/tree-sitter-cpp", CPP_COMMIT, @@ -386,6 +490,26 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result ( + "https://github.com/WhatsApp/tree-sitter-erlang", + ERLANG_COMMIT, + "0.19", + "erlang/parser.wasm", + "dbab33f03e07b89f4385fcdd48d87d86ba35c82a0a426788d55b8c25410bc491", + 421639, + "erlang/LICENSE", + "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + ), + "pascal" => ( + "https://github.com/Isopod/tree-sitter-pascal", + PASCAL_COMMIT, + "0.10.2", + "pascal/parser.wasm", + "be3634fca99c19f5e1035a1a9c7d93d6ee82b35e6d5024f02be4883b71329c3e", + 716886, + "pascal/LICENSE", + "2e2fcc500eacb15b76c11fd2229aebf0a5b4c8ed476f068447c6dce778a17ac9", + ), "go" => ( "https://github.com/tree-sitter/tree-sitter-go", GO_COMMIT, @@ -556,6 +680,36 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result ( + "https://github.com/tree-sitter/tree-sitter-scala", + SCALA_COMMIT, + "v0.26.2", + "scala/parser.wasm", + "37d7fe5a91ca98941dc05493b0c05a0df0f36df5035890fa00b02497c68aaac3", + 3973559, + "scala/LICENSE", + "1f95ed26e1f4074074c9c7083e61c0a9e4c3b9f435745044995f3beb4ed28575", + ), + "swift" => ( + "https://github.com/alex-pinkus/tree-sitter-swift", + SWIFT_COMMIT, + "crate-0.7.3", + "swift/parser.wasm", + "cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843", + 3726622, + "swift/LICENSE", + "3533cec129bb4bba015c0d61d86dd7c3b7e82110e4d2ff7837a01eff5bad5ccc", + ), + "vbnet" => ( + "https://github.com/govindbanura/tree-sitter-vbnet", + VBNET_COMMIT, + "CodeGraph-patched-538b708", + "vbnet/parser.wasm", + "e38a09e1826c7ec06340c0531a98bbb5ee79bdd710bba3d3349b79a19721e844", + 6477499, + "vbnet/LICENSE", + "fa7ab39bcf92c216d429e8aa8be8a5a40db85bfbe4ff14a7bb0ecbbcca937454", + ), "terraform" => ( "https://github.com/tree-sitter-grammars/tree-sitter-hcl", TERRAFORM_COMMIT, @@ -580,10 +734,10 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result None, } || asset.loader_symbol.as_deref() - != if asset.language == "csharp" { - Some("c_sharp") - } else { - None + != match asset.language.as_str() { + "csharp" => Some("c_sharp"), + "cobol" => Some("COBOL"), + _ => None, } || (match asset.language.as_str() { "objc" => { @@ -620,7 +774,21 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result ( @@ -74,6 +98,22 @@ fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support( include_bytes!("../../../grammars/c/parser.wasm").as_slice(), include_bytes!("../../../grammars/c/LICENSE").as_slice(), ), + "cfml" => ( + include_bytes!("../../../grammars/cfml/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfml/LICENSE").as_slice(), + ), + "cfquery" => ( + include_bytes!("../../../grammars/cfquery/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfquery/LICENSE").as_slice(), + ), + "cfscript" => ( + include_bytes!("../../../grammars/cfscript/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cfscript/LICENSE").as_slice(), + ), + "cobol" => ( + include_bytes!("../../../grammars/cobol/parser.wasm").as_slice(), + include_bytes!("../../../grammars/cobol/LICENSE").as_slice(), + ), "cpp" => ( include_bytes!("../../../grammars/cpp/parser.wasm").as_slice(), include_bytes!("../../../grammars/cpp/LICENSE").as_slice(), @@ -86,6 +126,26 @@ fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support( include_bytes!("../../../grammars/dart/parser.wasm").as_slice(), include_bytes!("../../../grammars/dart/LICENSE").as_slice(), ), + "erlang" => ( + include_bytes!("../../../grammars/erlang/parser.wasm").as_slice(), + include_bytes!("../../../grammars/erlang/LICENSE").as_slice(), + ), + "pascal" => ( + include_bytes!("../../../grammars/pascal/parser.wasm").as_slice(), + include_bytes!("../../../grammars/pascal/LICENSE").as_slice(), + ), + "scala" => ( + include_bytes!("../../../grammars/scala/parser.wasm").as_slice(), + include_bytes!("../../../grammars/scala/LICENSE").as_slice(), + ), + "swift" => ( + include_bytes!("../../../grammars/swift/parser.wasm").as_slice(), + include_bytes!("../../../grammars/swift/LICENSE").as_slice(), + ), + "vbnet" => ( + include_bytes!("../../../grammars/vbnet/parser.wasm").as_slice(), + include_bytes!("../../../grammars/vbnet/LICENSE").as_slice(), + ), "go" => ( include_bytes!("../../../grammars/go/parser.wasm").as_slice(), include_bytes!("../../../grammars/go/LICENSE").as_slice(), diff --git a/crates/codeguard-cli/src/check_command.rs b/crates/codeguard-cli/src/check_command.rs index 1b9f93db..dfceacaf 100644 --- a/crates/codeguard-cli/src/check_command.rs +++ b/crates/codeguard-cli/src/check_command.rs @@ -1451,8 +1451,31 @@ pub fn run(args: &[String]) -> ExitCode { ) }) .count(); + #[cfg(feature = "wasm-precheck")] + let syntax_candidates = crate::check_syntax_candidates::observe( + &root, + &discovery, + &python_lint, + parsed.selection == Selection::Java, + deadline, + if request_cancelled { + Some("request_cancelled") + } else if scope_recheck.is_some() || source_recheck.is_some() { + Some("source_or_scope_changed") + } else { + None + }, + ); + #[cfg(not(feature = "wasm-precheck"))] + let syntax_candidates = json!({ + "status":"not_run","reason":"binary_without_wasm_precheck","execution_phase":"after_native", + "authority":"candidate_unqualified","delivery_decision":"incomplete", + "source_file_count":discovery.languages.values().map(|item| item.source_files.len()).sum::(), + "skipped_count":0,"unrouted_count":0,"native_preferred_count":0,"observations":[], + "next_action":"使用包含固定语法资产的发行包运行候选初检,并完成适用原生检查" + }); let report = json!({ - "schema_version":"0.31.0", "report_type":"check_feedback", + "schema_version":"0.33.0", "report_type":"check_feedback", "operation":"check", "selection":parsed.selection.as_str(), "command_status":if request_cancelled { "cancelled" } else { "incomplete" }, "exit_code":if request_cancelled { 130 } else { 3 }, "delivery_decision":if parsed.selection == Selection::All { "incomplete" } else { "not_evaluated" }, "authority":"local_unverified", "reason":if request_cancelled { "request_cancelled" } else if parsed.selection == Selection::All { "full_project_obligations_and_trusted_policy_unavailable" } else { "java_selection_obligations_and_trusted_policy_unavailable" }, @@ -1460,6 +1483,7 @@ pub fn run(args: &[String]) -> ExitCode { "native_results":{"python_lint":python_lint,"python_cve":python_cve,"rust_lint":rust_lint,"rust_comments":rust_comments,"rust_build":rust_build,"rust_cve":rust_cve,"go_lint":go_lint,"java_p3c":java_p3c,"java_javadoc":java_javadoc,"java_dependencies":java_dependencies,"java_cve":java_cve,"npm_cve":npm_cve}, "execution_tasks":execution_tasks, "obligation_status":"unresolved", "required_obligations":null, "category_candidates":candidates, "unresolved_conditions":unresolved, + "syntax_candidates":syntax_candidates, "execution_budget":check_budget_record( parsed.timeout_ms, parsed.timeout_source, parsed.jobs_limit, parsed.jobs_source, usize::from(python_present) + python_cve_roots.len() + 4 * usize::from(rust_present) + usize::from(go_present) + usize::from(java_present) + usize::from(javadoc_configured) + usize::from(dependency_configured) + usize::from(cve_configured) + npm_roots.len(), started_native_task_count @@ -1829,6 +1853,54 @@ pub fn run(args: &[String]) -> ExitCode { for task in &execution_tasks { println!("执行任务 {}: {}", task["id"], task["status"]); } + if let Some(observations) = report["syntax_candidates"]["observations"].as_array() { + if report["syntax_candidates"]["status"] == "not_run" { + if report["syntax_candidates"]["reason"] == "native_preferred" { + println!( + "候选语法初检未运行:{} 个文件已由本轮原生工具检查;其余交付义务仍待核验。", + report["syntax_candidates"]["native_preferred_count"] + ); + } else { + println!( + "候选语法初检未运行:{};仍需适用原生检查。", + report["syntax_candidates"]["reason"] + ); + } + } else { + let suspected = observations + .iter() + .filter(|item| { + item["recovery_count"] + .as_u64() + .is_some_and(|count| count > 0) + }) + .count(); + println!( + "候选语法初检:{} 个片段已观察,{} 个存在待原生确认的恢复节点,{} 个文件由原生检查覆盖,{} 个范围未执行;仍未完成完整检查。", + observations + .iter() + .filter(|item| item["status"] == "candidate_observed") + .count(), + suspected, + report["syntax_candidates"]["native_preferred_count"], + report["syntax_candidates"]["skipped_count"] + ); + for item in observations + .iter() + .filter(|item| { + item["recovery_count"] + .as_u64() + .is_some_and(|count| count > 0) + }) + .take(8) + { + println!( + " {} [{}] 候选恢复 {} 处;先运行适用原生工具确认。", + item["path"], item["language"], item["recovery_count"] + ); + } + } + } if report["unresolved_conditions"] .as_array() .is_some_and(|reasons| { diff --git a/crates/codeguard-cli/src/check_syntax_candidates.rs b/crates/codeguard-cli/src/check_syntax_candidates.rs new file mode 100644 index 00000000..c48e4747 --- /dev/null +++ b/crates/codeguard-cli/src/check_syntax_candidates.rs @@ -0,0 +1,236 @@ +//! 全项目原生检查之后的有界候选语法观察;永不产生已确认违规或通过。 + +use crate::discovery::DiscoveryReport; +use crate::grammar_probe_command::read_plain_source; +use crate::grammar_route::route_source; +use crate::syntax_worker_runner::run_syntax_worker_candidate; +use serde_json::{Value, json}; +use sha2::{Digest, Sha256}; +use std::collections::BTreeSet; +use std::path::Path; +use std::sync::atomic::AtomicBool; +use std::time::{Duration, Instant}; + +const MAX_FILES: usize = 64; +const MAX_FRAGMENTS: usize = 64; +const MAX_VISIBLE_RECOVERIES: usize = 8; + +/// 对已发现源码按方言选择固定资产,受文件、片段和剩余时间限制。 +/// 参数为项目根、静态发现、语言选择、共同截止时间及范围稳定状态;返回不具门禁权威的报告。 +pub fn observe( + root: &Path, + discovery: &DiscoveryReport, + python_lint: &Value, + java_only: bool, + deadline: Instant, + skip_reason: Option<&str>, +) -> Value { + let mut paths = BTreeSet::new(); + for (language, evidence) in &discovery.languages { + if !java_only || language == "java" { + paths.extend(evidence.source_files.iter()); + } + } + let source_file_count = paths.len(); + let mut observations = Vec::new(); + let mut skipped_count = 0; + let mut unrouted_count = 0; + let mut native_preferred_count = 0; + if let Some(reason) = skip_reason { + return report( + "not_run", + reason, + source_file_count, + source_file_count, + 0, + 0, + observations, + ); + } + let executable = match std::env::current_exe() { + Ok(executable) => executable, + Err(_) => { + return report( + "not_run", + "worker_executable_unavailable", + source_file_count, + source_file_count, + 0, + 0, + observations, + ); + } + }; + let candidate_deadline = deadline.min(Instant::now() + Duration::from_secs(90)); + let cancelled = AtomicBool::new(false); + for (index, relative) in paths.into_iter().enumerate() { + if index >= MAX_FILES + || observations.len() >= MAX_FRAGMENTS + || Instant::now() >= candidate_deadline + || codeguard_runtime::sigint_cancellation_requested() + { + skipped_count += 1; + continue; + } + let source = match read_plain_source(&root.join(relative)) { + Ok(source) => source, + Err(reason) => { + observations.push(json!({ + "path":relative,"language":null,"scope":"whole_file","byte_offset":0, + "status":"candidate_unavailable","reason":reason,"grammar_qualified":false, + "source_sha256":null,"grammar_sha256":null,"recovery_count":0,"recoveries":[] + })); + continue; + } + }; + if native_python_covers(python_lint, relative, &source) { + native_preferred_count += 1; + continue; + } + let routes = route_source(relative, &source); + if routes.is_empty() { + unrouted_count += 1; + } + for route in routes { + if observations.len() >= MAX_FRAGMENTS || Instant::now() >= candidate_deadline { + skipped_count += 1; + continue; + } + match run_syntax_worker_candidate( + &executable, route.language, relative, route.source, candidate_deadline, &cancelled, + ) { + Ok(observation) => { + if read_plain_source(&root.join(relative)).as_deref() != Ok(source.as_slice()) { + observations.push(json!({ + "path":relative,"language":route.language,"scope":route.scope,"byte_offset":route.byte_offset, + "status":"candidate_unavailable","reason":"source_changed_during_precheck","grammar_qualified":false, + "source_sha256":null,"grammar_sha256":null,"recovery_count":0,"recoveries":[] + })); + continue; + } + // 嵌入片段的 worker 坐标以片段为起点,公开报告还原为文件坐标。 + let base_row = source[..route.byte_offset].iter().filter(|byte| **byte == b'\n').count(); + let base_column = source[..route.byte_offset].rsplit(|byte| *byte == b'\n').next().map_or(0, <[u8]>::len); + let recovery_count = observation.recoveries.len(); + let recoveries: Vec = observation.recoveries.iter().take(MAX_VISIBLE_RECOVERIES).map(|recovery| { + json!({ + "kind":recovery.kind, + "syntax_kind":recovery.syntax_kind, + "start_byte":route.byte_offset + recovery.start_byte, + "end_byte":route.byte_offset + recovery.end_byte, + "start_row":base_row + recovery.start_row, + "start_column_byte":if recovery.start_row == 0 { base_column + recovery.start_column_byte } else { recovery.start_column_byte }, + "end_row":base_row + recovery.end_row, + "end_column_byte":if recovery.end_row == 0 { base_column + recovery.end_column_byte } else { recovery.end_column_byte }, + }) + }).collect(); + observations.push(json!({ + "path":relative,"language":route.language,"scope":route.scope,"byte_offset":route.byte_offset, + "status":"candidate_observed","reason":null,"grammar_qualified":false, + "source_sha256":observation.source_sha256,"grammar_sha256":observation.grammar_sha256, + "recovery_count":recovery_count,"recoveries":recoveries + })); + } + Err(reason) => observations.push(json!({ + "path":relative,"language":route.language,"scope":route.scope,"byte_offset":route.byte_offset, + "status":"candidate_unavailable","reason":reason,"grammar_qualified":false, + "source_sha256":null,"grammar_sha256":null,"recovery_count":0,"recoveries":[] + })), + } + } + } + let observed = observations + .iter() + .any(|item| item["status"] == "candidate_observed"); + let status = if observed { + "observed_partial" + } else if observations.is_empty() { + "not_run" + } else { + "attempted_incomplete" + }; + let reason = if skipped_count > 0 { + "bounded_scope" + } else if unrouted_count > 0 { + "unrouted_source" + } else if !observed && !observations.is_empty() { + "candidate_unavailable" + } else if native_preferred_count > 0 && observations.is_empty() { + "native_preferred" + } else { + "candidate_unqualified" + }; + report( + status, + reason, + source_file_count, + skipped_count, + unrouted_count, + native_preferred_count, + observations, + ) +} + +// 仅本轮 Ruff 已完整扫描同一份 Python 字节时跳过重复解析;配置发现不算执行。 +fn native_python_covers(python_lint: &Value, relative: &str, source: &[u8]) -> bool { + if !relative.ends_with(".py") { + return false; + } + let digest = format!("{:x}", Sha256::digest(source)); + python_lint["files"].as_array().is_some_and(|files| { + files.iter().any(|file| { + file["path"] == relative + && matches!( + file["run_status"].as_str(), + Some("passed" | "findings" | "suppressed") + ) + && file["source_sha256"] == digest + && file["tool_sha256"].as_str().is_some() + && file["config_sha256"].as_str().is_some() + }) + }) +} + +fn report( + status: &str, + reason: &str, + source_file_count: usize, + skipped_count: usize, + unrouted_count: usize, + native_preferred_count: usize, + observations: Vec, +) -> Value { + json!({ + "status":status,"reason":reason,"execution_phase":"after_native", + "authority":"candidate_unqualified","delivery_decision":"incomplete", + "source_file_count":source_file_count,"skipped_count":skipped_count, + "unrouted_count":unrouted_count,"native_preferred_count":native_preferred_count,"observations":observations, + "next_action":"核对适用语言版本与原生 lint/编译器;候选恢复节点不是已确认违规,零恢复也不表示完整通过" + }) +} + +#[cfg(test)] +mod tests { + use super::native_python_covers; + use serde_json::json; + use sha2::{Digest, Sha256}; + + #[test] + fn only_completed_matching_native_python_scan_preempts_candidate() { + let source = b"import os\n"; + let digest = format!("{:x}", Sha256::digest(source)); + for status in ["passed", "findings", "suppressed"] { + let native = json!({"files":[{"path":"app.py","run_status":status, + "source_sha256":digest,"tool_sha256":"tool","config_sha256":"config"}]}); + assert!(native_python_covers(&native, "app.py", source)); + assert!(!native_python_covers(&native, "other.py", source)); + assert!(!native_python_covers(&native, "app.rs", source)); + assert!(!native_python_covers(&native, "app.py", b"changed\n")); + } + for status in ["incomplete", "not_run"] { + let native = json!({"files":[{"path":"app.py","run_status":status, + "source_sha256":digest,"tool_sha256":"tool","config_sha256":"config"}]}); + assert!(!native_python_covers(&native, "app.py", source)); + } + } +} diff --git a/crates/codeguard-cli/src/grammar_probe_command.rs b/crates/codeguard-cli/src/grammar_probe_command.rs new file mode 100644 index 00000000..94cab403 --- /dev/null +++ b/crates/codeguard-cli/src/grammar_probe_command.rs @@ -0,0 +1,136 @@ +//! 显式单文件候选语法观察;不将未经验收的 grammar 结果变为 lint 结论。 + +use crate::syntax_worker_runner::run_syntax_worker_candidate; +use codeguard_adapters::bundled_grammar_candidate; +use serde_json::json; +use std::fs::File; +use std::io::Read; +use std::path::{Component, Path, PathBuf}; +use std::process::ExitCode; +use std::sync::atomic::AtomicBool; +use std::time::{Duration, Instant}; + +/// 对固定语言和普通 UTF-8 文件执行隔离候选解析,始终返回未完成。 +/// 参数依次是语言、源码文件和可选 `--format=json`;返回 3 表示需要原生确认。 +pub fn run(args: &[String]) -> ExitCode { + let (language, source_path) = match args { + [language, source] => (language, source), + [language, source, format] if format == "--format=json" => (language, source), + _ => { + eprintln!("用法: grammar probe [--format=json]"); + return ExitCode::from(2); + } + }; + if let Err(reason) = bundled_grammar_candidate(language) { + if reason == "不支持的 grammar 语种" { + eprintln!("不支持的 grammar 语种"); + return ExitCode::from(2); + } + return emit_incomplete(language, source_path, &reason); + } + let path = PathBuf::from(source_path); + let source = match read_plain_source(&path) { + Ok(source) => source, + Err(reason) => return emit_incomplete(language, source_path, reason), + }; + let executable = match std::env::current_exe() { + Ok(path) => path, + Err(_) => return ExitCode::from(4), + }; + let deadline = Instant::now() + Duration::from_secs(90); + let relative_name = match path.file_name().and_then(|name| name.to_str()) { + Some(name) => name, + None => return emit_incomplete(language, source_path, "source_path_invalid"), + }; + let result = run_syntax_worker_candidate( + &executable, + language, + relative_name, + &source, + deadline, + &AtomicBool::new(false), + ); + match result { + Ok(observation) => { + println!( + "{}", + json!({ + "schema_version":"0.1.0", + "report_type":"grammar_candidate_probe", + "status":"incomplete", + "language":language, + "path":source_path, + "source_sha256":observation.source_sha256, + "grammar_sha256":observation.grammar_sha256, + "grammar_qualified":false, + "precheck":observation.precheck, + "recoveries":observation.recoveries, + "native":{"status":"not_run","reason":"explicit_candidate_probe"}, + "delivery_decision":"not_evaluated", + "next_action":if observation.recoveries.is_empty() { + "run_or_configure_applicable_native_lint_before_delivery" + } else { + "confirm_suspected_recoveries_with_applicable_native_tool" + } + }) + ); + ExitCode::from(3) + } + Err(reason) => emit_incomplete(language, source_path, &reason), + } +} + +fn emit_incomplete(language: &str, source_path: &str, reason: &str) -> ExitCode { + println!( + "{}", + json!({ + "schema_version":"0.1.0", + "report_type":"grammar_candidate_probe", + "language":language, + "path":source_path, + "status":"incomplete", + "reason":reason, + "native":{"status":"not_run","reason":"explicit_candidate_probe"}, + "delivery_decision":"not_evaluated" + }) + ); + ExitCode::from(3) +} + +pub(crate) fn read_plain_source(path: &Path) -> Result, &'static str> { + if path + .components() + .any(|component| matches!(component, Component::ParentDir)) + { + return Err("source_path_parent_component_disallowed"); + } + let absolute = if path.is_absolute() { + path.to_path_buf() + } else { + std::env::current_dir() + .map_err(|_| "source_cwd_unavailable")? + .join(path) + }; + let mut prefix = PathBuf::new(); + for component in absolute.components() { + prefix.push(component); + let metadata = std::fs::symlink_metadata(&prefix).map_err(|_| "source_path_unavailable")?; + if metadata.file_type().is_symlink() { + return Err("source_path_symlink_disallowed"); + } + } + let metadata = std::fs::metadata(&absolute).map_err(|_| "source_unavailable")?; + if !metadata.is_file() || metadata.len() > 1024 * 1024 { + return Err("source_not_regular_or_too_large"); + } + let mut source = Vec::new(); + File::open(&absolute) + .map_err(|_| "source_unreadable")? + .take(1024 * 1024 + 1) + .read_to_end(&mut source) + .map_err(|_| "source_unreadable")?; + if source.len() > 1024 * 1024 || std::str::from_utf8(&source).is_err() { + return Err("source_size_or_encoding_invalid"); + } + Ok(source) +} diff --git a/crates/codeguard-cli/src/grammar_route.rs b/crates/codeguard-cli/src/grammar_route.rs new file mode 100644 index 00000000..d7de92d3 --- /dev/null +++ b/crates/codeguard-cli/src/grammar_route.rs @@ -0,0 +1,105 @@ +//! 按源码后缀和明确的嵌入边界选择候选 grammar;不推断项目语言版本。 + +/// 一段可独立解析的候选源码;嵌入片段的位置相对于原文件的字节起点。 +#[derive(Clone, Debug)] +pub struct GrammarRoute<'a> { + /// 固定资产清单中的语言标识。 + pub language: &'static str, + /// 交给隔离解析进程的原始字节。 + pub source: &'a [u8], + /// 源码片段在文件中的字节偏移。 + pub byte_offset: usize, + /// 整文件或显式 CFQuery 标签体。 + pub scope: &'static str, +} + +/// 从普通源码路径选择固定 grammar;歧义后缀不作猜测。 +/// 参数为相对路径及本轮源码字节;返回零个或多个待核对的候选片段。 +pub fn route_source<'a>(relative_path: &str, source: &'a [u8]) -> Vec> { + let extension = relative_path + .rsplit_once('.') + .map(|(_, extension)| extension); + let language = match extension { + Some("ets") => "arkts", + Some("c") => "c", + Some("cfm" | "cfc") => "cfml", + Some("cfs") => "cfscript", + Some("cbl" | "cob" | "cpy") => "cobol", + Some("cpp" | "cc" | "hpp") => "cpp", + Some("cs") => "csharp", + Some("dart") => "dart", + Some("erl" | "hrl") => "erlang", + Some("go") => "go", + Some("java") => "java", + Some("js" | "jsx" | "mjs" | "cjs") => "javascript", + Some("kt" | "kts") => "kotlin", + Some("lua") => "lua", + Some("luau") => "luau", + Some("nix") => "nix", + Some("m" | "mm") => "objc", + Some("pas" | "dpr" | "dpk" | "lpr") => "pascal", + Some("php") => "php", + Some("py") => "python", + Some("r") => "r", + Some("rb") => "ruby", + Some("rs") => "rust", + Some("scala" | "sc") => "scala", + Some("sol") => "solidity", + Some("swift") => "swift", + Some("tf" | "tfvars" | "tofu") => "terraform", + Some("tsx") => "tsx", + Some("ts") => "typescript", + Some("vb") => "vbnet", + Some("zig") => "zig", + _ => return Vec::new(), + }; + let mut routes = vec![GrammarRoute { + language, + source, + byte_offset: 0, + scope: "whole_file", + }]; + if language == "cfml" { + // 只取完整且有明确标签边界的查询体;普通 SQL 文件不属于 CFQuery。 + let lowercase = source.to_ascii_lowercase(); + let mut cursor = 0; + while let Some(open_relative) = find_bytes(&lowercase[cursor..], b"') + { + cursor = after_name; + continue; + } + let Some(tag_end_relative) = lowercase[after_name..] + .iter() + .position(|byte| *byte == b'>') + else { + break; + }; + let body_start = after_name + tag_end_relative + 1; + let Some(close_relative) = find_bytes(&lowercase[body_start..], b"") else { + break; + }; + let body_end = body_start + close_relative; + if body_end > body_start { + routes.push(GrammarRoute { + language: "cfquery", + source: &source[body_start..body_end], + byte_offset: body_start, + scope: "cfquery_body", + }); + } + cursor = body_end + b"".len(); + } + } + routes +} + +fn find_bytes(haystack: &[u8], needle: &[u8]) -> Option { + haystack + .windows(needle.len()) + .position(|window| window == needle) +} diff --git a/crates/codeguard-cli/src/grammar_status_command.rs b/crates/codeguard-cli/src/grammar_status_command.rs index 2954ea6f..0f32e838 100644 --- a/crates/codeguard-cli/src/grammar_status_command.rs +++ b/crates/codeguard-cli/src/grammar_status_command.rs @@ -137,7 +137,7 @@ fn coverage_report() -> Result { "runtime_observation":candidate.map(|item| item.codeguard_runtime_validation.as_str()), "released":false, "gap":if candidate.is_some_and(|item| item.codeguard_runtime_validation == "rust_loader_incompatible") {"rust_loader_incompatible"} - else if asset.bytes.is_some_and(|bytes| bytes > 8 * 1024 * 1024) {"current_loader_size_limit"} + else if asset.bytes.is_some_and(|bytes| bytes > 20 * 1024 * 1024) {"current_loader_size_limit"} else if candidate.is_some() {"language_qualification_and_release_pending"} else {"asset_provenance_license_and_loader_validation_pending"}, }) @@ -157,7 +157,7 @@ fn coverage_report() -> Result { "gate_effect":"none", "execution":"not_run", "delivery_decision":"not_evaluated", - "next_action":"固定各缺口资产的上游来源与许可证,逐语言验证 Rust 加载、版本语料及原生对照;不得凭此库存跳过原生 lint。", + "next_action":"按语言完成独立版本与方言语料、原生工具对照和误报评测,接入原生优先 lint/check 与任务反馈,并验收发行包;不得凭候选库存跳过原生 lint。", "assets":assets, })) } diff --git a/crates/codeguard-cli/src/lib.rs b/crates/codeguard-cli/src/lib.rs index 3f701f1e..088488f2 100644 --- a/crates/codeguard-cli/src/lib.rs +++ b/crates/codeguard-cli/src/lib.rs @@ -80,6 +80,8 @@ pub mod check_budget; pub mod check_command; pub mod check_plan; pub mod check_request; +#[cfg(all(unix, feature = "wasm-precheck"))] +mod check_syntax_candidates; mod checkstyle_preparation; mod checkstyle_preparation_recheck; pub mod checkstyle_probe; @@ -100,6 +102,10 @@ pub mod git_index_safety; pub mod git_index_safety_command; #[cfg(unix)] pub mod go_lint_command; +#[cfg(feature = "wasm-precheck")] +pub mod grammar_probe_command; +#[cfg(feature = "wasm-precheck")] +pub mod grammar_route; pub mod grammar_status_command; #[cfg(unix)] pub mod hook_execute_command; @@ -197,6 +203,8 @@ mod whitelist_correction_projection; pub mod work_sync; pub mod workspace_refresh; pub mod workspace_view_command; +#[cfg(all(feature = "wasm-precheck", unix))] +pub mod zig_lint_command; mod cargo_module_graph; mod module_graph; diff --git a/crates/codeguard-cli/src/main.rs b/crates/codeguard-cli/src/main.rs index 7c146d9b..ae178c87 100644 --- a/crates/codeguard-cli/src/main.rs +++ b/crates/codeguard-cli/src/main.rs @@ -66,6 +66,18 @@ fn main() -> ExitCode { println!( "语法资产覆盖:grammar status [--format human|json];只读列出固定 CodeGraph 来源的 32 种独立 grammar、CodeGuard 候选与未接入项;不加载 WASM、不运行 lint。" ); + #[cfg(feature = "wasm-precheck")] + println!( + "显式候选语法观察:grammar probe [--format=json];隔离加载 32 份固定资产之一,始终返回未完成和退出码 3,不代替原生 lint。" + ); + #[cfg(all(feature = "wasm-precheck", unix))] + println!( + "check all 会在原生节点之后按源码方言有界执行 32 份固定 WASM 的候选初检;check_feedback 0.33.0 的 syntax_candidates 保留疑似位置、原生优先计数和未执行范围,始终不能代替原生义务或放行交付。" + ); + #[cfg(all(feature = "wasm-precheck", unix))] + println!( + "Zig 原生优先局部检查:lint zig FILE [--zig-tool ABS_PATH] [--format=json];显式 Zig 0.16.0 使用 ast-check,未提供工具时使用未验收 WASM 候选;始终不签发完整 lint 或交付通过。" + ); println!( "检查预算:check all 支持 --jobs 1–64 和 CODEGUARD_JOBS;--timeout 优先于 CODEGUARD_TIMEOUT,默认 30m。项目默认值见 .codeguard/runtime.json 1.1;当前仅原生执行受截止时间约束。" ); @@ -82,6 +94,10 @@ fn main() -> ExitCode { [command, operation, rest @ ..] if command == "grammar" && operation == "status" => { codeguard_cli::grammar_status_command::run(rest) } + #[cfg(feature = "wasm-precheck")] + [command, operation, rest @ ..] if command == "grammar" && operation == "probe" => { + codeguard_cli::grammar_probe_command::run(rest) + } #[cfg(unix)] [command, rest @ ..] if command == "doctor" => codeguard_cli::doctor_command::run(rest), [command, rest @ ..] if command == "plan" => codeguard_cli::plan_command::run(rest), @@ -155,6 +171,17 @@ fn main() -> ExitCode { [command, rest @ ..] if command == "lint" => { if rest.first().is_some_and(|language| language == "java") { codeguard_cli::java_lint_dispatch::run(&rest[1..]) + } else if cfg!(feature = "wasm-precheck") + && rest.first().is_some_and(|language| language == "zig") + { + #[cfg(feature = "wasm-precheck")] + { + codeguard_cli::zig_lint_command::run(&rest[1..]) + } + #[cfg(not(feature = "wasm-precheck"))] + { + ExitCode::from(2) + } } else if rest .first() .is_some_and(|language| language == "typescript") diff --git a/crates/codeguard-cli/src/zig_lint_command.rs b/crates/codeguard-cli/src/zig_lint_command.rs new file mode 100644 index 00000000..9d4d7733 --- /dev/null +++ b/crates/codeguard-cli/src/zig_lint_command.rs @@ -0,0 +1,278 @@ +//! Zig 0.16 单文件原生 AST 检查优先;缺少可核对工具时才作候选 WASM 初检。 + +use crate::grammar_probe_command::read_plain_source; +use crate::syntax_worker_runner::run_syntax_worker_candidate; +use codeguard_runtime::{ProcessSpec, Termination, read_bounded_regular_file, run_process}; +use serde_json::{Value, json}; +use sha2::{Digest, Sha256}; +use std::collections::BTreeMap; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::process::ExitCode; +use std::sync::atomic::AtomicBool; +use std::time::{Duration, Instant}; + +struct Args { + source: PathBuf, + zig_tool: Option, + json: bool, +} + +/// 执行单文件 Zig 原生语法检查或未验收 WASM 初检,不签发完整 lint/交付通过。 +/// 参数为源码文件、可选受控 Zig 二进制路径和输出格式;退出码 3 表示仍需完整验收。 +pub fn run(args: &[String]) -> ExitCode { + let args = match parse_args(args) { + Ok(args) => args, + Err(reason) => { + eprintln!("{reason}"); + return ExitCode::from(2); + } + }; + let deadline = Instant::now() + Duration::from_secs(30); + let mut report = json!({ + "schema_version":"0.1.0", "report_type":"zig_lint_feedback", + "operation":"lint", "language":"zig", "path":args.source, + "status":"incomplete", "coverage_proven":false, + "delivery_decision":"not_evaluated", "authority":"local_unverified", + "source_sha256":null, + "native":{"status":"not_run","reason":"explicit_zig_tool_not_provided","version":null,"tool_sha256":null,"diagnostics":[]}, + "syntax_precheck":null, + "next_action":"提供适用的 Zig 0.16.0 原生工具并运行 ast-check;候选语法初检不能代替完整 lint、编译或测试" + }); + if args + .source + .extension() + .is_none_or(|extension| extension != "zig") + { + report["native"]["reason"] = json!("zig_source_extension_required"); + emit(&report, args.json); + return ExitCode::from(3); + } + let source = match read_plain_source(&args.source) { + Ok(source) => source, + Err(reason) => { + report["native"]["reason"] = json!(reason); + emit(&report, args.json); + return ExitCode::from(3); + } + }; + report["source_sha256"] = json!(format!("{:x}", Sha256::digest(&source))); + if let Some(tool) = args.zig_tool.as_deref() { + if let Some(native) = observe_native(tool, &source, deadline) { + let completed = matches!( + native["status"].as_str(), + Some("completed" | "diagnostics_observed") + ); + report["native"] = native; + if completed { + report["next_action"] = + json!(if report["native"]["status"] == "diagnostics_observed" { + "核对原生 Zig AST 诊断的源码位置并修复;仍需执行项目完整 lint、构建和测试" + } else { + "Zig ast-check 未发现局部语法错误;仍需执行项目完整 lint、构建和测试" + }); + emit(&report, args.json); + return ExitCode::from(3); + } + } else { + report["native"]["reason"] = json!("zig_tool_unavailable_or_untrusted"); + } + } + let name = args + .source + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("source.zig"); + match std::env::current_exe() { + Ok(executable) => match run_syntax_worker_candidate( + &executable, + "zig", + name, + &source, + deadline, + &AtomicBool::new(false), + ) { + Ok(observation) => { + report["syntax_precheck"] = json!({ + "status":"incomplete", + "grammar_qualified":false, + "grammar_sha256":observation.grammar_sha256, + "precheck":observation.precheck, + "recoveries":observation.recoveries + }); + report["next_action"] = json!(if report["syntax_precheck"]["recoveries"] + .as_array() + .is_some_and(|items| !items.is_empty()) + { + "先用匹配 Zig 版本的原生语法检查确认疑似位置;不要仅凭 WASM 修改源码或关闭任务" + } else { + "候选语法初检未见恢复节点;仍需配置并运行原生 Zig 检查" + }); + } + Err(reason) => { + report["syntax_precheck"] = json!({"status":"incomplete","reason":reason}); + } + }, + Err(_) => { + report["syntax_precheck"] = + json!({"status":"incomplete","reason":"worker_executable_unavailable"}); + } + } + emit(&report, args.json); + ExitCode::from(3) +} + +fn observe_native(tool: &Path, source: &[u8], deadline: Instant) -> Option { + if !tool.is_absolute() { + return None; + } + let executable = tool.canonicalize().ok()?; + if !executable.is_file() { + return None; + } + let tool_sha256 = format!( + "{:x}", + Sha256::digest(read_bounded_regular_file(&executable, 64 * 1024 * 1024).ok()?) + ); + let cancelled = AtomicBool::new(false); + let version = run_process( + &ProcessSpec { + executable: executable.clone(), + args: vec![OsString::from("version")], + cwd: std::env::current_dir().ok()?, + env: BTreeMap::new(), + stdin: None, + deadline, + output_limit_bytes: 1024, + }, + &cancelled, + ); + if version.termination != Termination::Exited(0) + || std::str::from_utf8(&version.stdout).ok()?.trim() != "0.16.0" + { + return Some( + json!({"status":"incomplete","reason":"zig_version_unverified_or_unsupported","version":null,"tool_sha256":tool_sha256,"diagnostics":[]}), + ); + } + let outcome = run_process( + &ProcessSpec { + executable: executable.clone(), + args: vec![ + OsString::from("ast-check"), + OsString::from("--color"), + OsString::from("off"), + ], + cwd: std::env::current_dir().ok()?, + env: BTreeMap::new(), + stdin: Some(source.to_vec()), + deadline, + output_limit_bytes: 64 * 1024, + }, + &cancelled, + ); + let current_tool_sha256 = read_bounded_regular_file(&executable, 64 * 1024 * 1024) + .ok() + .map(|bytes| format!("{:x}", Sha256::digest(bytes))); + if current_tool_sha256.as_deref() != Some(tool_sha256.as_str()) { + return Some( + json!({"status":"incomplete","reason":"zig_tool_changed_during_check","version":"0.16.0","tool_sha256":tool_sha256,"diagnostics":[]}), + ); + } + let diagnostics = parse_diagnostic_positions(&outcome.stderr); + Some(json!({ + "status":match outcome.termination { + Termination::Exited(0) if outcome.stderr.is_empty() => "completed", + Termination::Exited(1) if !diagnostics.is_empty() => "diagnostics_observed", + _ => "incomplete", + }, + "reason":match outcome.termination { + Termination::Exited(0) if outcome.stderr.is_empty() => "ast_check_no_diagnostics", + Termination::Exited(1) if !diagnostics.is_empty() => "ast_check_diagnostics", + _ => "zig_ast_check_incomplete", + }, + "version":"0.16.0", + "tool_sha256":tool_sha256, + "diagnostic_count":diagnostics.len(), + "diagnostics":diagnostics + })) +} + +fn parse_diagnostic_positions(raw: &[u8]) -> Vec { + let Ok(text) = std::str::from_utf8(raw) else { + return Vec::new(); + }; + text.lines() + .filter_map(|line| { + let rest = line.strip_prefix(":")?; + let (row, rest) = rest.split_once(':')?; + let (column, rest) = rest.split_once(':')?; + if !rest.trim_start().starts_with("error:") { + return None; + } + let row = row.parse::().ok()?; + let column = column.parse::().ok()?; + if row == 0 || column == 0 { + return None; + } + Some(json!({"line":row,"column":column,"rule_id":"zig.ast_check.error"})) + }) + .take(32) + .collect() +} + +fn parse_args(args: &[String]) -> Result { + let mut source = None; + let mut zig_tool = None; + let mut json = false; + let mut index = 0; + while index < args.len() { + match args[index].as_str() { + "--zig-tool" => { + index += 1; + let value = args.get(index).ok_or("--zig-tool 缺少路径")?; + if zig_tool.replace(PathBuf::from(value)).is_some() { + return Err("--zig-tool 重复"); + } + } + "--format=json" => json = true, + "--format=human" => json = false, + value if !value.starts_with('-') && source.is_none() => { + source = Some(PathBuf::from(value)) + } + _ => return Err("lint zig 参数无效"), + } + index += 1; + } + Ok(Args { + source: source.ok_or("lint zig 缺少源码文件")?, + zig_tool, + json, + }) +} + +fn emit(report: &Value, json_format: bool) { + if json_format { + println!("{report}"); + } else { + println!( + "Zig 局部检查未完成:原生 {},候选语法 {};{}", + report["native"]["status"].as_str().unwrap_or("incomplete"), + report["syntax_precheck"]["status"] + .as_str() + .unwrap_or("未运行"), + report["next_action"] + .as_str() + .unwrap_or("核对原生 Zig 结果") + ); + for diagnostic in report["native"]["diagnostics"] + .as_array() + .into_iter() + .flatten() + { + println!( + " 原生 AST 错误:{}:{}", + diagnostic["line"], diagnostic["column"] + ); + } + } +} diff --git a/crates/codeguard-cli/tests/check_all_grammar_candidates.rs b/crates/codeguard-cli/tests/check_all_grammar_candidates.rs new file mode 100644 index 00000000..a480b310 --- /dev/null +++ b/crates/codeguard-cli/tests/check_all_grammar_candidates.rs @@ -0,0 +1,253 @@ +#![cfg(all(feature = "wasm-precheck", unix))] + +use std::collections::BTreeSet; +use std::fs; +use std::process::Command; + +#[test] +fn completed_native_ruff_preempts_only_its_matching_python_file() { + use std::os::unix::fs::PermissionsExt; + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-native-preferred-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + fs::write(root.join("app.py"), "import os\n").unwrap(); + fs::write(root.join("main.zig"), "const Empty = struct {};\n").unwrap(); + fs::write(root.join("ruff.toml"), "[lint]\nselect = ['F401']\n").unwrap(); + let tool = root.join("fake-ruff"); + fs::write(&tool, "#!/bin/sh\nif [ \"$1\" = '--version' ]; then echo 'ruff 0.16.8'; exit 0; fi\nif [ \"$2\" = '--show-files' ]; then echo \"$3\"; exit 0; fi\nif [ \"$2\" = '--show-settings' ]; then printf 'linter.rules.enabled = [\\n\\tunused-import (F401),\\n]\\nlinter.per_file_ignores = {}\\n'; exit 0; fi\nif [ \"$2\" = '--no-cache' ]; then if [ \"$3\" = '--ignore-noqa' ]; then source=$6; else source=$5; fi; printf '[{\"code\":\"F401\",\"message\":\"unused\",\"filename\":\"%s\",\"location\":{\"row\":1,\"column\":1},\"severity\":\"error\"}]\\n' \"$source\"; exit 1; fi\nexit 2\n").unwrap(); + fs::set_permissions(&tool, fs::Permissions::from_mode(0o700)).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["check", "all"]) + .arg(&root) + .args([ + "--ruff-tool", + tool.to_str().unwrap(), + "--format=json", + "--timeout", + "40s", + ]) + .output() + .unwrap(); + fs::remove_dir_all(&root).unwrap(); + assert_eq!( + output.status.code(), + Some(3), + "{}", + String::from_utf8_lossy(&output.stderr) + ); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!( + report["native_results"]["python_lint"]["files"][0]["run_status"], "findings", + "{report}" + ); + assert_eq!( + report["native_results"]["python_lint"]["files"][0]["findings"][0]["rule_id"], + "F401" + ); + assert_eq!(report["syntax_candidates"]["native_preferred_count"], 1); + let observations = report["syntax_candidates"]["observations"] + .as_array() + .unwrap(); + assert!(!observations.iter().any(|row| row["path"] == "app.py")); + assert!( + observations + .iter() + .any(|row| row["path"] == "main.zig" && row["status"] == "candidate_observed") + ); + assert_eq!(report["delivery_decision"], "incomplete"); +} + +#[test] +fn check_all_routes_distinct_dialects_after_native_without_claiming_clean() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-check-grammar-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + fs::write(root.join("component.tsx"), "const C = () =>
;\n").unwrap(); + fs::write(root.join("script.js"), "const x = 1;\n").unwrap(); + fs::write( + root.join("component.cfs"), + "component { function f() { return 1; } }\n", + ) + .unwrap(); + fs::write( + root.join("page.cfm"), + "SELECT #x# FROM users\n", + ) + .unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["check", "all"]) + .arg(&root) + .args(["--format=json", "--timeout", "90s"]) + .output() + .unwrap(); + fs::remove_dir_all(&root).unwrap(); + assert_eq!( + output.status.code(), + Some(3), + "{}", + String::from_utf8_lossy(&output.stderr) + ); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["schema_version"], "0.33.0"); + assert_eq!(report["delivery_decision"], "incomplete"); + let observations = report["syntax_candidates"]["observations"] + .as_array() + .unwrap(); + for language in ["tsx", "javascript", "cfml", "cfscript", "cfquery"] { + assert!( + observations.iter().any(|item| item["language"] == language), + "{language}: {observations:?}" + ); + } + assert!( + observations + .iter() + .all(|item| item["grammar_qualified"] == false) + ); + assert!(observations.iter().all(|item| item["status"] != "clean")); + assert_eq!( + report["syntax_candidates"]["execution_phase"], + "after_native" + ); +} + +#[test] +fn check_all_invokes_all_32_pinned_candidates_across_bounded_projects() { + let root = std::env::temp_dir().canonicalize().unwrap().join(format!( + "codeguard-check-all-grammars-{}", + std::process::id() + )); + fs::create_dir_all(&root).unwrap(); + for (index, (name, source)) in [ + ("a.ets", "@Component struct C { build() { Text('hi') } }"), + ("a.c", "int main(void) { return 0; }"), + ( + "a.cfm", + "SELECT #x# FROM users", + ), + ("a.cfs", "component { function f() { return 1; } }"), + ( + "a.cbl", + " IDENTIFICATION DIVISION.\n PROGRAM-ID. HELLO.\n", + ), + ("a.cpp", "int main() { return 0; }"), + ("a.cs", "class C { static int F() { return 1; } }"), + ("a.dart", "String greet(String name) => 'Hello $name';"), + ("a.erl", "-module(hello).\nhello() -> ok.\n"), + ("a.go", "package main\nfunc main() {}\n"), + ("a.java", "class A {}"), + ("a.js", "const value = 1;"), + ("a.kt", "fun main() { val x = 1 }"), + ("a.lua", "local x = 1\n"), + ("a.luau", "local x: number = 1\n"), + ("a.nix", "let x = 1; in x"), + ("a.m", "@interface Foo : NSObject\n@end\n"), + ("a.pas", "program Hello;\nbegin\n writeln('Hi');\nend.\n"), + ("a.php", " Int { return 1 }"), + ("a.tf", "resource \"x\" \"y\" { foo = \"bar\" }"), + ("a.tsx", "const C = () =>
;"), + ("a.ts", "const value: number = 1;"), + ( + "a.vb", + "Public Class C\n Public Function F() As Integer\n Return 1\n End Function\nEnd Class\n", + ), + ("a.zig", "const Empty = struct {};\n"), + ] + .into_iter() + .enumerate() + { + let group = root.join(format!("group-{}", index / 8)); + fs::create_dir_all(&group).unwrap(); + fs::write(group.join(name), source).unwrap(); + } + let mut languages = BTreeSet::new(); + for group_index in 0..4 { + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["check", "all"]) + .arg(root.join(format!("group-{group_index}"))) + .args(["--format=json", "--timeout", "120s"]) + .output() + .unwrap(); + assert_eq!( + output.status.code(), + Some(3), + "{}", + String::from_utf8_lossy(&output.stderr) + ); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!( + report["syntax_candidates"]["skipped_count"], 0, + "group {group_index}" + ); + assert_eq!( + report["syntax_candidates"]["delivery_decision"], + "incomplete" + ); + let observations = report["syntax_candidates"]["observations"] + .as_array() + .unwrap(); + for language in observations + .iter() + .filter(|item| item["status"] == "candidate_observed") + .filter_map(|item| item["language"].as_str()) + { + languages.insert(language.to_owned()); + } + } + fs::remove_dir_all(&root).unwrap(); + let expected = + serde_json::from_str::(include_str!("../../../grammars/manifest.json")) + .unwrap()["assets"] + .as_array() + .unwrap() + .iter() + .map(|asset| asset["language"].as_str().unwrap().to_owned()) + .collect::>(); + assert_eq!(languages, expected); +} + +#[test] +fn oversized_source_is_an_explicit_candidate_gap() { + let root = std::env::temp_dir().canonicalize().unwrap().join(format!( + "codeguard-check-large-grammar-{}", + std::process::id() + )); + fs::create_dir_all(&root).unwrap(); + fs::write(root.join("large.zig"), vec![b'a'; 1024 * 1024 + 1]).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["check", "all"]) + .arg(&root) + .args(["--format=json", "--timeout", "30s"]) + .output() + .unwrap(); + fs::remove_dir_all(&root).unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!( + report["syntax_candidates"]["status"], + "attempted_incomplete" + ); + assert_eq!( + report["syntax_candidates"]["reason"], + "candidate_unavailable" + ); + assert_eq!( + report["syntax_candidates"]["observations"][0]["status"], + "candidate_unavailable" + ); + assert_eq!( + report["syntax_candidates"]["observations"][0]["grammar_sha256"], + serde_json::Value::Null + ); +} diff --git a/crates/codeguard-cli/tests/check_all_java_p3c.rs b/crates/codeguard-cli/tests/check_all_java_p3c.rs index 905d3393..b1b06c02 100644 --- a/crates/codeguard-cli/tests/check_all_java_p3c.rs +++ b/crates/codeguard-cli/tests/check_all_java_p3c.rs @@ -219,7 +219,7 @@ fn missing_p3c_configuration_is_reported_without_running_maven() { fs::set_permissions(&tool, fs::Permissions::from_mode(0o700)).unwrap(); let report = project.check(&["--maven-tool", tool.to_str().unwrap()]); assert!(!marker.exists()); - assert_eq!(report["schema_version"], "0.31.0"); + assert_eq!(report["schema_version"], "0.33.0"); assert_eq!(report["execution_tasks"][0]["id"], "java.p3c"); assert_eq!(report["execution_tasks"][0]["status"], "native_incomplete"); let java = &report["native_results"]["java_p3c"]; diff --git a/crates/codeguard-cli/tests/check_all_npm.rs b/crates/codeguard-cli/tests/check_all_npm.rs index 35199c40..e5f728c7 100644 --- a/crates/codeguard-cli/tests/check_all_npm.rs +++ b/crates/codeguard-cli/tests/check_all_npm.rs @@ -411,7 +411,7 @@ fn real_npm_audit_enters_check_all_workbench() { String::from_utf8_lossy(&out.stderr) ); let report: Value = serde_json::from_slice(&out.stdout).unwrap(); - assert_eq!(report["schema_version"], "0.31.0"); + assert_eq!(report["schema_version"], "0.33.0"); assert_eq!( report["native_results"]["npm_cve"][0]["feedback"]["local_coherent"], true, "{report}" diff --git a/crates/codeguard-cli/tests/check_all_partial_contract.rs b/crates/codeguard-cli/tests/check_all_partial_contract.rs index 473b1fd3..8cccf2cb 100644 --- a/crates/codeguard-cli/tests/check_all_partial_contract.rs +++ b/crates/codeguard-cli/tests/check_all_partial_contract.rs @@ -59,7 +59,25 @@ fn check_feedback_schema_cannot_encode_allow() { .unwrap(); assert_eq!(previous["properties"]["schema_version"]["const"], "0.30.0"); assert_eq!(schema["additionalProperties"], false); - assert_eq!(schema["properties"]["schema_version"]["const"], "0.31.0"); + assert_eq!(schema["properties"]["schema_version"]["const"], "0.33.0"); + let archived: Value = serde_json::from_str(include_str!( + "../../../schemas/check-feedback-v0.32.schema.json" + )) + .unwrap(); + assert_eq!(archived["properties"]["schema_version"]["const"], "0.32.0"); + assert_eq!( + schema["properties"]["syntax_candidates"]["properties"]["native_preferred_count"]["type"], + "integer" + ); + assert_eq!( + schema["properties"]["syntax_candidates"]["properties"]["observations"]["items"]["properties"] + ["grammar_qualified"]["const"], + false + ); + assert_eq!( + schema["properties"]["syntax_candidates"]["properties"]["delivery_decision"]["const"], + "incomplete" + ); assert_eq!( schema["properties"]["export"]["properties"]["status"]["enum"], serde_json::json!(["not_requested", "saved", "failed"]) @@ -212,7 +230,7 @@ fn check_all_keeps_local_checker_candidate_separate_from_execution() { let (exit, report) = project.check(&[]); assert_eq!(exit, 3); - assert_eq!(report["schema_version"], "0.31.0"); + assert_eq!(report["schema_version"], "0.33.0"); assert_eq!(report["discovery"]["schema_version"], "0.4.0"); let candidates = report["discovery"]["native_tool_candidates"] .as_array() @@ -528,7 +546,7 @@ fn rust_only_project_keeps_categories_as_candidates_without_inventing_policy_obl let (exit, report) = project.check(&[]); assert_eq!(exit, 3); assert_eq!(report["report_type"], "check_feedback"); - assert_eq!(report["schema_version"], "0.31.0"); + assert_eq!(report["schema_version"], "0.33.0"); assert_eq!(report["execution_budget"]["timeout_ms"], 1_800_000); assert_eq!(report["execution_budget"]["source"], "builtin_default"); assert_eq!( @@ -991,6 +1009,9 @@ fn check_all_cancelled_native_task_returns_130_and_keeps_discovery() { assert_eq!(report["command_status"], "cancelled"); assert_eq!(report["exit_code"], 130); assert_eq!(report["reason"], "request_cancelled"); + assert_eq!(report["syntax_candidates"]["status"], "not_run"); + #[cfg(feature = "wasm-precheck")] + assert_eq!(report["syntax_candidates"]["reason"], "request_cancelled"); assert!( report["execution_budget"]["started_native_task_count"] .as_u64() @@ -1057,6 +1078,17 @@ fn original_ruff_finding_survives_check_all_partial_result() { .iter() .any(|finding| finding["rule_id"] == "F401") })); + #[cfg(feature = "wasm-precheck")] + { + assert_eq!(report["syntax_candidates"]["native_preferred_count"], 1); + assert!( + !report["syntax_candidates"]["observations"] + .as_array() + .unwrap() + .iter() + .any(|item| item["path"] == "app.py") + ); + } assert!( report["category_candidates"] .as_array() diff --git a/crates/codeguard-cli/tests/grammar_probe_cli.rs b/crates/codeguard-cli/tests/grammar_probe_cli.rs new file mode 100644 index 00000000..605b1256 --- /dev/null +++ b/crates/codeguard-cli/tests/grammar_probe_cli.rs @@ -0,0 +1,90 @@ +#![cfg(all(feature = "wasm-precheck", unix))] + +use std::fs; +use std::process::Command; + +#[test] +fn public_candidate_probe_executes_pinned_worker_without_claiming_lint() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-grammar-probe-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + for (language, filename, source, expect_recoveries) in [ + ("python", "a.py", "x = 1\n", false), + ("tsx", "a.tsx", "const C = () =>
;\n", false), + ("java", "A.java", "class A {", true), + ] { + let path = root.join(filename); + fs::write(&path, source).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["grammar", "probe", language]) + .arg(&path) + .arg("--format=json") + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3), "{language}"); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["report_type"], "grammar_candidate_probe"); + assert_eq!(report["precheck"]["status"], "incomplete"); + assert_eq!(report["native"]["status"], "not_run"); + assert_eq!(report["delivery_decision"], "not_evaluated"); + assert_eq!( + report["recoveries"].as_array().unwrap().is_empty(), + !expect_recoveries, + "{language}" + ); + } + fs::remove_dir_all(root).unwrap(); +} + +#[test] +fn missing_source_has_versioned_incomplete_json_and_closed_schema() { + let schema_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../schemas/grammar-probe-v0.1.schema.json"); + let schema: serde_json::Value = + serde_json::from_slice(&fs::read(schema_path).expect("public probe schema")).unwrap(); + assert_eq!(schema["$id"], "urn:codeguard:schema:grammar-probe:0.1.0"); + assert_eq!(schema["additionalProperties"], false); + + let path = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-missing-probe-{}", std::process::id())); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["grammar", "probe", "zig"]) + .arg(&path) + .arg("--format=json") + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["schema_version"], "0.1.0"); + assert_eq!(report["status"], "incomplete"); + assert_eq!(report["native"]["status"], "not_run"); + assert_eq!(report["delivery_decision"], "not_evaluated"); + assert!(report["reason"].as_str().unwrap().contains("source")); + + let manifest: serde_json::Value = serde_json::from_slice( + &fs::read( + std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../grammars/manifest.json"), + ) + .unwrap(), + ) + .unwrap(); + let mut manifest_languages = manifest["assets"] + .as_array() + .unwrap() + .iter() + .map(|asset| asset["language"].as_str().unwrap()) + .collect::>(); + let mut schema_languages = schema["properties"]["language"]["enum"] + .as_array() + .unwrap() + .iter() + .map(|language| language.as_str().unwrap()) + .collect::>(); + manifest_languages.sort_unstable(); + schema_languages.sort_unstable(); + assert_eq!(schema_languages, manifest_languages); +} diff --git a/crates/codeguard-cli/tests/grammar_route.rs b/crates/codeguard-cli/tests/grammar_route.rs new file mode 100644 index 00000000..f0e56f76 --- /dev/null +++ b/crates/codeguard-cli/tests/grammar_route.rs @@ -0,0 +1,71 @@ +#![cfg(feature = "wasm-precheck")] + +use codeguard_cli::grammar_route::route_source; +use std::collections::BTreeSet; + +#[test] +fn routes_every_pinned_grammar_without_merging_dialects() { + let cases = [ + ("arkts", "a.ets"), + ("c", "a.c"), + ("cfml", "a.cfm"), + ("cobol", "a.cbl"), + ("cpp", "a.cpp"), + ("csharp", "a.cs"), + ("dart", "a.dart"), + ("erlang", "a.erl"), + ("go", "a.go"), + ("java", "a.java"), + ("javascript", "a.js"), + ("kotlin", "a.kt"), + ("lua", "a.lua"), + ("luau", "a.luau"), + ("nix", "a.nix"), + ("objc", "a.m"), + ("pascal", "a.pas"), + ("php", "a.php"), + ("python", "a.py"), + ("r", "a.r"), + ("ruby", "a.rb"), + ("rust", "a.rs"), + ("scala", "a.scala"), + ("solidity", "a.sol"), + ("swift", "a.swift"), + ("terraform", "a.tf"), + ("tsx", "a.tsx"), + ("typescript", "a.ts"), + ("vbnet", "a.vb"), + ("zig", "a.zig"), + ]; + let mut observed = BTreeSet::new(); + for (language, path) in cases { + let routes = route_source(path, b"source"); + assert_eq!(routes.len(), 1, "{path}"); + assert_eq!(routes[0].language, language, "{path}"); + observed.insert(language); + } + let cfscript = route_source("component.cfs", b"component {}"); + assert_eq!(cfscript[0].language, "cfscript"); + observed.insert("cfscript"); + let cfml = route_source( + "page.cfm", + b"SELECT id FROM users", + ); + assert!(cfml.iter().any(|route| route.language == "cfquery")); + observed.insert("cfquery"); + assert_eq!(observed.len(), 32); +} + +#[test] +fn ambiguous_and_embedded_sources_do_not_get_speculative_routes() { + assert!(route_source("a.h", b"int x;").is_empty()); + assert!(route_source("a.sql", b"SELECT 1").is_empty()); + assert!( + route_source("a.cfm", b"SELECT 1") + .iter() + .all(|r| r.language != "cfquery") + ); + let routes = route_source("a.tsx", b"const C = () =>
;"); + assert_eq!(routes.len(), 1); + assert_eq!(routes[0].language, "tsx"); +} diff --git a/crates/codeguard-cli/tests/grammar_status_cli.rs b/crates/codeguard-cli/tests/grammar_status_cli.rs index 97467d63..09c2c039 100644 --- a/crates/codeguard-cli/tests/grammar_status_cli.rs +++ b/crates/codeguard-cli/tests/grammar_status_cli.rs @@ -12,13 +12,20 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { assert_eq!(report["report_type"], "grammar_coverage_inventory"); assert_eq!(report["codegraph_grammar_count"], 32); assert_eq!(report["codegraph_vendored_count"], 30); - assert_eq!(report["candidate_count"], 23); + assert_eq!(report["candidate_count"], 32); assert_eq!(report["released_count"], 0); assert_eq!(report["authority"], "source_inventory_only"); assert_eq!(report["parser_capability"], "unverified"); assert_eq!(report["gate_effect"], "none"); assert_eq!(report["execution"], "not_run"); assert_eq!(report["delivery_decision"], "not_evaluated"); + assert!(report["next_action"].as_str().unwrap().contains("原生优先")); + assert!( + !report["next_action"] + .as_str() + .unwrap() + .contains("补齐缺口资产") + ); let assets = report["assets"].as_array().unwrap(); assert_eq!(assets.len(), 32); for asset in assets { @@ -28,9 +35,14 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { for language in [ "arkts", "c", + "cfml", + "cfquery", + "cfscript", + "cobol", "cpp", "csharp", "dart", + "erlang", "go", "java", "javascript", @@ -39,15 +51,19 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { "luau", "nix", "objc", + "pascal", "php", "python", "r", "ruby", "rust", + "scala", "solidity", + "swift", "terraform", "typescript", "tsx", + "vbnet", "zig", ] { let asset = assets @@ -61,7 +77,7 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { .iter() .find(|row| row["language"] == "cobol") .unwrap(); - assert_eq!(cobol["gap"], "current_loader_size_limit"); + assert_eq!(cobol["gap"], "language_qualification_and_release_pending"); assert!(cobol["source_bytes"].as_u64().unwrap() > 8 * 1024 * 1024); let dart = assets.iter().find(|row| row["language"] == "dart").unwrap(); assert_eq!(dart["integration_status"], "candidate_unvalidated"); diff --git a/crates/codeguard-cli/tests/python_cve_cli.rs b/crates/codeguard-cli/tests/python_cve_cli.rs index 78a708e6..e210850d 100644 --- a/crates/codeguard-cli/tests/python_cve_cli.rs +++ b/crates/codeguard-cli/tests/python_cve_cli.rs @@ -477,7 +477,7 @@ fn check_all_observes_each_python_build_root_without_allowing_delivery() { let tool = project.native_tool(); let (exit, report) = project.check_all(Some(&tool)); assert_eq!(exit, 3); - assert_eq!(report["schema_version"], "0.31.0"); + assert_eq!(report["schema_version"], "0.33.0"); assert_eq!(report["delivery_decision"], "incomplete"); let scans = report["native_results"]["python_cve"].as_array().unwrap(); assert_eq!(scans.len(), 2); diff --git a/crates/codeguard-cli/tests/syntax_worker_candidate.rs b/crates/codeguard-cli/tests/syntax_worker_candidate.rs index 556669dc..cc629b89 100644 --- a/crates/codeguard-cli/tests/syntax_worker_candidate.rs +++ b/crates/codeguard-cli/tests/syntax_worker_candidate.rs @@ -237,6 +237,79 @@ fn rebuilt_dart_runs_in_worker_without_claiming_clean() { assert!(!result.grammar_qualified); } +#[test] +fn erlang_candidate_runs_in_worker_without_claiming_clean() { + let result = run_syntax_worker_candidate( + env!("CARGO_BIN_EXE_codeguard").as_ref(), + "erlang", + "src/hello.erl", + b"-module(hello).\nhello() -> ok.\n", + Instant::now() + Duration::from_secs(60), + &AtomicBool::new(false), + ) + .expect("Erlang grammar candidate"); + assert!(result.recoveries.is_empty()); + assert_eq!(result.precheck.status, SyntaxPrecheckStatus::Incomplete); + assert!(!result.grammar_qualified); +} + +#[test] +fn pascal_candidate_runs_in_worker_without_claiming_clean() { + let result = run_syntax_worker_candidate( + env!("CARGO_BIN_EXE_codeguard").as_ref(), + "pascal", + "src/hello.pas", + b"program Hello;\nbegin\n writeln('Hi');\nend.\n", + Instant::now() + Duration::from_secs(60), + &AtomicBool::new(false), + ) + .expect("Pascal grammar candidate"); + assert!(result.recoveries.is_empty()); + assert_eq!(result.precheck.status, SyntaxPrecheckStatus::Incomplete); + assert!(!result.grammar_qualified); +} + +#[test] +fn remaining_source_grammars_run_in_worker_without_claiming_clean() { + for (language, path, source) in [ + ("cfml", "web/index.cfm", b"".as_slice()), + ("cfquery", "web/query.sql", b"SELECT #x# FROM users".as_slice()), + ("cfscript", "web/component.cfs", b"component { function f() { return 1; } }".as_slice()), + ("scala", "src/Main.scala", b"object Main { def f(x: Int): Int = x + 1 }".as_slice()), + ("swift", "Sources/Main.swift", b"func f() -> Int { return 1 }".as_slice()), + ("vbnet", "src/C.vb", b"Public Class C\n Public Function F() As Integer\n Return 1\n End Function\nEnd Class\n".as_slice()), + ] { + let result = run_syntax_worker_candidate( + env!("CARGO_BIN_EXE_codeguard").as_ref(), + language, + path, + source, + Instant::now() + Duration::from_secs(60), + &AtomicBool::new(false), + ) + .unwrap_or_else(|reason| panic!("{language} candidate: {reason}")); + assert!(result.recoveries.is_empty(), "{language}"); + assert_eq!(result.precheck.status, SyntaxPrecheckStatus::Incomplete); + assert!(!result.grammar_qualified); + } +} + +#[test] +fn cobol_candidate_runs_in_worker_without_claiming_clean() { + let result = run_syntax_worker_candidate( + env!("CARGO_BIN_EXE_codeguard").as_ref(), + "cobol", + "src/HELLO.cbl", + b" IDENTIFICATION DIVISION.\n PROGRAM-ID. HELLO.\n", + Instant::now() + Duration::from_secs(90), + &AtomicBool::new(false), + ) + .expect("COBOL candidate"); + assert!(result.recoveries.is_empty()); + assert_eq!(result.precheck.status, SyntaxPrecheckStatus::Incomplete); + assert!(!result.grammar_qualified); +} + #[test] fn invalid_input_and_cancellation_cannot_yield_observations() { let exe = env!("CARGO_BIN_EXE_codeguard").as_ref(); diff --git a/crates/codeguard-cli/tests/zig_lint_cli.rs b/crates/codeguard-cli/tests/zig_lint_cli.rs new file mode 100644 index 00000000..f2cd0f3c --- /dev/null +++ b/crates/codeguard-cli/tests/zig_lint_cli.rs @@ -0,0 +1,129 @@ +#![cfg(all(feature = "wasm-precheck", unix))] + +use std::fs; +use std::os::unix::fs::PermissionsExt; +use std::process::Command; + +#[test] +fn native_zig_diagnostic_takes_priority_over_wasm_candidate() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-zig-native-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let source = root.join("broken.zig"); + fs::write(&source, "const Empty = struct {\n").unwrap(); + let tool = root.join("zig-tool"); + fs::write( + &tool, + "#!/bin/sh\nif [ \"$1\" = version ]; then printf '0.16.0\\n'; exit 0; fi\nif [ \"$1\" = ast-check ]; then while IFS= read -r line; do :; done; printf ':1:23: error: expected closing brace\\n' >&2; exit 1; fi\nexit 2\n", + ) + .unwrap(); + fs::set_permissions(&tool, fs::Permissions::from_mode(0o700)).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["lint", "zig"]) + .arg(&source) + .args(["--zig-tool", tool.to_str().unwrap(), "--format=json"]) + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!( + report["native"]["status"], "diagnostics_observed", + "{report}" + ); + assert_eq!(report["native"]["diagnostic_count"], 1); + assert_eq!(report["native"]["tool_sha256"].as_str().unwrap().len(), 64); + assert_eq!(report["syntax_precheck"], serde_json::Value::Null); + assert_eq!(report["delivery_decision"], "not_evaluated"); + fs::remove_dir_all(root).unwrap(); +} + +#[test] +fn absent_explicit_zig_tool_uses_unqualified_wasm_without_claiming_clean() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-zig-fallback-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let source = root.join("empty.zig"); + fs::write(&source, "const Empty = struct {};\n").unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["lint", "zig"]) + .arg(&source) + .arg("--format=json") + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["native"]["status"], "not_run"); + assert_eq!( + report["syntax_precheck"]["precheck"]["status"], + "incomplete" + ); + assert_eq!(report["syntax_precheck"]["grammar_qualified"], false); + assert_eq!(report["delivery_decision"], "not_evaluated"); + fs::remove_dir_all(root).unwrap(); +} + +#[test] +fn clean_native_ast_check_does_not_claim_full_lint_or_run_wasm() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-zig-native-clean-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let source = root.join("empty.zig"); + fs::write(&source, "const Empty = struct {};\n").unwrap(); + let tool = root.join("zig-tool"); + fs::write( + &tool, + "#!/bin/sh\nif [ \"$1\" = version ]; then printf '0.16.0\\n'; exit 0; fi\nif [ \"$1\" = ast-check ]; then while IFS= read -r line; do :; done; exit 0; fi\nexit 2\n", + ) + .unwrap(); + fs::set_permissions(&tool, fs::Permissions::from_mode(0o700)).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["lint", "zig"]) + .arg(&source) + .args(["--zig-tool", tool.to_str().unwrap(), "--format=json"]) + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["native"]["status"], "completed", "{report}"); + assert_eq!(report["syntax_precheck"], serde_json::Value::Null); + assert_eq!(report["status"], "incomplete"); + assert_eq!(report["coverage_proven"], false); + fs::remove_dir_all(root).unwrap(); +} + +#[test] +fn changed_zig_executable_cannot_authorize_native_completion() { + let root = std::env::temp_dir() + .canonicalize() + .unwrap() + .join(format!("codeguard-zig-changed-tool-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let source = root.join("empty.zig"); + fs::write(&source, "const Empty = struct {};\n").unwrap(); + let tool = root.join("zig-tool"); + fs::write( + &tool, + "#!/bin/sh\nif [ \"$1\" = version ]; then printf '0.16.0\\n'; exit 0; fi\nif [ \"$1\" = ast-check ]; then while IFS= read -r line; do :; done; printf '#changed\\n' >> \"$0\"; exit 0; fi\nexit 2\n", + ) + .unwrap(); + fs::set_permissions(&tool, fs::Permissions::from_mode(0o700)).unwrap(); + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["lint", "zig"]) + .arg(&source) + .args(["--zig-tool", tool.to_str().unwrap(), "--format=json"]) + .output() + .unwrap(); + assert_eq!(output.status.code(), Some(3)); + let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + assert_eq!(report["native"]["status"], "incomplete"); + assert_eq!(report["native"]["reason"], "zig_tool_changed_during_check"); + assert_eq!(report["syntax_precheck"]["grammar_qualified"], false); + assert_eq!(report["delivery_decision"], "not_evaluated"); + fs::remove_dir_all(root).unwrap(); +} diff --git a/crates/codeguard-runtime/src/wasm_grammar.rs b/crates/codeguard-runtime/src/wasm_grammar.rs index 08fd4ca2..3f950616 100644 --- a/crates/codeguard-runtime/src/wasm_grammar.rs +++ b/crates/codeguard-runtime/src/wasm_grammar.rs @@ -4,6 +4,9 @@ use tree_sitter::{ wasmtime::{Config, Engine}, }; +// COBOL 固定来源资产约 16 MiB;20 MiB 仍限制非清单输入的尺寸。 +const MAX_GRAMMAR_WASM_BYTES: usize = 20 * 1024 * 1024; + /// 经调用方固定清单校验的 Tree-sitter WASM grammar 的 Rust 加载与解析器。 /// 仅提供语法树;是否属于源码违规由上层规则和原生检查结果决定。 pub struct WasmGrammar { @@ -25,11 +28,11 @@ impl WasmGrammar { if name.is_empty() || !name .bytes() - .all(|byte| byte.is_ascii_lowercase() || byte == b'-' || byte == b'_') + .all(|byte| byte.is_ascii_alphabetic() || byte == b'-' || byte == b'_') { return Err("无效的 grammar 名称".into()); } - if wasm.len() < 8 || wasm.len() > 8 * 1024 * 1024 || !wasm.starts_with(b"\0asm") { + if wasm.len() < 8 || wasm.len() > MAX_GRAMMAR_WASM_BYTES || !wasm.starts_with(b"\0asm") { return Err("WASM 字节无效或超过大小上限".into()); } if expected_sha256.len() != 64 diff --git a/crates/codeguard-runtime/tests/wasm_grammar_load.rs b/crates/codeguard-runtime/tests/wasm_grammar_load.rs index 2669c3d1..7d53cc0f 100644 --- a/crates/codeguard-runtime/tests/wasm_grammar_load.rs +++ b/crates/codeguard-runtime/tests/wasm_grammar_load.rs @@ -27,6 +27,143 @@ const PHP: &[u8] = include_bytes!("../../../grammars/php/parser.wasm"); const KOTLIN: &[u8] = include_bytes!("../../../grammars/kotlin/parser.wasm"); const DART: &[u8] = include_bytes!("../../../grammars/dart/parser.wasm"); const DART_REBUILT_SOURCE: &[u8] = include_bytes!("../../../grammars/dart/source.wasm"); +const ERLANG: &[u8] = include_bytes!("../../../grammars/erlang/parser.wasm"); +const PASCAL: &[u8] = include_bytes!("../../../grammars/pascal/parser.wasm"); +const COBOL: &[u8] = include_bytes!("../../../grammars/cobol/parser.wasm"); +const CFML: &[u8] = include_bytes!("../../../grammars/cfml/parser.wasm"); +const CFQUERY: &[u8] = include_bytes!("../../../grammars/cfquery/parser.wasm"); +const CFSCRIPT: &[u8] = include_bytes!("../../../grammars/cfscript/parser.wasm"); +const SCALA: &[u8] = include_bytes!("../../../grammars/scala/parser.wasm"); +const SWIFT: &[u8] = include_bytes!("../../../grammars/swift/parser.wasm"); +const VBNET: &[u8] = include_bytes!("../../../grammars/vbnet/parser.wasm"); + +#[test] +fn final_source_grammars_load_offline_and_separate_basic_syntax() { + for (name, wasm, sha, valid, invalid) in [ + ( + "cfml", + CFML, + "17aeb294c58dd47045b470fc082ccceac3100c8e548b13764d4f3987a062322f", + b"".as_slice(), + b"".as_slice(), + ), + ( + "cfquery", + CFQUERY, + "9d4eaaec46eec7e6400d4b8d6c85fac7dfe33867ed5b4e5c218dfa7851c32558", + b"SELECT * FROM users".as_slice(), + b"SELECT #unclosed".as_slice(), + ), + ( + "cfscript", + CFSCRIPT, + "e381db5d2b8a7744fc7d8e51b0a14ff03f86c8ff497cdfe32d1da467f19d4096", + b"component { function f() { return 1; } }".as_slice(), + b"component { function f( {".as_slice(), + ), + ( + "scala", + SCALA, + "37d7fe5a91ca98941dc05493b0c05a0df0f36df5035890fa00b02497c68aaac3", + b"object Main { def f(x: Int): Int = x + 1 }".as_slice(), + b"object Main { def f( = }".as_slice(), + ), + ( + "swift", + SWIFT, + "cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843", + b"func f() -> Int { return 1 }".as_slice(), + b"func f( {".as_slice(), + ), + ( + "vbnet", + VBNET, + "e38a09e1826c7ec06340c0531a98bbb5ee79bdd710bba3d3349b79a19721e844", + b"Public Class C\n Public Function F() As Integer\n Return 1\n End Function\nEnd Class\n" + .as_slice(), + b"Public Class C\nPublic Function F(\n".as_slice(), + ), + ] { + let mut grammar = WasmGrammar::load(name, wasm, sha, 15) + .unwrap_or_else(|reason| panic!("{name} offline load: {reason}")); + assert!( + !grammar.parse(valid).unwrap().root_node().has_error(), + "{name} valid" + ); + assert!( + grammar.parse(invalid).unwrap().root_node().has_error(), + "{name} invalid" + ); + } +} + +#[test] +fn pinned_cobol_asset_loads_with_its_original_export_name() { + let mut grammar = WasmGrammar::load( + "COBOL", + COBOL, + "65b98799f92e831d8b5ed8cd811464c71fac31c4beabf66990a545a4f65e02f1", + 14, + ) + .expect("pinned COBOL grammar under bounded worker input"); + assert!( + !grammar + .parse(b" IDENTIFICATION DIVISION.\n PROGRAM-ID. HELLO.\n") + .unwrap() + .root_node() + .has_error() + ); +} + +#[test] +fn pascal_grammar_loads_offline_and_separates_basic_syntax() { + let mut grammar = WasmGrammar::load( + "pascal", + PASCAL, + "be3634fca99c19f5e1035a1a9c7d93d6ee82b35e6d5024f02be4883b71329c3e", + 14, + ) + .expect("pinned Pascal grammar"); + assert!( + !grammar + .parse(b"program Hello;\nbegin\n writeln('Hi');\nend.\n") + .unwrap() + .root_node() + .has_error() + ); + assert!( + grammar + .parse(b"program Hello;\nbegin\n writeln('Hi');\n") + .unwrap() + .root_node() + .has_error() + ); +} + +#[test] +fn erlang_grammar_loads_offline_and_separates_basic_syntax() { + let mut grammar = WasmGrammar::load( + "erlang", + ERLANG, + "dbab33f03e07b89f4385fcdd48d87d86ba35c82a0a426788d55b8c25410bc491", + 14, + ) + .expect("pinned Erlang grammar"); + assert!( + !grammar + .parse(b"-module(hello).\nhello() -> ok.\n") + .unwrap() + .root_node() + .has_error() + ); + assert!( + grammar + .parse(b"-module(hello).\nhello( -> ok.\n") + .unwrap() + .root_node() + .has_error() + ); +} #[test] fn rebuilt_dart_grammar_loads_with_real_scanner_and_rejects_broken_source() { diff --git a/docs/Codeguard-Architecture.md b/docs/Codeguard-Architecture.md index aea168cf..6becb12e 100644 --- a/docs/Codeguard-Architecture.md +++ b/docs/Codeguard-Architecture.md @@ -28,7 +28,25 @@ The existing [OpenSpec change](../openspec/changes/introduce-rust-codeguard-cli/ | [Core aggregation](../crates/codeguard-core/src/aggregate.rs), [delivery gate](../crates/codeguard-core/src/delivery_gate.rs) | Pure result semantics, not trusted public gate availability | | [Acceptance records](../tests/acceptance) | Scoped observations, test method, and residual gaps | -WASM requirements and 19 implementation tasks are recorded in the existing change. An opt-in Rust worker and narrow Java/TypeScript/TSX single-file feedback paths and a Python Ruff-unavailable candidate path now exist. All twenty-three candidate grammars remain unqualified; ArkTS, C, C++, C#, Go, JavaScript, Lua, Luau, Nix, Rust, Terraform, Zig, Objective-C, Solidity, R, Ruby, PHP, Kotlin and Dart are pinned Rust-loadable candidates without public lint routes. Project-wide native-first routing, qualified grammar ranges, capability-matched task closure, and host integrations remain incomplete; design examples are not current command output. +WASM requirements and 19 implementation tasks are recorded in the existing change. An opt-in Rust worker and narrow Java/TypeScript/TSX single-file feedback paths and a Python Ruff-unavailable candidate path now exist. All thirty-two candidate grammars remain unqualified; ArkTS, C, C++, C#, Go, JavaScript, Lua, Luau, Nix, Rust, Terraform, Zig, Objective-C, Solidity, R, Ruby, PHP, Kotlin, Dart, Erlang, Pascal, CFML, CFQuery, CFScript, COBOL, Scala, Swift and VB.NET are pinned Rust-loadable candidates without language-qualified lint routes. Project-wide native-first routing, qualified grammar ranges, capability-matched task closure, and host integrations remain incomplete; design examples are not current command output. + +A source build with `--features wasm-precheck` now exposes `codeguard grammar probe --format=json` for all 32 pinned candidates. It uses the isolated Rust worker and reports unqualified observations with exit 3, not a lint or delivery verdict. Successful observations and input failures for a valid language share the [closed 0.1.0 JSON schema](../schemas/grammar-probe-v0.1.schema.json) and remain incomplete. Native-first `lint/check`, language/dialect acceptance, task/host feedback and distribution remain separate open work; current discovery also groups JavaScript/TSX under TypeScript and has no separate CFQuery/CFScript source mapping. + +The source-built `check all` now runs a bounded candidate pass after its existing native checks. A separate [grammar router](../crates/codeguard-cli/src/grammar_route.rs) distinguishes `.tsx`, JavaScript, and `.cfs`; complete `...` bodies are parsed with CFQuery, while ordinary `.sql` and ambiguous `.h` are not guessed. Four bounded real CLI fixtures collectively invoked all 32 pinned workers. [Check feedback 0.33.0](../schemas/check-feedback.schema.json) records selected dialect, source/grammar digests, file-relative recovery positions, skipped work and incomplete status; Python files with completed, source-matched Ruff scans skip duplicate WASM; style-only P3C does not confirm syntax. Candidate observations never become confirmed violations or delivery permission. The pass has a 64-file/64-fragment/90-second cap and was about 54 seconds for four bounded fixtures on this Mac; a single 31-file Linux run observed 26/32 before its 90-second cap. It is a partial candidate route, not a qualified native fallback, task/host integration or released npm capability. See [acceptance evidence](../tests/acceptance/check-all-32-grammar-candidates.md). + +```mermaid +flowchart LR + A[check all discovery] --> B[Native adapters and blockers] + B --> C[Source and scope recheck] + C -->|stable| D[Dialect router] + C -->|changed| G[Incomplete report] + D --> E[Selected isolated WASM worker] + E --> F[Unqualified observations] + B --> G + F --> G +``` + +A first narrow native-first route is now available for Zig: `lint zig FILE --zig-tool ABS_PATH --format=json` runs a Zig 0.16.0 `ast-check` executable with stable bytes on the selected source bytes before considering WASM. Native AST positions remain visible without source snippets; when no explicit tool is supplied, the pinned Zig grammar remains an unqualified fallback. Both outcomes stay incomplete because AST checking is narrower than full lint, build and tests. See the [0.1.0 feedback schema](../schemas/zig-lint-feedback-v0.1.schema.json). ## 2. Architectural drivers @@ -241,9 +259,9 @@ A completed native violation never selects fallback to obtain a clean result. A Reuse pinned CodeGraph grammar WASM artifacts and applicable upstream licenses, source references, patches and corpus cases. Do not copy CodeGraph's graph extraction or source-blanking heuristics into a syntax verdict. CodeGraph's `src/extraction/grammars.ts` loads language artifacts through `web-tree-sitter`; successful loading there does not prove compatibility with Codeguard's Rust runtime. The local source review on 2026-09-28 found modified grammar artifacts and about 65 MB of grammar files, so a live directory is not a release input. -The read-only `codeguard grammar status` command projects a [pinned CodeGraph coverage inventory](../grammars/codegraph-coverage.json): 30 vendored WASM files and two dependency-provided grammars. CodeGuard currently pins 23 Rust-loadable candidates, including ArkTS, Nix and Terraform; none is qualified for release. ArkTS, Nix and Terraform provenance and worker evidence are recorded in the [candidate acceptance](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). ArkTS, Nix and Terraform have pinned bytes, licenses and narrow Rust worker evidence, but no public lint route or release qualification; see the [limited acceptance record](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The corrected Zig source WASM requires a pinned import adaptation to load in Rust; public `lint zig` and language qualification remain open. Python has a narrow source-build-only fallback for unavailable or undeclared Ruff, with native results taking priority and no delivery approval. An initialized single-file scope now syncs one stable native-confirmation task; candidate zero recoveries do not close it. This inventory is deliberately separate from the pinned [candidate asset manifest](../grammars/manifest.json). In particular, the COBOL source file exceeds the current loader's 8 MiB input limit. Inventory rows never trigger loading or count as supported parser capability. +The read-only `codeguard grammar status` command projects a [pinned CodeGraph coverage inventory](../grammars/codegraph-coverage.json): 30 vendored WASM files and two dependency-provided grammars. CodeGuard currently pins 32 Rust-loadable candidates, including ArkTS, Nix and Terraform; none is qualified for release. ArkTS, Nix and Terraform provenance and worker evidence are recorded in the [candidate acceptance](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). ArkTS, Nix and Terraform have pinned bytes, licenses and narrow Rust worker evidence, but no language-qualified standalone lint route or release qualification; see the [limited acceptance record](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The corrected Zig source WASM requires a pinned import adaptation to load in Rust; public `lint zig` and language qualification remain open. Python has a narrow source-build-only fallback for unavailable or undeclared Ruff, with native results taking priority and no delivery approval. An initialized single-file scope now syncs one stable native-confirmation task; candidate zero recoveries do not close it. This inventory is deliberately separate from the pinned [candidate asset manifest](../grammars/manifest.json). COBOL now loads under a bounded 20 MiB input limit, but its cold-start and memory budget remain unqualified. Inventory rows never trigger loading or count as supported parser capability. -R, Ruby, PHP and Kotlin now also have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow positive/negative worker samples; the PHP fixture covers mixed HTML/PHP. They remain unqualified candidates. The original CodeGraph Dart WASM remains incompatible with Rust, but CodeGuard now has a byte-reproducible Zig rebuild that compiles the real external scanner and uses a pinned WASI import adaptation. Rust loader and isolated-worker fixtures pass; Dart remains unqualified for public lint and release. See the [Dart rebuild record](../tests/acceptance/dart-grammar-rebuild-candidate.md). +R, Ruby, PHP and Kotlin now also have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow positive/negative worker samples; the PHP fixture covers mixed HTML/PHP. They remain unqualified candidates. The original CodeGraph Dart WASM remains incompatible with Rust, but CodeGuard now has a byte-reproducible Zig rebuild that compiles the real external scanner and uses a pinned WASI import adaptation. Rust loader and isolated-worker fixtures pass; Dart remains unqualified for public lint and release. See the [Dart rebuild record](../tests/acceptance/dart-grammar-rebuild-candidate.md). Erlang also has pinned CodeGraph bytes, upstream 0.19 license and ABI 14 with narrow Rust and worker samples. It has no qualified native comparison or public lint route; see the [Erlang candidate record](../tests/acceptance/erlang-grammar-candidate.md). Pascal now has pinned CodeGraph bytes and its original Isopod dependency commit and license; ABI 14 and narrow worker tests pass, but native comparison and public lint remain open. See the [Pascal candidate record](../tests/acceptance/pascal-grammar-candidate.md). The remaining CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET assets also load in the Rust worker, bringing the candidate inventory to 32/32 with zero released syntax capabilities. CFQuery misses `SELECT FROM`, VB.NET misparses a valid unindented method, and COBOL has a high load cost; see the [seven-asset acceptance record](../tests/acceptance/final-seven-grammar-candidates.md). ```text grammars/ # proposed release assets, not project state diff --git a/docs/Codeguard-Architecture.zh_CN.md b/docs/Codeguard-Architecture.zh_CN.md index 8595a64a..94f409ec 100644 --- a/docs/Codeguard-Architecture.zh_CN.md +++ b/docs/Codeguard-Architecture.zh_CN.md @@ -28,7 +28,25 @@ | [核心聚合](../crates/codeguard-core/src/aggregate.rs)、[交付门禁](../crates/codeguard-core/src/delivery_gate.rs) | 纯结果语义,不代表公开可信门禁已可用 | | [验收记录](../tests/acceptance) | 限定范围的观察、测试方法和剩余缺口 | -WASM 的规范与 19 项实施任务已纳入既有 change;可选 Rust worker 与 Java/TypeScript/TSX 局部单文件反馈路径及 Python Ruff 不可用时的候选路径已存在;二十三份候选 grammar 都尚未验收;ArkTS、C、C++、C#、Go、JavaScript、Lua、Luau、Nix、Rust、Terraform、Zig、Objective-C、Solidity、R、Ruby、PHP、Kotlin、Dart 仅有固定字节的 Rust 可加载候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收、任务的能力匹配关闭及宿主接线仍未完成;设计示例不是当前命令输出。 +WASM 的规范与 19 项实施任务已纳入既有 change;可选 Rust worker 与 Java/TypeScript/TSX 局部单文件反馈路径及 Python Ruff 不可用时的候选路径已存在;三十二份候选 grammar 都尚未验收;ArkTS、C、C++、C#、Go、JavaScript、Lua、Luau、Nix、Rust、Terraform、Zig、Objective-C、Solidity、R、Ruby、PHP、Kotlin、Dart、Erlang、Pascal、CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 仅有固定字节的 Rust 可加载候选资产,尚无逐语言验收的独立 lint 路由。项目级原生优先调度、grammar 版本范围验收、任务的能力匹配关闭及宿主接线仍未完成;设计示例不是当前命令输出。 + +源码以 `--features wasm-precheck` 构建后,可通过 `codeguard grammar probe --format=json` 显式调用全部 32 份固定候选资产。命令使用隔离 Rust worker,以退出码 3 报告未经语言验收的观察,不能作为 lint 或交付结论。成功观察与有效语种的输入失败都遵守[0.1.0 封闭 JSON Schema](../schemas/grammar-probe-v0.1.schema.json),保持未完成。原生优先 `lint/check`、语言/方言验收、任务/宿主反馈及发行仍需独立完成;现有发现清单还把 JavaScript/TSX 归入 TypeScript,并未为 CFQuery/CFScript 建立独立源码映射。 + +源码构建的 `check all` 现会在既有原生检查之后执行有界候选初检。[语法路由](../crates/codeguard-cli/src/grammar_route.rs)区分 `.tsx`、JavaScript 和 `.cfs`,只对完整的 `...` 标签体选用 CFQuery;普通 `.sql`、有歧义的 `.h` 不猜测语种。四个有界真实 CLI 样例合计逐份调用了 32 种固定 worker。[检查反馈 0.33.0](../schemas/check-feedback.schema.json)记录方言、源码及 grammar 摘要、原文件位置、未执行范围和未完成状态;Ruff 本轮完整检查且摘要匹配的 Python 文件跳过重复 WASM;P3C 等规范检查不视为语法确认。候选观察不生成已确认违规或交付许可。候选阶段限 64 文件、64 片段、90 秒,本机四批 32 语种样例约 54 秒;Linux 单次 31 文件检查在 90 秒上限内完成 26/32。当前只是候选路由,尚非逐语言验收的原生兜底、任务/宿主接线或已发布 npm 能力;见[验收记录](../tests/acceptance/check-all-32-grammar-candidates.md)。 + +```mermaid +flowchart LR + A[check all 静态发现] --> B[原生适配器及环境阻塞] + B --> C[源码及范围复核] + C -->|稳定| D[方言路由] + C -->|已变化| G[未完成报告] + D --> E[选中的隔离 WASM worker] + E --> F[未验收候选观察] + B --> G + F --> G +``` + +首个局部原生优先入口为 Zig:`lint zig FILE --zig-tool ABS_PATH --format=json` 对选定源码字节先运行版本报告为 Zig 0.16.0 且字节保持一致的 `ast-check`;原生错误只暴露行列位置,不回显源码。未提供显式工具时,固定 Zig grammar 作为未验收候选兜底。两种结果都保持未完成,因为 AST 检查范围小于完整 lint、构建和测试;见 [0.1.0 报告 Schema](../schemas/zig-lint-feedback-v0.1.schema.json)。 ## 2. 架构驱动 @@ -241,9 +259,9 @@ flowchart TD 复用固定版本的 CodeGraph grammar WASM,以及适用的上游许可证、源码引用、补丁和语料。不能把 CodeGraph 的图提取或源码遮盖启发式直接用于语法判定。CodeGraph 的 `src/extraction/grammars.ts` 通过 `web-tree-sitter` 加载语言资产,在那里可加载不证明兼容 Codeguard 的 Rust 运行时。发行时必须固定不可变的来源与资产清单,不能把正在修改的本地目录直接当作发行输入。 -只读 `codeguard grammar status` 现投影[固定来源覆盖库存](../grammars/codegraph-coverage.json):CodeGraph 随仓 30 份 WASM,依赖提供另两种独立 grammar;CodeGuard 有 C、C++、C#、Go、Java、JavaScript、Lua、Luau、Objective-C、Python、Rust、Solidity、TypeScript、TSX、Zig、ArkTS、Nix、Terraform、R、Ruby、PHP、Kotlin、Dart 二十三份资产候选。C、C++、C#、Go、JavaScript、Lua、Luau、Rust 的 CodeGraph 随仓字节及上游标签许可证已固定,可由 Rust worker 解析基础正反例,但尚未进行语言验收或公开 lint 接线。ArkTS、Nix、Terraform 的来源、许可证、字节及 Rust 正反例也已固定,仅为候选,尚无公开 lint 路由或发行验收;见[局部验收](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md)。Objective-C 与 Solidity 来自锁定的 `tree-sitter-wasms@0.1.13`,保留原始字节和许可证,并以固定散列的 `dylink` 元数据转换加载;仍未做语言验收与发行。Zig 新版来源 WASM 的导入经固定哈希适配后由 Rust 加载,但仍无公开 `lint zig` 路由,尚无已验收发行能力。Python 已有源码可选构建中的局部 `lint` 兜底,仅覆盖 Ruff 不可用或项目未声明配置的情形;原生结果优先且不能批准交付。已初始化工作区的单文件范围可同步稳定的原生确认任务;候选零恢复节点不会关闭任务。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。尤其 COBOL 来源资产超过当前加载器 8 MiB 限额。 +只读 `codeguard grammar status` 现投影[固定来源覆盖库存](../grammars/codegraph-coverage.json):CodeGraph 随仓 30 份 WASM,依赖提供另两种独立 grammar;CodeGuard 有 C、C++、C#、Go、Java、JavaScript、Lua、Luau、Objective-C、Python、Rust、Solidity、TypeScript、TSX、Zig、ArkTS、Nix、Terraform、R、Ruby、PHP、Kotlin、Dart、Erlang、Pascal、CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 三十二份资产候选。C、C++、C#、Go、JavaScript、Lua、Luau、Rust 的 CodeGraph 随仓字节及上游标签许可证已固定,可由 Rust worker 解析基础正反例,但尚未进行语言验收或公开 lint 接线。ArkTS、Nix、Terraform 的来源、许可证、字节及 Rust 正反例也已固定,仅为候选,尚无逐语言验收的独立 lint 路由或发行验收;见[局部验收](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md)。Objective-C 与 Solidity 来自锁定的 `tree-sitter-wasms@0.1.13`,保留原始字节和许可证,并以固定散列的 `dylink` 元数据转换加载;仍未做语言验收与发行。Zig 新版来源 WASM 的导入经固定哈希适配后由 Rust 加载,已有局部 `lint zig` 原生优先候选入口,但尚无已验收发行能力。Python 已有源码可选构建中的局部 `lint` 兜底,仅覆盖 Ruff 不可用或项目未声明配置的情形;原生结果优先且不能批准交付。已初始化工作区的单文件范围可同步稳定的原生确认任务;候选零恢复节点不会关闭任务。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。COBOL 现可在 20 MiB 输入限额下加载,但冷启动与内存预算未验收。 -R、Ruby、PHP、Kotlin 也已固定 CodeGraph 字节、许可证和 Rust 实测 ABI,并通过隔离 worker 的窄范围正反例;PHP 样例覆盖 HTML/PHP 混合内容,仍仅为未验收候选。CodeGraph 原 Dart WASM 仍不能由 Rust 直接加载;CodeGuard 现以固定上游 C 源码和真实外部 scanner 经 Zig 可重复构建,再做固定 WASI 导入适配。Rust 加载与隔离 worker 的窄范围测试通过,但公开 lint 与发行仍未验收;见[Dart 重建局部验收](../tests/acceptance/dart-grammar-rebuild-candidate.md)。 +R、Ruby、PHP、Kotlin 也已固定 CodeGraph 字节、许可证和 Rust 实测 ABI,并通过隔离 worker 的窄范围正反例;PHP 样例覆盖 HTML/PHP 混合内容,仍仅为未验收候选。CodeGraph 原 Dart WASM 仍不能由 Rust 直接加载;CodeGuard 现以固定上游 C 源码和真实外部 scanner 经 Zig 可重复构建,再做固定 WASI 导入适配。Rust 加载与隔离 worker 的窄范围测试通过,但公开 lint 与发行仍未验收;见[Dart 重建局部验收](../tests/acceptance/dart-grammar-rebuild-candidate.md)。Erlang 也已固定 CodeGraph 字节、上游 0.19 许可证及 ABI 14,Rust 与隔离 worker 的窄范围样例通过;原生对照和公开 lint 路由尚缺,见[Erlang 候选局部验收](../tests/acceptance/erlang-grammar-candidate.md)。Pascal 已固定 CodeGraph 字节、原始 Isopod 依赖提交和许可证,ABI 14 及窄范围 worker 样例通过;原生对照和公开 lint 尚缺,见[Pascal 候选局部验收](../tests/acceptance/pascal-grammar-candidate.md)。其余七份 CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET 来源 WASM 也已固定并由 Rust worker 加载,累计 32/32 份候选、0 项已发行。CFQuery 漏掉 `SELECT FROM`,VB.NET 对合法未缩进方法体误报,COBOL 成本高;都不能发布为 lint,见[七份局部验收](../tests/acceptance/final-seven-grammar-candidates.md)。 ```text grammars/ # 规划中的发行资产,不是项目状态 diff --git a/docs/Codeguard-Command-Reference.md b/docs/Codeguard-Command-Reference.md index 3010698f..c5df332a 100644 --- a/docs/Codeguard-Command-Reference.md +++ b/docs/Codeguard-Command-Reference.md @@ -12,6 +12,8 @@ Current slices include static discovery/init, selected native checks, partial ag The opt-in `codeguard-cli/wasm-precheck` build adds narrow `lint typescript ` and `lint java ` paths when no explicit native execution context is provided. TypeScript first recognizes an ordinary project-local ESLint 10 entry and one flat config, then uses an executable Node from `PATH` to run the existing bounded native probe; when Node is unresolved, it reports setup instead of starting WASM. Only when no project-local ESLint package is observed does it return [TypeScript feedback 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json) or TSX 0.4.0 candidate feedback. Untrusted local paths, package identity or config selection remain setup blockers. Java returns [Java feedback 0.1.0](../schemas/java-syntax-precheck-feedback-v0.1.schema.json). These paths retain exit 3 and never turn an unvalidated grammar or local native observation into delivery approval. Default/published binaries retain the existing native-context behavior. See [native-first acceptance](../tests/acceptance/native-first-eslint-candidate.md). +The same source build also adds a bounded `syntax_candidates` pass to `check all` after its native nodes. [Feedback 0.33.0](../schemas/check-feedback.schema.json) keeps all 32 pinned grammars callable through bounded uses of the unified command while preserving native blockers, skipped scope and an incomplete verdict; source-matched Python files completed by Ruff count under `native_preferred_count` and skip duplicate WASM; `.tsx`, JavaScript, `.cfs` and explicit CFQuery tag bodies use distinct routes. This is candidate observation, not language-qualified native fallback or published package support. See [32-grammar acceptance](../tests/acceptance/check-all-32-grammar-candidates.md). + With `--workspace` pointing to an initialized, canonical workspace, the TypeScript/TSX fallback emits [feedback 0.5.0](../schemas/eslint-local-feedback-v0.5.schema.json). It saves one source-scoped ESLint native-confirmation blocker and returns its real `setup.task_id` only after successful sync. Repeated scans and a later WASM result with no recovery nodes keep that task open; a versioned local report now links bounded suspected positions to that task through its report digest, while capability-matched native verification remains unfinished. See the [workbench acceptance record](../tests/acceptance/typescript-syntax-confirmation-task.md). `codeguard hook plan [--format=json]` is a current, read-only host-event bridge. It reads a bounded [1.0 request](../schemas/hook-trigger-request.schema.json) from stdin and returns a [1.1 candidate tier](../schemas/hook-trigger-plan-v1.1.schema.json) with exit 3, `execution=not_run` and `delivery_decision=not_evaluated`. A confirmed edit may request fast file checks for at most eight distinct paths, 512 bytes per path and 2 KiB combined; an over-budget event instead requests scope resolution with `fast_scope_budget_exceeded`, without silently dropping files. This is a signal to select a bounded batch check, not to resubmit the same list forever. It does not invoke a checker, take a Git snapshot or block any host. The earlier [1.0 response schema](../schemas/hook-trigger-plan.schema.json) remains available for historical readers. See the [CLI acceptance record](../tests/acceptance/hook-plan-cli-candidate.md). @@ -20,7 +22,7 @@ A separate Python execution slice now accepts `codeguard lint python . --file sr The current partial execution entry is `codeguard hook execute PATH --timeout DURATION --format=json [--ruff-tool ABS_PATH] [--git-tool ABS_PATH]`, reading the same 1.0.0 `hook_trigger_request` from stdin. The explicit timeout is capped at 120 seconds. Session start only discovers; Stop reads at most 64 findings and 64 reports with an 8 MiB report-byte budget and returns `hook_next_guidance` without running a checker. An oversized backlog returns `not_run/guidance_scope_exceeded`; use `codeguard next PATH --format=json` explicitly. An empty task list recommends a fresh full check, never a pass. `repair_ready` first bounds one task history to 128 events and 1 MiB, then verifies an existing stable task through the same `task verify` implementation in a bounded child process; a missing task, oversized history or failed child remains incomplete. Only task/checker identity, observation, saved-event state and a bounded reason are projected back, while the full native report stays in the existing local verification path. Explicit tool options supported by `task verify` may be passed to `hook execute`; they are rejected on unrelated events. A confirmed Python-only edit runs local Ruff. With an explicit Git binary, `pre_commit` reads the current staged index, including an alternate `GIT_INDEX_FILE`; the Git observation itself is bounded by the lesser of the supplied timeout and 15 seconds. Its `hook_git_index_summary` reports index identity, total violation count, at most 32 paths of at most 512 bytes each, truncation and object status while `source_check=not_run`; it cannot prove full quality coverage. Missing Git or failed index observation is `not_run`. Failed or uncertain writes, mixed languages, push and CI also remain `not_run`. The outer `hook_execution_feedback` is now 0.5; historical 0.1–0.4 schemas are preserved. `prompt_submitted` returns constant `read_only_intent_guidance` with no source check or delivery verdict. `host_blocking_verified=false` and `delivery_decision=not_evaluated` remain fixed even if the host claims blocking. No plugin Hook invokes this entry automatically yet; it is not a strict gate. -Current `detect` 0.4.0 reports local ESLint and Maven Wrapper candidates separately from checker configuration. It skips `node_modules` during ordinary source discovery while observing fixed tool paths without following links. A candidate never means the native tool was executed or approved; `check_feedback` carries this discovery under version 0.31.0. +Current `detect` 0.4.0 reports local ESLint and Maven Wrapper candidates separately from checker configuration. It skips `node_modules` during ordinary source discovery while observing fixed tool paths without following links. A candidate never means the native tool was executed or approved; `check_feedback` carries this discovery under version 0.33.0. The candidate Claude Code soft adapter is `codeguard hook claude PATH --timeout DURATION --format=json [--ruff-tool ABS_PATH]`. It reads at most 1 MiB of host JSON on stdin and validates the event name and working directory. SessionStart does read-only discovery; UserPromptSubmit returns constant non-blocking timing guidance without inspecting prompt text or running a checker; successful Write/Edit/MultiEdit accepts only a regular file under the chosen project root and calls the same Rust local executor; PostToolUseFailure runs the no-check route without echoing the tool error. Stop reads bounded local facts, never a checker or editable task Markdown. A stable task on an initial Stop yields one `hookSpecificOutput.additionalContext` continuation; an already active Stop or no task returns `systemMessage` only, avoiding repeated wakeups. Context is bounded to 1200 characters for local edit feedback, and host exit 0 does not mean a check passed. Duplicate keys, oversized input, missing or escaping paths and mismatched events yield explicit unrun feedback. The separate plugin does not invoke this candidate yet. See the [candidate acceptance record](../tests/acceptance/claude-post-tool-hook-candidate.md). diff --git a/docs/Codeguard-Command-Reference.zh_CN.md b/docs/Codeguard-Command-Reference.zh_CN.md index a259f7ef..7470c177 100644 --- a/docs/Codeguard-Command-Reference.zh_CN.md +++ b/docs/Codeguard-Command-Reference.zh_CN.md @@ -13,7 +13,7 @@ | help/version/detect/capabilities | 有公开查询;`help COMMAND` 不是当前通用子帮助能力 | | init/config/rules/plan/tools | 局部观察/预览;init apply 为 partial,安装 apply 写入前阻塞 | | doctor | 当前 `doctor [path] --ruff-tool ...`,不是目标 `doctor all .` 的完整多工具形式;已可保存/同步局部准备报告 | -| lint | python/java/typescript/go 有局部入口;没有公开 lint rust,Clippy 通过 check all | +| lint | python/java/typescript/go 与源码可选构建的 Zig 有局部入口;没有公开 lint rust,Clippy 通过 check all | | comments/build | 当前公开 rust;Java Javadoc 走 `lint java FILE --checker javadoc`,不是 comments java | | cve/check | rust/python/typescript CVE 与 check all/java;完整策略和交付仍未评估 | | 工作台 | sync/status/next/show/lease/attempt/部分 verify;不正式关闭、重开或自批 | @@ -22,6 +22,8 @@ [已验收实现切片](../openspec/changes/introduce-rust-codeguard-cli/implementation-baseline.md)跟踪当前局部能力;[tasks](../openspec/changes/introduce-rust-codeguard-cli/tasks.md)独占完成状态。WASM 的完整统一入口仍为 S14 待办。可选 `codeguard-cli/wasm-precheck` 构建处理 `lint typescript <显式单文件>` 时,若观察到本地 ESLint 10 入口与唯一 flat config,会优先用 `PATH` 中可执行 Node 调用既有有界原生探针;缺 Node 则返回准备缺口。仅未观察到本地 ESLint 包时才输出 [TypeScript 0.3.0 候选反馈](../schemas/eslint-local-feedback-v0.3.schema.json)或 TSX 0.4.0。本地入口、包身份或配置不可信时保留具体环境阻塞,不启动 WASM。`lint java <显式单文件>` 仍输出 [Java 0.1.0 候选反馈](../schemas/java-syntax-precheck-feedback-v0.1.schema.json)。这些局部路径均不批准交付并保持退出 3;部分显式参数、Javadoc/Checkstyle 和符号链接沿用原路径,默认及已发布二进制也不含这项自动调度。见[原生优先局部验收](../tests/acceptance/native-first-eslint-candidate.md)与技术方案 5.3–5.4;后文未标当前的语法、退出0/1与闭环承诺均为目标契约。 +同一源码构建现在也会在 `check all` 的原生节点之后输出有界 `syntax_candidates`。[反馈 0.33.0](../schemas/check-feedback.schema.json)让 32 份固定 grammar 均能经统一入口分批被选用,同时保留原生阻塞、未执行范围和未完成结论;Ruff 已完整覆盖的同摘要 Python 文件计入 `native_preferred_count`,不重复运行 WASM;`.tsx`、JavaScript、`.cfs` 与明确的 CFQuery 标签体分别路由。这仍是候选观察,不等于逐语言验收的原生兜底或已发布包能力,见[32 份验收](../tests/acceptance/check-all-32-grammar-candidates.md)。 + 对已初始化且使用规范绝对路径的 `--workspace`,TypeScript/TSX 候选回退改用[反馈 0.5.0](../schemas/eslint-local-feedback-v0.5.schema.json):按源码范围保存同一张 ESLint 原生确认阻塞任务,仅同步成功时返回真实 `setup.task_id`。重复扫描和后续 WASM 无恢复节点不关闭任务。版本化本地报告已通过报告摘要关联有界疑似位置;能力匹配原生复检仍未接通,见[局部验收](../tests/acceptance/typescript-syntax-confirmation-task.md)。 ## 1. 命令体系与协作路线 diff --git a/docs/Codeguard-Technical-Design.md b/docs/Codeguard-Technical-Design.md index efaf2c11..665980e2 100644 --- a/docs/Codeguard-Technical-Design.md +++ b/docs/Codeguard-Technical-Design.md @@ -14,7 +14,11 @@ The existing [OpenSpec change](../openspec/changes/introduce-rust-codeguard-cli/ Current source is the authority for callable behavior. Target contracts are labelled as such. The product priority is configuration discovery → native results → useful repair guidance. Internal consistency checks support this experience; they are not a demand for users to manually construct execution certificates. -WASM requirements and 19 implementation tasks are recorded in the existing change. Candidate Rust worker and narrow Java/TypeScript/TSX single-file reports and a Python Ruff-unavailable candidate report now exist behind an opt-in feature; all twenty-three candidate grammars remain unqualified; ArkTS, C, C++, C#, Go, JavaScript, Lua, Luau, Nix, Rust, Terraform, Zig, Objective-C, Solidity, R, Ruby, PHP, Kotlin and Dart are only Rust-loadable candidates. Project-wide native-first routing, qualified grammar ranges, and host integrations remain incomplete. Design examples are not current command output. +WASM requirements and 19 implementation tasks are recorded in the existing change. Candidate Rust worker and narrow Java/TypeScript/TSX single-file reports and a Python Ruff-unavailable candidate report now exist behind an opt-in feature; all thirty-two candidate grammars remain unqualified; ArkTS, C, C++, C#, Go, JavaScript, Lua, Luau, Nix, Rust, Terraform, Zig, Objective-C, Solidity, R, Ruby, PHP, Kotlin, Dart, Erlang, Pascal, CFML, CFQuery, CFScript, COBOL, Scala, Swift and VB.NET are only Rust-loadable candidates. Project-wide native-first routing, qualified grammar ranges, and host integrations remain incomplete. Design examples are not current command output. + +A source build with `--features wasm-precheck` now exposes `codeguard grammar probe --format=json` for all 32 pinned candidates. It uses the isolated Rust worker and reports unqualified observations with exit 3, not a lint or delivery verdict. Successful observations and input failures for a valid language share the [closed 0.1.0 JSON schema](../schemas/grammar-probe-v0.1.schema.json) and remain incomplete. Native-first `lint/check`, language/dialect acceptance, task/host feedback and distribution remain separate open work; current discovery also groups JavaScript/TSX under TypeScript and has no separate CFQuery/CFScript source mapping. + +A first narrow native-first route is now available for Zig: `lint zig FILE --zig-tool ABS_PATH --format=json` runs a Zig 0.16.0 `ast-check` executable with stable bytes on the selected source bytes before considering WASM. Native AST positions remain visible without source snippets; when no explicit tool is supplied, the pinned Zig grammar remains an unqualified fallback. Both outcomes stay incomplete because AST checking is narrower than full lint, build and tests. See the [0.1.0 feedback schema](../schemas/zig-lint-feedback-v0.1.schema.json). ## 2. Technology choices and trade-offs @@ -185,15 +189,38 @@ When some files have suspected issues and others are unresolved, use overall `in These are the target semantic fields, not a shipped project-wide lint/check report. A narrow [candidate precheck schema](../schemas/syntax-precheck-candidate.schema.json) and [strict Rust reader](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs) bind source SHA-256, pinned grammar identity and file dialect, recalculate status, and reject unknown versions or forged `clean`. Optional CLI single-file [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json), [TSX](../schemas/eslint-local-feedback-v0.4.schema.json) and [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) producers include recovery positions and setup guidance. With an initialized workspace, TypeScript/TSX now uses [feedback 0.5.0](../schemas/eslint-local-feedback-v0.5.schema.json) and attaches one stable native-confirmation task to the source scope; the [0.2.0 preparation report](../schemas/eslint-preparation-observation-v0.2.schema.json) stores bounded suspected positions with source and grammar identities and links them by digest to the task. Host rendering and capability-matched native closure remain absent. The bundled grammars remain unvalidated, so these reports cannot return `clean`. Missing required native execution remains incomplete (`3`); a suspected parser issue alone is not a confirmed violation (`1`). If a dedicated syntax-only operation is later introduced, its success must be explicitly scoped to syntax; no new `syntax` command is claimed here. +The source-built `check all` now adds a narrower actual project report: native adapters run first, then a [bounded source router](../crates/codeguard-cli/src/check_syntax_candidates.rs) selects pinned worker candidates. The closed [0.33.0 schema](../schemas/check-feedback.schema.json) counts files preempted by native checks; [0.32.0](../schemas/check-feedback-v0.32.schema.json) remains archived for older readers. Only a completed Ruff scan of matching Python source bytes skips duplicate WASM. A style checker such as P3C is not syntax confirmation. The following is an excerpt, not a complete `check_feedback` instance: + +```json +{ + "schema_version": "0.33.0", + "command_status": "incomplete", + "delivery_decision": "incomplete", + "syntax_candidates": { + "status": "observed_partial", + "execution_phase": "after_native", + "authority": "candidate_unqualified", + "delivery_decision": "incomplete", + "native_preferred_count": 1, + "observations": [ + {"path": "src/view.tsx", "language": "tsx", "status": "candidate_observed", "grammar_qualified": false, "recovery_count": 0} + ], + "next_action": "Run the applicable native checker before delivery" + } +} +``` + +The actual report also includes native results, source/grammar digests, fragment offsets, bounded file-relative recovery anchors, skipped counts and unresolved obligations. A complete `` tag body is an embedded candidate; ordinary SQL or ambiguous C/C++ headers are not guessed. Four bounded 32-grammar CLI fixtures took about 54 seconds on this Mac; a single 31-file Linux run completed 26/32 within 90 seconds; language-version corpora, native differential checks, task synchronization, host delivery and package release are still open. + The opt-in CLI build first checks for a local ESLint 10 package and a single ordinary flat config on single-file TypeScript requests without explicit native context. With an executable Node resolved from `PATH`, it invokes the existing bounded native version/report probe; without Node it reports the preparation gap rather than running WASM first. Only when no project-local ESLint package is observed does the CLI emit [ESLint feedback 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json) for `.ts/.mts/.cts` or [0.4.0](../schemas/eslint-local-feedback-v0.4.schema.json) for `.tsx`. TSX uses its own pinned grammar. Candidate prechecks preserve `native=not_run` and `delivery=not_evaluated`, and remain incomplete even with zero recoveries. An ambiguous config, untrusted local path or invalid package identity remains a setup blocker and does not trigger WASM; a partial explicit context also retains its existing path. This is a single-file slice, not project script equivalence, per-module orchestration or automatic host feedback; see the [native-first acceptance](../tests/acceptance/native-first-eslint-candidate.md). ### 5.4 Grammar import and runtime lifecycle — target Import only pinned WASM bytes with upstream license, commit/patch provenance, SHA-256, ABI, tested runtime and language/dialect ranges, corpus reference and known gaps. Verify each copied CodeGraph artifact in the selected Rust Tree-sitter runtime; do not copy TypeScript extraction logic or assume CodeGraph support equals syntax acceptance. A release manifest belongs to distribution assets, not writable `.codeguard/` project state. -Use `codeguard grammar status --format=json` to query the separate source coverage inventory. It reports 32 distinct CodeGraph grammar assets, twenty-three CodeGuard asset candidates (ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin and Dart), and zero released capabilities without running a parser. Python has a narrow source-build-only `lint` fallback for unavailable or undeclared Ruff, never a clean or delivery result. A bound, single-file result uses [feedback 0.15.0](../schemas/python-lint-feedback-v0.15.schema.json) and persists a [0.1.0 confirmation observation](../schemas/python-syntax-confirmation-observation-v0.1.schema.json) through the existing work sync. The task identity binds workspace and source scope; current-source SHA-256 and pinned grammar are checked before import. Native capability-matched closure remains open. C, C++, C#, Go, JavaScript, Lua, Luau and Rust have pinned vendored bytes and narrow Rust worker smoke tests, but no public lint route or language qualification. ArkTS, Nix and Terraform have pinned bytes, licenses and narrow Rust worker evidence, but no public lint route or release qualification; see the [limited acceptance record](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The two dependency-provided assets now have pinned original and adapted bytes plus license references, but are still unqualified candidates without public lint routes. COBOL exceeds the current 8 MiB loader limit. +Use `codeguard grammar status --format=json` to query the separate source coverage inventory. It reports 32 distinct CodeGraph grammar assets, thirty-two CodeGuard asset candidates (ArkTS, C, C++, C#, Go, Java, JavaScript, Lua, Luau, Objective-C, Python, Rust, Solidity, TypeScript, TSX, Zig, Nix, Terraform, R, Ruby, PHP, Kotlin, Dart, Erlang, Pascal, CFML, CFQuery, CFScript, COBOL, Scala, Swift and VB.NET), and zero released capabilities without running a parser. Python has a narrow source-build-only `lint` fallback for unavailable or undeclared Ruff, never a clean or delivery result. A bound, single-file result uses [feedback 0.15.0](../schemas/python-lint-feedback-v0.15.schema.json) and persists a [0.1.0 confirmation observation](../schemas/python-syntax-confirmation-observation-v0.1.schema.json) through the existing work sync. The task identity binds workspace and source scope; current-source SHA-256 and pinned grammar are checked before import. Native capability-matched closure remains open. C, C++, C#, Go, JavaScript, Lua, Luau and Rust have pinned vendored bytes and narrow Rust worker smoke tests, but no language-qualified standalone lint route or language qualification. ArkTS, Nix and Terraform have pinned bytes, licenses and narrow Rust worker evidence, but no language-qualified standalone lint route or release qualification; see the [limited acceptance record](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md). The two dependency-provided assets now have pinned original and adapted bytes plus license references, but are still unqualified candidates without language-qualified lint routes. COBOL now loads under a bounded 20 MiB input limit, but cold-start and memory budgets remain unqualified. -R, Ruby, PHP and Kotlin now also have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow positive/negative worker samples; the PHP fixture covers mixed HTML/PHP. They remain unqualified candidates. The original CodeGraph Dart WASM remains incompatible with Rust, but CodeGuard now has a byte-reproducible Zig rebuild that compiles the real external scanner and uses a pinned WASI import adaptation. Rust loader and isolated-worker fixtures pass; Dart remains unqualified for public lint and release. See the [Dart rebuild record](../tests/acceptance/dart-grammar-rebuild-candidate.md). +R, Ruby, PHP and Kotlin now also have pinned CodeGraph bytes, licenses, measured Rust ABI and narrow positive/negative worker samples; the PHP fixture covers mixed HTML/PHP. They remain unqualified candidates. The original CodeGraph Dart WASM remains incompatible with Rust, but CodeGuard now has a byte-reproducible Zig rebuild that compiles the real external scanner and uses a pinned WASI import adaptation. Rust loader and isolated-worker fixtures pass; Dart remains unqualified for public lint and release. See the [Dart rebuild record](../tests/acceptance/dart-grammar-rebuild-candidate.md). Erlang also has pinned CodeGraph bytes, upstream 0.19 license and ABI 14 with narrow Rust and worker samples. It has no qualified native comparison or public lint route; see the [Erlang candidate record](../tests/acceptance/erlang-grammar-candidate.md). Pascal now has pinned CodeGraph bytes and its original Isopod dependency commit and license; ABI 14 and narrow worker tests pass, but native comparison and public lint remain open. See the [Pascal candidate record](../tests/acceptance/pascal-grammar-candidate.md). The remaining CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET assets also load in the Rust worker, bringing the candidate inventory to 32/32 with zero released syntax capabilities. CFQuery misses `SELECT FROM`, VB.NET misparses a valid unindented method, and COBOL has a high load cost; see the [seven-asset acceptance record](../tests/acceptance/final-seven-grammar-candidates.md). Use a parent-controlled parser worker with a total deadline, per-file input bound, memory/process limit and capped diagnostics. Lazy-load selected grammars, parse without general network/filesystem imports, and terminate a stuck worker without losing native results from other modules. Host-specific enforcement and Rust MSRV compatibility must be tested; numeric production budgets remain measurement-driven rather than invented promises. @@ -246,7 +273,7 @@ Do not infer pass/fail from generic words such as `error`, `warning`, or `BUILD | Next action | Repair source, recommend/require native setup and confirmation, restore configuration, rescan, or obtain a concrete decision? | | Delivery | Is this only a local observation or a fully evaluated delivery result? | -[RunReport parsing](../crates/codeguard-cli/src/run_report.rs) supports a common structured contract; [check orchestration](../crates/codeguard-cli/src/check_command.rs) currently emits `check_feedback` `0.31.0`. Adapters also emit their own versioned local observations. Consumers must dispatch by protocol identity/version rather than assume a universal JSON shape. Human output is currently primarily Chinese; English documentation does not imply localized runtime messages. +[RunReport parsing](../crates/codeguard-cli/src/run_report.rs) supports a common structured contract; [check orchestration](../crates/codeguard-cli/src/check_command.rs) currently emits `check_feedback` `0.33.0`. Adapters also emit their own versioned local observations. Consumers must dispatch by protocol identity/version rather than assume a universal JSON shape. Human output is currently primarily Chinese; English documentation does not imply localized runtime messages. ### 7.3 Conversation report examples — target presentation @@ -418,7 +445,7 @@ Report review rules apply across all maintained documents: distinguish installed ### 7.5 Protocol versions and identity closure -The current common `RunReport` is `1.4`, aggregate `check_feedback` is `0.31.0`, and `check_aborted` is `0.11.0`; adapter-local observations have separate versions. Protocol versions must not be rewritten to match software `0.1.0`. The conversation/JSON briefs above are target examples, not complete instances of these three protocols. +The current common `RunReport` is `1.4`, aggregate `check_feedback` is `0.33.0`, and `check_aborted` is `0.11.0`; adapter-local observations have separate versions. Protocol versions must not be rewritten to match software `0.1.0`. The conversation/JSON briefs above are target examples, not complete instances of these three protocols. The target evidence chain correlates workspace/request/run/obligation/finding/task/attempt. Source locations use reversible paths and content identities; dependency locations use component, resolved version, graph and advisory identities. Lossy rendering of non-UTF-8 paths cannot participate in matching. Digests bind bytes, not approval authority. Upgrades preserve version semantics and never turn old empty findings into complete passes. diff --git a/docs/Codeguard-Technical-Design.zh_CN.md b/docs/Codeguard-Technical-Design.zh_CN.md index 32214523..0fff231d 100644 --- a/docs/Codeguard-Technical-Design.zh_CN.md +++ b/docs/Codeguard-Technical-Design.zh_CN.md @@ -14,7 +14,11 @@ 可调用行为以当前源码为准,目标契约明确标注。产品优先级是配置发现 → 原生结果 → 有用的修复指引。内部一致性校验为这个体验服务,不要求用户手工构造执行证明。 -WASM 的规范与 19 项实施任务已纳入既有 change;可选特性下的 Rust worker 与 Java/TypeScript/TSX 局部单文件候选报告及 Python Ruff 不可用时的候选报告已存在;二十三份候选 grammar 均未验收;ArkTS、C、C++、C#、Go、JavaScript、Lua、Luau、Nix、Rust、Terraform、Zig、Objective-C、Solidity、R、Ruby、PHP、Kotlin、Dart 仅有固定字节的 Rust 可加载候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 +WASM 的规范与 19 项实施任务已纳入既有 change;可选特性下的 Rust worker 与 Java/TypeScript/TSX 局部单文件候选报告及 Python Ruff 不可用时的候选报告已存在;三十二份候选 grammar 均未验收;ArkTS、C、C++、C#、Go、JavaScript、Lua、Luau、Nix、Rust、Terraform、Zig、Objective-C、Solidity、R、Ruby、PHP、Kotlin、Dart、Erlang、Pascal、CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 仅有固定字节的 Rust 可加载候选资产,尚无逐语言验收的独立 lint 路由。项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 + +源码以 `--features wasm-precheck` 构建后,可通过 `codeguard grammar probe --format=json` 显式调用全部 32 份固定候选资产。命令使用隔离 Rust worker,以退出码 3 报告未经语言验收的观察,不能作为 lint 或交付结论。成功观察与有效语种的输入失败都遵守[0.1.0 封闭 JSON Schema](../schemas/grammar-probe-v0.1.schema.json),保持未完成。原生优先 `lint/check`、语言/方言验收、任务/宿主反馈及发行仍需独立完成;现有发现清单还把 JavaScript/TSX 归入 TypeScript,并未为 CFQuery/CFScript 建立独立源码映射。 + +首个局部原生优先入口为 Zig:`lint zig FILE --zig-tool ABS_PATH --format=json` 对选定源码字节先运行版本报告为 Zig 0.16.0 且字节保持一致的 `ast-check`;原生错误只暴露行列位置,不回显源码。未提供显式工具时,固定 Zig grammar 作为未验收候选兜底。两种结果都保持未完成,因为 AST 检查范围小于完整 lint、构建和测试;见 [0.1.0 报告 Schema](../schemas/zig-lint-feedback-v0.1.schema.json)。 ## 2. 技术选型与权衡 @@ -185,15 +189,38 @@ flowchart LR 这些是目标语义字段,尚非已发行的项目级 lint/check 报告。局部的[候选初检 schema](../schemas/syntax-precheck-candidate.schema.json) 与 [Rust 严格读者](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs)已绑定源码 SHA-256、固定 grammar 身份和文件方言,重新计算状态,并拒绝未知版本及伪造的 `clean`。可选 CLI 的 [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json)、[TSX](../schemas/eslint-local-feedback-v0.4.schema.json) 与 [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) 单文件生产端已提供恢复位置和准备指引。TypeScript/TSX 在已初始化工作区改用[反馈 0.5.0](../schemas/eslint-local-feedback-v0.5.schema.json),按源码范围关联一张稳定的原生确认任务;[0.2.0 准备报告](../schemas/eslint-preparation-observation-v0.2.schema.json)以源码和 grammar 身份保存有界疑似位置,并通过报告摘要关联到任务;宿主渲染和能力匹配原生关闭仍未接通。内置 grammar 仍是未验收候选,因此不能返回 `clean`。保持既有退出语义:必需原生执行缺失仍为未完成(`3`);解析器疑似问题本身不是已确认违规(`1`)。若未来增加独立语法操作,其成功必须限定为语法初检;本文不宣称已有 `syntax` 命令。 +源码构建的 `check all` 现另有较窄的真实项目报告:先执行原生适配器,再由[有界源码路由](../crates/codeguard-cli/src/check_syntax_candidates.rs)选择固定 worker 候选。[0.33.0 封闭 Schema](../schemas/check-feedback.schema.json)增加逐文件原生优先计数;[0.32.0](../schemas/check-feedback-v0.32.schema.json) 保留为历史协议。只有 Ruff 对同一 Python 源码摘要返回完整扫描状态时才跳过该文件的重复 WASM;P3C 等规范检查不能冒充语法确认。下面仅摘录字段,不是完整 `check_feedback` 实例: + +```json +{ + "schema_version": "0.33.0", + "command_status": "incomplete", + "delivery_decision": "incomplete", + "syntax_candidates": { + "status": "observed_partial", + "execution_phase": "after_native", + "authority": "candidate_unqualified", + "delivery_decision": "incomplete", + "native_preferred_count": 1, + "observations": [ + {"path": "src/view.tsx", "language": "tsx", "status": "candidate_observed", "grammar_qualified": false, "recovery_count": 0} + ], + "next_action": "交付前运行适用的原生检查器" + } +} +``` + +实际报告还包含原生结果、源码与 grammar 摘要、片段偏移、有界原文件恢复坐标、未执行数量和未解决义务。完整 `` 标签体可作嵌入候选;普通 SQL 和有歧义的 C/C++ 头文件不猜测。本机四批 32 份 grammar 的 CLI 样例约 54 秒;Linux 单次 31 文件检查在 90 秒内完成 26/32;语言版本语料、原生差分对照、任务同步、宿主交付和发行包验收仍待完成。 + 可选特性构建的 CLI 在无显式原生上下文的 TypeScript 单文件请求中,先核对本地 ESLint 10 包及唯一普通 flat config。若从 `PATH` 解析到可执行 Node,就调用既有有界原生版本与报告探针;缺 Node 时报告准备缺口,不让 WASM 抢跑。仅未观察到本地 ESLint 包时,`.ts/.mts/.cts` 输出 [ESLint 反馈 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json),`.tsx` 用独立 grammar 输出 [0.4.0](../schemas/eslint-local-feedback-v0.4.schema.json)。候选初检保留 `native=not_run`、`delivery=not_evaluated`,即使零恢复节点也保持未完成。配置选择歧义、本地路径不可信或包身份损坏时保留环境阻塞而不启动 WASM;部分显式上下文也沿用原路径。该增量不证明项目脚本参数等价、逐模块调度或宿主对话交付,见[原生优先局部验收](../tests/acceptance/native-first-eslint-candidate.md)。 ### 5.4 Grammar 引入与运行生命周期——目标 只引入固定 WASM 字节及上游许可证、提交/补丁来源、SHA-256、ABI、已验证运行时和语言/方言范围、语料引用与已知缺口。逐个验证 CodeGraph 资产与选定 Rust Tree-sitter 运行时兼容,不能复制 TypeScript 提取逻辑或把 CodeGraph 支持等同语法验收。发行清单属于分发资产,不属于可写的 `.codeguard/` 项目状态。 -可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 二十三份资产候选(ArkTS、C、C++、C#、Go、Java、JavaScript、Lua、Luau、Objective-C、Python、Rust、Solidity、TypeScript、TSX、Zig、Nix、Terraform、R、Ruby、PHP、Kotlin、Dart)和零项已发行能力,不运行解析器;Python 已有源码可选构建中的局部 `lint` 兜底,结果不能视为通过。已绑定工作区的单文件反馈使用 [0.15.0 协议](../schemas/python-lint-feedback-v0.15.schema.json),并通过现有 work sync 保存 [0.1.0 确认观察](../schemas/python-syntax-confirmation-observation-v0.1.schema.json)。任务身份绑定工作区和源码范围;导入前核对当前源码 SHA-256 与固定 grammar。能力匹配的原生关闭仍未完成。C、C++、C#、Go、JavaScript、Lua、Luau、Rust 的随仓字节和上游许可证已固定,完成窄范围 Rust worker 解析验证,尚无公开 lint 路由或语言验收。ArkTS、Nix、Terraform 的来源、许可证、字节及 Rust 正反例也已固定,仅为候选,尚无公开 lint 路由或发行验收;见[局部验收](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md)。依赖提供的 Objective-C 与 Solidity 已固定原始和适配后字节、许可证及依赖包完整性,但仍未验收语言版本或公开 lint 路由;COBOL 超过现有加载器的 8 MiB 限额。 +可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 三十二份资产候选(ArkTS、C、C++、C#、Go、Java、JavaScript、Lua、Luau、Objective-C、Python、Rust、Solidity、TypeScript、TSX、Zig、Nix、Terraform、R、Ruby、PHP、Kotlin、Dart、Erlang、Pascal、CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET)和零项已发行能力,不运行解析器;Python 已有源码可选构建中的局部 `lint` 兜底,结果不能视为通过。已绑定工作区的单文件反馈使用 [0.15.0 协议](../schemas/python-lint-feedback-v0.15.schema.json),并通过现有 work sync 保存 [0.1.0 确认观察](../schemas/python-syntax-confirmation-observation-v0.1.schema.json)。任务身份绑定工作区和源码范围;导入前核对当前源码 SHA-256 与固定 grammar。能力匹配的原生关闭仍未完成。C、C++、C#、Go、JavaScript、Lua、Luau、Rust 的随仓字节和上游许可证已固定,完成窄范围 Rust worker 解析验证,尚无逐语言验收的独立 lint 路由或语言验收。ArkTS、Nix、Terraform 的来源、许可证、字节及 Rust 正反例也已固定,仅为候选,尚无逐语言验收的独立 lint 路由或发行验收;见[局部验收](../tests/acceptance/arkts-nix-terraform-grammar-candidates.md)。依赖提供的 Objective-C 与 Solidity 已固定原始和适配后字节、许可证及依赖包完整性,但仍未验收语言版本或公开 lint 路由;COBOL 现可在 20 MiB 输入限额下加载,但冷启动与内存预算未验收。 -R、Ruby、PHP、Kotlin 也已固定 CodeGraph 字节、许可证和 Rust 实测 ABI,并通过隔离 worker 的窄范围正反例;PHP 样例覆盖 HTML/PHP 混合内容,仍仅为未验收候选。CodeGraph 原 Dart WASM 仍不能由 Rust 直接加载;CodeGuard 现以固定上游 C 源码和真实外部 scanner 经 Zig 可重复构建,再做固定 WASI 导入适配。Rust 加载与隔离 worker 的窄范围测试通过,但公开 lint 与发行仍未验收;见[Dart 重建局部验收](../tests/acceptance/dart-grammar-rebuild-candidate.md)。 +R、Ruby、PHP、Kotlin 也已固定 CodeGraph 字节、许可证和 Rust 实测 ABI,并通过隔离 worker 的窄范围正反例;PHP 样例覆盖 HTML/PHP 混合内容,仍仅为未验收候选。CodeGraph 原 Dart WASM 仍不能由 Rust 直接加载;CodeGuard 现以固定上游 C 源码和真实外部 scanner 经 Zig 可重复构建,再做固定 WASI 导入适配。Rust 加载与隔离 worker 的窄范围测试通过,但公开 lint 与发行仍未验收;见[Dart 重建局部验收](../tests/acceptance/dart-grammar-rebuild-candidate.md)。Erlang 也已固定 CodeGraph 字节、上游 0.19 许可证及 ABI 14,Rust 与隔离 worker 的窄范围样例通过;原生对照和公开 lint 路由尚缺,见[Erlang 候选局部验收](../tests/acceptance/erlang-grammar-candidate.md)。Pascal 已固定 CodeGraph 字节、原始 Isopod 依赖提交和许可证,ABI 14 及窄范围 worker 样例通过;原生对照和公开 lint 尚缺,见[Pascal 候选局部验收](../tests/acceptance/pascal-grammar-candidate.md)。其余七份 CFML/CFQuery/CFScript/COBOL/Scala/Swift/VB.NET 来源 WASM 也已固定并由 Rust worker 加载,累计 32/32 份候选、0 项已发行。CFQuery 漏掉 `SELECT FROM`,VB.NET 对合法未缩进方法体误报,COBOL 成本高;都不能发布为 lint,见[七份局部验收](../tests/acceptance/final-seven-grammar-candidates.md)。 由父进程控制解析工作进程,设置总截止时间、单文件输入上限、内存/进程限制及诊断数量上限。按需加载 grammar,不提供通用网络/文件系统导入;终止卡住的进程时保留其它模块的原生结果。宿主约束执行和 Rust MSRV 兼容性须测试,生产数值预算须经测量后确定,不编造性能承诺。 @@ -246,7 +273,7 @@ flowchart TD | 下一步 | 修源码、推荐/要求准备原生工具并确认、恢复配置、重扫,还是提出具体决策? | | 交付 | 只是局部观察,还是完整评估的交付结果? | -[RunReport 解析](../crates/codeguard-cli/src/run_report.rs)支持通用结构化契约,[检查编排](../crates/codeguard-cli/src/check_command.rs)当前输出 `check_feedback` `0.31.0`,适配器另有专属版本化局部观察。消费者必须按协议身份与版本分派,不能假定统一 JSON 形状。当前 human 输出以中文为主,英文文档不代表运行时消息已有英文国际化。 +[RunReport 解析](../crates/codeguard-cli/src/run_report.rs)支持通用结构化契约,[检查编排](../crates/codeguard-cli/src/check_command.rs)当前输出 `check_feedback` `0.33.0`,适配器另有专属版本化局部观察。消费者必须按协议身份与版本分派,不能假定统一 JSON 形状。当前 human 输出以中文为主,英文文档不代表运行时消息已有英文国际化。 ### 7.3 对话报告示例——目标呈现 @@ -418,7 +445,7 @@ Codeguard:1 个暂存路径需要处理 ### 7.5 协议版本与身份闭包 -当前通用 `RunReport` 为 `1.4`,聚合 `check_feedback` 为 `0.31.0`,`check_aborted` 为 `0.11.0`;适配器局部观察另有版本。版本属于具体协议,不能因为软件是 `0.1.0` 而统一改写。上面的对话/JSON 简报是目标示例,不是这三个协议的完整实例。 +当前通用 `RunReport` 为 `1.4`,聚合 `check_feedback` 为 `0.33.0`,`check_aborted` 为 `0.11.0`;适配器局部观察另有版本。版本属于具体协议,不能因为软件是 `0.1.0` 而统一改写。上面的对话/JSON 简报是目标示例,不是这三个协议的完整实例。 目标证据链关联 workspace/request/run/obligation/finding/task/attempt;源码定位使用可逆路径表示与内容身份,依赖定位使用组件、解析版本、图和 advisory。非 UTF-8 路径不能经有损显示字符串参与匹配。摘要只能绑定字节,不能证明字节来源已批准。报告升级保留旧字段的版本语义,不将旧空 findings 升格为完整通过。 diff --git a/grammars/cfml/LICENSE b/grammars/cfml/LICENSE new file mode 100644 index 00000000..aaf7a85d --- /dev/null +++ b/grammars/cfml/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Gareth Edwards & Gavin Baumanis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/cfml/README.md b/grammars/cfml/README.md new file mode 100644 index 00000000..b09fa1cb --- /dev/null +++ b/grammars/cfml/README.md @@ -0,0 +1,5 @@ +# CFML grammar 候选来源 + +固定 CodeGraph `1072f82ce24db3d133258d30165cef6b74d108b2` 的 `tree-sitter-cfml.wasm`,SHA-256 `17aeb294c58dd47045b470fc082ccceac3100c8e548b13764d4f3987a062322f`。CodeGraph [CFML 接入记录](https://github.com/colbymchenry/codegraph/pull/1153) 声明三份 WASM 从 `cfmleditor/tree-sitter-cfml` 重建并逐字节一致,约为 `v0.26.29`;本清单固定该标签提交 `5279bde9b31d54efa68efb77a4b18ee9508518e4`。`LICENSE` 来自该提交,SHA-256 `7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a`。CodeGuard 自身已核对 CodeGraph 固定提交的制品字节,尚未独立重复上游构建。 + +Rust 离线加载实测 ABI 15,基础正反例及隔离 worker 通过。CFML 文件还涉及 tag、bare-script、`` 和 `` 的语境切换;仅加载此单一 grammar 不等于完成这些语境或原生检查验收。 diff --git a/grammars/cfml/parser.wasm b/grammars/cfml/parser.wasm new file mode 100644 index 00000000..f488a229 Binary files /dev/null and b/grammars/cfml/parser.wasm differ diff --git a/grammars/cfquery/LICENSE b/grammars/cfquery/LICENSE new file mode 100644 index 00000000..aaf7a85d --- /dev/null +++ b/grammars/cfquery/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Gareth Edwards & Gavin Baumanis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/cfquery/README.md b/grammars/cfquery/README.md new file mode 100644 index 00000000..3be19f93 --- /dev/null +++ b/grammars/cfquery/README.md @@ -0,0 +1,5 @@ +# CFQuery grammar 候选来源 + +固定同一 CodeGraph 提交的 `tree-sitter-cfquery.wasm`,SHA-256 `9d4eaaec46eec7e6400d4b8d6c85fac7dfe33867ed5b4e5c218dfa7851c32558`;上游 `cfmleditor/tree-sitter-cfml@5279bde9b31d54efa68efb77a4b18ee9508518e4`,许可证字节与 [CFML 来源](../cfml/README.md)一致。Rust 离线加载实测 ABI 15。 + +该 grammar 面向 `` 内的 SQL 与 `#...#` 插值,不是完整 SQL 语义检查器。实测 `SELECT #x# FROM users` 无恢复、未闭合 `#` 有恢复,但 **`SELECT FROM` 也无恢复**。因此当前结果只能是未验收的结构观察,不能用零恢复声称 SQL lint 通过。没有公开原生优先路由或发行资格。 diff --git a/grammars/cfquery/parser.wasm b/grammars/cfquery/parser.wasm new file mode 100644 index 00000000..48f8c313 Binary files /dev/null and b/grammars/cfquery/parser.wasm differ diff --git a/grammars/cfscript/LICENSE b/grammars/cfscript/LICENSE new file mode 100644 index 00000000..aaf7a85d --- /dev/null +++ b/grammars/cfscript/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Gareth Edwards & Gavin Baumanis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/cfscript/README.md b/grammars/cfscript/README.md new file mode 100644 index 00000000..99b81820 --- /dev/null +++ b/grammars/cfscript/README.md @@ -0,0 +1,5 @@ +# CFScript grammar 候选来源 + +固定同一 CodeGraph 提交的 `tree-sitter-cfscript.wasm`,SHA-256 `e381db5d2b8a7744fc7d8e51b0a14ff03f86c8ff497cdfe32d1da467f19d4096`;上游 `cfmleditor/tree-sitter-cfml@5279bde9b31d54efa68efb77a4b18ee9508518e4`,许可证字节与 [CFML 来源](../cfml/README.md)一致。Rust 离线加载实测 ABI 15,基础组件函数正反例及隔离 worker 通过。 + +`.cfs` 裸脚本与 `.cfc`/`.cfm` 中嵌入的 `` 有不同入口和源码定位需求。语境切换、原生对照、版本语料、公开 lint 路由与发行包均未验收。 diff --git a/grammars/cfscript/parser.wasm b/grammars/cfscript/parser.wasm new file mode 100644 index 00000000..c50aa75a Binary files /dev/null and b/grammars/cfscript/parser.wasm differ diff --git a/grammars/cobol/LICENSE b/grammars/cobol/LICENSE new file mode 100644 index 00000000..ff8ed93c --- /dev/null +++ b/grammars/cobol/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Max Brunsfeld + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/cobol/README.md b/grammars/cobol/README.md new file mode 100644 index 00000000..57b990dc --- /dev/null +++ b/grammars/cobol/README.md @@ -0,0 +1,5 @@ +# COBOL grammar 候选来源 + +固定 CodeGraph 提交中的 `tree-sitter-cobol.wasm`,16355286 字节,SHA-256 `65b98799f92e831d8b5ed8cd811464c71fac31c4beabf66990a545a4f65e02f1`。CodeGraph 的[来源和补丁说明](https://github.com/colbymchenry/codegraph/blob/main/docs/grammars/tree-sitter-cobol.md)固定上游 `yutaro-sakamoto/tree-sitter-cobol@e99dbdc3d800d5fa2796476efd60af91f6b43d93` 与本目录 `source.patch`(SHA-256 `04fe11a51243ddf7d31e0b6378068c725a51463534218c43c7021761c69701e5`)。`LICENSE` 与上游提交相同,SHA-256 `d724405ce238a22c0d35769c5a36b386ad5958192efe8bbb304fb2896254575f`。 + +原 WASM 导出名为 `tree_sitter_COBOL`,固定清单以 `loader_symbol=COBOL` 加载,不改写二进制导出。Rust 加载实测 ABI 14。20 MiB 资产上限允许这一份固定字节进入隔离 worker;一次本机冷加载观察约 20 秒、峰值常驻内存约 458 MB,后续 worker 测试约 12 秒。这不构成正式资源预算。固定/自由格式转换、方言、copybook、原生编译器对照、公开 lint 路由及发行仍缺;大体积和解析成本使其不适合未经预算的编辑快检。 diff --git a/grammars/cobol/parser.wasm b/grammars/cobol/parser.wasm new file mode 100644 index 00000000..12496a95 Binary files /dev/null and b/grammars/cobol/parser.wasm differ diff --git a/grammars/cobol/source.patch b/grammars/cobol/source.patch new file mode 100644 index 00000000..72191bd1 --- /dev/null +++ b/grammars/cobol/source.patch @@ -0,0 +1,513 @@ +diff --git a/grammar.js b/grammar.js +index 6d48b47..e700a18 100644 +--- a/grammar.js ++++ b/grammar.js +@@ -19,6 +19,7 @@ module.exports = grammar({ + $._LINE_COMMENT, + $.comment_entry, + $._multiline_string, ++ $._exec_block, + ], + + extras: $ => [ +@@ -29,20 +30,30 @@ module.exports = grammar({ + $._LINE_COMMENT_ALIAS, + $.copy_statement, + $.comment, ++ $.directive, + ], + + rules: { +- start: $ => repeat( +- choice( +- $.program_definition, +- //optional($.function_definition) //todo +- ) ++ start: $ => optional(choice( ++ repeat1($.program_definition), ++ $.copybook_fragment, ++ //optional($.function_definition) //todo ++ )), ++ ++ // A standalone copybook (.cpy): data descriptions or procedure code ++ // without a program header. ++ copybook_fragment: $ => choice( ++ $.record_description_list, ++ $._procedure_division_contenet + ), + + _LINE_COMMENT_ALIAS: $ => alias($._LINE_COMMENT, $.comment), + + comment: $ => /\*>[^\n]*/, + ++ // GnuCOBOL / COBOL-2002 compiler directives: >>SOURCE, >>IF, >>DEFINE, ... ++ directive: $ => />>[^\n]*/, ++ + program_definition: $ => prec.right(seq( + $.identification_division, + optional($.environment_division), +@@ -60,7 +71,8 @@ module.exports = grammar({ + optional(choice( + $.as_literal, + $.is_initial, +- $.is_common)), ++ $.is_common, ++ $.is_recursive)), + '.')), + repeat(choice( + $.author_section, +@@ -90,6 +102,11 @@ module.exports = grammar({ + $._COMMON + ), + ++ is_recursive: $ => seq( ++ optional($._IS), ++ $._RECURSIVE ++ ), ++ + author_section: $ => seq( + $._AUTHOR, '.', + field('comment', repeat1($.comment_entry)), +@@ -102,17 +119,17 @@ module.exports = grammar({ + + date_written_section: $ => seq( + $._DATE_WRITTEN, '.', +- field('comment', repeat1($.comment_entry)), ++ field('comment', repeat($.comment_entry)), + ), + + date_compiled_section: $ => seq( + $._DATE_COMPILED, '.', +- field('comment', repeat1($.comment_entry)), ++ field('comment', repeat($.comment_entry)), + ), + + security_section: $ => seq( + $._SECURITY, '.', +- field('comment', repeat1($.comment_entry)), ++ field('comment', repeat($.comment_entry)), + ), + + function_definition: $ => seq( +@@ -734,7 +751,7 @@ module.exports = grammar({ + file_description: $ => seq( + $.file_type, + $.file_description_entry, +- $.record_description_list ++ optional($.record_description_list) + ), + + file_type: $ => choice( +@@ -870,12 +887,12 @@ module.exports = grammar({ + ), + + record_description_list: $ => seq( +- repeat1(seq($.data_description, repeat1('.'))) ++ repeat1(choice(seq($.data_description, repeat1('.')), prec(1, seq($.exec_statement, optional('.'))))) + ), + + working_storage_section: $ => seq( + $._WORKING_STORAGE, $._SECTION, '.', +- repeat(seq($.data_description, repeat1('.'))) ++ repeat(choice(seq($.data_description, repeat1('.')), seq($.exec_statement, optional('.')))) + ), + + data_description: $ => choice( +@@ -1070,7 +1087,7 @@ module.exports = grammar({ + $.picture_edit, + ), + +- picture_x: $ => /([xX](\([0-9]+\))?)+/, ++ picture_x: $ => /([xX](\(([0-9]+|[a-zA-Z][a-zA-Z0-9-]*)\))?)+/, + + picture_n: $ => /([nN](\([0-9]+\))?)+/, + +@@ -1119,6 +1136,11 @@ module.exports = grammar({ + seq($.BINARY_SHORT, $.SIGNED), + seq($.BINARY_SHORT, $.UNSIGNED), + $.BINARY_SHORT, ++ seq($.BINARY_LONG_LONG, $.SIGNED), ++ seq($.BINARY_LONG_LONG, $.UNSIGNED), ++ $.BINARY_LONG_LONG, ++ $.FLOAT_LONG, ++ $.FLOAT_SHORT, + seq($.BINARY_LONG, $.SIGNED), + seq($.BINARY_LONG, $.UNSIGNED), + $.BINARY_LONG, +@@ -1197,7 +1219,7 @@ module.exports = grammar({ + )), + + value_item: $ => seq( +- $._literal, ++ choice($._literal, $.qualified_word), + optional(seq( + $.THRU, + $._literal +@@ -1227,7 +1249,7 @@ module.exports = grammar({ + + linkage_section: $ => seq( + $._LINKAGE, $._SECTION, '.', +- $.record_description_list ++ optional($.record_description_list) + ), + + report_section: $ => /report_section/, +@@ -1357,6 +1379,19 @@ module.exports = grammar({ + '.' + ), + ++ exec_statement: $ => $._exec_block, ++ ++ free_statement: $ => prec.right(seq( ++ $._FREE, ++ repeat1($._target_x) ++ )), ++ ++ entry_statement: $ => prec.right(seq( ++ $._ENTRY, ++ field('name', $.string), ++ optional(seq($._USING, repeat1($._call_param))) ++ )), ++ + end_program: $ => prec(1, seq( + $._END_PROGRAM, + $.program_name, +@@ -1364,6 +1399,9 @@ module.exports = grammar({ + )), + + _statement: $ => choice( ++ $.exec_statement, ++ $.entry_statement, ++ $.free_statement, + $.accept_statement, + $.add_statement, + $.allocate_statement, +@@ -1465,12 +1503,19 @@ module.exports = grammar({ + ), + + replacing_clause: $ => seq( ++ $._REPLACING, ++ repeat1($.replacing_pair) ++ ), ++ ++ replacing_pair: $ => seq( + field('leading_or_trailing', optional(choice($.LEADING, $.TRAILING))), +- field('x', choice($.WORD, $.string)), +- optional($._BY), +- field('by', choice($.WORD, $.string)), ++ field('x', choice($.pseudo_text, $.WORD, $.string)), ++ $._BY, ++ field('by', choice($.pseudo_text, $.WORD, $.string)), + ), + ++ pseudo_text: $ => /==([^=\n]|=[^=\n])*==/, ++ + start_statement: $ => seq( + $._START, + field('file_name', $.WORD), +@@ -1670,9 +1715,9 @@ module.exports = grammar({ + repeat1($._call_param) + ))), + optional(choice( +- field('returning', seq($._RETURNING, $._identifier), +- field('giving', seq($._GIVING, $._identifier)), +- ))) ++ field('returning', seq($._RETURNING, $._identifier)), ++ field('giving', seq($._GIVING, $._identifier)) ++ )) + ), + + _call_param: $ => choice( +@@ -1902,6 +1947,7 @@ module.exports = grammar({ + + _evaluate_object: $ => choice( + $.expr, ++ prec.right(seq(choice('=', '>', '<', '>=', '<=', $._NOT_EQUAL), $.expr)), + $.ANY, + $.TRUE, + $.FALSE +@@ -1951,6 +1997,10 @@ module.exports = grammar({ + expr: $ => prec.left(choice( + seq($.NOT, $.expr), + seq($.expr, choice($.AND, $.OR), $.expr), ++ // Abbreviated combined relation: `X < 0 OR > Y` — the subject of the ++ // second comparison is implied. (The AND_LT/OR_GT combined tokens the ++ // grammar carries for this never win against keyword lexing.) ++ seq($.expr, choice($.AND, $.OR), $._comparator, $._expr_calc), + $._expr_bool, + seq("(", $.expr, ")") + )), +@@ -1965,6 +2015,11 @@ module.exports = grammar({ + )), + + _expr_calc_binary: $ => choice( ++ prec.left(1, seq($._expr_calc, $.B_AND, $._expr_calc)), ++ prec.left(1, seq($._expr_calc, $.B_OR, $._expr_calc)), ++ prec.left(1, seq($._expr_calc, $.B_XOR, $._expr_calc)), ++ prec.left(1, seq($._expr_calc, $.B_SHIFT_L, $._expr_calc)), ++ prec.left(1, seq($._expr_calc, $.B_SHIFT_R, $._expr_calc)), + prec.left(1, seq($._expr_calc, '+', $._expr_calc)), + prec.left(1, seq($._expr_calc, '-', $._expr_calc)), + prec.left(2, seq($._expr_calc, '**', $._expr_calc)), +@@ -1974,6 +2029,7 @@ module.exports = grammar({ + ), + + _expr_calc_unary: $ => prec(4, choice( ++ seq($.B_NOT, $._expr_calc), + seq('+', $._expr_calc), + seq('-', $._expr_calc), + seq('^', $._expr_calc), +@@ -2753,7 +2809,7 @@ module.exports = grammar({ + seq($.TRIM_FUNCTION, '(', $._trim_args, ')', optional($.func_refmod)), + seq($.NUMVALC_FUNC, '(', $._numvalc_args, ')'), + seq($.LOCALE_DT_FUNC, '(', $._locale_dt_args, ')', optional($.func_refmod)), +- seq($.WORD, optional($.func_args)), ++ seq($.WORD, optional($.func_args), optional($.func_refmod)), + ))), + + func_refmod: $ => choice( +@@ -2868,6 +2924,16 @@ module.exports = grammar({ + _BINARY_CHAR: $ => /[bB][iI][nN][aA][rR][yY]-[cC][hH][aA][rR]/, + _BINARY_DOUBLE: $ => /[bB][iI][nN][aA][rR][yY]-[dD][oO][uU][bB][lL][eE]/, + _BINARY_LONG: $ => /[bB][iI][nN][aA][rR][yY]-[lL][oO][nN][gG]/, ++ _BINARY_LONG_LONG: $ => /[bB][iI][nN][aA][rR][yY]-[lL][oO][nN][gG]-[lL][oO][nN][gG]/, ++ _FREE: $ => /[fF][rR][eE][eE]/, ++ B_AND: $ => /[bB]-[aA][nN][dD]/, ++ B_OR: $ => /[bB]-[oO][rR]/, ++ B_XOR: $ => /[bB]-[xX][oO][rR]/, ++ B_NOT: $ => /[bB]-[nN][oO][tT]/, ++ B_SHIFT_L: $ => /[bB]-[sS][hH][iI][fF][tT]-[lL][cC]?/, ++ B_SHIFT_R: $ => /[bB]-[sS][hH][iI][fF][tT]-[rR][cC]?/, ++ _FLOAT_LONG: $ => /[fF][lL][oO][aA][tT]-[lL][oO][nN][gG]/, ++ _FLOAT_SHORT: $ => /[fF][lL][oO][aA][tT]-[sS][hH][oO][rR][tT]/, + _BINARY_SHORT: $ => /[bB][iI][nN][aA][rR][yY]-[sS][hH][oO][rR][tT]/, + _BLANK: $ => /[bB][lL][aA][nN][kK]/, + _BLANK_LINE: $ => /[bB][lL][aA][nN][kK]-[lL][iI][nN][eE]/, +@@ -3335,6 +3401,9 @@ module.exports = grammar({ + BINARY_CHAR: $ => $._BINARY_CHAR, + BINARY_DOUBLE: $ => $._BINARY_DOUBLE, + BINARY_LONG: $ => $._BINARY_LONG, ++ BINARY_LONG_LONG: $ => $._BINARY_LONG_LONG, ++ FLOAT_LONG: $ => $._FLOAT_LONG, ++ FLOAT_SHORT: $ => $._FLOAT_SHORT, + BINARY_SHORT: $ => $._BINARY_SHORT, + //BLANK: $ => $._BLANK, + BLANK_LINE: $ => $._BLANK_LINE, +@@ -3754,7 +3823,7 @@ module.exports = grammar({ + + COMPUTATIONAL: $ => $._COMPUTATIONAL, + _COMPUTATIONAL: $ => /[cC][oO][mM][pP][uU][tT][aA][tT][iI][oO][nN][aA][lL]/, +- _NOT_EQUAL: $ => /(!=)|([nN][oO][tT][ \t]+(([eE][qQ][uU][aA][lL])|=))/, ++ _NOT_EQUAL: $ => /(!=)|([nN][oO][tT]([ \t]+[eE][qQ][uU][aA][lL]|[ \t]*=))/, + _NOT_LESS: $ => /([nN][oO][tT][ \t]+(<|[lL][eE][sS][sS]))/, + _NOT_GREATER: $ => /([nN][oO][tT][ \t]+(>|[gG][rR][eE][aA][tT][eE][rR]))/, + +diff --git a/src/scanner.c b/src/scanner.c +index 6c1ae90..b69cf53 100644 +--- a/src/scanner.c ++++ b/src/scanner.c +@@ -1,4 +1,5 @@ + #include ++#include + #include + + enum TokenType { +@@ -8,10 +9,21 @@ enum TokenType { + LINE_COMMENT, + COMMENT_ENTRY, + multiline_string, ++ EXEC_BLOCK, + }; + ++// Wide mode: a preprocessor that converts free-format COBOL to fixed format ++// by left-padding every line 7 columns writes the sentinel "CGWIDE" into the ++// sequence area (columns 1-6) of the FIRST line. Free-format lines routinely ++// run past column 72, so when the sentinel is seen the fixed-format right ++// margin (column 73+ = ignored identification area) is pushed out of reach. ++// The one-byte flag is scanner state, carried through serialize/deserialize. ++#define CG_FIXED_WIDTH 72 ++#define CG_WIDE_WIDTH 4096 ++static const char CG_WIDE_SENTINEL[6] = {'C', 'G', 'W', 'I', 'D', 'E'}; ++ + void *tree_sitter_COBOL_external_scanner_create() { +- return NULL; ++ return calloc(1, 1); + } + + static bool is_white_space(int c) { +@@ -31,7 +43,7 @@ char* any_content_keyword[] = { + "procedure division", + }; + +-static bool start_with_word( TSLexer *lexer, char *words[], int number_of_words) { ++static bool start_with_word( TSLexer *lexer, char *words[], int number_of_words, int width) { + while(lexer->lookahead == ' ' || lexer->lookahead == '\t') { + lexer->advance(lexer, true); + } +@@ -45,7 +57,7 @@ static bool start_with_word( TSLexer *lexer, char *words[], int number_of_words) + + while(true) { + // At the end of the line +- if(lexer->get_column(lexer) > 71 || lexer->lookahead == '\n' || lexer->lookahead == 0) { ++ if(lexer->get_column(lexer) > width - 1 || lexer->lookahead == '\n' || lexer->lookahead == 0) { + return false; + } + +@@ -58,7 +70,7 @@ static bool start_with_word( TSLexer *lexer, char *words[], int number_of_words) + } + + if(all_match_failed) { +- for(; lexer->get_column(lexer) < 71 && lexer->lookahead != '\n' && lexer->lookahead != 0; ++ for(; lexer->get_column(lexer) < width - 1 && lexer->lookahead != '\n' && lexer->lookahead != 0; + lexer->advance(lexer, true)) { + } + return false; +@@ -94,6 +106,9 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + return false; + } + ++ char *wide = (char *)payload; ++ const int width = (wide && *wide) ? CG_WIDE_WIDTH : CG_FIXED_WIDTH; ++ + if(valid_symbols[WHITE_SPACES]) { + if(is_white_space(lexer->lookahead)) { + while(is_white_space(lexer->lookahead)) { +@@ -106,9 +121,20 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + + if(valid_symbols[LINE_PREFIX_COMMENT] && lexer->get_column(lexer) <= 5) { ++ // The sequence area is ignored content — but the free-format ++ // preprocessor plants the CGWIDE sentinel here on the first line. ++ int match = 0; + while(lexer->get_column(lexer) <= 5) { ++ if(match >= 0 && match < 6 && lexer->lookahead == CG_WIDE_SENTINEL[match]) { ++ match++; ++ } else { ++ match = -1; ++ } + lexer->advance(lexer, true); + } ++ if(match == 6 && wide) { ++ *wide = 1; ++ } + lexer->result_symbol = LINE_PREFIX_COMMENT; + lexer->mark_end(lexer); + return true; +@@ -132,7 +158,7 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + + if(valid_symbols[LINE_SUFFIX_COMMENT]) { +- if(lexer->get_column(lexer) >= 72) { ++ if(lexer->get_column(lexer) >= width) { + while(lexer->lookahead != '\n' && lexer->lookahead != 0) { + lexer->advance(lexer, true); + } +@@ -143,7 +169,7 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + + if(valid_symbols[COMMENT_ENTRY]) { +- if(!start_with_word(lexer, any_content_keyword, number_of_comment_entry_keywords)) { ++ if(!start_with_word(lexer, any_content_keyword, number_of_comment_entry_keywords, width)) { + lexer->mark_end(lexer); + lexer->result_symbol = COMMENT_ENTRY; + return true; +@@ -152,18 +178,66 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + } + ++ if(valid_symbols[EXEC_BLOCK]) { ++ // EXEC (CICS|SQL|DLI|...) ... END-EXEC embedded block. Match the word ++ // EXEC (case-insensitive) followed by whitespace, then consume through ++ // the next END-EXEC. On any mismatch return false so the internal ++ // lexer re-reads the same characters as an ordinary WORD. ++ if(lexer->lookahead == 'e' || lexer->lookahead == 'E') { ++ const char *kw = "exec"; ++ int ki = 0; ++ while(ki < 4 && (lexer->lookahead == towupper(kw[ki]) || lexer->lookahead == towlower(kw[ki]))) { ++ lexer->advance(lexer, false); ++ ki++; ++ } ++ if(ki == 4 && (lexer->lookahead == ' ' || lexer->lookahead == '\t' || ++ lexer->lookahead == '\n' || lexer->lookahead == '\r')) { ++ char ring[8] = {0,0,0,0,0,0,0,0}; ++ while(lexer->lookahead != 0) { ++ for(int i = 0; i < 7; ++i) ring[i] = ring[i+1]; ++ ring[7] = (char)towlower(lexer->lookahead); ++ lexer->advance(lexer, false); ++ if(ring[0]=='e' && ring[1]=='n' && ring[2]=='d' && ring[3]=='-' && ++ ring[4]=='e' && ring[5]=='x' && ring[6]=='e' && ring[7]=='c') { ++ lexer->result_symbol = EXEC_BLOCK; ++ lexer->mark_end(lexer); ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ } ++ + if(valid_symbols[multiline_string]) { ++ int quote = lexer->lookahead; ++ if(quote != '"' && quote != '\'') { ++ return false; ++ } + while(true) { +- if(lexer->lookahead != '"') { ++ if(lexer->lookahead != quote) { + return false; + } + lexer->advance(lexer, false); +- while(lexer->lookahead != '"' && lexer->lookahead != 0 && lexer->get_column(lexer) < 72) { ++ bool closed = false; ++ while(true) { ++ while(lexer->lookahead != quote && lexer->lookahead != 0 && lexer->get_column(lexer) < width) { ++ lexer->advance(lexer, false); ++ } ++ if(lexer->lookahead != quote) { ++ break; ++ } + lexer->advance(lexer, false); ++ if(lexer->lookahead == quote) { ++ // doubled quote = escaped quote inside the literal ++ lexer->advance(lexer, false); ++ continue; ++ } ++ closed = true; ++ break; + } +- if(lexer->lookahead == '"') { ++ if(closed) { + lexer->result_symbol = multiline_string; +- lexer->advance(lexer, false); + lexer->mark_end(lexer); + return true; + } +@@ -187,7 +261,7 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + + lexer->advance(lexer, true); +- while(lexer->lookahead == ' ' && lexer->get_column(lexer) < 72) { ++ while(lexer->lookahead == ' ' && lexer->get_column(lexer) < width) { + lexer->advance(lexer, true); + } + } +@@ -197,11 +271,19 @@ bool tree_sitter_COBOL_external_scanner_scan(void *payload, TSLexer *lexer, + } + + unsigned tree_sitter_COBOL_external_scanner_serialize(void *payload, char *buffer) { ++ if(payload && buffer) { ++ buffer[0] = *(char *)payload; ++ return 1; ++ } + return 0; + } + + void tree_sitter_COBOL_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { ++ if(payload) { ++ *(char *)payload = (buffer && length >= 1) ? buffer[0] : 0; ++ } + } + + void tree_sitter_COBOL_external_scanner_destroy(void *payload) { ++ free(payload); + } diff --git a/grammars/erlang/LICENSE b/grammars/erlang/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/grammars/erlang/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/grammars/erlang/README.md b/grammars/erlang/README.md new file mode 100644 index 00000000..5355a5cc --- /dev/null +++ b/grammars/erlang/README.md @@ -0,0 +1,5 @@ +# Erlang grammar 候选来源 + +CodeGuard 固定 CodeGraph 提交 `1072f82ce24db3d133258d30165cef6b74d108b2` 的 `src/extraction/wasm/tree-sitter-erlang.wasm`:421639 字节,SHA-256 `dbab33f03e07b89f4385fcdd48d87d86ba35c82a0a426788d55b8c25410bc491`。该提交中的字节与 `parser.wasm` 完全相同。CodeGraph 的 [Erlang 接入说明](https://github.com/colbymchenry/codegraph/pull/1165) 标明来源是 `WhatsApp/tree-sitter-erlang` 标签 `0.19`,并提醒不能以同名 npm 包替代该来源。 + +标签 `0.19` 指向提交 `836aa2b6c3af2c7cef3f84049b0ed6d44485a870`;`LICENSE` 从该提交复制,SHA-256 `c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4`。Rust `WasmStore` 对固定的 CodeGraph 字节实测 ABI 14,基本合法和非法函数样例及隔离 worker 通过。此处未重新构建并比对上游标签生成的 WASM;语言版本、方言语料、原生工具对照、公开 lint 路由和发行包均未验收。 diff --git a/grammars/erlang/parser.wasm b/grammars/erlang/parser.wasm new file mode 100644 index 00000000..e0e8dd79 Binary files /dev/null and b/grammars/erlang/parser.wasm differ diff --git a/grammars/manifest.json b/grammars/manifest.json index ad35609a..80d3835e 100644 --- a/grammars/manifest.json +++ b/grammars/manifest.json @@ -4,7 +4,7 @@ "source_commit": "1072f82ce24db3d133258d30165cef6b74d108b2", "codegraph_license": "LICENSE.codegraph", "codegraph_license_sha256": "e6d98f98c666bebe065ac2492a0a19232cc318d4d67bac3ca42ffb77bacc8809", - "build_tool": "tree-sitter-cli 0.25.10 build --wasm; Zig: tree-sitter-cli 0.27.0 generate --abi 15 + Zig 0.16.0 wasm32-wasi; Dart: pinned parser.c/scanner.c + Zig 0.16.0 wasm32-wasi; ArkTS/Terraform: pinned npm prebuilt WASM", + "build_tool": "tree-sitter-cli 0.25.10 build --wasm; Zig: tree-sitter-cli 0.27.0 generate --abi 15 + Zig 0.16.0 wasm32-wasi; Dart: pinned parser.c/scanner.c + Zig 0.16.0 wasm32-wasi; CFML: tree-sitter-cli 0.26.9; Scala: v0.26.2 release WASM; Swift: crate 0.7.3 sources; VB.NET/COBOL: CodeGraph-patched upstream; ArkTS/Terraform: pinned npm prebuilt WASM", "assets": [ { "language": "c", @@ -387,6 +387,169 @@ "known_limitations": ["Pinned Dart parser and real external scanner rebuilt with Zig and byte-pinned WASI import adaptation; only narrow syntax fixtures passed; native differential, language versions, host integration and release remain unqualified"], "release_status": "candidate_unvalidated" }, + { + "language": "erlang", + "dialect": "erlang", + "grammar_repository": "https://github.com/WhatsApp/tree-sitter-erlang", + "grammar_commit": "836aa2b6c3af2c7cef3f84049b0ed6d44485a870", + "grammar_version": "0.19", + "path": "erlang/parser.wasm", + "sha256": "dbab33f03e07b89f4385fcdd48d87d86ba35c82a0a426788d55b8c25410bc491", + "bytes": 421639, + "license": "erlang/LICENSE", + "license_sha256": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph WASM and upstream 0.19 license; only narrow Rust syntax samples; native differential, language versions, public lint route and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "pascal", + "dialect": "pascal", + "grammar_repository": "https://github.com/Isopod/tree-sitter-pascal", + "grammar_commit": "042119eca2e18a60e56317fb06ee3ba5c32cb447", + "grammar_version": "0.10.2", + "path": "pascal/parser.wasm", + "sha256": "be3634fca99c19f5e1035a1a9c7d93d6ee82b35e6d5024f02be4883b71329c3e", + "bytes": 716886, + "license": "pascal/LICENSE", + "license_sha256": "2e2fcc500eacb15b76c11fd2229aebf0a5b4c8ed476f068447c6dce778a17ac9", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph WASM and original dependency commit; only narrow Pascal syntax samples; Delphi/FreePascal dialect corpus, native differential, public lint route and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "cfml", + "dialect": "cfml", + "grammar_repository": "https://github.com/cfmleditor/tree-sitter-cfml", + "grammar_commit": "5279bde9b31d54efa68efb77a4b18ee9508518e4", + "grammar_version": "v0.26.29", + "path": "cfml/parser.wasm", + "sha256": "17aeb294c58dd47045b470fc082ccceac3100c8e548b13764d4f3987a062322f", + "bytes": 2700518, + "license": "cfml/LICENSE", + "license_sha256": "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "cfquery", + "dialect": "cfquery", + "grammar_repository": "https://github.com/cfmleditor/tree-sitter-cfml", + "grammar_commit": "5279bde9b31d54efa68efb77a4b18ee9508518e4", + "grammar_version": "v0.26.29", + "path": "cfquery/parser.wasm", + "sha256": "9d4eaaec46eec7e6400d4b8d6c85fac7dfe33867ed5b4e5c218dfa7851c32558", + "bytes": 2411407, + "license": "cfquery/LICENSE", + "license_sha256": "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "cfscript", + "dialect": "cfscript", + "grammar_repository": "https://github.com/cfmleditor/tree-sitter-cfml", + "grammar_commit": "5279bde9b31d54efa68efb77a4b18ee9508518e4", + "grammar_version": "v0.26.29", + "path": "cfscript/parser.wasm", + "sha256": "e381db5d2b8a7744fc7d8e51b0a14ff03f86c8ff497cdfe32d1da467f19d4096", + "bytes": 2162812, + "license": "cfscript/LICENSE", + "license_sha256": "7e17ba5e26b0438ca04ebf2d9e7931da3080509da6625e117f6feb943ecf767a", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "cobol", + "dialect": "cobol", + "grammar_repository": "https://github.com/yutaro-sakamoto/tree-sitter-cobol", + "grammar_commit": "e99dbdc3d800d5fa2796476efd60af91f6b43d93", + "grammar_version": "CodeGraph-patched-e99dbdc", + "path": "cobol/parser.wasm", + "sha256": "65b98799f92e831d8b5ed8cd811464c71fac31c4beabf66990a545a4f65e02f1", + "bytes": 16355286, + "license": "cobol/LICENSE", + "license_sha256": "d724405ce238a22c0d35769c5a36b386ad5958192efe8bbb304fb2896254575f", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["16.4 MB fixed source WASM has uppercase export and high cold-load cost; fixed-format samples only; free-format normalization, native differential, resource budget, public lint and release remain unqualified"], + "release_status": "candidate_unvalidated", + "loader_symbol": "COBOL" + }, + { + "language": "scala", + "dialect": "scala", + "grammar_repository": "https://github.com/tree-sitter/tree-sitter-scala", + "grammar_commit": "b931fcc338390925eb893d70ad070033f5856ccf", + "grammar_version": "v0.26.2", + "path": "scala/parser.wasm", + "sha256": "37d7fe5a91ca98941dc05493b0c05a0df0f36df5035890fa00b02497c68aaac3", + "bytes": 3973559, + "license": "scala/LICENSE", + "license_sha256": "1f95ed26e1f4074074c9c7083e61c0a9e4c3b9f435745044995f3beb4ed28575", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "swift", + "dialect": "swift", + "grammar_repository": "https://github.com/alex-pinkus/tree-sitter-swift", + "grammar_commit": "31d17fe7e818a2048c808b5c6fdc2dc792f4f5b5", + "grammar_version": "crate-0.7.3", + "path": "swift/parser.wasm", + "sha256": "cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843", + "bytes": 3726622, + "license": "swift/LICENSE", + "license_sha256": "3533cec129bb4bba015c0d61d86dd7c3b7e82110e4d2ff7837a01eff5bad5ccc", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, + { + "language": "vbnet", + "dialect": "vbnet", + "grammar_repository": "https://github.com/govindbanura/tree-sitter-vbnet", + "grammar_commit": "538b7087bf80e86004531b392fe1186379c0a2b5", + "grammar_version": "CodeGraph-patched-538b708", + "path": "vbnet/parser.wasm", + "sha256": "e38a09e1826c7ec06340c0531a98bbb5ee79bdd710bba3d3349b79a19721e844", + "bytes": 6477499, + "license": "vbnet/LICENSE", + "license_sha256": "fa7ab39bcf92c216d429e8aa8be8a5a40db85bfbe4ff14a7bb0ecbbcca937454", + "abi_version": 15, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Pinned CodeGraph asset; only narrow syntax fixtures; native differential, language and dialect ranges, public lint route, resource budget and release remain unqualified"], + "release_status": "candidate_unvalidated" + }, { "language": "r", "dialect": "r", diff --git a/grammars/pascal/LICENSE b/grammars/pascal/LICENSE new file mode 100644 index 00000000..9f44cc5b --- /dev/null +++ b/grammars/pascal/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Benjamin Gray + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/pascal/README.md b/grammars/pascal/README.md new file mode 100644 index 00000000..23612479 --- /dev/null +++ b/grammars/pascal/README.md @@ -0,0 +1,5 @@ +# Pascal grammar 候选来源 + +CodeGuard 固定 CodeGraph 提交 `1072f82ce24db3d133258d30165cef6b74d108b2` 的 `src/extraction/wasm/tree-sitter-pascal.wasm`:716886 字节,SHA-256 `be3634fca99c19f5e1035a1a9c7d93d6ee82b35e6d5024f02be4883b71329c3e`。该提交中的字节与本目录 `parser.wasm` 完全相同。引入该 WASM 的 CodeGraph 合并提交 `77135445db0d5af66a0af57e176d73669a6b3767` 的父提交 `package.json` 将 `tree-sitter-pascal` 精确锁定为 `github:Isopod/tree-sitter-pascal#042119eca2e18a60e56317fb06ee3ba5c32cb447`。 + +上游该提交的 `package.json` 版本为 `0.10.2`,本目录 `LICENSE` 与上游原始字节相同,SHA-256 `2e2fcc500eacb15b76c11fd2229aebf0a5b4c8ed476f068447c6dce778a17ac9`。Rust `WasmStore` 对固定的 CodeGraph 字节实测 ABI 14,基本合法和非法 Pascal 程序及隔离 worker 通过。尚未从上游源码重新构建出与 CodeGraph 一致的 WASM;Delphi/FreePascal 方言语料、原生检查器对照、公开 lint 路由和发行包均未验收。 diff --git a/grammars/pascal/parser.wasm b/grammars/pascal/parser.wasm new file mode 100644 index 00000000..8356025b Binary files /dev/null and b/grammars/pascal/parser.wasm differ diff --git a/grammars/scala/LICENSE b/grammars/scala/LICENSE new file mode 100644 index 00000000..bd0a4d6c --- /dev/null +++ b/grammars/scala/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Max Brunsfeld and GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/scala/README.md b/grammars/scala/README.md new file mode 100644 index 00000000..0ff52b18 --- /dev/null +++ b/grammars/scala/README.md @@ -0,0 +1,5 @@ +# Scala grammar 候选来源 + +固定 CodeGraph 提交中的 `tree-sitter-scala.wasm`,SHA-256 `37d7fe5a91ca98941dc05493b0c05a0df0f36df5035890fa00b02497c68aaac3`。CodeGraph [Scala 来源记录](https://github.com/colbymchenry/codegraph/blob/main/docs/design/scala-kernel-port-checklist.md) 指出该字节是上游 `tree-sitter/tree-sitter-scala` 发行版 `v0.26.2` 的 WASM;标签提交 `b931fcc338390925eb893d70ad070033f5856ccf`。`LICENSE` 来自该提交,SHA-256 `1f95ed26e1f4074074c9c7083e61c0a9e4c3b9f435745044995f3beb4ed28575`。 + +Rust 离线加载实测 ABI 15,基础正反例及隔离 worker 通过。Scala 2/3 版本语料、原生编译器对照、公开 lint 路由及发行均未验收。 diff --git a/grammars/scala/parser.wasm b/grammars/scala/parser.wasm new file mode 100644 index 00000000..3c77d4b5 Binary files /dev/null and b/grammars/scala/parser.wasm differ diff --git a/grammars/swift/LICENSE b/grammars/swift/LICENSE new file mode 100644 index 00000000..f158d700 --- /dev/null +++ b/grammars/swift/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 alex-pinkus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/swift/README.md b/grammars/swift/README.md new file mode 100644 index 00000000..5bb26211 --- /dev/null +++ b/grammars/swift/README.md @@ -0,0 +1,5 @@ +# Swift grammar 候选来源 + +固定 CodeGraph 提交中的 `tree-sitter-swift.wasm`,SHA-256 `cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843`。CodeGraph [Swift 来源记录](https://github.com/colbymchenry/codegraph/blob/main/docs/design/swift-kernel-port-checklist.md) 指出实际生成源是 crates.io `tree-sitter-swift` **0.7.3** crate(CodeGraph Cargo.lock 校验和 `fe36052155b9dd69ca82b3b8f1b4ccfb2d867125ac1a4db1dd7331829242668c`),其 `src/parser.c` SHA-256 `d3edff6effe31b9a507f496577407987343b101b23eb7bee7a9b050e8ab5d27a`。清单中的 `31d17fe7e818a2048c808b5c6fdc2dc792f4f5b5` 是对应语法规约的上游标签提交;**该标签生成的 C 文件与 crate 发行物不同,不能当作 WASM 的字节来源**。本目录 `LICENSE` 取自固定 crate,SHA-256 `3533cec129bb4bba015c0d61d86dd7c3b7e82110e4d2ff7837a01eff5bad5ccc`。 + +Rust 离线加载实测 ABI 15,基础正反例及隔离 worker 通过。Swift 版本语料、编译器对照、公开 lint 路由和发行包尚未验收。 diff --git a/grammars/swift/parser.wasm b/grammars/swift/parser.wasm new file mode 100644 index 00000000..a05fa7a1 Binary files /dev/null and b/grammars/swift/parser.wasm differ diff --git a/grammars/vbnet/LICENSE b/grammars/vbnet/LICENSE new file mode 100644 index 00000000..84146ad4 --- /dev/null +++ b/grammars/vbnet/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Govind Banura + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/grammars/vbnet/README.md b/grammars/vbnet/README.md new file mode 100644 index 00000000..a3552e3e --- /dev/null +++ b/grammars/vbnet/README.md @@ -0,0 +1,5 @@ +# VB.NET grammar 候选来源 + +固定 CodeGraph 提交中的 `tree-sitter-vbnet.wasm`,SHA-256 `e38a09e1826c7ec06340c0531a98bbb5ee79bdd710bba3d3349b79a19721e844`。CodeGraph 的[来源和补丁说明](https://github.com/colbymchenry/codegraph/blob/main/docs/grammars/tree-sitter-vbnet.md)把上游固定为 `govindbanura/tree-sitter-vbnet@538b7087bf80e86004531b392fe1186379c0a2b5`,并应用本目录 `source.patch`(SHA-256 `33963ebe3ba60929fb58d90efd54f206f98a54ea13ae325d784732c828b7b93a`)。`LICENSE` 与上游提交相同,SHA-256 `fa7ab39bcf92c216d429e8aa8be8a5a40db85bfbe4ff14a7bb0ecbbcca937454`。 + +Rust 离线加载实测 ABI 15,缩进后的类方法和破损声明样例及隔离 worker 通过。**已观察到误报:合法的未缩进类方法体被解析为 `MISSING ":"`**。该候选不得用于公开源码违规判定;需先修复 grammar 并与原生 VB.NET 编译器对照。版本语料、公开路由与发行包也未验收。 diff --git a/grammars/vbnet/parser.wasm b/grammars/vbnet/parser.wasm new file mode 100644 index 00000000..365a6c60 Binary files /dev/null and b/grammars/vbnet/parser.wasm differ diff --git a/grammars/vbnet/source.patch b/grammars/vbnet/source.patch new file mode 100644 index 00000000..8caba699 --- /dev/null +++ b/grammars/vbnet/source.patch @@ -0,0 +1,1293 @@ +diff --git a/grammar.js b/grammar.js +index 21c8523..00bf2b1 100644 +--- a/grammar.js ++++ b/grammar.js +@@ -21,10 +21,14 @@ const PRECEDENCE = { + + module.exports = grammar({ + name: "vbnet", ++ word: ($) => $._identifier_token, ++ ++ externals: ($) => [$._query_clause_continuation, $.xml_literal], ++ + extras: $ => [ + $.comment, + $.preprocessor_directive, +- /[ \t\v\f]+/, ++ /[ \t\v\f\uFEFF]+/, + /\r?\n/, + /_[ \t]*\r?\n/, + ], +@@ -38,17 +42,14 @@ module.exports = grammar({ + $._type, + ], + conflicts: ($) => [ ++ [$.binary_expression, $.assignment_expression, $.inline_assignment_statement], + [$.simple_name, $.generic_name], + [$.await_expression, $.with_expression], + [$._name_reference, $._type], + [$.object_creation_expression, $.array_creation_expression, $.array_type], +- [$.string_literal, $.character_literal], + [$._primary_expression, $.variable_declarator], +- [$.lambda_expression, $.with_expression], +- [$.lambda_expression], + [$.binary_expression, $.assignment_expression], + [$._primary_expression, $.select_element], +- [$.with_expression, $.select_element], + [$.select_clause], + [$._primary_expression, $.group_element], + [$._terminator, $._block_terminator], +@@ -66,7 +67,6 @@ module.exports = grammar({ + [$.aggregate_element, $.into_element], + [$.group_by_clause], + [$.else_clause], +- [$.if_statement], + [$.case_else_clause], + [$.case_clause], + [$.elseif_clause], +@@ -75,7 +75,6 @@ module.exports = grammar({ + [$._primary_expression, $.simple_name, $.generic_name], + [$._primary_expression, $.variable_declarator, $.labeled_statement], + [$._statement, $.with_statement], +- [$.dictionary_initializer, $.collection_initializer], + [ + $.class_declaration, + $.structure_declaration, +@@ -89,7 +88,6 @@ module.exports = grammar({ + ], + ], + +- word: ($) => $._identifier_token, + + rules: { + source_file: ($) => +@@ -157,13 +155,14 @@ module.exports = grammar({ + ), + + _terminator: ($) => +- choice(seq(optional(":"), choice("\n", "\r\n")), $._eof), ++ prec.right(choice(seq(optional(":"), choice("\n", "\r\n")), prec(-1, ":"), $._eof)), + +- _block_terminator: ($) => prec.right(repeat1(choice("\n", "\r\n", $._eof))), ++ _block_terminator: ($) => prec.right(repeat1(choice("\n", "\r\n", ":", $._eof))), + + _eof: ($) => token(prec(-10, "$")), + +- _identifier_token: ($) => token(prec(-1, /[a-zA-Z_][a-zA-Z0-9_]*/)), ++ _identifier_token: ($) => ++ token(prec(-1, /[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Pc}]*[%$&!#@]?/u)), + + identifier: ($) => + choice( +@@ -194,7 +193,6 @@ module.exports = grammar({ + ci("MustInherit"), + ci("NotInheritable"), + ci("Overrides"), +- ci("MustOverride"), + ci("NotOverridable"), + ci("Overridable"), + ci("Overloads"), +@@ -225,43 +223,6 @@ module.exports = grammar({ + $._statement // Fallback to regular statements + ), + +- _non_statement_identifier: $ => choice( +- // Match identifiers that don't start with statement keywords +- token(prec(1, seq( +- negative_lookahead(seq( +- choice( +- /[Tt][Rr][Yy]/, +- /[Ss][Ee][Ll][Ee][Cc][Tt]/, +- /[Ii][Ff]/, +- /[Ww][Hh][Ii][Ll][Ee]/, +- /[Dd][Oo]/, +- /[Ff][Oo][Rr]/, +- /[Uu][Ss][Ii][Nn][Gg]/, +- /[Ww][Ii][Tt][Hh]/, +- /[Tt][Hh][Rr][Oo][Ww]/, +- /[Rr][Ee][Tt][Uu][Rr][Nn]/, +- /[Ee][Xx][Ii][Tt]/, +- /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/, +- /[Ss][Tt][Oo][Pp]/, +- /[Ee][Nn][Dd]/, +- /[Gg][Oo][Tt][Oo]/, +- /[Rr][Ee][Ss][Uu][Mm][Ee]/, +- /[Ee][Rr][Rr][Oo][Rr]/, +- /[Oo][Nn]/, +- /[Rr][Ee][Dd][Ii][Mm]/, +- /[Ee][Rr][Aa][Ss][Ee]/, +- /[Ss][Yy][Nn][Cc][Ll][Oo][Cc][Kk]/, +- /[Rr][Aa][Ii][Ss][Ee][Ee][Vv][Ee][Nn][Tt]/, +- /[Aa][Dd][Dd][Hh][Aa][Nn][Dd][Ll][Ee][Rr]/, +- /[Rr][Ee][Mm][Oo][Vv][Ee][Hh][Aa][Nn][Dd][Ll][Ee][Rr]/ +- ), +- choice(/\s/, /\r/, /\n/, /$/) +- )), +- /[a-zA-Z_][a-zA-Z0-9_]*/ +- ))), +- seq("[", /[^\]]+/, "]") // Bracketed identifier can be anything +- ), +- + local_declaration_modifier: ($) => + choice(ci("Dim"), ci("Const"), ci("Static")), + +@@ -300,6 +261,8 @@ module.exports = grammar({ + _primary_expression: ($) => + choice( + $._literal, ++ $.array_literal, ++ $.tuple_expression, + $.identifier, + $.parenthesized_expression, + $.generic_invocation_expression, // Add this before regular invocation +@@ -320,17 +283,26 @@ module.exports = grammar({ + ), + + generic_invocation_expression: ($) => +- prec( +- PRECEDENCE.INVOCATION + 1, ++ prec.right( ++ PRECEDENCE.INVOCATION + 1, + seq( + field("function", $._expression), + field("type_arguments", $.type_argument_list), +- field("arguments", $.argument_list) ++ optional(field("arguments", $.argument_list)) + ) + ), + + parenthesized_expression: ($) => seq("(", $._expression, ")"), + ++ tuple_expression: ($) => ++ seq( ++ "(", ++ choice($._expression, seq(field("name", $.identifier), ":=", $._expression)), ++ ",", ++ commaSep1(choice($._expression, seq(field("name", $.identifier), ":=", $._expression))), ++ ")" ++ ), ++ + member_access_expression: ($) => + prec.left( + PRECEDENCE.MEMBER_ACCESS, +@@ -350,20 +322,23 @@ module.exports = grammar({ + ) + ), + +- argument_list: ($) => seq("(", optional(commaSep1($._argument)), ")"), ++ argument_list: ($) => seq("(", optional($._arguments), ")"), + +- _argument: ($) => +- choice($._expression, $.named_argument, $.omitted_argument), ++ // Argument slots may be omitted between commas (`f(a,, b)`, `f(, x)`) — ++ // VB passes Optional parameters positionally by leaving the slot empty. ++ _arguments: ($) => ++ seq($._argument, repeat(seq(",", optional($._argument)))), + +- omitted_argument: ($) => token(prec(1, ",")), ++ _argument: ($) => choice($._expression, $.named_argument), + + array_access_expression: ($) => + prec( + PRECEDENCE.ARRAY_ACCESS, + seq( + field("array", $._expression), ++ optional("?"), + "(", +- field("indices", commaSep1($._expression)), ++ field("indices", $._arguments), + ")" + ) + ), +@@ -471,16 +446,53 @@ module.exports = grammar({ + ), + + lambda_expression: ($) => +- seq( +- choice(ci("Function"), ci("Sub")), +- field("parameters", $.lambda_parameter_list), +- field("body", choice($._expression, $._statement_block)) ++ choice( ++ prec.right( ++ seq( ++ optional(choice(ci("Async"), ci("Iterator"))), ++ choice(ci("Function"), ci("Sub")), ++ field("parameters", $.lambda_parameter_list), ++ field( ++ "body", ++ choice( ++ $._expression, ++ alias($.inline_if_statement, $.if_statement), ++ alias($.inline_throw_statement, $.throw_statement) ++ ) ++ ) ++ ) ++ ), ++ seq( ++ optional(choice(ci("Async"), ci("Iterator"))), ++ ci("Function"), ++ field("parameters", $.lambda_parameter_list), ++ optional($.as_clause), ++ $._block_terminator, ++ repeat($._statement), ++ ci("End"), ci("Function") ++ ), ++ seq( ++ optional(choice(ci("Async"), ci("Iterator"))), ++ ci("Sub"), ++ field("parameters", $.lambda_parameter_list), ++ $._block_terminator, ++ repeat($._statement), ++ ci("End"), ci("Sub") ++ ) + ), + + lambda_parameter_list: ($) => seq("(", commaSep($.lambda_parameter), ")"), + + lambda_parameter: ($) => +- seq(field("name", $.identifier), optional($.as_clause)), ++ seq( ++ optional(field("modifiers", repeat1(choice(ci("ByVal"), ci("ByRef"))))), ++ field("name", $.identifier), ++ optional(choice( ++ $.array_rank_specifier, ++ seq("(", field("bounds", commaSep1($._expression)), ")") ++ )), ++ optional($.as_clause) ++ ), + + typeof_is_expression: ($) => + prec.left( +@@ -488,7 +500,7 @@ module.exports = grammar({ + seq( + ci("TypeOf"), + field("expression", $._expression), +- ci("Is"), ++ choice(seq(ci("Is"), ci("Not")), token(prec(12, ci("IsNot"))), ci("Is")), + field("type", $._type) + ) + ), +@@ -504,29 +516,12 @@ module.exports = grammar({ + "initializer", + choice( + $.object_initializer, +- $.collection_initializer, +- $.dictionary_initializer // Add this new option ++ $.collection_initializer + ) + ) + ) + ), + +- dictionary_initializer: ($) => +- seq( +- ci("From"), +- "{", +- commaSep($.dictionary_element), +- "}" +- ), +- +- dictionary_element: ($) => +- seq( +- "{", +- field("key", $._expression), +- ",", +- field("value", $._expression), +- "}" +- ), + + + object_initializer: ($) => +@@ -551,6 +546,8 @@ module.exports = grammar({ + collection_initializer: ($) => + seq(ci("From"), "{", commaSep($._expression), "}"), + ++ array_literal: ($) => seq("{", commaSep($._expression), "}"), ++ + + array_creation_expression: ($) => + seq( +@@ -646,6 +643,9 @@ module.exports = grammar({ + seq(field("object", $._expression), "!", field("member", $.identifier)), + _literal: ($) => + choice( ++ $.xml_literal, ++ $.interpolated_string_literal, ++ $.date_literal, + $.string_literal, + $.character_literal, + $.integer_literal, +@@ -654,16 +654,49 @@ module.exports = grammar({ + $.nothing_literal, + $.date_literal + ), +- string_literal: ($) => seq('"', repeat(choice(/[^"\n]+/, '""')), '"'), +- character_literal: ($) => seq('"', choice(/[^"\n]/, '""'), '"', "c"), ++ string_literal: ($) => token(seq('"', repeat(choice(/[^"]/, '""')), '"')), ++ interpolated_string_literal: ($) => ++ seq( ++ '$"', ++ repeat( ++ choice( ++ token.immediate(prec(101, /[^"{}]+/)), ++ token.immediate(prec(101, '""')), ++ token.immediate(prec(101, "{{")), ++ token.immediate(prec(101, "}}")), ++ $.interpolation ++ ) ++ ), ++ token.immediate('"') ++ ), ++ interpolation: ($) => ++ seq( ++ token.immediate(prec(101, "{")), ++ $._expression, ++ optional(seq(",", /-?\d+/)), ++ optional(seq(":", /[^}"\r\n]+/)), ++ "}" ++ ), ++ date_literal: ($) => token(prec(2, /#[ \t]*\d[^#\r\n]*#/)), ++ character_literal: ($) => token(seq('"', choice(/[^"\r\n]/, '""'), '"', /[cC]/)), + integer_literal: ($) => +- token(seq(/\d+/, optional(choice("I", "UI", "L", "UL", "S", "US")))), ++ token( ++ seq( ++ choice( ++ /\d+(_+\d+)*/, ++ /&[Hh][0-9A-Fa-f]+(_+[0-9A-Fa-f]+)*/, ++ /&[Oo][0-7]+(_+[0-7]+)*/, ++ /&[Bb][01]+(_+[01]+)*/ ++ ), ++ optional(choice(/[Uu][SsIiLl]/, /[SsIiLl]/, "%", "&")) ++ ) ++ ), + floating_point_literal: ($) => + token( + seq( + choice(seq(/\d+/, ".", /\d+/), seq(".", /\d+/), /\d+/), + optional(/[eE][+-]?\d+/), +- optional(choice("F", "D", "R")) ++ optional(/[FfRrDd!#@]/) + ) + ), + boolean_literal: ($) => choice(ci("True"), ci("False")), +@@ -672,7 +705,7 @@ module.exports = grammar({ + + // Names and types + _name_reference: ($) => +- choice($.simple_name, $.qualified_name, $.global_qualified_name), ++ choice($.simple_name, $.generic_name, $.qualified_name, $.global_qualified_name), + + simple_name: ($) => $.identifier, + +@@ -682,7 +715,7 @@ module.exports = grammar({ + seq( + field("qualifier", $._name_reference), + ".", +- field("name", $.simple_name) ++ field("name", choice($.simple_name, $.generic_name)) + ) + ), + global_qualified_name: ($) => +@@ -694,6 +727,7 @@ module.exports = grammar({ + $.simple_name, + $.qualified_name, + $.generic_name, ++ $.global_qualified_name, + $.predefined_type, + $.array_type, + $.tuple_type +@@ -720,7 +754,8 @@ module.exports = grammar({ + ), + + generic_name: ($) => seq(field("name", $.identifier), $.type_argument_list), +- type_argument_list: ($) => seq("(", ci("Of"), commaSep1($._type), ")"), ++ type_argument_list: ($) => ++ seq("(", ci("Of"), optional($._type), repeat(seq(",", optional($._type))), ")"), + array_type: ($) => + seq(field("element_type", $._type), $.array_rank_specifier), + array_rank_specifier: ($) => seq("(", repeat(","), ")"), +@@ -742,10 +777,14 @@ module.exports = grammar({ + field("type", $._type) + ), + +- as_clause: ($) => seq( +- ci("As"), +- field("declared_type", $._type) +- ), ++ as_clause: ($) => ++ seq( ++ ci("As"), ++ choice( ++ $.object_creation_expression, ++ field("declared_type", $._type) ++ ) ++ ), + + implements_member_clause: ($) => + seq(ci("Implements"), commaSep1($._name_reference)), +@@ -856,7 +895,7 @@ module.exports = grammar({ + + enum_member_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + field("name", $.identifier), + optional(seq("=", field("value", $._expression))), + $._terminator +@@ -882,6 +921,10 @@ module.exports = grammar({ + prec(10, $.inherits_statement), + prec(10, $.implements_statement), + prec(100, $.constructor_declaration), ++ prec(150, $.external_method_declaration), ++ prec(160, $.custom_event_declaration), ++ prec(170, $.abstract_method_declaration), ++ prec(171, $.abstract_property_declaration), + // Explicitly add statements that can appear at class level + prec(200, $.try_statement), // Very high precedence + prec(200, $.select_statement), // Very high precedence +@@ -936,33 +979,21 @@ module.exports = grammar({ + variable_declarator: ($) => + seq( + field("name", $.identifier), ++ optional("?"), + optional(choice( + // Array bounds specification + seq("(", field("bounds", commaSep1($._expression)), ")"), + // Array rank specification + $.array_rank_specifier + )), +- optional(choice( +- // Regular type declaration +- $.as_clause, +- seq( +- ci("As"), +- ci("New"), +- field("type", $._type), +- optional(field("arguments", $.argument_list)), +- optional(field("initializer", choice( +- $.object_initializer, +- $.collection_initializer +- ))) +- ) +- )), ++ optional($.as_clause), + optional(seq("=", field("initializer", $._expression))) + ), + + + field_declaration: ($) => + prec.dynamic(-100, seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), + commaSep1($.variable_declarator), + $._terminator +@@ -970,7 +1001,8 @@ module.exports = grammar({ + + field_variable_declarator: ($) => + seq( +- field("name", $._non_statement_identifier), ++ field("name", $.identifier), ++ optional("?"), + optional($.array_rank_specifier), + optional($.as_clause), + optional(seq("=", field("initializer", $._expression))) +@@ -978,12 +1010,13 @@ module.exports = grammar({ + + property_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + ci("Property"), + field("name", $.identifier), + optional(field("parameters", $.parameter_list)), +- $.as_clause, ++ optional($.as_clause), ++ optional(seq("=", field("initializer", $._expression))), + optional($.implements_member_clause), + optional(seq("=", field("initializer", $._expression))), + choice( +@@ -1001,7 +1034,7 @@ module.exports = grammar({ + + property_getter: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), + ci("Get"), + $._block_terminator, +@@ -1013,7 +1046,7 @@ module.exports = grammar({ + + property_setter: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), + ci("Set"), + optional(seq("(", field("parameter", $.parameter), ")")), +@@ -1028,7 +1061,7 @@ module.exports = grammar({ + prec( + 1, + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), + choice( + seq( +@@ -1063,7 +1096,7 @@ module.exports = grammar({ + prec( + 100, + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), + $._sub_new, + optional(field("parameters", $.parameter_list)), +@@ -1087,7 +1120,7 @@ module.exports = grammar({ + + event_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + ci("Event"), + field("name", $.identifier), +@@ -1098,7 +1131,7 @@ module.exports = grammar({ + + operator_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + ci("Operator"), + field( +@@ -1152,7 +1185,7 @@ module.exports = grammar({ + + interface_method_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + choice(ci("Sub"), ci("Function")), + field("name", $.identifier), +@@ -1164,7 +1197,7 @@ module.exports = grammar({ + + interface_property_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + ci("Property"), + field("name", $.identifier), +@@ -1175,7 +1208,7 @@ module.exports = grammar({ + + interface_event_declaration: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional(field("modifiers", repeat1($.member_modifier))), // Changed + ci("Event"), + field("name", $.identifier), +@@ -1209,7 +1242,7 @@ module.exports = grammar({ + + parameter: ($) => + seq( +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + optional( + field( + "modifiers", +@@ -1273,7 +1306,7 @@ module.exports = grammar({ + + declaration_statement: ($) => + prec(1, seq( // Add precedence +- optional(field("attributes", $.attribute_list)), ++ repeat(field("attributes", $.attribute_list)), + field("modifiers", choice( + $.local_declaration_modifier, + repeat1($.local_declaration_modifier) +@@ -1282,6 +1315,65 @@ module.exports = grammar({ + $._terminator + )), + ++ _inline_statements: ($) => ++ prec.right(seq($._inline_statement, repeat(seq(":", $._inline_statement)))), ++ ++ _inline_statement: ($) => ++ choice( ++ alias($.inline_if_statement, $.if_statement), ++ alias($.inline_assignment_statement, $.assignment_statement), ++ alias($.inline_return_statement, $.return_statement), ++ alias($.inline_throw_statement, $.throw_statement), ++ alias($.inline_goto_statement, $.goto_statement), ++ alias($.inline_exit_statement, $.exit_statement), ++ alias($.inline_continue_statement, $.continue_statement), ++ alias($.inline_call_statement, $.call_statement), ++ alias($.inline_raiseevent_statement, $.raiseevent_statement), ++ alias($.inline_expression_statement, $.expression_statement) ++ ), ++ ++ inline_assignment_statement: ($) => ++ prec.right( ++ PRECEDENCE.ASSIGNMENT + 1, ++ seq( ++ field("left", choice( ++ $.identifier, ++ $.member_access_expression, ++ $.array_access_expression ++ )), ++ field( ++ "operator", ++ choice("=", "+=", "-=", "*=", "/=", "\\=", "^=", "&=", "<<=", ">>=") ++ ), ++ field("right", $._expression) ++ ) ++ ), ++ inline_return_statement: ($) => prec.right(1, seq(ci("Return"), optional($._expression))), ++ inline_throw_statement: ($) => prec.right(1, seq(ci("Throw"), optional($._expression))), ++ inline_goto_statement: ($) => seq(ci("GoTo"), field("label", $.identifier)), ++ inline_exit_statement: ($) => ++ seq( ++ ci("Exit"), ++ choice(ci("Do"), ci("For"), ci("While"), ci("Select"), ci("Sub"), ci("Function"), ci("Property"), ci("Try")) ++ ), ++ inline_continue_statement: ($) => ++ seq(ci("Continue"), choice(ci("Do"), ci("For"), ci("While"))), ++ inline_call_statement: ($) => prec.right(1, seq(ci("Call"), $._expression)), ++ inline_raiseevent_statement: ($) => ++ prec.right(1, seq(ci("RaiseEvent"), field("event", $.identifier), optional(field("arguments", $.argument_list)))), ++ inline_expression_statement: ($) => prec.right(1, $._expression), ++ ++ inline_if_statement: ($) => ++ prec.right( ++ seq( ++ ci("If"), ++ field("condition", $._expression), ++ ci("Then"), ++ field("then_statement", $._inline_statements), ++ optional(seq(ci("Else"), field("else_statement", $._inline_statements))) ++ ) ++ ), ++ + expression_statement: ($) => seq($._expression, $._terminator), + + assignment_statement: ($) => +@@ -1301,21 +1393,96 @@ module.exports = grammar({ + $._terminator + ) + ), ++ custom_event_declaration: ($) => ++ seq( ++ repeat(field("attributes", $.attribute_list)), ++ optional(field("modifiers", repeat1($.member_modifier))), ++ ci("Custom"), ++ ci("Event"), ++ field("name", $.identifier), ++ $.as_clause, ++ optional($.implements_member_clause), ++ $._block_terminator, ++ repeat($.event_accessor), ++ ci("End"), ci("Event"), ++ $._terminator ++ ), ++ ++ event_accessor: ($) => ++ seq( ++ choice(ci("AddHandler"), ci("RemoveHandler"), ci("RaiseEvent")), ++ optional(field("parameters", $.parameter_list)), ++ $._block_terminator, ++ repeat($._statement), ++ ci("End"), ++ choice(ci("AddHandler"), ci("RemoveHandler"), ci("RaiseEvent")), ++ $._terminator ++ ), ++ ++ _mustoverride_token: ($) => token(prec(11, ci("MustOverride"))), ++ ++ abstract_method_declaration: ($) => ++ seq( ++ repeat(field("attributes", $.attribute_list)), ++ optional(field("modifiers", repeat1($.member_modifier))), ++ $._mustoverride_token, ++ optional(field("modifiers", repeat1($.member_modifier))), ++ choice(ci("Sub"), ci("Function")), ++ field("name", $.identifier), ++ optional(field("type_parameters", $.type_parameter_list)), ++ optional(field("parameters", $.parameter_list)), ++ optional($.as_clause), ++ optional($.implements_member_clause), ++ $._terminator ++ ), ++ ++ abstract_property_declaration: ($) => ++ seq( ++ repeat(field("attributes", $.attribute_list)), ++ optional(field("modifiers", repeat1($.member_modifier))), ++ $._mustoverride_token, ++ optional(field("modifiers", repeat1($.member_modifier))), ++ ci("Property"), ++ field("name", $.identifier), ++ optional(field("parameters", $.parameter_list)), ++ optional($.as_clause), ++ optional($.implements_member_clause), ++ $._terminator ++ ), ++ ++ external_method_declaration: ($) => ++ seq( ++ repeat(field("attributes", $.attribute_list)), ++ optional(field("modifiers", repeat1($.member_modifier))), ++ ci("Declare"), ++ optional(choice(ci("Auto"), ci("Ansi"), ci("Unicode"))), ++ choice(ci("Sub"), ci("Function")), ++ field("name", $.identifier), ++ ci("Lib"), ++ field("library", $.string_literal), ++ optional(seq(ci("Alias"), field("alias", $.string_literal))), ++ optional(field("parameters", $.parameter_list)), ++ optional($.as_clause), ++ $._terminator ++ ), ++ + call_statement: ($) => seq(ci("Call"), $._expression, $._terminator), + + if_statement: ($) => + seq( + ci("If"), + field("condition", $._expression), +- ci("Then"), + choice( +- // Single-line if ++ // Single-line if: inline statements, optional Else, one terminator + seq( +- field("then_statement", $._statement), +- optional(seq(ci("Else"), field("else_statement", $._statement))) ++ ci("Then"), ++ field("then_statement", $._inline_statements), ++ optional(seq(ci("Else"), field("else_statement", $._inline_statements))), ++ $._terminator + ), + // Multi-line if + seq( ++ optional(ci("Then")), + $._block_terminator, + field("then_branch", repeat($._statement)), + repeat($.elseif_clause), +@@ -1331,7 +1498,7 @@ module.exports = grammar({ + seq( + ci("ElseIf"), + field("condition", $._expression), +- ci("Then"), ++ optional(ci("Then")), + $._block_terminator, + field("body", repeat($._statement)) + ), +@@ -1445,7 +1612,7 @@ module.exports = grammar({ + using_statement: ($) => + seq( + ci("Using"), +- field("resource", choice($.variable_declarator, $._expression)), ++ commaSep1(field("resource", choice($.variable_declarator, $._expression))), + $._block_terminator, + field("body", repeat($._statement)), + ci("End"), +@@ -1590,14 +1757,25 @@ module.exports = grammar({ + $._terminator + ), // LINQ Query expressions + query_expression: ($) => +- seq($.from_clause, repeat($.query_body_clause), $.select_or_group_clause), +- from_clause: ($) => seq(ci("From"), commaSep1($.collection_range_variable)), ++ prec.right( ++ choice( ++ seq( ++ $.from_clause, ++ repeat(seq(optional($._query_clause_continuation), $.query_body_clause)), ++ optional(seq(optional($._query_clause_continuation), $.select_or_group_clause)) ++ ), ++ $.aggregate_clause ++ ) ++ ), ++ from_clause: ($) => prec.right(seq(ci("From"), commaSep1($.collection_range_variable))), + collection_range_variable: ($) => +- seq( +- field("variable", $.identifier), +- optional($.as_clause), +- ci("In"), +- field("collection", $._expression) ++ prec.right( ++ seq( ++ field("variable", $.identifier), ++ optional($.as_clause), ++ ci("In"), ++ field("collection", $._expression) ++ ) + ), + query_body_clause: ($) => + choice( +@@ -1606,48 +1784,62 @@ module.exports = grammar({ + $.where_clause, + $.join_clause, + $.order_by_clause, +- $.aggregate_clause +- ), +- let_clause: ($) => seq(ci("Let"), commaSep1($.expression_range_variable)), ++ $.aggregate_clause, ++ $.distinct_clause, ++ $.skip_take_clause ++ ), ++ distinct_clause: ($) => ci("Distinct"), ++ skip_take_clause: ($) => ++ prec.right(seq(choice(ci("Skip"), ci("Take")), optional(ci("While")), $._expression)), ++ let_clause: ($) => prec.right(seq(ci("Let"), commaSep1($.expression_range_variable))), + expression_range_variable: ($) => +- seq( ++ prec.right(seq( + field("variable", $.identifier), + "=", + field("expression", $._expression) +- ), +- where_clause: ($) => seq(ci("Where"), field("condition", $._expression)), ++ )), ++ where_clause: ($) => ++ prec.right(seq(ci("Where"), field("condition", $._expression))), + join_clause: ($) => +- seq( +- ci("Join"), +- $.collection_range_variable, +- ci("On"), +- commaSep1($.join_condition) ++ prec.right( ++ seq( ++ ci("Join"), ++ $.collection_range_variable, ++ optional($._query_clause_continuation), ++ ci("On"), ++ commaSep1($.join_condition) ++ ) + ), + join_condition: ($) => +- seq( ++ prec.right(seq( + field("left", $._expression), + ci("Equals"), + field("right", $._expression) +- ), +- order_by_clause: ($) => seq(ci("Order"), ci("By"), commaSep1($.ordering)), ++ )), ++ order_by_clause: ($) => prec.right(seq(ci("Order"), ci("By"), commaSep1($.ordering))), + ordering: ($) => +- seq( +- field("expression", $._expression), +- optional(choice(ci("Ascending"), ci("Descending"))) ++ prec.right( ++ seq( ++ field("expression", $._expression), ++ optional(choice(ci("Ascending"), ci("Descending"))) ++ ) + ), + aggregate_clause: ($) => +- seq( +- ci("Aggregate"), +- $.collection_range_variable, +- repeat($.query_body_clause), +- ci("Into"), +- commaSep1($.aggregate_element) ++ prec.right( ++ seq( ++ ci("Aggregate"), ++ $.collection_range_variable, ++ repeat(seq(optional($._query_clause_continuation), $.query_body_clause)), ++ optional($._query_clause_continuation), ++ ci("Into"), ++ commaSep1($.aggregate_element) ++ ) + ), + aggregate_element: ($) => +- seq( ++ prec.right(seq( + optional(seq(field("name", $.identifier), "=")), + field("function", $.aggregate_function) +- ), ++ )), + aggregate_function: ($) => + seq( + field( +@@ -1668,42 +1860,44 @@ module.exports = grammar({ + select_or_group_clause: ($) => choice($.select_clause, $.group_by_clause), + select_clause: ($) => seq(ci("Select"), commaSep1($.select_element)), + select_element: ($) => +- choice( ++ prec.right(choice( + $._expression, + seq( + field("name", $.identifier), + "=", + field("expression", $._expression) + ) +- ), ++ )), + group_by_clause: ($) => +- seq( +- ci("Group"), +- commaSep1($.group_element), +- ci("By"), +- commaSep1($.by_element), +- ci("Into"), +- commaSep1($.into_element) ++ prec.right( ++ seq( ++ ci("Group"), ++ commaSep1($.group_element), ++ ci("By"), ++ commaSep1($.by_element), ++ ci("Into"), ++ commaSep1($.into_element) ++ ) + ), + group_element: ($) => +- choice( ++ prec.right(choice( + $._expression, + seq( + field("name", $.identifier), + "=", + field("expression", $._expression) + ) +- ), ++ )), + by_element: ($) => +- choice( ++ prec.right(choice( + $._expression, + seq( + field("name", $.identifier), + "=", + field("expression", $._expression) + ) +- ), +- into_element: ($) => choice($.identifier, $.aggregate_element), ++ )), ++ into_element: ($) => prec.right(choice($.identifier, $.aggregate_element)), + + // Comments + comment: ($) => token(prec(100, choice( +@@ -1714,7 +1908,7 @@ module.exports = grammar({ + ))), + + // Preprocessor Directives +- preprocessor_directive: ($) => token(seq("#", /[^\r\n]*/)), ++ preprocessor_directive: ($) => token(seq("#", /[ \t]*[A-Za-z][^\r\n]*/)), + }, + }); + +diff --git a/src/scanner.c b/src/scanner.c +new file mode 100644 +index 0000000..8334fdb +--- /dev/null ++++ b/src/scanner.c +@@ -0,0 +1,303 @@ ++#include "tree_sitter/parser.h" ++#include ++#include ++ ++// External tokens for the two constructs that are not LR(1)-parseable with ++// tree-sitter's newline-as-extra treatment: ++// ++// 1. QUERY_CLAUSE_CONTINUATION — a newline run that CONTINUES a LINQ query ++// (`From x In xs` ↵ `Where …`). At a clause boundary the parser cannot ++// know from the newline alone whether the query ends (newline = statement ++// terminator) or continues (newline = insignificant, next line starts with ++// a query keyword). The scanner looks past the newline at the next word ++// and only emits the token when it is a query-clause keyword — so the ++// terminator/continuation choice is made by the lexer, not the LR table. ++// ++// 2. XML_LITERAL — a whole VB XML literal (``, including ++// `<%= expr %>` embedded expressions, comments, CDATA) consumed as one ++// opaque token. Only valid where a literal can begin an expression, so a ++// relational `<` (which always FOLLOWS an expression) can never collide. ++ ++enum TokenType { ++ QUERY_CLAUSE_CONTINUATION, ++ XML_LITERAL, ++}; ++ ++void *tree_sitter_vbnet_external_scanner_create(void) { return NULL; } ++void tree_sitter_vbnet_external_scanner_destroy(void *payload) { (void)payload; } ++unsigned tree_sitter_vbnet_external_scanner_serialize(void *payload, char *buffer) { ++ (void)payload; (void)buffer; ++ return 0; // stateless ++} ++void tree_sitter_vbnet_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { ++ (void)payload; (void)buffer; (void)length; ++} ++ ++static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); } ++static inline void skip_ws(TSLexer *lexer) { lexer->advance(lexer, true); } ++ ++// Read one alphabetic word (advancing past it), lowercased into buf. ++// Returns its length (0 if the next char is not a letter). ++static int read_word(TSLexer *lexer, char *buf, int cap) { ++ int n = 0; ++ while (iswalpha((wint_t)lexer->lookahead)) { ++ if (n < cap - 1) buf[n] = (char)towlower((wint_t)lexer->lookahead); ++ n++; ++ advance(lexer); ++ } ++ buf[n < cap - 1 ? n : cap - 1] = 0; ++ return n; ++} ++ ++static bool is_query_keyword(const char *w) { ++ static const char *kws[] = { ++ "where", "select", "order", "group", "join", "let", "skip", ++ "take", "distinct", "aggregate", "from", "into", "on", NULL, ++ }; ++ for (int i = 0; kws[i]; i++) ++ if (strcmp(w, kws[i]) == 0) return true; ++ return false; ++} ++ ++// [ \t\r]* '\n' [ \t\r\n]* followed by a query-clause keyword. ++// The token covers only the whitespace/newline run (mark_end before the ++// keyword lookahead), so the clause keyword itself lexes normally after it. ++static bool scan_query_continuation(TSLexer *lexer) { ++ bool saw_newline = false; ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == ' ' || c == '\t' || c == '\r') { ++ advance(lexer); ++ } else if (c == '\n') { ++ saw_newline = true; ++ advance(lexer); ++ } else { ++ break; ++ } ++ } ++ if (!saw_newline) return false; ++ lexer->mark_end(lexer); ++ ++ char w[12]; ++ int n = read_word(lexer, w, sizeof w); ++ if (n == 0 || n >= (int)(sizeof w)) return false; ++ if (!is_query_keyword(w)) return false; ++ ++ // `Select Case` opens a statement, never a select clause. ++ if (strcmp(w, "select") == 0) { ++ while (lexer->lookahead == ' ' || lexer->lookahead == '\t') advance(lexer); ++ char w2[8]; ++ int m = read_word(lexer, w2, sizeof w2); ++ if (m > 0 && m < (int)(sizeof w2) && strcmp(w2, "case") == 0) return false; ++ } ++ ++ lexer->result_symbol = QUERY_CLAUSE_CONTINUATION; ++ return true; ++} ++ ++// Consume a VB string inside an embedded `<%= … %>` region ("" escapes). ++static void consume_vb_string(TSLexer *lexer) { ++ advance(lexer); // opening quote ++ for (;;) { ++ if (lexer->lookahead == 0) return; ++ if (lexer->lookahead == '"') { ++ advance(lexer); ++ if (lexer->lookahead != '"') return; // closing (not an escaped "") ++ // escaped quote: fall through, keep consuming ++ } ++ advance(lexer); ++ } ++} ++ ++// Consume `<%= … %>` starting at the '%' (the '<' is already consumed). ++// Embedded expressions NEST (`<%= From t In ts Select <%= t.Name %> %>`, ++// the staxrip WriteTagfile shape), so track <% / %> depth. ++static bool consume_embedded_expression(TSLexer *lexer) { ++ advance(lexer); // '%' ++ int depth = 1; ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; ++ if (c == '"') { consume_vb_string(lexer); continue; } ++ if (c == '<') { ++ advance(lexer); ++ if (lexer->lookahead == '%') { depth++; advance(lexer); } ++ continue; ++ } ++ if (c == '%') { ++ advance(lexer); ++ if (lexer->lookahead == '>') { ++ advance(lexer); ++ if (--depth == 0) return true; ++ } ++ continue; ++ } ++ advance(lexer); ++ } ++} ++ ++// Consume `` / `` / `` starting at '!'. ++static bool consume_bang_construct(TSLexer *lexer) { ++ advance(lexer); // '!' ++ if (lexer->lookahead == '-') { ++ // comment: to --> ++ int dashes = 0; ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; ++ if (c == '-') { dashes++; advance(lexer); continue; } ++ if (c == '>' && dashes >= 2) { advance(lexer); return true; } ++ dashes = 0; ++ advance(lexer); ++ } ++ } ++ if (lexer->lookahead == '[') { ++ // CDATA: to ]]> ++ int brackets = 0; ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; ++ if (c == ']') { brackets++; advance(lexer); continue; } ++ if (c == '>' && brackets >= 2) { advance(lexer); return true; } ++ brackets = 0; ++ advance(lexer); ++ } ++ } ++ // DOCTYPE-ish: to bare > ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; ++ if (c == '>') { advance(lexer); return true; } ++ advance(lexer); ++ } ++} ++ ++// Consume `` starting at the '?'. ++static bool consume_processing_instruction(TSLexer *lexer) { ++ advance(lexer); // '?' ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; ++ if (c == '?') { ++ advance(lexer); ++ if (lexer->lookahead == '>') { advance(lexer); return true; } ++ continue; ++ } ++ advance(lexer); ++ } ++} ++ ++static bool is_name_start(int32_t c) { ++ return iswalpha((wint_t)c) || c == '_'; ++} ++ ++static bool scan_xml_literal(TSLexer *lexer) { ++ // Only same-line blanks are skipped: a leading newline must stay unconsumed ++ // so it can serve as a statement/block terminator (a successful scan would ++ // otherwise swallow it as trivia). XML on a continuation line still works: ++ // the newline is consumed as an extra first, then the scanner re-runs. ++ while (lexer->lookahead == ' ' || lexer->lookahead == '\t') skip_ws(lexer); ++ if (lexer->lookahead != '<') return false; ++ advance(lexer); ++ // Only element-start markup opens an XML literal here; comments/PIs as the ++ // outermost construct (`Dim d = lookahead)) return false; ++ ++ int depth = 0; // open (unclosed) elements ++ bool in_tag = true; // inside <...> of an element tag ++ bool closing = false; ++ int32_t quote = 0; ++ ++ for (;;) { ++ int32_t c = lexer->lookahead; ++ if (c == 0) return false; // unterminated: let the normal parser error ++ ++ if (in_tag) { ++ if (quote) { ++ if (c == quote) quote = 0; ++ advance(lexer); ++ continue; ++ } ++ if (c == '"' || c == '\'') { quote = c; advance(lexer); continue; } ++ if (c == '<') { ++ advance(lexer); ++ if (lexer->lookahead == '%') { ++ // attribute value embedded expression: attr=<%= x %> ++ if (!consume_embedded_expression(lexer)) return false; ++ continue; ++ } ++ continue; // stray < in a tag: malformed, keep consuming ++ } ++ if (c == '/') { ++ advance(lexer); ++ if (lexer->lookahead == '>') { ++ // self-closing tag ++ advance(lexer); ++ in_tag = false; ++ if (depth == 0) break; // single self-closed root: done ++ continue; ++ } ++ continue; ++ } ++ if (c == '>') { ++ advance(lexer); ++ if (closing) { ++ depth--; ++ if (depth <= 0) break; // root element closed: done ++ } else { ++ depth++; ++ } ++ in_tag = false; ++ continue; ++ } ++ advance(lexer); ++ continue; ++ } ++ ++ // text content between tags ++ if (c == '<') { ++ advance(lexer); ++ int32_t d = lexer->lookahead; ++ if (d == '/') { advance(lexer); closing = true; in_tag = true; continue; } ++ if (d == '%') { ++ if (!consume_embedded_expression(lexer)) return false; ++ continue; ++ } ++ if (d == '!') { ++ if (!consume_bang_construct(lexer)) return false; ++ continue; ++ } ++ if (d == '?') { ++ if (!consume_processing_instruction(lexer)) return false; ++ continue; ++ } ++ closing = false; ++ in_tag = true; // opening tag ++ continue; ++ } ++ advance(lexer); ++ } ++ ++ lexer->mark_end(lexer); ++ lexer->result_symbol = XML_LITERAL; ++ return true; ++} ++ ++bool tree_sitter_vbnet_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) { ++ (void)payload; ++ int32_t c = lexer->lookahead; ++ bool ws = (c == ' ' || c == '\t' || c == '\n' || c == '\r'); ++ ++ // A scan attempt advances the lexer, so exactly ONE attempt runs per ++ // invocation — never chain a second attempt after a failed first (its ++ // reads would start mid-stream). The leading character picks the branch; ++ // a false return discards the attempt entirely. ++ if (valid_symbols[QUERY_CLAUSE_CONTINUATION] && ws) { ++ return scan_query_continuation(lexer); ++ } ++ if (valid_symbols[XML_LITERAL] && (c == '<' || ws)) { ++ return scan_xml_literal(lexer); ++ } ++ return false; ++} diff --git a/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md b/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md index e76f45f7..9fa28b8d 100644 --- a/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md +++ b/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md @@ -14,6 +14,10 @@ - **WHEN** 前端具备有效 ESLint 而 Java 模块缺少 JDK - **THEN** 前端运行原生 lint,Java 模块提供语法初检;两者的范围、来源和准备状态分别保留 +#### Scenario: Explicit Zig 0.16 source check takes precedence over the candidate grammar +- **WHEN** `lint zig` 收到可核对的 Zig 0.16.0 工具与普通 `.zig` 文件 +- **THEN** 优先以受控进程运行原生 `zig ast-check`;原生诊断必须保留,不能因 WASM 观察覆盖。只有该原生工具未提供或不可运行时,才可返回未验收 WASM 候选观察,并始终保持整体未完成;`ast-check` 不等于全部 Zig lint、测试或构建。 + #### Scenario: A local checker is absent from PATH - **WHEN** 项目声明的本地原生工具已可按受支持方式定位 - **THEN** 核对其配置和版本后优先运行,不创建错误的安装任务 @@ -70,6 +74,12 @@ CodeGuard MUST 提供只读的来源覆盖清单,区分 CodeGraph 随仓 WASM 目标范围 MUST 包含当前固定 CodeGraph 来源的 32 份独立 grammar,并包含 Zig;`jsx` 与 `javascript` 共用同一份 grammar,不重复计数。每份 grammar 都须分别完成合法再分发来源、许可、字节与 ABI、Rust 离线加载、版本/方言正反语料、原生工具对照、统一 `lint/check` 的原生优先路由、任务/对话反馈及发行包实装验收。部分候选或来源库存不能充当全部接入。若上游 WASM 与 Rust 运行时导入不兼容,适配 MUST 固定原始和派生字节、限定变换范围并以正反解析样本复验;不能回退到已知产生误报的旧 grammar 来制造可加载状态。 +在正式 `lint/check` 路由验收之前,CLI MAY 暴露显式的单文件 `grammar probe` 候选观察。该命令 MUST 通过与正式路径相同的固定资产核验及隔离 worker,报告源码与 grammar 摘要、恢复锚点、未验收状态及原生确认需求;无论有无恢复节点,MUST 返回未完成,不能产生已确认违规、任务关闭或交付通过。有效语种的输入/worker 失败 MUST 使用同一版本化封闭 JSON 协议报告具体未完成原因,未知语种属于参数错误。它不能自动代替已配置的原生工具执行。 + +#### Scenario: Explicit candidate probe uses one of the 32 assets +- **WHEN** 用户明确对受支持语种和普通 UTF-8 文件执行 `grammar probe` +- **THEN** 固定 WASM 在隔离 worker 中解析该文件并返回候选观察;语法正常仍为未完成,恢复锚点只提示原生确认 + #### Scenario: Zig source grammar fixes a known false positive but needs a runtime adapter - **WHEN** 当前 Zig grammar 能解析合法空容器,而原始 WASM 包含 Rust 运行时不支持的导入 diff --git a/openspec/changes/introduce-rust-codeguard-cli/tasks.md b/openspec/changes/introduce-rust-codeguard-cli/tasks.md index e9a22a3e..48dd676e 100644 --- a/openspec/changes/introduce-rust-codeguard-cli/tasks.md +++ b/openspec/changes/introduce-rust-codeguard-cli/tasks.md @@ -1057,3 +1057,19 @@ TDD缺自动同步先RED。相关普通:build9、work sync15、next6,共30 14.1 / 14.19 Dart 重建增量:固定 CodeGraph 来源提交所对应的 `UserNobody14/tree-sitter-dart@d4d8f3e337d8be23be27ffc35a0aef972343cd54`,将 `parser.c`、真实 `scanner.c`、头文件与 MIT 许可证逐字节和上游核对。Zig 0.16.0 离线重建生成原始 WASM,固定 SHA-256 与适配后 SHA-256;受控 Rust 适配只更改 import section 中同签名的 `__main_argc_argv` 名称,未修改 scanner 或语法表。重建脚本重复产出相同字节,Rust 加载实测 ABI 15、注释/字符串插值正反例和隔离 worker 候选观察通过。当前 23/32 份候选、9 份未入候选、发行验收仍为 0。`grammar status` 分别显示 CodeGraph 原资产与重建/适配候选摘要。尚缺 Dart SDK 原生对照、版本/方言语料、公开原生优先 `lint dart`、任务与对话反馈和发行包验收;14.1、14.19 不勾选。见[Dart 重建局部验收](../../../tests/acceptance/dart-grammar-rebuild-candidate.md)。 14.4 / 14.19 Dart 语料与性能局部增量:固定上游 15 份 corpus 共 150 例(预期正常 146、预期错误 4),Rust WASM 的错误分类全部匹配。父进程按语言选择并验证目标资产,不再为单文件 worker 全量散列 23 份 WASM;13 项隔离 worker 测试在并行执行下通过。该语料仍来自同一 grammar 仓库,不是独立 Dart SDK oracle;性能只有单次回归观察,逐版本独立语料、原生对照及冷暖启动预算仍缺,14.4、14.17、14.19 均不勾选。 + +14.1 / 14.4 / 14.19 Erlang 增量:固定 CodeGraph `1072f82ce24db3d133258d30165cef6b74d108b2` 中的 Erlang WASM 原始字节,并固定 WhatsApp `tree-sitter-erlang` 标签 `0.19` 对应的提交与许可证;Rust 离线加载实测 ABI 14,基本合法/非法语法与隔离 worker 候选状态通过。当前累计 24/32 份候选、8 份未入候选、0 项发行验收。尚未独立重建出与 CodeGraph 相同的 WASM、没有版本/方言语料、原生 Erlang 检查器对照、误报漏报评估、统一命令原生优先路由和发行包实装;14.1、14.4、14.17、14.19 不勾选。见[Erlang 局部验收](../../../tests/acceptance/erlang-grammar-candidate.md)。 + +14.1 / 14.4 / 14.19 Pascal 增量:固定 CodeGraph 来源 WASM 字节与原项目锁定的 `Isopod/tree-sitter-pascal@042119eca2e18a60e56317fb06ee3ba5c32cb447` 许可证,Rust 离线加载实测 ABI 14,基本合法/非法程序和隔离 worker 候选状态通过。当前累计 25/32 份候选、7 份未入候选、0 项发行验收。缺逐版本 Delphi/FreePascal 语料、原生对照、误报漏报评估、统一命令原生优先路由、宿主反馈、资源预算与发行包实装;14.1、14.4、14.17、14.19 不勾选。见[Pascal 局部验收](../../../tests/acceptance/pascal-grammar-candidate.md)。 + +14.1 / 14.2 / 14.4 / 14.19 全来源资产候选增量:CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 七份 CodeGraph WASM 已固定来源字节、许可证、上游提交或发行包及适用补丁;Rust 离线加载和隔离 worker 的窄范围正反例通过。清单累计 32/32 份候选,已发行语法能力仍为 0。COBOL 通过受限 20 MiB 输入和固定 `COBOL` 导出名加载,但冷启动/内存成本高,固定/自由格式尚未验收;CFQuery 漏掉 `SELECT FROM`,VB.NET 对合法未缩进类方法体产生 `MISSING`,均不得发布为违规检测。CFML 嵌入语境、逐语言版本/方言语料、原生工具对照、公开原生优先 `lint/check`、任务/宿主反馈、资源预算和发行包验收仍缺;14.1–14.19 不因资产凑齐而勾选。见[七份局部验收](../../../tests/acceptance/final-seven-grammar-candidates.md)。 + +14.4 / 14.7 候选诊断增量:源码构建的 `grammar probe --format=json` 明确调用固定资产与隔离 worker,保留摘要、恢复锚点和未完成状态;该手动诊断不是原生优先 `lint/check`、宿主自动触发或已发行支持。32 份候选已具备内部 worker 路径,仍需各语种正反语料、原生对照和统一路由验收,父任务不勾选。 + +14.7 协议增量:为显式 `grammar probe` 增加 0.1.0 封闭 JSON Schema,语言枚举与 32 份固定资产清单同步;成功观察、文件缺失均保持 `incomplete`/原生未运行/交付未评估,已用 Draft 2020-12 校验真实输出并确认伪造 `clean` 和额外字段被拒。该协议只覆盖手动单文件候选,不能代替 S14 的统一多文件报告与未知 major 消费端验收,14.7 不勾选。 + +14.6 / 14.7 Zig 原生优先局部增量:源码可选 WASM 构建中的 `lint zig FILE --zig-tool ABS_PATH` 先核对 Zig 0.16.0,再以受控 stdin 执行原生 `ast-check`;原生诊断存在时保留位置且不运行 WASM。未提供或工具版本不合时,使用固定 Zig grammar 返回未验收候选;两条路径均不签发完整 lint 或交付通过。真实本机 Zig 0.16.0 正反例、伪工具优先级测试、缺工具回退与 0.1.0 报告 Schema 验证通过。尚缺项目本地/PATH 工具准备发现、多模块统一路由、版本语料、任务和宿主反馈、发行验收,14.6/14.7/14.19 不勾选。 + +14.6 / 14.7 / 14.19 全项目候选路由增量:源码可选构建中的 `check all` 现先执行原生节点,再按方言把已发现源码送入固定隔离 worker;TSX、JavaScript、CFScript 分路由,CFQuery 只从完整标签体提取,歧义 `.h` 和普通 `.sql` 不猜测。四个有界项目的真实 `check all` 样例合计调用全部 32 份资产,输出 0.32.0 封闭候选字段并保持原生阻塞、退出码 3、交付未完成。单项目 31 文件的早期样例在 macOS 45 秒预算内仅 26/32、90 秒约 54 秒可完成;Linux CI 在 90 秒内仍为 26/32,因此跨平台验收改为分批项目,预算超限范围明确保持未完成。64 文件/64 片段上限不放宽。逐语种原生选择/版本语料、误报漏报对照、任务宿主反馈、发行验收仍缺;14.6/14.7/14.17/14.19 不勾选。见[32 份路由局部验收](../../../tests/acceptance/check-all-32-grammar-candidates.md)。 + +14.6 / 14.7 逐文件原生优先局部增量:源码可选构建中的 `check all` 现只在 Ruff 本轮完整检查同一路径、工具/配置摘要存在且源码 SHA-256 与候选阶段重新读取的字节一致时,对该 Python 文件跳过重复 WASM;`findings` 原生诊断仍原样保留,混合项目的 Zig 文件继续跑固定 worker,整体仍为退出码 3 和 `incomplete`。封闭协议升至 0.33.0,0.32.0 单独归档,新增 `native_preferred_count`;未完成扫描、路径错配或源码变化不得跳过。见[Python 原生优先局部验收](../../../tests/acceptance/check-all-native-preferred-python.md)。尚未覆盖其它 31 种 grammar 的逐模块原生能力判定、独立语法 oracle、任务/宿主反馈及发行验收;14.6/14.7/14.19 保持未完成。 diff --git a/schemas/check-feedback-v0.31.schema.json b/schemas/check-feedback-v0.31.schema.json new file mode 100644 index 00000000..9d68ff1e --- /dev/null +++ b/schemas/check-feedback-v0.31.schema.json @@ -0,0 +1,5550 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:codeguard:schema:check-feedback:0.31.0", + "title": "CodeGuard partial project or language check feedback", + "$defs": { + "rust_cve": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "checker_id", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "coverage_proven", + "database_freshness", + "local_scan_complete", + "reason", + "tool_sha256", + "lock_sha256", + "manifest_sha256", + "dependency_count", + "database_advisory_count", + "database_last_commit", + "database_last_updated", + "native_warnings_present", + "findings", + "next_actions", + "execution_budget" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "rust_cve_local_observation" + }, + "operation": { + "const": "cve" + }, + "language": { + "const": "rust" + }, + "checker_id": { + "const": "rust.cargo_audit" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "database_freshness": { + "const": "unverified" + }, + "local_scan_complete": { + "type": "boolean" + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "dependency_count": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "database_advisory_count": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "database_last_commit": { + "type": [ + "string", + "null" + ] + }, + "database_last_updated": { + "type": [ + "string", + "null" + ] + }, + "native_warnings_present": { + "type": "boolean" + }, + "findings": { + "type": "array", + "maxItems": 100000, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "advisory_id", + "package_name", + "package_version", + "package_source_sha256", + "package_checksum", + "cve_aliases", + "cvss_vector", + "severity" + ], + "properties": { + "advisory_id": { + "type": "string", + "pattern": "^RUSTSEC-" + }, + "package_name": { + "type": "string", + "minLength": 1 + }, + "package_version": { + "type": "string", + "minLength": 1 + }, + "package_source_sha256": { + "$ref": "#/$defs/rust_cve/$defs/digest" + }, + "package_checksum": { + "type": [ + "string", + "null" + ] + }, + "cve_aliases": { + "type": "array", + "items": { + "type": "string", + "pattern": "^CVE-" + } + }, + "cvss_vector": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "const": "unverified" + } + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1 + }, + "source": { + "type": "string" + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + }, + "required": [ + "command_status" + ] + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + } + ], + "$defs": { + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "nullable_digest": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_cve/$defs/digest" + } + ] + } + } + }, + "nullableSha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "goModuleResult": { + "type": "object", + "additionalProperties": false, + "required": [ + "root", + "status", + "diagnostic_count" + ], + "properties": { + "root": { + "type": "string", + "minLength": 1 + }, + "status": { + "enum": [ + "incomplete", + "findings_observed_unverified", + "clean_observed_unverified" + ] + }, + "diagnostic_count": { + "type": "integer", + "minimum": 0 + }, + "reason": { + "type": "string", + "minLength": 1 + } + } + }, + "goFinding": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "module_root", + "rule_id", + "path", + "line", + "column", + "native_message_sha256", + "message_status" + ], + "properties": { + "finding_id": { + "type": "string", + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "module_root": { + "type": "string", + "minLength": 1 + }, + "rule_id": { + "type": "string", + "minLength": 1 + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "native_message_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "message_status": { + "const": "native_text_private_untrusted" + } + } + }, + "npmCheckResult": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "feedback", + "observation", + "backlog_status" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "feedback": { + "oneOf": [ + { + "type": "null" + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈0.1/0.2/0.3;持久任务不授权门禁", + "oneOf": [ + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "const": "not_connected" + }, + "next_action": { + "type": "string", + "minLength": 1 + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action", + "execution_budget" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "const": "not_connected" + }, + "next_action": { + "type": "string", + "minLength": 1 + }, + "execution_budget": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action", + "execution_budget", + "workbench" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$" + }, + "next_action": { + "type": "string", + "minLength": 1 + }, + "execution_budget": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + ] + }, + "workbench": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$" + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "enum": [ + "synced_partial", + "sync_incomplete" + ] + } + } + }, + "then": { + "required": [ + "new_blockers", + "failed_reports" + ] + } + } + ] + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + } + ] + } + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm工作台观察0.1/0.2与输入状态准备观察0.3;不授予覆盖", + "oneOf": [ + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE工作台观察,不能自证漏洞或关闭", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "lock_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "diagnostic_reason": { + "type": "string", + "pattern": "^[a-z0-9_]{1,80}$" + }, + "component_count": { + "type": "integer", + "minimum": 0, + "maximum": 10000 + }, + "advisories": { + "type": "array", + "maxItems": 10000, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "diagnostic_reason": { + "enum": [ + "npm_execution_context_missing", + "npm_manifest_invalid", + "npm_scripts_invalid" + ] + } + }, + "required": [ + "diagnostic_reason" + ] + }, + "then": { + "properties": { + "component_count": { + "const": 0 + }, + "advisories": { + "maxItems": 0 + } + } + } + }, + { + "not": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_missing" + } + }, + "required": [ + "diagnostic_reason" + ] + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm缺锁准备观察;未启动工具且没有漏洞结果", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories", + "lock_state" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "lock_sha256": { + "type": "null" + }, + "diagnostic_reason": { + "const": "npm_lock_missing" + }, + "component_count": { + "const": 0 + }, + "advisories": { + "type": "array", + "maxItems": 0 + }, + "lock_state": { + "const": "missing" + } + } + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm输入不可用的准备观察0.3;无原生漏洞结果", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories", + "manifest_state", + "lock_state" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + } + ] + }, + "lock_sha256": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + } + ] + }, + "diagnostic_reason": { + "enum": [ + "npm_manifest_missing", + "npm_manifest_not_regular", + "npm_manifest_path_alias", + "npm_manifest_unavailable", + "npm_lock_missing", + "npm_lock_not_regular", + "npm_lock_path_alias", + "npm_lock_unavailable" + ] + }, + "component_count": { + "const": 0 + }, + "advisories": { + "type": "array", + "maxItems": 0 + }, + "manifest_state": { + "enum": [ + "present", + "missing", + "not_regular", + "path_alias", + "unavailable" + ] + }, + "lock_state": { + "enum": [ + "present", + "missing", + "not_regular", + "path_alias", + "unavailable" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + } + } + }, + "then": { + "properties": { + "manifest_sha256": { + "type": "string" + } + } + }, + "else": { + "properties": { + "manifest_sha256": { + "type": "null" + } + } + } + }, + { + "if": { + "properties": { + "lock_state": { + "const": "present" + } + } + }, + "then": { + "properties": { + "lock_sha256": { + "type": "string" + } + } + }, + "else": { + "properties": { + "lock_sha256": { + "type": "null" + } + } + } + }, + { + "not": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "present" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "missing" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_missing" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "missing" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_missing" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "not_regular" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_not_regular" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "not_regular" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_not_regular" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "path_alias" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_path_alias" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "path_alias" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_path_alias" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "unavailable" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_unavailable" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "unavailable" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_unavailable" + } + } + } + } + ] + } + ] + } + ] + }, + "backlog_status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{0,127}$" + } + } + }, + "rust_comments": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Unverified selected Cargo rustdoc library observation", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "checker_id", + "scope", + "rule_selection", + "local_scan_complete", + "coverage_proven", + "reason", + "tool_sha256", + "manifest_sha256", + "lock_sha256", + "findings", + "backlog_status", + "execution_budget", + "next_actions", + "recheck_argv", + "workspace_binding", + "workspace_id", + "run_id", + "backlog_sync" + ], + "properties": { + "schema_version": { + "const": "0.4.0" + }, + "report_type": { + "const": "rustdoc_local_observation" + }, + "operation": { + "const": "comments" + }, + "language": { + "const": "rust" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "checker_id": { + "const": "rust.cargo_rustdoc" + }, + "scope": { + "const": "selected_root_library_default_features" + }, + "rule_selection": { + "const": "explicit_probe_not_approved_project_policy" + }, + "local_scan_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "backlog_status": { + "enum": [ + "not_integrated", + "queued", + "synced", + "sync_incomplete", + "failed" + ] + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "rustdoc", + "--lib", + "--locked", + "--offline", + "--message-format=json", + "--", + "--warn", + "missing_docs", + "--warn", + "rustdoc::broken_intra_doc_links" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "rule_id", + "level", + "path", + "line", + "column", + "classification", + "byte_start", + "byte_end", + "native_range_sha256", + "identity_status", + "repair_brief", + "target_path" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "rule_id": { + "enum": [ + "missing_docs", + "rustdoc::broken_intra_doc_links" + ] + }, + "level": { + "enum": [ + "warning", + "error" + ] + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "classification": { + "const": "observed_unverified" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "identity_status": { + "enum": [ + "unique_candidate", + "ambiguous" + ] + }, + "repair_brief": { + "$ref": "#/$defs/rust_comments/$defs/repair_brief" + }, + "target_path": { + "type": "string", + "minLength": 1 + } + }, + "allOf": [ + { + "if": { + "properties": { + "identity_status": { + "const": "ambiguous" + } + } + }, + "then": { + "properties": { + "finding_id": { + "type": "null" + }, + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + }, + "else": { + "properties": { + "finding_id": { + "type": "string" + } + } + } + } + ] + } + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "invalid", + "legacy_unbound" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^rustdoc-[0-9]+-[0-9]+$" + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + } + }, + "$defs": { + "hash": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "repair_brief": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "evidence", + "rule_basis", + "allowed_paths", + "steps", + "recheck_argv", + "working_directory", + "tool_requirement", + "attempt_history", + "history_status", + "closure_conditions" + ], + "properties": { + "status": { + "enum": [ + "repair_guidance", + "investigation_required" + ] + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "path", + "source_sha256", + "byte_start", + "byte_end", + "rule_id", + "observation_reason" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "rule_id": { + "enum": [ + "missing_docs", + "rustdoc::broken_intra_doc_links" + ] + }, + "observation_reason": { + "type": "string", + "minLength": 1 + } + } + }, + "rule_basis": { + "type": "string", + "minLength": 1 + }, + "allowed_paths": { + "type": "array", + "maxItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "steps": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "rustdoc", + "--lib", + "--locked", + "--offline", + "--message-format=json", + "--", + "--warn", + "missing_docs", + "--warn", + "rustdoc::broken_intra_doc_links" + ] + }, + "working_directory": { + "const": "selected_project_root" + }, + "tool_requirement": { + "type": "string", + "minLength": 1 + }, + "attempt_history": { + "const": [] + }, + "history_status": { + "const": "not_integrated" + }, + "closure_conditions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "investigation_required" + } + } + }, + "then": { + "properties": { + "allowed_paths": { + "maxItems": 0 + } + } + }, + "else": { + "properties": { + "allowed_paths": { + "minItems": 1 + } + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + } + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + }, + "local_scan_complete": { + "const": false + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + } + } + }, + "then": { + "properties": { + "reason": { + "const": "native_observed_unverified" + }, + "tool_sha256": { + "type": "string" + }, + "manifest_sha256": { + "type": "string" + }, + "lock_sha256": { + "type": "string" + }, + "findings": { + "items": { + "properties": { + "identity_status": { + "const": "unique_candidate" + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "items": { + "properties": { + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "workspace_binding": { + "const": "bound" + } + } + }, + "then": { + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1 + } + } + }, + "else": { + "properties": { + "workspace_id": { + "type": "null" + }, + "backlog_status": { + "const": "not_integrated" + }, + "backlog_sync": { + "type": "null" + } + } + } + } + ] + }, + "rust_build": { + "title": "Unverified selected Cargo type check observation", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "checker_id", + "scope", + "rule_selection", + "local_scan_complete", + "coverage_proven", + "reason", + "tool_sha256", + "manifest_sha256", + "lock_sha256", + "findings", + "backlog_status", + "execution_budget", + "next_actions", + "recheck_argv", + "workspace_binding", + "workspace_id", + "run_id", + "backlog_sync", + "build_level", + "test_execution", + "build_success" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "rust_build_local_observation" + }, + "operation": { + "const": "build" + }, + "language": { + "const": "rust" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "checker_id": { + "const": "rust.cargo_check" + }, + "scope": { + "const": "selected_root_all_targets_default_features" + }, + "rule_selection": { + "const": "explicit_probe_not_approved_project_policy" + }, + "local_scan_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "backlog_status": { + "enum": [ + "not_integrated", + "queued", + "synced", + "sync_incomplete", + "failed" + ] + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "check", + "--locked", + "--offline", + "--all-targets", + "--message-format=json" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "rule_id", + "level", + "path", + "line", + "column", + "classification", + "byte_start", + "byte_end", + "native_range_sha256", + "identity_status", + "repair_brief", + "target_path", + "package_id_sha256", + "target_kinds", + "target_sha256" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "rule_id": { + "type": "string", + "pattern": "^E[0-9]{4}$" + }, + "level": { + "const": "error" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "classification": { + "const": "observed_unverified" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "identity_status": { + "enum": [ + "unique_candidate", + "ambiguous" + ] + }, + "repair_brief": { + "$ref": "#/$defs/rust_build/$defs/repair_brief" + }, + "target_path": { + "type": "string", + "minLength": 1 + }, + "package_id_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "target_kinds": { + "type": "array", + "minItems": 1, + "maxItems": 16, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 8192 + } + }, + "target_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + } + }, + "allOf": [ + { + "if": { + "properties": { + "identity_status": { + "const": "ambiguous" + } + } + }, + "then": { + "properties": { + "finding_id": { + "type": "null" + }, + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + }, + "else": { + "properties": { + "finding_id": { + "type": "string" + } + } + } + } + ] + } + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "invalid", + "legacy_unbound" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^cargo-build-[0-9]+-[0-9]+$" + }, + "backlog_sync": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "new_findings", + "new_blockers", + "failed_reports" + ], + "properties": { + "new_findings": { + "type": "integer", + "minimum": 0 + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "build_level": { + "const": "type_check" + }, + "test_execution": { + "const": false + }, + "build_success": { + "type": [ + "boolean", + "null" + ] + } + }, + "$defs": { + "hash": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "repair_brief": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "evidence", + "rule_basis", + "allowed_paths", + "steps", + "recheck_argv", + "working_directory", + "tool_requirement", + "attempt_history", + "history_status", + "closure_conditions" + ], + "properties": { + "status": { + "enum": [ + "repair_guidance", + "investigation_required" + ] + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "path", + "source_sha256", + "byte_start", + "byte_end", + "rule_id", + "observation_reason", + "native_range_sha256", + "line", + "column" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "rule_id": { + "type": "string", + "pattern": "^E[0-9]{4}$" + }, + "observation_reason": { + "type": "string", + "minLength": 1 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + } + } + }, + "rule_basis": { + "type": "string", + "minLength": 1 + }, + "allowed_paths": { + "type": "array", + "maxItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "steps": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "check", + "--locked", + "--offline", + "--all-targets", + "--message-format=json" + ] + }, + "working_directory": { + "const": "selected_project_root" + }, + "tool_requirement": { + "type": "string", + "minLength": 1 + }, + "attempt_history": { + "const": [] + }, + "history_status": { + "const": "not_integrated" + }, + "closure_conditions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "investigation_required" + } + } + }, + "then": { + "properties": { + "allowed_paths": { + "maxItems": 0 + } + } + }, + "else": { + "properties": { + "allowed_paths": { + "minItems": 1 + } + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + } + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + }, + "local_scan_complete": { + "const": false + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + } + } + }, + "then": { + "properties": { + "reason": { + "const": "native_observed_unverified" + }, + "tool_sha256": { + "type": "string" + }, + "manifest_sha256": { + "type": "string" + }, + "lock_sha256": { + "type": "string" + }, + "findings": { + "items": { + "properties": { + "identity_status": { + "const": "unique_candidate" + } + } + } + }, + "build_success": { + "type": "boolean" + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "items": { + "properties": { + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "workspace_binding": { + "const": "bound" + } + } + }, + "then": { + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1 + } + } + }, + "else": { + "properties": { + "workspace_id": { + "type": "null" + }, + "backlog_status": { + "const": "not_integrated" + }, + "backlog_sync": { + "type": "null" + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + }, + "build_success": { + "const": true + } + } + }, + "then": { + "properties": { + "findings": { + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + }, + "build_success": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "minItems": 1 + } + } + } + } + ] + } + }, + "type": "object", + "additionalProperties": false, + "allOf": [ + { + "if": { + "properties": { + "selection": { + "const": "all" + } + }, + "required": [ + "selection" + ] + }, + "then": { + "properties": { + "delivery_decision": { + "const": "incomplete" + } + } + }, + "else": { + "properties": { + "delivery_decision": { + "const": "not_evaluated" + }, + "native_results": { + "properties": { + "python_lint": { + "type": "null" + }, + "python_cve": { + "type": "array", + "maxItems": 0 + }, + "rust_lint": { + "type": "null" + }, + "rust_cve": { + "type": "null" + }, + "go_lint": { + "type": "null" + }, + "npm_cve": { + "type": "array", + "maxItems": 0 + } + } + }, + "execution_tasks": { + "items": { + "properties": { + "id": { + "enum": [ + "java.p3c", + "java.javadoc", + "java.dependencies", + "java.cve" + ] + } + } + } + }, + "category_candidates": { + "items": { + "properties": { + "language": { + "const": "java" + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + }, + "required": [ + "command_status" + ] + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + }, + "reason": { + "enum": [ + "full_project_obligations_and_trusted_policy_unavailable", + "java_selection_obligations_and_trusted_policy_unavailable" + ] + } + } + } + }, + { + "if": { + "properties": { + "selection": { + "const": "all" + }, + "command_status": { + "const": "incomplete" + } + }, + "required": [ + "selection", + "command_status" + ] + }, + "then": { + "properties": { + "reason": { + "const": "full_project_obligations_and_trusted_policy_unavailable" + } + } + } + }, + { + "if": { + "properties": { + "selection": { + "const": "java" + }, + "command_status": { + "const": "incomplete" + } + }, + "required": [ + "selection", + "command_status" + ] + }, + "then": { + "properties": { + "reason": { + "const": "java_selection_obligations_and_trusted_policy_unavailable" + } + } + } + } + ], + "required": [ + "schema_version", + "report_type", + "operation", + "selection", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "reason", + "discovery", + "native_results", + "execution_tasks", + "obligation_status", + "required_obligations", + "category_candidates", + "unresolved_conditions", + "execution_budget", + "next", + "export" + ], + "properties": { + "schema_version": { + "const": "0.31.0" + }, + "export": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "reason_code" + ], + "properties": { + "status": { + "enum": [ + "not_requested", + "saved", + "failed" + ] + }, + "reason_code": { + "type": [ + "string", + "null" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "failed" + } + }, + "required": [ + "status" + ] + }, + "then": { + "properties": { + "reason_code": { + "enum": [ + "output_parent_unavailable", + "output_not_regular_file", + "output_existing_file_is_not_codeguard_report", + "output_identity_unavailable", + "output_temp_create_failed", + "output_temp_write_failed", + "output_replace_failed", + "output_existing_read_failed", + "output_existing_too_large" + ] + } + } + }, + "else": { + "properties": { + "reason_code": { + "type": "null" + } + } + } + } + ] + }, + "execution_tasks": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "oneOf": [ + { + "enum": [ + "python.lint", + "rust.lint", + "go.lint", + "java.p3c", + "java.javadoc", + "java.dependencies", + "java.cve", + "rust.comments", + "rust.build", + "rust.cve" + ] + }, + { + "type": "string", + "pattern": "^npm\\.cve\\.[0-9]+$" + }, + { + "type": "string", + "pattern": "^python\\.cve\\.[0-9]+$" + } + ] + }, + "status": { + "enum": [ + "native_observed_unverified", + "native_incomplete", + "cancelled", + "deadline_exceeded", + "dependency_failed", + "cancelled_before_start", + "deadline_before_start", + "internal_failure" + ] + } + } + } + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement", + "jobs_limit", + "jobs_source", + "native_task_count", + "started_native_task_count" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + }, + "jobs_limit": { + "type": "integer", + "minimum": 1, + "maximum": 64 + }, + "jobs_source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "native_task_count": { + "type": "integer", + "minimum": 0 + }, + "started_native_task_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "report_type": { + "const": "check_feedback" + }, + "operation": { + "const": "check" + }, + "selection": { + "enum": [ + "all", + "java" + ] + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "enum": [ + "incomplete", + "not_evaluated" + ] + }, + "authority": { + "const": "local_unverified" + }, + "reason": { + "enum": [ + "full_project_obligations_and_trusted_policy_unavailable", + "java_selection_obligations_and_trusted_policy_unavailable", + "request_cancelled" + ] + }, + "discovery": { + "type": "object", + "required": [ + "schema_version", + "report_type", + "observation_complete", + "languages", + "native_tool_candidates" + ], + "properties": { + "schema_version": { + "const": "0.4.0" + }, + "report_type": { + "const": "discovery" + }, + "observation_complete": { + "type": "boolean" + }, + "languages": { + "type": "array" + }, + "native_tool_candidates": { + "type": "array" + } + } + }, + "native_results": { + "type": "object", + "additionalProperties": false, + "required": [ + "python_lint", + "python_cve", + "rust_lint", + "go_lint", + "java_p3c", + "java_javadoc", + "java_dependencies", + "java_cve", + "npm_cve", + "rust_comments", + "rust_build", + "rust_cve" + ], + "properties": { + "python_cve": { + "type": "array", + "maxItems": 1000, + "items": { + "type": "object", + "required": ["build_root", "reason", "native_report_valid", "findings"], + "properties": { + "build_root": {"type": "string"}, + "reason": {"type": "string"}, + "native_report_valid": {"type": "boolean"}, + "findings": {"type": "array"}, + "delivery_decision": {"const": "not_evaluated"}, + "coverage_proven": {"const": false} + } + } + }, + "go_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "checker_id", + "command_status", + "exit_code", + "delivery_decision", + "coverage_proven", + "authority", + "tool_approval", + "rulepack_approval", + "native_status", + "reason", + "native_tool_version", + "tool_sha256", + "manifest_sha256", + "go_sum_sha256", + "source_file_count", + "module_count", + "modules_completed", + "module_results", + "native_diagnostic_count", + "findings", + "native_recheck_argv", + "next_actions", + "workspace_binding", + "workspace_id", + "run_id", + "module_identities", + "backlog_status", + "backlog_sync", + "source_snapshot_sha256" + ], + "properties": { + "schema_version": { + "const": "0.6.0" + }, + "report_type": { + "const": "go_lint_local_feedback" + }, + "operation": { + "const": "lint" + }, + "language": { + "const": "go" + }, + "checker_id": { + "const": "go.vet" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_unverified", + "clean_observed_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "root": { + "type": "string" + }, + "native_tool_version": { + "type": [ + "string", + "null" + ] + }, + "tool_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "manifest_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "go_sum_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "source_file_count": { + "type": "integer", + "minimum": 0 + }, + "module_count": { + "type": "integer", + "minimum": 0 + }, + "modules_completed": { + "type": "integer", + "minimum": 0 + }, + "module_results": { + "type": "array", + "items": { + "$ref": "#/$defs/goModuleResult" + } + }, + "native_diagnostic_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "$ref": "#/$defs/goFinding" + } + }, + "native_recheck_argv": { + "const": [ + "go", + "vet", + "-json", + "./..." + ] + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "workspace_binding": { + "enum": [ + "bound", + "legacy_unbound", + "uninitialized", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]+$" + }, + "module_identities": { + "type": "object", + "maxProperties": 64, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "required": [ + "manifest_sha256", + "go_sum_sha256" + ], + "properties": { + "manifest_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "go_sum_sha256": { + "$ref": "#/$defs/nullableSha256" + } + } + } + }, + "backlog_status": { + "enum": [ + "not_attempted", + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "new_findings", + "new_blockers", + "imported_reports", + "historical_findings", + "failed_reports" + ], + "properties": { + "new_findings": { + "type": "integer", + "minimum": 0 + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "imported_reports": { + "type": "integer", + "minimum": 0 + }, + "historical_findings": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "source_snapshot_sha256": { + "$ref": "#/$defs/nullableSha256" + } + } + } + ] + }, + "rust_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "configuration", + "configuration_ref", + "local_scan_complete", + "reason", + "tool_sha256", + "findings", + "scope", + "coverage_proven", + "authority", + "recheck_command", + "operation", + "language", + "command_status", + "delivery_decision", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "manifest_sha256", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "rust_clippy_local_observation" + }, + "checker_id": { + "const": "rust.cargo_clippy" + }, + "configuration": { + "enum": [ + "unknown", + "configured" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "local_scan_complete": { + "type": "boolean" + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "type": [ + "string", + "null" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "rule_id", + "path", + "line", + "column", + "level", + "finding_id", + "finding_fingerprint", + "source_sha256" + ], + "properties": { + "rule_id": { + "type": "string" + }, + "path": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "level": { + "enum": [ + "warning", + "error" + ] + }, + "finding_id": { + "type": "string" + }, + "finding_fingerprint": { + "type": "string" + }, + "source_sha256": { + "type": "string" + } + } + } + }, + "scope": { + "const": "default_features_all_targets" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "recheck_command": { + "type": "string" + }, + "operation": { + "const": "lint" + }, + "language": { + "const": "rust" + }, + "command_status": { + "const": "incomplete" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "manifest_sha256": { + "type": [ + "string", + "null" + ] + }, + "backlog_status": { + "enum": [ + "synced_partial", + "backlog_update_failed", + "not_initialized" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + } + } + } + ] + }, + "java_p3c": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "command_status", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "checker_id", + "language", + "category", + "source_file_count", + "observed_file_count", + "finding_count", + "findings", + "local_observation_complete", + "coverage_proven", + "authority", + "delivery_decision", + "files", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_p3c_project_observation" + }, + "operation": { + "const": "lint" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "checker_id": { + "const": "java.maven.p3c" + }, + "language": { + "const": "java" + }, + "category": { + "const": "lint" + }, + "source_file_count": { + "type": "integer", + "minimum": 1 + }, + "observed_file_count": { + "type": "integer", + "minimum": 0 + }, + "finding_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array" + }, + "local_observation_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "backlog_status": { + "enum": [ + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + }, + "files": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "build_root", + "configuration", + "configuration_ref", + "reason", + "observation" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration": { + "enum": [ + "configured", + "missing", + "unknown", + "invalid" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "configuration_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "reason": { + "enum": [ + "native_probe_returned", + "finding_projection_incomplete", + "p3c_configuration_not_confirmed", + "p3c_configuration_changed_before_scan", + "p3c_configuration_changed_during_scan", + "p3c_ruleset_selection_unresolved", + "request_cancelled", + "request_deadline_exceeded" + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "local_status", + "reason", + "declared_rulesets", + "native_plan_sha256", + "findings", + "coverage_proven", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_p3c_local_feedback" + }, + "local_status": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "declared_rulesets": { + "type": "array", + "minItems": 1, + "maxItems": 10, + "uniqueItems": true + }, + "native_plan_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "findings": { + "type": "array" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + } + } + } + } + } + ] + }, + "java_dependencies": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "language", + "category", + "source_file_count", + "configured_build_root_count", + "observed_graph_count", + "local_probe_complete", + "project_checker_attribution", + "coverage_proven", + "authority", + "delivery_decision", + "probes" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_dependency_project_probe" + }, + "checker_id": { + "const": "java.maven.dependency" + }, + "language": { + "const": "java" + }, + "category": { + "const": "dependencies" + }, + "source_file_count": { + "type": "integer", + "minimum": 0 + }, + "configured_build_root_count": { + "type": "integer", + "minimum": 0 + }, + "observed_graph_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "project_checker_attribution": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "category", + "native_status", + "reason", + "native_plan_sha256", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "graph_sha256", + "nodes", + "edges", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "maven_dependency_tree_probe" + }, + "checker_id": { + "const": "java.maven.dependency" + }, + "category": { + "const": "dependencies" + }, + "native_status": { + "enum": [ + "incomplete", + "graph_observed_untrusted" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "native_plan_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "maven_tool_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "java_runtime_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "dependency_closure_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "graph_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "nodes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "group_id", + "artifact_id", + "version", + "type", + "scope", + "classifier", + "optional", + "artifact_sha256" + ], + "properties": { + "group_id": { + "type": "string" + }, + "artifact_id": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "classifier": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "artifact_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + } + } + } + }, + "edges": { + "type": "array", + "items": { + "type": "array", + "prefixItems": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ], + "items": false + } + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + } + } + } + ] + }, + "java_cve": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "command_status", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "checker_id", + "language", + "category", + "configured_build_root_count", + "observed_report_count", + "local_probe_complete", + "database_freshness", + "coverage_proven", + "authority", + "delivery_decision", + "attribution_probes", + "probes", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "java_cve_project_probe" + }, + "operation": { + "const": "check" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "minLength": 1 + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "checker_id": { + "const": "java.maven.dependency_check" + }, + "language": { + "const": "java" + }, + "category": { + "const": "cve" + }, + "configured_build_root_count": { + "type": "integer", + "minimum": 0 + }, + "observed_report_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "database_freshness": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "backlog_status": { + "enum": [ + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + }, + "attribution_probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "status", + "bindings" + ], + "properties": { + "build_root": { + "type": "string" + }, + "status": { + "enum": [ + "dependency_graph_unavailable", + "dependency_graph_ambiguous", + "native_reports_unavailable", + "native_identity_unavailable", + "native_identity_mismatch", + "native_report_invalid", + "candidate_evaluated_untrusted" + ] + }, + "bindings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "observation_index", + "coordinate_state", + "graph_node_index", + "artifact_state" + ], + "properties": { + "observation_index": { + "type": "integer", + "minimum": 0 + }, + "coordinate_state": { + "enum": [ + "exact_coordinate_candidate", + "missing_maven_purl", + "unsupported_purl", + "conflicting_purls", + "not_in_graph", + "ambiguous_graph_coordinate" + ] + }, + "graph_node_index": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "artifact_state": { + "enum": [ + "attribution_unavailable", + "owasp_digest_missing", + "maven_digest_missing", + "digest_evidence_invalid", + "digest_mismatch", + "exact_digest_candidate" + ] + } + } + } + } + } + } + }, + "probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string" + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "category", + "native_status", + "reason", + "plugin_version", + "native_plan_sha256", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "database_tree_sha256", + "native_report_sha256", + "database_freshness", + "dependency_count", + "database_sources", + "advisories", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "owasp_maven_probe" + }, + "checker_id": { + "const": "java.maven.dependency_check" + }, + "category": { + "const": "cve" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_untrusted", + "empty_report_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "plugin_version": { + "type": [ + "string", + "null" + ] + }, + "native_plan_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "maven_tool_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "java_runtime_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "dependency_closure_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "database_tree_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "native_report_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "database_freshness": { + "const": "unverified" + }, + "dependency_count": { + "type": "integer", + "minimum": 0 + }, + "database_sources": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "timestamp" + ], + "properties": { + "name": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + } + }, + "advisories": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "source", + "advisory_id", + "score", + "package_ids", + "dependency_sha256", + "suppressed_by_native_tool" + ], + "properties": { + "source": { + "type": "string" + }, + "advisory_id": { + "type": "string" + }, + "score": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 10 + }, + "package_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "dependency_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "suppressed_by_native_tool": { + "type": "boolean" + } + } + } + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + } + } + } + ] + }, + "java_javadoc": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "project_checker_attribution", + "language", + "category", + "source_file_count", + "observed_file_count", + "local_probe_complete", + "coverage_proven", + "authority", + "delivery_decision", + "files", + "maven_multifile_probes", + "probe_mode" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "java_javadoc_project_probe" + }, + "checker_id": { + "enum": [ + "java.jdk.javadoc", + "java.maven.javadoc" + ] + }, + "project_checker_attribution": { + "const": "unverified" + }, + "language": { + "const": "java" + }, + "category": { + "const": "comments" + }, + "source_file_count": { + "type": "integer", + "minimum": 1 + }, + "observed_file_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "maven_multifile_probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "native_status", + "reason", + "source_count", + "observed_source_count", + "findings", + "native_plan_sha256", + "pom_mode", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "project_checker_attribution", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "maven_javadoc_multifile_probe" + }, + "checker_id": { + "const": "java.maven.javadoc" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_untrusted", + "clean_log_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "source_count": { + "type": "integer", + "minimum": 1 + }, + "observed_source_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "line", + "column", + "rule_id" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "rule_id": { + "type": "string", + "minLength": 1 + } + } + } + }, + "native_plan_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "pom_mode": { + "enum": [ + "unverified", + "direct_pom_replay" + ] + }, + "maven_tool_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "java_runtime_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "dependency_closure_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "project_checker_attribution": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + }, + "files": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "build_root", + "configuration", + "configuration_ref", + "configuration_sha256", + "reason", + "observation" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration": { + "enum": [ + "configured", + "missing", + "unknown", + "invalid" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "configuration_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "reason": { + "enum": [ + "request_cancelled", + "request_deadline_exceeded", + "javadoc_configuration_not_confirmed", + "javadoc_configuration_changed_before_scan", + "javadoc_configuration_changed_during_scan", + "javadoc_source_scope_unverified", + "native_probe_returned", + "maven_multifile_probe_selected" + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "report_type", + "local_status", + "findings", + "coverage_proven", + "delivery_decision" + ], + "properties": { + "report_type": { + "const": "java_javadoc_local_feedback" + }, + "local_status": { + "enum": [ + "incomplete", + "clean_scope_unproven", + "findings_observed_untrusted" + ] + }, + "findings": { + "type": "array" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "reason": { + "const": "maven_multifile_probe_selected" + } + } + }, + "then": { + "properties": { + "observation": { + "type": "null" + } + } + } + } + ] + } + }, + "probe_mode": { + "enum": [ + "jdk_single_file", + "maven_multifile" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "probe_mode": { + "const": "maven_multifile" + } + } + }, + "then": { + "properties": { + "checker_id": { + "const": "java.maven.javadoc" + }, + "files": { + "items": { + "properties": { + "observation": { + "type": "null" + } + } + } + } + } + }, + "else": { + "properties": { + "checker_id": { + "const": "java.jdk.javadoc" + }, + "maven_multifile_probes": { + "maxItems": 0 + } + } + } + } + ] + } + ] + }, + "python_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "files", + "command_status", + "exit_code", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.12.0" + }, + "report_type": { + "const": "python_lint_feedback" + }, + "files": { + "type": "array" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + }, + "npm_cve": { + "type": "array", + "items": { + "$ref": "#/$defs/npmCheckResult" + } + }, + "rust_comments": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_comments" + } + ] + }, + "rust_build": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_build" + } + ] + }, + "rust_cve": { + "oneOf": [ + {"type": "null"}, + {"$ref": "#/$defs/rust_cve"} + ] + } + } + }, + "obligation_status": { + "const": "unresolved" + }, + "required_obligations": { + "type": "null" + }, + "category_candidates": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "language", + "legacy_status", + "capability_status", + "category", + "checker_id", + "next_action", + "status", + "reason" + ], + "properties": { + "language": { + "type": "string", + "minLength": 1 + }, + "legacy_status": { + "enum": [ + "stable", + "planned", + "unknown" + ] + }, + "capability_status": { + "enum": [ + "gap", + null + ] + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "checker_id": { + "type": [ + "string", + "null" + ], + "minLength": 1 + }, + "next_action": { + "type": [ + "string", + "null" + ], + "minLength": 1 + }, + "status": { + "enum": [ + "observed_unverified", + "native_incomplete", + "not_configured", + "configuration_unresolved", + "not_integrated" + ] + }, + "reason": { + "enum": [ + "trusted_policy_and_coverage_unavailable", + "native_scan_incomplete", + "p3c_declared_rulesets_unverified_coverage", + "javadoc_single_file_probe_unverified_coverage", + "javadoc_checker_not_configured", + "javadoc_configuration_unresolved", + "javadoc_multifile_probe_unverified_project_coverage", + "dependency_graph_observed_unverified_coverage", + "cve_report_observed_database_unverified", + "configured_checker_not_integrated", + "recognized_checker_not_configured", + "checker_configuration_not_observed", + "checker_configuration_mixed_across_sources", + "checker_configuration_unresolved", + "checker_build_systems_mixed", + "gradle_model_not_resolved", + "native_adapter_not_integrated", + "planned_language_adapter_gap", + "npm_advisory_coverage_and_freshness_unverified", + "rust_cve_database_freshness_unverified", + "rust_cve_native_incomplete", + "python_cve_native_incomplete", + "python_cve_advisory_coverage_and_freshness_unverified" + ] + } + } + } + }, + "unresolved_conditions": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "next": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "repair_brief_preview" + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + } +} diff --git a/schemas/check-feedback-v0.32.schema.json b/schemas/check-feedback-v0.32.schema.json new file mode 100644 index 00000000..bfef49b1 --- /dev/null +++ b/schemas/check-feedback-v0.32.schema.json @@ -0,0 +1,5603 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:codeguard:schema:check-feedback:0.32.0", + "title": "CodeGuard partial project or language check feedback", + "$defs": { + "rust_cve": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "checker_id", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "coverage_proven", + "database_freshness", + "local_scan_complete", + "reason", + "tool_sha256", + "lock_sha256", + "manifest_sha256", + "dependency_count", + "database_advisory_count", + "database_last_commit", + "database_last_updated", + "native_warnings_present", + "findings", + "next_actions", + "execution_budget" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "rust_cve_local_observation" + }, + "operation": { + "const": "cve" + }, + "language": { + "const": "rust" + }, + "checker_id": { + "const": "rust.cargo_audit" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "database_freshness": { + "const": "unverified" + }, + "local_scan_complete": { + "type": "boolean" + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_cve/$defs/nullable_digest" + }, + "dependency_count": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "database_advisory_count": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "database_last_commit": { + "type": [ + "string", + "null" + ] + }, + "database_last_updated": { + "type": [ + "string", + "null" + ] + }, + "native_warnings_present": { + "type": "boolean" + }, + "findings": { + "type": "array", + "maxItems": 100000, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "advisory_id", + "package_name", + "package_version", + "package_source_sha256", + "package_checksum", + "cve_aliases", + "cvss_vector", + "severity" + ], + "properties": { + "advisory_id": { + "type": "string", + "pattern": "^RUSTSEC-" + }, + "package_name": { + "type": "string", + "minLength": 1 + }, + "package_version": { + "type": "string", + "minLength": 1 + }, + "package_source_sha256": { + "$ref": "#/$defs/rust_cve/$defs/digest" + }, + "package_checksum": { + "type": [ + "string", + "null" + ] + }, + "cve_aliases": { + "type": "array", + "items": { + "type": "string", + "pattern": "^CVE-" + } + }, + "cvss_vector": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "const": "unverified" + } + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1 + }, + "source": { + "type": "string" + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + }, + "required": [ + "command_status" + ] + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + } + ], + "$defs": { + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "nullable_digest": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_cve/$defs/digest" + } + ] + } + } + }, + "nullableSha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "goModuleResult": { + "type": "object", + "additionalProperties": false, + "required": [ + "root", + "status", + "diagnostic_count" + ], + "properties": { + "root": { + "type": "string", + "minLength": 1 + }, + "status": { + "enum": [ + "incomplete", + "findings_observed_unverified", + "clean_observed_unverified" + ] + }, + "diagnostic_count": { + "type": "integer", + "minimum": 0 + }, + "reason": { + "type": "string", + "minLength": 1 + } + } + }, + "goFinding": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "module_root", + "rule_id", + "path", + "line", + "column", + "native_message_sha256", + "message_status" + ], + "properties": { + "finding_id": { + "type": "string", + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "module_root": { + "type": "string", + "minLength": 1 + }, + "rule_id": { + "type": "string", + "minLength": 1 + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "native_message_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "message_status": { + "const": "native_text_private_untrusted" + } + } + }, + "npmCheckResult": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "feedback", + "observation", + "backlog_status" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "feedback": { + "oneOf": [ + { + "type": "null" + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈0.1/0.2/0.3;持久任务不授权门禁", + "oneOf": [ + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "const": "not_connected" + }, + "next_action": { + "type": "string", + "minLength": 1 + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action", + "execution_budget" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "const": "not_connected" + }, + "next_action": { + "type": "string", + "minLength": 1 + }, + "execution_budget": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE反馈,不能自证库或门禁权威", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "status", + "reason", + "local_coherent", + "configuration", + "dependency_total", + "findings", + "advisory_coverage", + "tool_approval", + "delivery_decision", + "workbench_status", + "next_action", + "execution_budget", + "workbench" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "npm_cve_feedback" + }, + "status": { + "enum": [ + "incomplete", + "local_observation" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "local_coherent": { + "type": "boolean" + }, + "configuration": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "dependency_total": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + }, + "advisory_coverage": { + "const": "not_evaluated" + }, + "tool_approval": { + "const": "unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "workbench_status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$" + }, + "next_action": { + "type": "string", + "minLength": 1 + }, + "execution_budget": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + } + ] + }, + "workbench": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$" + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "enum": [ + "synced_partial", + "sync_incomplete" + ] + } + } + }, + "then": { + "required": [ + "new_blockers", + "failed_reports" + ] + } + } + ] + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "local_coherent": { + "const": true + } + } + }, + "then": { + "properties": { + "status": { + "const": "local_observation" + }, + "dependency_total": { + "type": "integer" + }, + "configuration": { + "type": "object", + "required": [ + "build_root", + "checker_id", + "category", + "configuration", + "configuration_ref", + "reason", + "next_action" + ], + "additionalProperties": false, + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "checker_id": { + "type": "string", + "minLength": 1 + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "configuration": { + "enum": [ + "configured", + "missing", + "invalid", + "unknown" + ] + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "next_action": { + "type": "string", + "minLength": 1 + } + } + } + } + }, + "else": { + "properties": { + "status": { + "const": "incomplete" + }, + "findings": { + "maxItems": 0 + }, + "dependency_total": { + "type": "null" + } + } + } + } + ] + } + ] + } + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm工作台观察0.1/0.2与输入状态准备观察0.3;不授予覆盖", + "oneOf": [ + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm局部CVE工作台观察,不能自证漏洞或关闭", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "lock_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "diagnostic_reason": { + "type": "string", + "pattern": "^[a-z0-9_]{1,80}$" + }, + "component_count": { + "type": "integer", + "minimum": 0, + "maximum": 10000 + }, + "advisories": { + "type": "array", + "maxItems": 10000, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "component_ref", + "severity", + "advisory_sources", + "nodes" + ], + "properties": { + "component_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "severity": { + "enum": [ + "info", + "low", + "moderate", + "high", + "critical" + ] + }, + "advisory_sources": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "minimum": 1 + } + }, + "nodes": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "node_ref", + "resolved_version" + ], + "properties": { + "node_ref": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "resolved_version": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + } + } + } + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "diagnostic_reason": { + "enum": [ + "npm_execution_context_missing", + "npm_manifest_invalid", + "npm_scripts_invalid" + ] + } + }, + "required": [ + "diagnostic_reason" + ] + }, + "then": { + "properties": { + "component_count": { + "const": 0 + }, + "advisories": { + "maxItems": 0 + } + } + } + }, + { + "not": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_missing" + } + }, + "required": [ + "diagnostic_reason" + ] + } + } + ] + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm缺锁准备观察;未启动工具且没有漏洞结果", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories", + "lock_state" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "lock_sha256": { + "type": "null" + }, + "diagnostic_reason": { + "const": "npm_lock_missing" + }, + "component_count": { + "const": 0 + }, + "advisories": { + "type": "array", + "maxItems": 0 + }, + "lock_state": { + "const": "missing" + } + } + }, + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "npm输入不可用的准备观察0.3;无原生漏洞结果", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "workspace_binding", + "workspace_id", + "run_id", + "authority", + "coverage_proven", + "delivery_decision", + "checker_id", + "build_root", + "manifest_sha256", + "lock_sha256", + "diagnostic_reason", + "component_count", + "advisories", + "manifest_state", + "lock_state" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "npm_cve_workbench_observation" + }, + "workspace_binding": { + "const": "bound" + }, + "workspace_id": { + "type": "string", + "minLength": 1 + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]{1,120}$" + }, + "authority": { + "const": "local_unverified" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "checker_id": { + "const": "node.npm.audit" + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + } + ] + }, + "lock_sha256": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + } + ] + }, + "diagnostic_reason": { + "enum": [ + "npm_manifest_missing", + "npm_manifest_not_regular", + "npm_manifest_path_alias", + "npm_manifest_unavailable", + "npm_lock_missing", + "npm_lock_not_regular", + "npm_lock_path_alias", + "npm_lock_unavailable" + ] + }, + "component_count": { + "const": 0 + }, + "advisories": { + "type": "array", + "maxItems": 0 + }, + "manifest_state": { + "enum": [ + "present", + "missing", + "not_regular", + "path_alias", + "unavailable" + ] + }, + "lock_state": { + "enum": [ + "present", + "missing", + "not_regular", + "path_alias", + "unavailable" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + } + } + }, + "then": { + "properties": { + "manifest_sha256": { + "type": "string" + } + } + }, + "else": { + "properties": { + "manifest_sha256": { + "type": "null" + } + } + } + }, + { + "if": { + "properties": { + "lock_state": { + "const": "present" + } + } + }, + "then": { + "properties": { + "lock_sha256": { + "type": "string" + } + } + }, + "else": { + "properties": { + "lock_sha256": { + "type": "null" + } + } + } + }, + { + "not": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "present" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "missing" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_missing" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "missing" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_missing" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "not_regular" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_not_regular" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "not_regular" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_not_regular" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "path_alias" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_path_alias" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "path_alias" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_path_alias" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "unavailable" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_manifest_unavailable" + } + } + } + }, + { + "if": { + "properties": { + "manifest_state": { + "const": "present" + }, + "lock_state": { + "const": "unavailable" + } + } + }, + "then": { + "properties": { + "diagnostic_reason": { + "const": "npm_lock_unavailable" + } + } + } + } + ] + } + ] + } + ] + }, + "backlog_status": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{0,127}$" + } + } + }, + "rust_comments": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Unverified selected Cargo rustdoc library observation", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "checker_id", + "scope", + "rule_selection", + "local_scan_complete", + "coverage_proven", + "reason", + "tool_sha256", + "manifest_sha256", + "lock_sha256", + "findings", + "backlog_status", + "execution_budget", + "next_actions", + "recheck_argv", + "workspace_binding", + "workspace_id", + "run_id", + "backlog_sync" + ], + "properties": { + "schema_version": { + "const": "0.4.0" + }, + "report_type": { + "const": "rustdoc_local_observation" + }, + "operation": { + "const": "comments" + }, + "language": { + "const": "rust" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "checker_id": { + "const": "rust.cargo_rustdoc" + }, + "scope": { + "const": "selected_root_library_default_features" + }, + "rule_selection": { + "const": "explicit_probe_not_approved_project_policy" + }, + "local_scan_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_comments/$defs/hash" + }, + "backlog_status": { + "enum": [ + "not_integrated", + "queued", + "synced", + "sync_incomplete", + "failed" + ] + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "rustdoc", + "--lib", + "--locked", + "--offline", + "--message-format=json", + "--", + "--warn", + "missing_docs", + "--warn", + "rustdoc::broken_intra_doc_links" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "rule_id", + "level", + "path", + "line", + "column", + "classification", + "byte_start", + "byte_end", + "native_range_sha256", + "identity_status", + "repair_brief", + "target_path" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "rule_id": { + "enum": [ + "missing_docs", + "rustdoc::broken_intra_doc_links" + ] + }, + "level": { + "enum": [ + "warning", + "error" + ] + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "classification": { + "const": "observed_unverified" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "identity_status": { + "enum": [ + "unique_candidate", + "ambiguous" + ] + }, + "repair_brief": { + "$ref": "#/$defs/rust_comments/$defs/repair_brief" + }, + "target_path": { + "type": "string", + "minLength": 1 + } + }, + "allOf": [ + { + "if": { + "properties": { + "identity_status": { + "const": "ambiguous" + } + } + }, + "then": { + "properties": { + "finding_id": { + "type": "null" + }, + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + }, + "else": { + "properties": { + "finding_id": { + "type": "string" + } + } + } + } + ] + } + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "invalid", + "legacy_unbound" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^rustdoc-[0-9]+-[0-9]+$" + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + } + }, + "$defs": { + "hash": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "repair_brief": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "evidence", + "rule_basis", + "allowed_paths", + "steps", + "recheck_argv", + "working_directory", + "tool_requirement", + "attempt_history", + "history_status", + "closure_conditions" + ], + "properties": { + "status": { + "enum": [ + "repair_guidance", + "investigation_required" + ] + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "path", + "source_sha256", + "byte_start", + "byte_end", + "rule_id", + "observation_reason" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "rule_id": { + "enum": [ + "missing_docs", + "rustdoc::broken_intra_doc_links" + ] + }, + "observation_reason": { + "type": "string", + "minLength": 1 + } + } + }, + "rule_basis": { + "type": "string", + "minLength": 1 + }, + "allowed_paths": { + "type": "array", + "maxItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "steps": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "rustdoc", + "--lib", + "--locked", + "--offline", + "--message-format=json", + "--", + "--warn", + "missing_docs", + "--warn", + "rustdoc::broken_intra_doc_links" + ] + }, + "working_directory": { + "const": "selected_project_root" + }, + "tool_requirement": { + "type": "string", + "minLength": 1 + }, + "attempt_history": { + "const": [] + }, + "history_status": { + "const": "not_integrated" + }, + "closure_conditions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "investigation_required" + } + } + }, + "then": { + "properties": { + "allowed_paths": { + "maxItems": 0 + } + } + }, + "else": { + "properties": { + "allowed_paths": { + "minItems": 1 + } + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + } + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + }, + "local_scan_complete": { + "const": false + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + } + } + }, + "then": { + "properties": { + "reason": { + "const": "native_observed_unverified" + }, + "tool_sha256": { + "type": "string" + }, + "manifest_sha256": { + "type": "string" + }, + "lock_sha256": { + "type": "string" + }, + "findings": { + "items": { + "properties": { + "identity_status": { + "const": "unique_candidate" + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "items": { + "properties": { + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "workspace_binding": { + "const": "bound" + } + } + }, + "then": { + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1 + } + } + }, + "else": { + "properties": { + "workspace_id": { + "type": "null" + }, + "backlog_status": { + "const": "not_integrated" + }, + "backlog_sync": { + "type": "null" + } + } + } + } + ] + }, + "rust_build": { + "title": "Unverified selected Cargo type check observation", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "checker_id", + "scope", + "rule_selection", + "local_scan_complete", + "coverage_proven", + "reason", + "tool_sha256", + "manifest_sha256", + "lock_sha256", + "findings", + "backlog_status", + "execution_budget", + "next_actions", + "recheck_argv", + "workspace_binding", + "workspace_id", + "run_id", + "backlog_sync", + "build_level", + "test_execution", + "build_success" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "rust_build_local_observation" + }, + "operation": { + "const": "build" + }, + "language": { + "const": "rust" + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "authority": { + "const": "local_unverified" + }, + "checker_id": { + "const": "rust.cargo_check" + }, + "scope": { + "const": "selected_root_all_targets_default_features" + }, + "rule_selection": { + "const": "explicit_probe_not_approved_project_policy" + }, + "local_scan_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "manifest_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "lock_sha256": { + "$ref": "#/$defs/rust_build/$defs/hash" + }, + "backlog_status": { + "enum": [ + "not_integrated", + "queued", + "synced", + "sync_incomplete", + "failed" + ] + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + } + } + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "check", + "--locked", + "--offline", + "--all-targets", + "--message-format=json" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "source_sha256", + "rule_id", + "level", + "path", + "line", + "column", + "classification", + "byte_start", + "byte_end", + "native_range_sha256", + "identity_status", + "repair_brief", + "target_path", + "package_id_sha256", + "target_kinds", + "target_sha256" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "rule_id": { + "type": "string", + "pattern": "^E[0-9]{4}$" + }, + "level": { + "const": "error" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "classification": { + "const": "observed_unverified" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "identity_status": { + "enum": [ + "unique_candidate", + "ambiguous" + ] + }, + "repair_brief": { + "$ref": "#/$defs/rust_build/$defs/repair_brief" + }, + "target_path": { + "type": "string", + "minLength": 1 + }, + "package_id_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "target_kinds": { + "type": "array", + "minItems": 1, + "maxItems": 16, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 8192 + } + }, + "target_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + } + }, + "allOf": [ + { + "if": { + "properties": { + "identity_status": { + "const": "ambiguous" + } + } + }, + "then": { + "properties": { + "finding_id": { + "type": "null" + }, + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + }, + "else": { + "properties": { + "finding_id": { + "type": "string" + } + } + } + } + ] + } + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "invalid", + "legacy_unbound" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^cargo-build-[0-9]+-[0-9]+$" + }, + "backlog_sync": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "new_findings", + "new_blockers", + "failed_reports" + ], + "properties": { + "new_findings": { + "type": "integer", + "minimum": 0 + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "build_level": { + "const": "type_check" + }, + "test_execution": { + "const": false + }, + "build_success": { + "type": [ + "boolean", + "null" + ] + } + }, + "$defs": { + "hash": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "repair_brief": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "evidence", + "rule_basis", + "allowed_paths", + "steps", + "recheck_argv", + "working_directory", + "tool_requirement", + "attempt_history", + "history_status", + "closure_conditions" + ], + "properties": { + "status": { + "enum": [ + "repair_guidance", + "investigation_required" + ] + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "finding_id", + "finding_fingerprint", + "path", + "source_sha256", + "byte_start", + "byte_end", + "rule_id", + "observation_reason", + "native_range_sha256", + "line", + "column" + ], + "properties": { + "finding_id": { + "type": [ + "string", + "null" + ], + "pattern": "^CG-[0-9a-f]{32}$" + }, + "finding_fingerprint": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "source_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "byte_start": { + "type": "integer", + "minimum": 0 + }, + "byte_end": { + "type": "integer", + "minimum": 0 + }, + "rule_id": { + "type": "string", + "pattern": "^E[0-9]{4}$" + }, + "observation_reason": { + "type": "string", + "minLength": 1 + }, + "native_range_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + } + } + }, + "rule_basis": { + "type": "string", + "minLength": 1 + }, + "allowed_paths": { + "type": "array", + "maxItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "steps": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "recheck_argv": { + "const": [ + "cargo", + "check", + "--locked", + "--offline", + "--all-targets", + "--message-format=json" + ] + }, + "working_directory": { + "const": "selected_project_root" + }, + "tool_requirement": { + "type": "string", + "minLength": 1 + }, + "attempt_history": { + "const": [] + }, + "history_status": { + "const": "not_integrated" + }, + "closure_conditions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "investigation_required" + } + } + }, + "then": { + "properties": { + "allowed_paths": { + "maxItems": 0 + } + } + }, + "else": { + "properties": { + "allowed_paths": { + "minItems": 1 + } + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + } + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + }, + "local_scan_complete": { + "const": false + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + } + } + }, + "then": { + "properties": { + "reason": { + "const": "native_observed_unverified" + }, + "tool_sha256": { + "type": "string" + }, + "manifest_sha256": { + "type": "string" + }, + "lock_sha256": { + "type": "string" + }, + "findings": { + "items": { + "properties": { + "identity_status": { + "const": "unique_candidate" + } + } + } + }, + "build_success": { + "type": "boolean" + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "items": { + "properties": { + "repair_brief": { + "properties": { + "status": { + "const": "investigation_required" + } + } + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "workspace_binding": { + "const": "bound" + } + } + }, + "then": { + "properties": { + "workspace_id": { + "type": "string", + "minLength": 1 + } + } + }, + "else": { + "properties": { + "workspace_id": { + "type": "null" + }, + "backlog_status": { + "const": "not_integrated" + }, + "backlog_sync": { + "type": "null" + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + }, + "build_success": { + "const": true + } + } + }, + "then": { + "properties": { + "findings": { + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "local_scan_complete": { + "const": true + }, + "build_success": { + "const": false + } + } + }, + "then": { + "properties": { + "findings": { + "minItems": 1 + } + } + } + } + ] + } + }, + "type": "object", + "additionalProperties": false, + "allOf": [ + { + "if": { + "properties": { + "selection": { + "const": "all" + } + }, + "required": [ + "selection" + ] + }, + "then": { + "properties": { + "delivery_decision": { + "const": "incomplete" + } + } + }, + "else": { + "properties": { + "delivery_decision": { + "const": "not_evaluated" + }, + "native_results": { + "properties": { + "python_lint": { + "type": "null" + }, + "python_cve": { + "type": "array", + "maxItems": 0 + }, + "rust_lint": { + "type": "null" + }, + "rust_cve": { + "type": "null" + }, + "go_lint": { + "type": "null" + }, + "npm_cve": { + "type": "array", + "maxItems": 0 + } + } + }, + "execution_tasks": { + "items": { + "properties": { + "id": { + "enum": [ + "java.p3c", + "java.javadoc", + "java.dependencies", + "java.cve" + ] + } + } + } + }, + "category_candidates": { + "items": { + "properties": { + "language": { + "const": "java" + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "command_status": { + "const": "cancelled" + } + }, + "required": [ + "command_status" + ] + }, + "then": { + "properties": { + "exit_code": { + "const": 130 + }, + "reason": { + "const": "request_cancelled" + } + } + }, + "else": { + "properties": { + "exit_code": { + "const": 3 + }, + "reason": { + "enum": [ + "full_project_obligations_and_trusted_policy_unavailable", + "java_selection_obligations_and_trusted_policy_unavailable" + ] + } + } + } + }, + { + "if": { + "properties": { + "selection": { + "const": "all" + }, + "command_status": { + "const": "incomplete" + } + }, + "required": [ + "selection", + "command_status" + ] + }, + "then": { + "properties": { + "reason": { + "const": "full_project_obligations_and_trusted_policy_unavailable" + } + } + } + }, + { + "if": { + "properties": { + "selection": { + "const": "java" + }, + "command_status": { + "const": "incomplete" + } + }, + "required": [ + "selection", + "command_status" + ] + }, + "then": { + "properties": { + "reason": { + "const": "java_selection_obligations_and_trusted_policy_unavailable" + } + } + } + } + ], + "required": [ + "schema_version", + "report_type", + "operation", + "selection", + "command_status", + "exit_code", + "delivery_decision", + "authority", + "reason", + "discovery", + "native_results", + "execution_tasks", + "obligation_status", + "required_obligations", + "category_candidates", + "syntax_candidates", + "unresolved_conditions", + "execution_budget", + "next", + "export" + ], + "properties": { + "schema_version": { + "const": "0.32.0" + }, + "export": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "reason_code" + ], + "properties": { + "status": { + "enum": [ + "not_requested", + "saved", + "failed" + ] + }, + "reason_code": { + "type": [ + "string", + "null" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "failed" + } + }, + "required": [ + "status" + ] + }, + "then": { + "properties": { + "reason_code": { + "enum": [ + "output_parent_unavailable", + "output_not_regular_file", + "output_existing_file_is_not_codeguard_report", + "output_identity_unavailable", + "output_temp_create_failed", + "output_temp_write_failed", + "output_replace_failed", + "output_existing_read_failed", + "output_existing_too_large" + ] + } + } + }, + "else": { + "properties": { + "reason_code": { + "type": "null" + } + } + } + } + ] + }, + "execution_tasks": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "oneOf": [ + { + "enum": [ + "python.lint", + "rust.lint", + "go.lint", + "java.p3c", + "java.javadoc", + "java.dependencies", + "java.cve", + "rust.comments", + "rust.build", + "rust.cve" + ] + }, + { + "type": "string", + "pattern": "^npm\\.cve\\.[0-9]+$" + }, + { + "type": "string", + "pattern": "^python\\.cve\\.[0-9]+$" + } + ] + }, + "status": { + "enum": [ + "native_observed_unverified", + "native_incomplete", + "cancelled", + "deadline_exceeded", + "dependency_failed", + "cancelled_before_start", + "deadline_before_start", + "internal_failure" + ] + } + } + } + }, + "execution_budget": { + "type": "object", + "additionalProperties": false, + "required": [ + "timeout_ms", + "source", + "enforcement", + "jobs_limit", + "jobs_source", + "native_task_count", + "started_native_task_count" + ], + "properties": { + "timeout_ms": { + "type": "integer", + "minimum": 1, + "maximum": 86400000 + }, + "source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "enforcement": { + "const": "native_execution_only" + }, + "jobs_limit": { + "type": "integer", + "minimum": 1, + "maximum": 64 + }, + "jobs_source": { + "enum": [ + "cli", + "registered_environment", + "project_default", + "builtin_default" + ] + }, + "native_task_count": { + "type": "integer", + "minimum": 0 + }, + "started_native_task_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "report_type": { + "const": "check_feedback" + }, + "operation": { + "const": "check" + }, + "selection": { + "enum": [ + "all", + "java" + ] + }, + "command_status": { + "enum": [ + "incomplete", + "cancelled" + ] + }, + "exit_code": { + "enum": [ + 3, + 130 + ] + }, + "delivery_decision": { + "enum": [ + "incomplete", + "not_evaluated" + ] + }, + "authority": { + "const": "local_unverified" + }, + "reason": { + "enum": [ + "full_project_obligations_and_trusted_policy_unavailable", + "java_selection_obligations_and_trusted_policy_unavailable", + "request_cancelled" + ] + }, + "discovery": { + "type": "object", + "required": [ + "schema_version", + "report_type", + "observation_complete", + "languages", + "native_tool_candidates" + ], + "properties": { + "schema_version": { + "const": "0.4.0" + }, + "report_type": { + "const": "discovery" + }, + "observation_complete": { + "type": "boolean" + }, + "languages": { + "type": "array" + }, + "native_tool_candidates": { + "type": "array" + } + } + }, + "native_results": { + "type": "object", + "additionalProperties": false, + "required": [ + "python_lint", + "python_cve", + "rust_lint", + "go_lint", + "java_p3c", + "java_javadoc", + "java_dependencies", + "java_cve", + "npm_cve", + "rust_comments", + "rust_build", + "rust_cve" + ], + "properties": { + "python_cve": { + "type": "array", + "maxItems": 1000, + "items": { + "type": "object", + "required": ["build_root", "reason", "native_report_valid", "findings"], + "properties": { + "build_root": {"type": "string"}, + "reason": {"type": "string"}, + "native_report_valid": {"type": "boolean"}, + "findings": {"type": "array"}, + "delivery_decision": {"const": "not_evaluated"}, + "coverage_proven": {"const": false} + } + } + }, + "go_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "language", + "checker_id", + "command_status", + "exit_code", + "delivery_decision", + "coverage_proven", + "authority", + "tool_approval", + "rulepack_approval", + "native_status", + "reason", + "native_tool_version", + "tool_sha256", + "manifest_sha256", + "go_sum_sha256", + "source_file_count", + "module_count", + "modules_completed", + "module_results", + "native_diagnostic_count", + "findings", + "native_recheck_argv", + "next_actions", + "workspace_binding", + "workspace_id", + "run_id", + "module_identities", + "backlog_status", + "backlog_sync", + "source_snapshot_sha256" + ], + "properties": { + "schema_version": { + "const": "0.6.0" + }, + "report_type": { + "const": "go_lint_local_feedback" + }, + "operation": { + "const": "lint" + }, + "language": { + "const": "go" + }, + "checker_id": { + "const": "go.vet" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_unverified", + "clean_observed_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "root": { + "type": "string" + }, + "native_tool_version": { + "type": [ + "string", + "null" + ] + }, + "tool_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "manifest_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "go_sum_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "source_file_count": { + "type": "integer", + "minimum": 0 + }, + "module_count": { + "type": "integer", + "minimum": 0 + }, + "modules_completed": { + "type": "integer", + "minimum": 0 + }, + "module_results": { + "type": "array", + "items": { + "$ref": "#/$defs/goModuleResult" + } + }, + "native_diagnostic_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "$ref": "#/$defs/goFinding" + } + }, + "native_recheck_argv": { + "const": [ + "go", + "vet", + "-json", + "./..." + ] + }, + "next_actions": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 + } + }, + "workspace_binding": { + "enum": [ + "bound", + "legacy_unbound", + "uninitialized", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "pattern": "^[A-Za-z0-9_-]+$" + }, + "module_identities": { + "type": "object", + "maxProperties": 64, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "required": [ + "manifest_sha256", + "go_sum_sha256" + ], + "properties": { + "manifest_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "go_sum_sha256": { + "$ref": "#/$defs/nullableSha256" + } + } + } + }, + "backlog_status": { + "enum": [ + "not_attempted", + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "new_findings", + "new_blockers", + "imported_reports", + "historical_findings", + "failed_reports" + ], + "properties": { + "new_findings": { + "type": "integer", + "minimum": 0 + }, + "new_blockers": { + "type": "integer", + "minimum": 0 + }, + "imported_reports": { + "type": "integer", + "minimum": 0 + }, + "historical_findings": { + "type": "integer", + "minimum": 0 + }, + "failed_reports": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "source_snapshot_sha256": { + "$ref": "#/$defs/nullableSha256" + } + } + } + ] + }, + "rust_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "configuration", + "configuration_ref", + "local_scan_complete", + "reason", + "tool_sha256", + "findings", + "scope", + "coverage_proven", + "authority", + "recheck_command", + "operation", + "language", + "command_status", + "delivery_decision", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "manifest_sha256", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "rust_clippy_local_observation" + }, + "checker_id": { + "const": "rust.cargo_clippy" + }, + "configuration": { + "enum": [ + "unknown", + "configured" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "local_scan_complete": { + "type": "boolean" + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "tool_sha256": { + "type": [ + "string", + "null" + ] + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "rule_id", + "path", + "line", + "column", + "level", + "finding_id", + "finding_fingerprint", + "source_sha256" + ], + "properties": { + "rule_id": { + "type": "string" + }, + "path": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "level": { + "enum": [ + "warning", + "error" + ] + }, + "finding_id": { + "type": "string" + }, + "finding_fingerprint": { + "type": "string" + }, + "source_sha256": { + "type": "string" + } + } + } + }, + "scope": { + "const": "default_features_all_targets" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "recheck_command": { + "type": "string" + }, + "operation": { + "const": "lint" + }, + "language": { + "const": "rust" + }, + "command_status": { + "const": "incomplete" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "manifest_sha256": { + "type": [ + "string", + "null" + ] + }, + "backlog_status": { + "enum": [ + "synced_partial", + "backlog_update_failed", + "not_initialized" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + } + } + } + ] + }, + "java_p3c": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "command_status", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "checker_id", + "language", + "category", + "source_file_count", + "observed_file_count", + "finding_count", + "findings", + "local_observation_complete", + "coverage_proven", + "authority", + "delivery_decision", + "files", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_p3c_project_observation" + }, + "operation": { + "const": "lint" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string" + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "checker_id": { + "const": "java.maven.p3c" + }, + "language": { + "const": "java" + }, + "category": { + "const": "lint" + }, + "source_file_count": { + "type": "integer", + "minimum": 1 + }, + "observed_file_count": { + "type": "integer", + "minimum": 0 + }, + "finding_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array" + }, + "local_observation_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "backlog_status": { + "enum": [ + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + }, + "files": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "build_root", + "configuration", + "configuration_ref", + "reason", + "observation" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration": { + "enum": [ + "configured", + "missing", + "unknown", + "invalid" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "configuration_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "reason": { + "enum": [ + "native_probe_returned", + "finding_projection_incomplete", + "p3c_configuration_not_confirmed", + "p3c_configuration_changed_before_scan", + "p3c_configuration_changed_during_scan", + "p3c_ruleset_selection_unresolved", + "request_cancelled", + "request_deadline_exceeded" + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "local_status", + "reason", + "declared_rulesets", + "native_plan_sha256", + "findings", + "coverage_proven", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_p3c_local_feedback" + }, + "local_status": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "declared_rulesets": { + "type": "array", + "minItems": 1, + "maxItems": 10, + "uniqueItems": true + }, + "native_plan_sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "findings": { + "type": "array" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + } + } + } + } + } + ] + }, + "java_dependencies": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "language", + "category", + "source_file_count", + "configured_build_root_count", + "observed_graph_count", + "local_probe_complete", + "project_checker_attribution", + "coverage_proven", + "authority", + "delivery_decision", + "probes" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "java_dependency_project_probe" + }, + "checker_id": { + "const": "java.maven.dependency" + }, + "language": { + "const": "java" + }, + "category": { + "const": "dependencies" + }, + "source_file_count": { + "type": "integer", + "minimum": 0 + }, + "configured_build_root_count": { + "type": "integer", + "minimum": 0 + }, + "observed_graph_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "project_checker_attribution": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "category", + "native_status", + "reason", + "native_plan_sha256", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "graph_sha256", + "nodes", + "edges", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.2.0" + }, + "report_type": { + "const": "maven_dependency_tree_probe" + }, + "checker_id": { + "const": "java.maven.dependency" + }, + "category": { + "const": "dependencies" + }, + "native_status": { + "enum": [ + "incomplete", + "graph_observed_untrusted" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "native_plan_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "maven_tool_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "java_runtime_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "dependency_closure_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "graph_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "nodes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "group_id", + "artifact_id", + "version", + "type", + "scope", + "classifier", + "optional", + "artifact_sha256" + ], + "properties": { + "group_id": { + "type": "string" + }, + "artifact_id": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "classifier": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "artifact_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + } + } + } + }, + "edges": { + "type": "array", + "items": { + "type": "array", + "prefixItems": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ], + "items": false + } + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + } + } + } + ] + }, + "java_cve": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "operation", + "command_status", + "exit_code", + "workspace_binding", + "workspace_id", + "run_id", + "tool_approval", + "rulepack_approval", + "checker_id", + "language", + "category", + "configured_build_root_count", + "observed_report_count", + "local_probe_complete", + "database_freshness", + "coverage_proven", + "authority", + "delivery_decision", + "attribution_probes", + "probes", + "backlog_status", + "backlog_sync", + "next" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "java_cve_project_probe" + }, + "operation": { + "const": "check" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "workspace_binding": { + "enum": [ + "bound", + "uninitialized", + "legacy_unbound", + "invalid" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + }, + "run_id": { + "type": "string", + "minLength": 1 + }, + "tool_approval": { + "const": "unverified" + }, + "rulepack_approval": { + "const": "unverified" + }, + "checker_id": { + "const": "java.maven.dependency_check" + }, + "language": { + "const": "java" + }, + "category": { + "const": "cve" + }, + "configured_build_root_count": { + "type": "integer", + "minimum": 0 + }, + "observed_report_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "database_freshness": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "backlog_status": { + "enum": [ + "synced_partial", + "not_initialized", + "backlog_update_failed" + ] + }, + "backlog_sync": { + "type": [ + "object", + "null" + ] + }, + "next": { + "type": [ + "object", + "null" + ] + }, + "attribution_probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "status", + "bindings" + ], + "properties": { + "build_root": { + "type": "string" + }, + "status": { + "enum": [ + "dependency_graph_unavailable", + "dependency_graph_ambiguous", + "native_reports_unavailable", + "native_identity_unavailable", + "native_identity_mismatch", + "native_report_invalid", + "candidate_evaluated_untrusted" + ] + }, + "bindings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "observation_index", + "coordinate_state", + "graph_node_index", + "artifact_state" + ], + "properties": { + "observation_index": { + "type": "integer", + "minimum": 0 + }, + "coordinate_state": { + "enum": [ + "exact_coordinate_candidate", + "missing_maven_purl", + "unsupported_purl", + "conflicting_purls", + "not_in_graph", + "ambiguous_graph_coordinate" + ] + }, + "graph_node_index": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "artifact_state": { + "enum": [ + "attribution_unavailable", + "owasp_digest_missing", + "maven_digest_missing", + "digest_evidence_invalid", + "digest_mismatch", + "exact_digest_candidate" + ] + } + } + } + } + } + } + }, + "probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string" + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "category", + "native_status", + "reason", + "plugin_version", + "native_plan_sha256", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "database_tree_sha256", + "native_report_sha256", + "database_freshness", + "dependency_count", + "database_sources", + "advisories", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "owasp_maven_probe" + }, + "checker_id": { + "const": "java.maven.dependency_check" + }, + "category": { + "const": "cve" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_untrusted", + "empty_report_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "plugin_version": { + "type": [ + "string", + "null" + ] + }, + "native_plan_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "maven_tool_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "java_runtime_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "dependency_closure_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "database_tree_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "native_report_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "database_freshness": { + "const": "unverified" + }, + "dependency_count": { + "type": "integer", + "minimum": 0 + }, + "database_sources": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "timestamp" + ], + "properties": { + "name": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + } + }, + "advisories": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "source", + "advisory_id", + "score", + "package_ids", + "dependency_sha256", + "suppressed_by_native_tool" + ], + "properties": { + "source": { + "type": "string" + }, + "advisory_id": { + "type": "string" + }, + "score": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 10 + }, + "package_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "dependency_sha256": { + "$ref": "#/$defs/nullableSha256" + }, + "suppressed_by_native_tool": { + "type": "boolean" + } + } + } + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + } + } + } + ] + }, + "java_javadoc": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "project_checker_attribution", + "language", + "category", + "source_file_count", + "observed_file_count", + "local_probe_complete", + "coverage_proven", + "authority", + "delivery_decision", + "files", + "maven_multifile_probes", + "probe_mode" + ], + "properties": { + "schema_version": { + "const": "0.3.0" + }, + "report_type": { + "const": "java_javadoc_project_probe" + }, + "checker_id": { + "enum": [ + "java.jdk.javadoc", + "java.maven.javadoc" + ] + }, + "project_checker_attribution": { + "const": "unverified" + }, + "language": { + "const": "java" + }, + "category": { + "const": "comments" + }, + "source_file_count": { + "type": "integer", + "minimum": 1 + }, + "observed_file_count": { + "type": "integer", + "minimum": 0 + }, + "local_probe_complete": { + "type": "boolean" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + }, + "maven_multifile_probes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "build_root", + "configuration_ref", + "observation" + ], + "properties": { + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration_ref": { + "type": "string", + "minLength": 1 + }, + "observation": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_type", + "checker_id", + "native_status", + "reason", + "source_count", + "observed_source_count", + "findings", + "native_plan_sha256", + "pom_mode", + "maven_tool_sha256", + "java_runtime_sha256", + "dependency_closure_sha256", + "project_checker_attribution", + "coverage_proven", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "maven_javadoc_multifile_probe" + }, + "checker_id": { + "const": "java.maven.javadoc" + }, + "native_status": { + "enum": [ + "incomplete", + "findings_observed_untrusted", + "clean_log_unverified" + ] + }, + "reason": { + "type": "string", + "minLength": 1 + }, + "source_count": { + "type": "integer", + "minimum": 1 + }, + "observed_source_count": { + "type": "integer", + "minimum": 0 + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "line", + "column", + "rule_id" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "rule_id": { + "type": "string", + "minLength": 1 + } + } + } + }, + "native_plan_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "pom_mode": { + "enum": [ + "unverified", + "direct_pom_replay" + ] + }, + "maven_tool_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "java_runtime_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "dependency_closure_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "project_checker_attribution": { + "const": "unverified" + }, + "coverage_proven": { + "const": false + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + } + } + }, + "files": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "build_root", + "configuration", + "configuration_ref", + "configuration_sha256", + "reason", + "observation" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "build_root": { + "type": "string", + "minLength": 1 + }, + "configuration": { + "enum": [ + "configured", + "missing", + "unknown", + "invalid" + ] + }, + "configuration_ref": { + "type": [ + "string", + "null" + ] + }, + "configuration_sha256": { + "type": [ + "string", + "null" + ], + "pattern": "^[0-9a-f]{64}$" + }, + "reason": { + "enum": [ + "request_cancelled", + "request_deadline_exceeded", + "javadoc_configuration_not_confirmed", + "javadoc_configuration_changed_before_scan", + "javadoc_configuration_changed_during_scan", + "javadoc_source_scope_unverified", + "native_probe_returned", + "maven_multifile_probe_selected" + ] + }, + "observation": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "report_type", + "local_status", + "findings", + "coverage_proven", + "delivery_decision" + ], + "properties": { + "report_type": { + "const": "java_javadoc_local_feedback" + }, + "local_status": { + "enum": [ + "incomplete", + "clean_scope_unproven", + "findings_observed_untrusted" + ] + }, + "findings": { + "type": "array" + }, + "coverage_proven": { + "const": false + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "reason": { + "const": "maven_multifile_probe_selected" + } + } + }, + "then": { + "properties": { + "observation": { + "type": "null" + } + } + } + } + ] + } + }, + "probe_mode": { + "enum": [ + "jdk_single_file", + "maven_multifile" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "probe_mode": { + "const": "maven_multifile" + } + } + }, + "then": { + "properties": { + "checker_id": { + "const": "java.maven.javadoc" + }, + "files": { + "items": { + "properties": { + "observation": { + "type": "null" + } + } + } + } + } + }, + "else": { + "properties": { + "checker_id": { + "const": "java.jdk.javadoc" + }, + "maven_multifile_probes": { + "maxItems": 0 + } + } + } + } + ] + } + ] + }, + "python_lint": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "files", + "command_status", + "exit_code", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.12.0" + }, + "report_type": { + "const": "python_lint_feedback" + }, + "files": { + "type": "array" + }, + "command_status": { + "const": "incomplete" + }, + "exit_code": { + "const": 3 + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + }, + "npm_cve": { + "type": "array", + "items": { + "$ref": "#/$defs/npmCheckResult" + } + }, + "rust_comments": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_comments" + } + ] + }, + "rust_build": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/rust_build" + } + ] + }, + "rust_cve": { + "oneOf": [ + {"type": "null"}, + {"$ref": "#/$defs/rust_cve"} + ] + } + } + }, + "obligation_status": { + "const": "unresolved" + }, + "required_obligations": { + "type": "null" + }, + "category_candidates": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "language", + "legacy_status", + "capability_status", + "category", + "checker_id", + "next_action", + "status", + "reason" + ], + "properties": { + "language": { + "type": "string", + "minLength": 1 + }, + "legacy_status": { + "enum": [ + "stable", + "planned", + "unknown" + ] + }, + "capability_status": { + "enum": [ + "gap", + null + ] + }, + "category": { + "enum": [ + "lint", + "comments", + "dependencies", + "cve", + "security", + "build" + ] + }, + "checker_id": { + "type": [ + "string", + "null" + ], + "minLength": 1 + }, + "next_action": { + "type": [ + "string", + "null" + ], + "minLength": 1 + }, + "status": { + "enum": [ + "observed_unverified", + "native_incomplete", + "not_configured", + "configuration_unresolved", + "not_integrated" + ] + }, + "reason": { + "enum": [ + "trusted_policy_and_coverage_unavailable", + "native_scan_incomplete", + "p3c_declared_rulesets_unverified_coverage", + "javadoc_single_file_probe_unverified_coverage", + "javadoc_checker_not_configured", + "javadoc_configuration_unresolved", + "javadoc_multifile_probe_unverified_project_coverage", + "dependency_graph_observed_unverified_coverage", + "cve_report_observed_database_unverified", + "configured_checker_not_integrated", + "recognized_checker_not_configured", + "checker_configuration_not_observed", + "checker_configuration_mixed_across_sources", + "checker_configuration_unresolved", + "checker_build_systems_mixed", + "gradle_model_not_resolved", + "native_adapter_not_integrated", + "planned_language_adapter_gap", + "npm_advisory_coverage_and_freshness_unverified", + "rust_cve_database_freshness_unverified", + "rust_cve_native_incomplete", + "python_cve_native_incomplete", + "python_cve_advisory_coverage_and_freshness_unverified" + ] + } + } + } + }, + "syntax_candidates": { + "type": "object", + "additionalProperties": false, + "required": ["status", "reason", "execution_phase", "authority", "delivery_decision", "source_file_count", "skipped_count", "unrouted_count", "observations", "next_action"], + "properties": { + "status": {"enum": ["not_run", "attempted_incomplete", "observed_partial"]}, + "reason": {"enum": ["source_or_scope_changed", "request_cancelled", "worker_executable_unavailable", "bounded_scope", "unrouted_source", "candidate_unavailable", "candidate_unqualified", "binary_without_wasm_precheck"]}, + "execution_phase": {"const": "after_native"}, + "authority": {"const": "candidate_unqualified"}, + "delivery_decision": {"const": "incomplete"}, + "source_file_count": {"type": "integer", "minimum": 0}, + "skipped_count": {"type": "integer", "minimum": 0}, + "unrouted_count": {"type": "integer", "minimum": 0}, + "next_action": {"type": "string", "minLength": 1}, + "observations": { + "type": "array", "maxItems": 64, + "items": { + "type": "object", "additionalProperties": false, + "required": ["path", "language", "scope", "byte_offset", "status", "reason", "grammar_qualified", "source_sha256", "grammar_sha256", "recovery_count", "recoveries"], + "properties": { + "path": {"type": "string", "minLength": 1}, + "language": {"type": ["string", "null"]}, + "scope": {"enum": ["whole_file", "cfquery_body"]}, + "byte_offset": {"type": "integer", "minimum": 0}, + "status": {"enum": ["candidate_observed", "candidate_unavailable"]}, + "reason": {"type": ["string", "null"]}, + "grammar_qualified": {"const": false}, + "source_sha256": {"type": ["string", "null"], "pattern": "^[0-9a-f]{64}$"}, + "grammar_sha256": {"type": ["string", "null"], "pattern": "^[0-9a-f]{64}$"}, + "recovery_count": {"type": "integer", "minimum": 0}, + "recoveries": { + "type": "array", "maxItems": 8, + "items": { + "type": "object", "additionalProperties": false, + "required": ["kind", "syntax_kind", "start_byte", "end_byte", "start_row", "start_column_byte", "end_row", "end_column_byte"], + "properties": { + "kind": {"enum": ["ERROR", "MISSING"]}, + "syntax_kind": {"type": "string", "minLength": 1}, + "start_byte": {"type": "integer", "minimum": 0}, + "end_byte": {"type": "integer", "minimum": 0}, + "start_row": {"type": "integer", "minimum": 0}, + "start_column_byte": {"type": "integer", "minimum": 0}, + "end_row": {"type": "integer", "minimum": 0}, + "end_column_byte": {"type": "integer", "minimum": 0} + } + } + } + } + } + } + } + }, + "unresolved_conditions": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "next": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "required": [ + "schema_version", + "report_type", + "authority", + "delivery_decision" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "report_type": { + "const": "repair_brief_preview" + }, + "authority": { + "const": "local_unverified" + }, + "delivery_decision": { + "const": "not_evaluated" + } + } + } + ] + } + } +} diff --git a/schemas/check-feedback.schema.json b/schemas/check-feedback.schema.json index 9d68ff1e..64a288a5 100644 --- a/schemas/check-feedback.schema.json +++ b/schemas/check-feedback.schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:codeguard:schema:check-feedback:0.31.0", + "$id": "urn:codeguard:schema:check-feedback:0.33.0", "title": "CodeGuard partial project or language check feedback", "$defs": { "rust_cve": { @@ -3362,6 +3362,7 @@ "obligation_status", "required_obligations", "category_candidates", + "syntax_candidates", "unresolved_conditions", "execution_budget", "next", @@ -3369,7 +3370,7 @@ ], "properties": { "schema_version": { - "const": "0.31.0" + "const": "0.33.0" }, "export": { "type": "object", @@ -5508,6 +5509,59 @@ } } }, + "syntax_candidates": { + "type": "object", + "additionalProperties": false, + "required": ["status", "reason", "execution_phase", "authority", "delivery_decision", "source_file_count", "skipped_count", "unrouted_count", "native_preferred_count", "observations", "next_action"], + "properties": { + "status": {"enum": ["not_run", "attempted_incomplete", "observed_partial"]}, + "reason": {"enum": ["source_or_scope_changed", "request_cancelled", "worker_executable_unavailable", "bounded_scope", "unrouted_source", "candidate_unavailable", "candidate_unqualified", "native_preferred", "binary_without_wasm_precheck"]}, + "execution_phase": {"const": "after_native"}, + "authority": {"const": "candidate_unqualified"}, + "delivery_decision": {"const": "incomplete"}, + "source_file_count": {"type": "integer", "minimum": 0}, + "skipped_count": {"type": "integer", "minimum": 0}, + "unrouted_count": {"type": "integer", "minimum": 0}, + "native_preferred_count": {"type": "integer", "minimum": 0}, + "next_action": {"type": "string", "minLength": 1}, + "observations": { + "type": "array", "maxItems": 64, + "items": { + "type": "object", "additionalProperties": false, + "required": ["path", "language", "scope", "byte_offset", "status", "reason", "grammar_qualified", "source_sha256", "grammar_sha256", "recovery_count", "recoveries"], + "properties": { + "path": {"type": "string", "minLength": 1}, + "language": {"type": ["string", "null"]}, + "scope": {"enum": ["whole_file", "cfquery_body"]}, + "byte_offset": {"type": "integer", "minimum": 0}, + "status": {"enum": ["candidate_observed", "candidate_unavailable"]}, + "reason": {"type": ["string", "null"]}, + "grammar_qualified": {"const": false}, + "source_sha256": {"type": ["string", "null"], "pattern": "^[0-9a-f]{64}$"}, + "grammar_sha256": {"type": ["string", "null"], "pattern": "^[0-9a-f]{64}$"}, + "recovery_count": {"type": "integer", "minimum": 0}, + "recoveries": { + "type": "array", "maxItems": 8, + "items": { + "type": "object", "additionalProperties": false, + "required": ["kind", "syntax_kind", "start_byte", "end_byte", "start_row", "start_column_byte", "end_row", "end_column_byte"], + "properties": { + "kind": {"enum": ["ERROR", "MISSING"]}, + "syntax_kind": {"type": "string", "minLength": 1}, + "start_byte": {"type": "integer", "minimum": 0}, + "end_byte": {"type": "integer", "minimum": 0}, + "start_row": {"type": "integer", "minimum": 0}, + "start_column_byte": {"type": "integer", "minimum": 0}, + "end_row": {"type": "integer", "minimum": 0}, + "end_column_byte": {"type": "integer", "minimum": 0} + } + } + } + } + } + } + } + }, "unresolved_conditions": { "type": "array", "uniqueItems": true, diff --git a/schemas/grammar-asset-manifest.schema.json b/schemas/grammar-asset-manifest.schema.json index 8c0003d3..b8d86f56 100644 --- a/schemas/grammar-asset-manifest.schema.json +++ b/schemas/grammar-asset-manifest.schema.json @@ -11,7 +11,7 @@ "source_commit": {"$ref": "#/$defs/commit"}, "codegraph_license": {"const": "LICENSE.codegraph"}, "codegraph_license_sha256": {"$ref": "#/$defs/sha256"}, - "build_tool": {"const": "tree-sitter-cli 0.25.10 build --wasm; Zig: tree-sitter-cli 0.27.0 generate --abi 15 + Zig 0.16.0 wasm32-wasi; Dart: pinned parser.c/scanner.c + Zig 0.16.0 wasm32-wasi; ArkTS/Terraform: pinned npm prebuilt WASM"}, + "build_tool": {"const": "tree-sitter-cli 0.25.10 build --wasm; Zig: tree-sitter-cli 0.27.0 generate --abi 15 + Zig 0.16.0 wasm32-wasi; Dart: pinned parser.c/scanner.c + Zig 0.16.0 wasm32-wasi; CFML: tree-sitter-cli 0.26.9; Scala: v0.26.2 release WASM; Swift: crate 0.7.3 sources; VB.NET/COBOL: CodeGraph-patched upstream; ArkTS/Terraform: pinned npm prebuilt WASM"}, "dependency_package_integrity": {"type": "string", "pattern": "^tree-sitter-wasms@0\\.1\\.13 sha512-[A-Za-z0-9+/]+=*$"}, "dependency_package_license": {"const": "LICENSE.tree-sitter-wasms"}, "dependency_package_license_sha256": {"$ref": "#/$defs/sha256"}, @@ -27,7 +27,7 @@ "properties": { "language": {"enum": ["arkts", "c", "cfml", "cfquery", "cfscript", "cobol", "cpp", "csharp", "dart", "erlang", "go", "java", "javascript", "kotlin", "lua", "luau", "nix", "objc", "pascal", "php", "python", "r", "ruby", "rust", "scala", "solidity", "swift", "terraform", "tsx", "typescript", "vbnet", "zig"]}, "dialect": {"type": "string", "minLength": 1}, - "loader_symbol": {"const": "c_sharp"}, + "loader_symbol": {"enum": ["c_sharp", "COBOL"]}, "grammar_repository": {"type": "string", "pattern": "^https://github\\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"}, "grammar_commit": {"$ref": "#/$defs/commit"}, "grammar_version": {"type": "string", "minLength": 1, "maxLength": 128}, diff --git a/schemas/grammar-probe-v0.1.schema.json b/schemas/grammar-probe-v0.1.schema.json new file mode 100644 index 00000000..34643f7c --- /dev/null +++ b/schemas/grammar-probe-v0.1.schema.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:codeguard:schema:grammar-probe:0.1.0", + "title": "Explicit, unqualified single-file grammar probe", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "report_type", "status", "language", "path", "native", "delivery_decision"], + "oneOf": [ + {"required": ["source_sha256", "grammar_sha256", "grammar_qualified", "precheck", "recoveries", "next_action"], "not": {"required": ["reason"]}}, + {"required": ["reason"], "not": {"anyOf": [{"required": ["precheck"]}, {"required": ["recoveries"]}]}} + ], + "properties": { + "schema_version": {"const": "0.1.0"}, + "report_type": {"const": "grammar_candidate_probe"}, + "status": {"const": "incomplete"}, + "language": {"enum": ["arkts", "c", "cfml", "cfquery", "cfscript", "cobol", "cpp", "csharp", "dart", "erlang", "go", "java", "javascript", "kotlin", "lua", "luau", "nix", "objc", "pascal", "php", "python", "r", "ruby", "rust", "scala", "solidity", "swift", "terraform", "tsx", "typescript", "vbnet", "zig"]}, + "path": {"type": "string", "minLength": 1}, + "source_sha256": {"$ref": "#/$defs/digest"}, + "grammar_sha256": {"$ref": "#/$defs/digest"}, + "grammar_qualified": {"const": false}, + "precheck": {"$ref": "#/$defs/precheck"}, + "recoveries": {"type": "array", "maxItems": 128, "items": {"$ref": "#/$defs/recovery"}}, + "native": {"type": "object", "additionalProperties": false, "required": ["status", "reason"], "properties": {"status": {"const": "not_run"}, "reason": {"const": "explicit_candidate_probe"}}}, + "delivery_decision": {"const": "not_evaluated"}, + "next_action": {"enum": ["run_or_configure_applicable_native_lint_before_delivery", "confirm_suspected_recoveries_with_applicable_native_tool"]}, + "reason": {"type": "string", "minLength": 1} + }, + "$defs": { + "digest": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "precheck": { + "type": "object", "additionalProperties": false, + "required": ["status", "scope_complete", "cancelled", "selected_files", "checked_files", "incomplete_files", "unsupported_files", "unqualified_files", "truncated_files", "suspected_recoveries"], + "properties": { + "status": {"const": "incomplete"}, + "scope_complete": {"type": "boolean"}, + "cancelled": {"const": false}, + "selected_files": {"const": 1}, + "checked_files": {"const": 1}, + "incomplete_files": {"const": 0}, + "unsupported_files": {"const": 0}, + "unqualified_files": {"const": 1}, + "truncated_files": {"type": "integer", "minimum": 0, "maximum": 1}, + "suspected_recoveries": {"type": "integer", "minimum": 0, "maximum": 128} + } + }, + "recovery": { + "type": "object", "additionalProperties": false, + "required": ["kind", "group_id", "syntax_kind", "start_byte", "end_byte", "start_row", "start_column_byte", "end_row", "end_column_byte"], + "properties": { + "kind": {"enum": ["ERROR", "MISSING"]}, + "group_id": {"type": "integer", "minimum": 1}, + "syntax_kind": {"type": "string", "minLength": 1, "maxLength": 128}, + "start_byte": {"type": "integer", "minimum": 0}, + "end_byte": {"type": "integer", "minimum": 0}, + "start_row": {"type": "integer", "minimum": 0}, + "start_column_byte": {"type": "integer", "minimum": 0}, + "end_row": {"type": "integer", "minimum": 0}, + "end_column_byte": {"type": "integer", "minimum": 0} + } + } + } +} diff --git a/schemas/zig-lint-feedback-v0.1.schema.json b/schemas/zig-lint-feedback-v0.1.schema.json new file mode 100644 index 00000000..c47c7a88 --- /dev/null +++ b/schemas/zig-lint-feedback-v0.1.schema.json @@ -0,0 +1,91 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:codeguard:schema:zig-lint-feedback:0.1.0", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "report_type", "operation", "language", "path", "status", "coverage_proven", "delivery_decision", "authority", "source_sha256", "native", "syntax_precheck", "next_action"], + "properties": { + "schema_version": {"const": "0.1.0"}, + "report_type": {"const": "zig_lint_feedback"}, + "operation": {"const": "lint"}, + "language": {"const": "zig"}, + "path": {"type": "string", "minLength": 1}, + "status": {"const": "incomplete"}, + "coverage_proven": {"const": false}, + "delivery_decision": {"const": "not_evaluated"}, + "authority": {"const": "local_unverified"}, + "source_sha256": {"anyOf": [{"type": "null"}, {"$ref": "#/$defs/digest"}]}, + "native": { + "type": "object", "additionalProperties": false, + "required": ["status", "reason", "version", "tool_sha256", "diagnostics"], + "properties": { + "status": {"enum": ["not_run", "incomplete", "completed", "diagnostics_observed"]}, + "reason": {"type": "string", "minLength": 1}, + "version": {"enum": [null, "0.16.0"]}, + "tool_sha256": {"anyOf": [{"type": "null"}, {"$ref": "#/$defs/digest"}]}, + "diagnostic_count": {"type": "integer", "minimum": 0, "maximum": 32}, + "diagnostics": {"type": "array", "maxItems": 32, "items": {"$ref": "#/$defs/diagnostic"}} + } + }, + "syntax_precheck": {"anyOf": [{"type": "null"}, {"$ref": "#/$defs/candidate"}]}, + "next_action": {"type": "string", "minLength": 1} + }, + "$defs": { + "digest": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "diagnostic": { + "type": "object", "additionalProperties": false, + "required": ["line", "column", "rule_id"], + "properties": { + "line": {"type": "integer", "minimum": 1}, + "column": {"type": "integer", "minimum": 1}, + "rule_id": {"const": "zig.ast_check.error"} + } + }, + "candidate": { + "type": "object", "additionalProperties": false, + "required": ["status"], + "oneOf": [ + {"required": ["grammar_qualified", "grammar_sha256", "precheck", "recoveries"], "not": {"required": ["reason"]}}, + {"required": ["reason"], "not": {"required": ["precheck"]}} + ], + "properties": { + "status": {"const": "incomplete"}, + "reason": {"type": "string", "minLength": 1}, + "grammar_qualified": {"const": false}, + "grammar_sha256": {"$ref": "#/$defs/digest"}, + "precheck": { + "type": "object", "additionalProperties": false, + "required": ["status", "scope_complete", "cancelled", "selected_files", "checked_files", "incomplete_files", "unsupported_files", "unqualified_files", "truncated_files", "suspected_recoveries"], + "properties": { + "status": {"const": "incomplete"}, + "scope_complete": {"type": "boolean"}, + "cancelled": {"const": false}, + "selected_files": {"const": 1}, + "checked_files": {"const": 1}, + "incomplete_files": {"const": 0}, + "unsupported_files": {"const": 0}, + "unqualified_files": {"const": 1}, + "truncated_files": {"type": "integer", "minimum": 0, "maximum": 1}, + "suspected_recoveries": {"type": "integer", "minimum": 0, "maximum": 128} + } + }, + "recoveries": {"type": "array", "maxItems": 128, "items": {"$ref": "#/$defs/recovery"}} + } + }, + "recovery": { + "type": "object", "additionalProperties": false, + "required": ["kind", "group_id", "syntax_kind", "start_byte", "end_byte", "start_row", "start_column_byte", "end_row", "end_column_byte"], + "properties": { + "kind": {"enum": ["ERROR", "MISSING"]}, + "group_id": {"type": "integer", "minimum": 1}, + "syntax_kind": {"type": "string", "minLength": 1, "maxLength": 128}, + "start_byte": {"type": "integer", "minimum": 0}, + "end_byte": {"type": "integer", "minimum": 0}, + "start_row": {"type": "integer", "minimum": 0}, + "start_column_byte": {"type": "integer", "minimum": 0}, + "end_row": {"type": "integer", "minimum": 0}, + "end_column_byte": {"type": "integer", "minimum": 0} + } + } + } +} diff --git a/tests/acceptance/check-all-32-grammar-candidates.md b/tests/acceptance/check-all-32-grammar-candidates.md new file mode 100644 index 00000000..86ff4213 --- /dev/null +++ b/tests/acceptance/check-all-32-grammar-candidates.md @@ -0,0 +1,15 @@ +# `check all` 的 32 份 grammar 候选路由局部验收 + +日期:2026-09-29。对应 OpenSpec S14.6、14.7、14.17、14.19 的局部进展,父任务均未完成。 + +源码以 `--features wasm-precheck` 构建后,`check all` 先运行现有原生节点,再对发现的普通源码执行有界候选阶段。新增路由按文件后缀选择 30 份直接 grammar,并对 `.cfs` 选 CFScript、完整 `...` 标签体选 CFQuery;`.tsx` 使用 TSX、`.js` 使用 JavaScript。`.h` 与普通 `.sql` 不凭后缀猜测。跨平台测试把 31 个源码文件分为四个有界项目,四次真实 `check all` 的报告合计出现 32 个 `candidate_observed`,语言并集与固定资产清单完全相同。每次保持退出码 3、`delivery_decision=incomplete`、`grammar_qualified=false`、`skipped_count=0`。 + +最初 macOS 单项目 31 文件样例在 45 秒预算内只完成 26 种,Swift 超时,后续 5 文件被跳过;预算调至 90 秒后,同机 54.09 秒完成 32 种。Linux CI 对同一单项目样例在 90 秒内仍只完成 26/32,故正式跨平台测试改为四个有界项目;本机四次调用合计 54.48 秒。该时间包括既有原生节点、每份资产的隔离进程及高成本 COBOL;不是冷暖启动统计、性能承诺或所有平台的内存验收。候选阶段限制 64 个文件、64 个片段,每个 worker 限 1 MiB 源码和 64 KiB 输出;未观察范围与原生阻塞保持未完成。 + +反馈协议由 `check_feedback` 0.31.0 升为 0.32.0,旧 Schema 独立保存。新增 `syntax_candidates` 只可表达未执行、尝试失败或部分候选观察;恢复位置被映射到原文件字节与行列,最多展示 8 个恢复节点,原生结果不会被覆盖。真实 `.tsx` 报告通过 Draft 2020-12 封闭 Schema 验证;原有聚合契约、单文件 probe 与路由测试通过。源码在候选 worker 执行前后复读,变化时放弃该片段观察。 + +源码可选构建的完整 CLI 测试集退出 0(需外部原生工具的用例仍按原标记忽略);默认无 WASM 构建的受影响聚合/CVE 用例、全目标 Clippy `-D warnings`、格式、分层检查和 OpenSpec strict 验证通过。取消后的定向回归确认候选阶段不启动,保留退出码 130;无 WASM 真实报告仍可通过 0.32.0 Schema,伪造 `allow` 被拒绝。完整 CLI 回归早于最后一处取消路径加固,之后已单独重跑该路径的两种构建及 Clippy。 + +另有 1 MiB 超限源码反例:本轮未启动对应 worker,不生成 grammar 摘要或疑似源码违规,聚合记录 `attempted_incomplete/candidate_unavailable`。该反例及 Clippy 在最后一次协议补充后已单独重跑。 + +仍缺逐语言版本/方言语料、原生语法能力的差分对照、误报/漏报量化、为 32 种语言分别选择适用原生工具与配置、候选任务同步、宿主对话反馈、无 WASM 构建与各发行平台实装。已知 CFQuery 漏检和 VB.NET 误报依旧存在,因此本次路由不能升级为已验收 lint 或交付许可;S14.6、14.7、14.17、14.19 不勾选。 diff --git a/tests/acceptance/check-all-native-preferred-python.md b/tests/acceptance/check-all-native-preferred-python.md new file mode 100644 index 00000000..426397f7 --- /dev/null +++ b/tests/acceptance/check-all-native-preferred-python.md @@ -0,0 +1,11 @@ +# `check all` 的 Python 原生优先局部验收 + +日期:2026-09-29。对应 OpenSpec 14.6、14.7 的局部增量,父任务仍未完成。 + +源码可选构建在 `check all` 的原生节点之后,仅当本轮 Ruff 对同一路径返回 `passed`、`findings` 或 `suppressed`,且报告源码 SHA-256 与候选阶段重新读取的字节一致、工具和配置摘要均存在时,跳过该 Python 文件的重复 WASM。`incomplete`、路径不一致或源码变化不能触发跳过。该跳过只代表本轮原生 Python 语法解析已执行,不代表其它质量类别通过。 + +真实 CLI 集成样例包含 Python 原生 F401 与 Zig 源码:F401 保留于 `native_results`;Python 不出现在候选 `observations`,`native_preferred_count=1`;Zig 仍由隔离 worker 解析,整体 `delivery_decision=incomplete` 且退出码 3。另有单元反例覆盖原生状态不完整、路径错配、源码摘要变化和非 Python 扩展名。聚合协议从 0.32.0 升至封闭的 0.33.0,并归档旧 schema;默认无 WASM 构建也输出新的计数字段 0。 + +这不等于 32 种语言均已具备逐模块原生优先选择。Java P3C 等规范检查不能单独确认语法;Go、Rust、TypeScript 等原生能力的项目范围和源码身份仍待逐语言对照。语法规则版本语料、任务/宿主反馈和发行验收也尚未完成。 + +验证:`cargo test -p codeguard-cli --features wasm-precheck` 完整测试集退出 0(需要外部工具的用例按原标记忽略);32 grammar 分批真实 CLI 回归通过。本机 Ruff 0.16.8 的原生用例补加计数与不重复解析断言后,经显式 `CODEGUARD_RUFF_BIN` 重跑通过。真实 Zig 项目输出通过 Draft 2020-12 的 0.33.0 Schema,伪造 `allow` 被拒;Clippy 全目标 `-D warnings`、OpenSpec strict 与 crate 分层检查通过。默认无 WASM 构建的受影响聚合、Java/P3C 与 npm 测试均退出 0。 diff --git a/tests/acceptance/erlang-grammar-candidate.md b/tests/acceptance/erlang-grammar-candidate.md new file mode 100644 index 00000000..bb270595 --- /dev/null +++ b/tests/acceptance/erlang-grammar-candidate.md @@ -0,0 +1,9 @@ +# Erlang grammar 候选局部验收 + +日期:2026-09-29。对应 OpenSpec 14.1、14.4、14.19 的局部进展,任务保持未完成。 + +RED:新增候选契约测试时,`bundled_grammar_candidate("erlang")` 返回“不支持的 grammar 语种”。GREEN:复制固定 CodeGraph 提交中的 421639 字节 WASM,固定 WhatsApp 上游 `0.19` 标签的完整提交及许可证;清单校验、Rust 离线加载和隔离 worker 测试通过。CodeGraph 提交中原文件的 SHA-256 与入库资产相同;上游许可证的 SHA-256 与标签提交中的原文件相同。来源细节见 [grammar 说明](../../grammars/erlang/README.md)。 + +合法 `-module(hello). hello() -> ok.` 无恢复错误,损坏的 `hello( -> ok.` 有恢复错误;实测 ABI 14。worker 的合法样例仍返回 `incomplete` 和 `grammar_qualified=false`。`grammar status` 更新为 32 种来源、24 份候选、0 项已发行。上游 Zig 重新构建的 WASM 导入 `__main_argc_argv`,当前 Rust 加载器拒绝;本候选直接使用已能加载且逐字节固定的 CodeGraph WASM,尚无上游源码重建字节一致性证明。 + +未完成独立版本/方言语料、原生 Erlang 检查器对照、误报漏报评估、公开原生优先路由、任务和宿主对话反馈、资源预算及发行包实装。该局部验收不能证明 Erlang lint 可用,也不能把初检零恢复当作交付通过。 diff --git a/tests/acceptance/final-seven-grammar-candidates.md b/tests/acceptance/final-seven-grammar-candidates.md new file mode 100644 index 00000000..717923ab --- /dev/null +++ b/tests/acceptance/final-seven-grammar-candidates.md @@ -0,0 +1,15 @@ +# 七份 CodeGraph grammar 候选局部验收 + +日期:2026-09-29。对应 OpenSpec 14.1、14.2、14.4、14.19 的局部进展;完整任务均未完成。 + +固定 CodeGraph `1072f82ce24db3d133258d30165cef6b74d108b2` 中 CFML、CFQuery、CFScript、COBOL、Scala、Swift、VB.NET 七份 WASM,逐份与提交中的原始字节核对。许可证、上游提交或发行包及必要补丁分别见 `grammars//README.md`;清单和 Rust 适配器同时固定摘要、字节长度、ABI 与候选状态。`grammar status` 现列出 32 种来源、32 份可由 Rust worker 加载的候选、0 项已发行,仍以退出码 3 明示未完成。 + +Rust 离线加载实测 CFML/CFQuery/CFScript/Scala/Swift/VB.NET 为 ABI 15,COBOL 为 ABI 14;隔离 worker 对七种基本正例返回 `incomplete`、`grammar_qualified=false`。COBOL 曾被原 8 MiB 上限及小写导出名校验挡住:RED 用例失败为“无效的 grammar 名称”;将受限输入上限调整为 20 MiB、允许固定的 `COBOL` 导出名后,固定格式程序及 worker 正例通过。本机一次冷加载约 20 秒、峰值常驻内存约 458 MB,后续 worker 样例约 12 秒;这只是单机观察,不是生产快检预算或 Linux 资源验收。 + +验收暴露的精度缺口必须保留:CFQuery 将 `SELECT FROM` 解析为无恢复节点,因而不能代替 SQL 语法/语义检查;未闭合的 `#` 插值才触发当前反例。VB.NET 将合法的未缩进类方法体解析出 `MISSING ":"`,属于已知误报;本轮仅用缩进后的正例证明资产可加载。CFML 三种 grammar 之间的嵌入片段切换也没有在 CodeGuard 中实现。不能将上述样例通过或候选数等同 32 种语言的 lint 可用。 + +源码构建新增 `grammar probe --format=json`,显式调用同一隔离 worker;Python、TSX 干净样例与 Java 缺失括号样例的 CLI 测试均保持 `incomplete`、原生未运行、交付未评估。完整工作区测试日志包含 183 个结果段、1156 通过、0 失败、106 忽略;此次数值不把被忽略的原生工具验收算作通过。Clippy、默认构建检查、OpenSpec 严格验证及清单 JSON Schema 验证通过。 + +公开候选诊断补齐 [0.1.0 封闭报告 Schema](../../schemas/grammar-probe-v0.1.schema.json):32 种语言枚举与资产清单由测试对齐;干净 Python 样例及缺失文件样例的真实输出均通过 Draft 2020-12 验证,伪造 `clean` 或额外字段被拒。输入失败也返回版本化 JSON 与退出码 3,不把缺失文件作为源码违规。此 Schema 只服务显式单文件诊断,仍不具备原生 lint 或交付权威。 + +剩余工作包括逐语言版本/方言独立语料、原生工具对照、误报漏报评估、原生优先统一 `lint/check` 路由、任务/对话反馈、COBOL 成本优化、发行包离线实装及宿主验证。未满足这些条件前,32 份候选只能提供显式诊断或局部受控观察,不能签发通过或关闭原生检查义务。 diff --git a/tests/acceptance/pascal-grammar-candidate.md b/tests/acceptance/pascal-grammar-candidate.md new file mode 100644 index 00000000..93d1ef42 --- /dev/null +++ b/tests/acceptance/pascal-grammar-candidate.md @@ -0,0 +1,9 @@ +# Pascal grammar 候选局部验收 + +日期:2026-09-29。对应 OpenSpec 14.1、14.4、14.19 的局部进展,任务保持未完成。 + +RED:新增候选契约测试时,`bundled_grammar_candidate("pascal")` 返回“不支持的 grammar 语种”。GREEN:CodeGraph 固定提交中的 716886 字节 WASM 与本目录资产逐字节相同;原始 `package.json` 把上游锁定为 `Isopod/tree-sitter-pascal@042119eca2e18a60e56317fb06ee3ba5c32cb447`,许可证与该提交原文件字节相同。来源细节见 [grammar 说明](../../grammars/pascal/README.md)。 + +Rust 离线加载实测 ABI 14。`program Hello; begin writeln('Hi'); end.` 无恢复错误,缺少 `end.` 的反例有恢复错误;隔离 worker 的合法样例仍返回 `incomplete` 和 `grammar_qualified=false`。`grammar status` 更新为 32 种来源、25 份候选、0 项已发行。 + +尚缺逐版本 Delphi/FreePascal 正反语料、原生工具对照、误报漏报评估、公开原生优先路由、任务和宿主对话反馈、资源预算及发行包实装。该局部验收不证明 Pascal lint 可用,也不允许以初检零恢复批准交付。 diff --git a/tests/acceptance/zig-grammar-candidate.md b/tests/acceptance/zig-grammar-candidate.md index 45dd553f..e1b7a67d 100644 --- a/tests/acceptance/zig-grammar-candidate.md +++ b/tests/acceptance/zig-grammar-candidate.md @@ -7,3 +7,5 @@ RED:直接用 Rust `WasmStore` 加载新 Zig 原始 WASM,因缺少 `__main_a GREEN:离线 Rust 加载实测 ABI 15;`struct`、`enum`、`union(enum)`、`opaque` 四种合法空容器没有解析恢复,未闭合容器产生解析错误。本机 Zig 0.16.0 的 `zig fmt --check` 对同一四种空容器样例返回 0,形成一项窄范围原生对照。隔离 worker 对合法 Zig 文件返回候选观察,但 `grammar_qualified=false`,聚合结果保持 `incomplete`;`grammar status` 显示 Zig 为第五份 `candidate_unvalidated`,`released_count=0`。初检没有公共 Zig `lint/check` 路由、工作台任务与宿主对话接线,因此**不宣称 Zig 语法检查能力已发布**。完整 Zig 版本/方言覆盖、合法与非法语料、原生对照、性能与发行包均待验收。 验证:`grammar_asset_manifest` 4/4,`wasm_grammar_load` 2/2,`grammar_status_cli` 2/2,`syntax_worker_candidate` 7/7;均以 `--locked` 离线构建,worker 测试启用 `wasm-precheck`。默认构建的 `cargo test --workspace --locked --quiet --no-fail-fast` 退出 0;启用 `codeguard-cli/wasm-precheck` 的全工作区、全部 targets 回归最终退出 0,共 180 组、1129 通过、106 条条件忽略、零失败。首轮特性回归暴露旧测试假定“工作区只有一张 Ruff 任务”;测试现按 `reason_code` 选取原生环境任务,同时核对候选初检的原生确认任务仍在。特性 Clippy `-D warnings`、格式、分层检查、OpenSpec strict 与 diff 检查退出 0。条件忽略的真实原生工具测试、Rust 1.85 MSRV 和发行包实装并未由这些结果证明。 + +后续局部增量:`lint zig FILE --zig-tool ABS_PATH --format=json` 在源码可选 WASM 构建中加入单文件原生优先路径。真实本机 Zig 0.16.0 的合法空容器返回 `native.status=completed`,缺失闭合括号返回 `diagnostics_observed` 及行列位置;两者均未运行 WASM,整体仍 `incomplete`。没有显式 Zig 工具时同一合法空容器由固定 WASM worker 观察,仍 `grammar_qualified=false`。独立伪工具回归证明原生诊断不会被 WASM 洗掉、原生 AST 无错误不会被提升为完整 lint、执行中工具字节变化会使原生结果失效;[0.1.0 报告 Schema](../../schemas/zig-lint-feedback-v0.1.schema.json)对原生正反例和候选回退的真实 JSON 均通过 Draft 2020-12 校验。此路径只覆盖 Zig 0.16.0 局部 AST 检查,不代表 `check all` 已接线、完整 lint 或发行支持。