diff --git a/README.md b/README.md index 5981e86d..fbac2d30 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ 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 pinned Java, Python, TypeScript, TSX, and Zig grammar candidates. 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 seven pinned grammar candidates: Java, Objective-C, Python, Solidity, TypeScript, TSX, and Zig. 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 five unqualified asset candidates (Java, Python, TypeScript, TSX, Zig) and zero released syntax capabilities. 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. 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 seven unqualified asset candidates (Java, Objective-C, Python, Solidity, TypeScript, TSX, Zig) and zero released syntax capabilities. 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. 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. ### npm installation and one-off use diff --git a/README.zh-CN.md b/README.zh-CN.md index d7a59ae6..9e174435 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -96,7 +96,7 @@ cargo build --locked -p codeguard-cli 工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java、Python、TypeScript、TSX 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 当前有 Java、Python、TypeScript、TSX 四份未验收资产候选,已发行语法能力为零。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 当前有 Java、Objective-C、Python、Solidity、TypeScript、TSX、Zig 七份未验收资产候选,已发行语法能力为零。Objective-C 与 Solidity 的依赖包原始字节、许可证和固定散列的 `dylink` 元数据转换已入库,可作为 Rust 隔离 worker 的候选观察,但没有公开 lint 路由或发行验收;Zig 也仍是未验收候选。Python 已有仅限源码可选构建的 CLI 候选兜底,结果保持不完整,不能批准交付。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。 ### npm 安装与一次性调用 diff --git a/crates/codeguard-adapters/src/grammar_asset_manifest.rs b/crates/codeguard-adapters/src/grammar_asset_manifest.rs index 7aec6a81..cb4c2444 100644 --- a/crates/codeguard-adapters/src/grammar_asset_manifest.rs +++ b/crates/codeguard-adapters/src/grammar_asset_manifest.rs @@ -28,6 +28,12 @@ pub struct GrammarAssetManifest { pub codegraph_license_sha256: String, /// 上游记录的构建工具版本与调用;只作来源声明。 pub build_tool: String, + /// CodeGraph 锁定的依赖包完整性;适用于 Objective-C 与 Solidity。 + pub dependency_package_integrity: Option, + /// 依赖包随附许可证路径。 + pub dependency_package_license: Option, + /// 依赖包许可证摘要。 + pub dependency_package_license_sha256: Option, /// 精确且无重复的候选语言资产。 pub assets: Vec, } @@ -52,6 +58,10 @@ pub struct GrammarAsset { pub sha256: String, /// WASM 原始字节长度。 pub bytes: usize, + /// 可重现适配前的依赖包原始路径。 + pub source_wasm: Option, + /// 可重现适配前的原始摘要。 + pub source_sha256: Option, /// 相对于 grammars/ 的许可证路径。 pub license: String, /// 许可证原始字节摘要。 @@ -70,13 +80,22 @@ pub struct GrammarAsset { pub release_status: String, } -/// 读取仓内固定清单,并检查 CodeGraph 许可证及五份资产的原始字节。 +/// 读取仓内固定清单,并检查来源、许可证及候选资产字节。 pub fn bundled_grammar_candidates() -> Result { let manifest = parse_grammar_asset_manifest(include_bytes!("../../../grammars/manifest.json"))?; let codegraph_license = include_bytes!("../../../grammars/LICENSE.codegraph"); if digest(codegraph_license) != CODEGRAPH_LICENSE_SHA256 { return Err("CodeGraph 许可证字节与固定来源不符".into()); } + if digest(include_bytes!( + "../../../grammars/LICENSE.tree-sitter-wasms" + )) != manifest + .dependency_package_license_sha256 + .as_deref() + .unwrap_or("") + { + return Err("依赖包许可证字节与固定来源不符".into()); + } for asset in &manifest.assets { let (wasm, license) = match asset.language.as_str() { "java" => ( @@ -99,6 +118,14 @@ pub fn bundled_grammar_candidates() -> Result { include_bytes!("../../../grammars/zig/parser.wasm").as_slice(), include_bytes!("../../../grammars/zig/LICENSE").as_slice(), ), + "objc" => ( + include_bytes!("../../../grammars/objc/parser.wasm").as_slice(), + include_bytes!("../../../grammars/objc/LICENSE").as_slice(), + ), + "solidity" => ( + include_bytes!("../../../grammars/solidity/parser.wasm").as_slice(), + include_bytes!("../../../grammars/solidity/LICENSE").as_slice(), + ), _ => return Err("候选语言未知".into()), }; verify_grammar_asset(asset, wasm, license)?; @@ -107,6 +134,18 @@ pub fn bundled_grammar_candidates() -> Result { { return Err("Zig grammar 来源适配关系不符".into()); } + if matches!(asset.language.as_str(), "objc" | "solidity") { + let source = if asset.language == "objc" { + include_bytes!("../../../grammars/objc/source.wasm").as_slice() + } else { + include_bytes!("../../../grammars/solidity/source.wasm").as_slice() + }; + if asset.source_sha256.as_deref() != Some(digest(source).as_str()) + || crate::adapt_legacy_dylink(&asset.language, source)? != wasm + { + return Err("依赖 grammar 来源适配关系不符".into()); + } + } } Ok(manifest) } @@ -126,7 +165,14 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result Result Result ( + "https://github.com/amaanq/tree-sitter-objc", + "dea2b2d6a1253c2f0f58b543c10d62edd2f860f2", + "2.1.0", + "objc/parser.wasm", + "2606d4c5809fab61de44d328072d1371d53aa4aff5734436cb2a0ce8db7f2b0c", + 7708267, + "objc/LICENSE", + "099c44248f8cf353123211318680e93465587c005a4b3730ce8cb5334de043d6", + ), + "solidity" => ( + "https://github.com/JoranHonig/tree-sitter-solidity", + "b239a95f94cfcc6e7b3e961bc73a28d55e214f02", + "1.2.0", + "solidity/parser.wasm", + "ba02ba3c98c8ce976ed962d727ef48940b3a18dd2243830a8158b558de64b4f2", + 423943, + "solidity/LICENSE", + "8844f0cc9b76b9c8a9d0251904eb7536b6bb9976e0ec577e8f27ab96d42523ef", + ), _ => return Err("grammar 语言未知".into()), }; if asset.dialect != asset.language + || (match asset.language.as_str() { + "objc" => { + asset.source_wasm.as_deref() != Some("objc/source.wasm") + || asset.source_sha256.as_deref() + != Some( + "7c1b5bfdca7e64b6c63b6040bb7ba0afc347df116f9030ca32f8535d7377f6ff", + ) + } + "solidity" => { + asset.source_wasm.as_deref() != Some("solidity/source.wasm") + || asset.source_sha256.as_deref() + != Some( + "160745e470f234cae903a9ba445d19e758d0b02e1197401fc765976c6254d2b6", + ) + } + _ => asset.source_wasm.is_some() || asset.source_sha256.is_some(), + }) || asset.grammar_repository != repo || asset.grammar_commit != commit || asset.grammar_version != version diff --git a/crates/codeguard-adapters/src/legacy_dylink_compat.rs b/crates/codeguard-adapters/src/legacy_dylink_compat.rs new file mode 100644 index 00000000..5669d0a2 --- /dev/null +++ b/crates/codeguard-adapters/src/legacy_dylink_compat.rs @@ -0,0 +1,102 @@ +//! 将固定依赖包的旧版 dylink 元数据转换成当前 Rust WasmStore 所需格式。 + +use sha2::{Digest, Sha256}; + +/// 仅改写固定来源 WASM 的动态链接自定义段,并验证结果摘要。 +/// 参数为语言名与原始字节;返回可由 Rust 加载的字节,不修改语法指令。 +pub fn adapt_legacy_dylink(language: &str, source: &[u8]) -> Result, String> { + let (source_sha, output_sha) = match language { + "objc" => ( + "7c1b5bfdca7e64b6c63b6040bb7ba0afc347df116f9030ca32f8535d7377f6ff", + "2606d4c5809fab61de44d328072d1371d53aa4aff5734436cb2a0ce8db7f2b0c", + ), + "solidity" => ( + "160745e470f234cae903a9ba445d19e758d0b02e1197401fc765976c6254d2b6", + "ba02ba3c98c8ce976ed962d727ef48940b3a18dd2243830a8158b558de64b4f2", + ), + _ => return Err("未知的旧版 dylink grammar".into()), + }; + if format!("{:x}", Sha256::digest(source)) != source_sha + || !source.starts_with(b"\0asm\x01\0\0\0") + { + return Err("旧版 dylink grammar 来源字节不符".into()); + } + let mut output = source[..8].to_vec(); + let mut offset = 8; + let mut converted = false; + while offset < source.len() { + let start = offset; + let id = source[offset]; + offset += 1; + let (length, payload_start) = read_leb(source, offset)?; + let end = payload_start + .checked_add(length) + .filter(|end| *end <= source.len()) + .ok_or("WASM section 越界")?; + if id == 0 { + let (name_len, name_start) = read_leb(source, payload_start)?; + let name_end = name_start + .checked_add(name_len) + .filter(|end_name| *end_name <= end) + .ok_or("WASM 自定义段名称越界")?; + if &source[name_start..name_end] == b"dylink" { + if converted { + return Err("重复 dylink 段".into()); + } + let legacy = &source[name_end..end]; + let mut position = 0; + for _ in 0..4 { + position = read_leb(legacy, position)?.1; + } + if legacy[position..].iter().any(|byte| *byte != 0) || legacy.len() != position + 1 + { + return Err("旧版 dylink 额外依赖布局不支持".into()); + } + let mut body = vec![8]; + body.extend_from_slice(b"dylink.0"); + body.push(1); + write_leb(position, &mut body); + body.extend_from_slice(&legacy[..position]); + output.push(0); + write_leb(body.len(), &mut output); + output.extend_from_slice(&body); + converted = true; + offset = end; + continue; + } + } + output.extend_from_slice(&source[start..end]); + offset = end; + } + if !converted || format!("{:x}", Sha256::digest(&output)) != output_sha { + return Err("旧版 dylink grammar 适配结果不符".into()); + } + Ok(output) +} + +fn read_leb(bytes: &[u8], mut offset: usize) -> Result<(usize, usize), String> { + let mut value = 0usize; + for shift in (0..35).step_by(7) { + let byte = *bytes.get(offset).ok_or("WASM LEB 长度缺失")?; + offset += 1; + value |= usize::from(byte & 0x7f) << shift; + if byte & 0x80 == 0 { + return Ok((value, offset)); + } + } + Err("WASM LEB 长度无效".into()) +} + +fn write_leb(mut value: usize, output: &mut Vec) { + loop { + let mut byte = (value & 0x7f) as u8; + value >>= 7; + if value != 0 { + byte |= 0x80; + } + output.push(byte); + if value == 0 { + break; + } + } +} diff --git a/crates/codeguard-adapters/src/lib.rs b/crates/codeguard-adapters/src/lib.rs index 646214f9..4e111ef7 100644 --- a/crates/codeguard-adapters/src/lib.rs +++ b/crates/codeguard-adapters/src/lib.rs @@ -64,11 +64,13 @@ mod eslint_message_report; mod eslint_parsed; mod go_candidate; mod grammar_asset_manifest; +mod legacy_dylink_compat; mod zig_wasm_compat; pub use grammar_asset_manifest::{ GrammarAsset, GrammarAssetManifest, bundled_grammar_candidates, parse_grammar_asset_manifest, verify_grammar_asset, }; +pub use legacy_dylink_compat::adapt_legacy_dylink; pub use zig_wasm_compat::adapt_zig_wasm; mod go_list_package; mod go_list_scope; diff --git a/crates/codeguard-adapters/tests/grammar_asset_manifest.rs b/crates/codeguard-adapters/tests/grammar_asset_manifest.rs index 231a6f72..6bb6a02f 100644 --- a/crates/codeguard-adapters/tests/grammar_asset_manifest.rs +++ b/crates/codeguard-adapters/tests/grammar_asset_manifest.rs @@ -1,11 +1,12 @@ use codeguard_adapters::{ - adapt_zig_wasm, bundled_grammar_candidates, parse_grammar_asset_manifest, verify_grammar_asset, + adapt_legacy_dylink, adapt_zig_wasm, bundled_grammar_candidates, parse_grammar_asset_manifest, + verify_grammar_asset, }; #[test] fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support() { let manifest = bundled_grammar_candidates().expect("bundled manifest"); - assert_eq!(manifest.assets.len(), 5); + assert_eq!(manifest.assets.len(), 7); for asset in &manifest.assets { let (wasm, license) = match asset.language.as_str() { "java" => ( @@ -28,6 +29,14 @@ fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support( include_bytes!("../../../grammars/zig/parser.wasm").as_slice(), include_bytes!("../../../grammars/zig/LICENSE").as_slice(), ), + "objc" => ( + include_bytes!("../../../grammars/objc/parser.wasm").as_slice(), + include_bytes!("../../../grammars/objc/LICENSE").as_slice(), + ), + "solidity" => ( + include_bytes!("../../../grammars/solidity/parser.wasm").as_slice(), + include_bytes!("../../../grammars/solidity/LICENSE").as_slice(), + ), other => panic!("unexpected language {other}"), }; verify_grammar_asset(asset, wasm, license).expect("pinned candidate bytes"); @@ -40,6 +49,27 @@ fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support( } } +#[test] +fn dependency_dylink_adaptation_is_byte_pinned_and_rejects_changed_source() { + for language in ["objc", "solidity"] { + let (source, adapted) = if language == "objc" { + ( + include_bytes!("../../../grammars/objc/source.wasm").as_slice(), + include_bytes!("../../../grammars/objc/parser.wasm").as_slice(), + ) + } else { + ( + include_bytes!("../../../grammars/solidity/source.wasm").as_slice(), + include_bytes!("../../../grammars/solidity/parser.wasm").as_slice(), + ) + }; + assert_eq!(adapt_legacy_dylink(language, source).unwrap(), adapted); + let mut changed = source.to_vec(); + changed[100] ^= 1; + assert!(adapt_legacy_dylink(language, &changed).is_err()); + } +} + #[test] fn zig_import_adaptation_is_byte_pinned_and_rejects_changed_source() { let source = include_bytes!("../../../grammars/zig/source.wasm"); diff --git a/crates/codeguard-cli/src/grammar_status_command.rs b/crates/codeguard-cli/src/grammar_status_command.rs index b64ae2c8..8be3e785 100644 --- a/crates/codeguard-cli/src/grammar_status_command.rs +++ b/crates/codeguard-cli/src/grammar_status_command.rs @@ -134,9 +134,8 @@ fn coverage_report() -> Result { "integration_status":candidate.map_or("not_integrated", |item| item.release_status.as_str()), "runtime_observation":candidate.map(|item| item.codeguard_runtime_validation.as_str()), "released":false, - "gap":if asset.provider == "tree_sitter_wasms_dependency" {"dependency_bytes_not_pinned"} + "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 candidate.is_some_and(|item| item.codeguard_runtime_validation == "rust_loader_incompatible") {"rust_loader_incompatible"} else if candidate.is_some() {"language_qualification_and_release_pending"} else {"asset_provenance_license_and_loader_validation_pending"}, }) @@ -195,9 +194,26 @@ fn validate_inventory(inventory: &CoverageInventory) -> Result<(), String> { } "tree_sitter_wasms_dependency" => { if !matches!(asset.language.as_str(), "objc" | "solidity") - || asset.source_path.is_some() - || asset.sha256.is_some() - || asset.bytes.is_some() + || asset.source_path.as_deref() + != Some( + format!( + "tree-sitter-wasms@0.1.13/out/tree-sitter-{}.wasm", + asset.language + ) + .as_str(), + ) + || asset.sha256.as_deref() + != Some(if asset.language == "objc" { + "7c1b5bfdca7e64b6c63b6040bb7ba0afc347df116f9030ca32f8535d7377f6ff" + } else { + "160745e470f234cae903a9ba445d19e758d0b02e1197401fc765976c6254d2b6" + }) + || asset.bytes + != Some(if asset.language == "objc" { + 7708264 + } else { + 423940 + }) { return Err("CodeGraph 依赖资产身份无效".into()); } diff --git a/crates/codeguard-cli/src/syntax_worker_command.rs b/crates/codeguard-cli/src/syntax_worker_command.rs index d897164b..405bab11 100644 --- a/crates/codeguard-cli/src/syntax_worker_command.rs +++ b/crates/codeguard-cli/src/syntax_worker_command.rs @@ -69,6 +69,8 @@ fn observe(language: &str, source: &[u8]) -> Result include_bytes!("../../../grammars/typescript/parser.wasm").as_slice(), "tsx" => include_bytes!("../../../grammars/tsx/parser.wasm").as_slice(), "zig" => include_bytes!("../../../grammars/zig/parser.wasm").as_slice(), + "objc" => include_bytes!("../../../grammars/objc/parser.wasm").as_slice(), + "solidity" => include_bytes!("../../../grammars/solidity/parser.wasm").as_slice(), _ => return Err("不支持的 grammar 语种".into()), }; let mut grammar = WasmGrammar::load(language, wasm, &asset.sha256, asset.abi_version as usize)?; diff --git a/crates/codeguard-cli/tests/grammar_status_cli.rs b/crates/codeguard-cli/tests/grammar_status_cli.rs index af863bb8..f6ea50f2 100644 --- a/crates/codeguard-cli/tests/grammar_status_cli.rs +++ b/crates/codeguard-cli/tests/grammar_status_cli.rs @@ -12,7 +12,7 @@ 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"], 5); + assert_eq!(report["candidate_count"], 7); assert_eq!(report["released_count"], 0); assert_eq!(report["authority"], "source_inventory_only"); assert_eq!(report["parser_capability"], "unverified"); @@ -25,7 +25,15 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { assert_eq!(asset["released"], false); assert!(!asset["gap"].as_str().unwrap().is_empty()); } - for language in ["java", "python", "typescript", "tsx", "zig"] { + for language in [ + "java", + "objc", + "python", + "solidity", + "typescript", + "tsx", + "zig", + ] { let asset = assets .iter() .find(|row| row["language"] == language) @@ -46,8 +54,8 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { .iter() .find(|row| row["language"] == language) .unwrap(); - assert_eq!(asset["gap"], "dependency_bytes_not_pinned"); - assert!(asset["source_sha256"].is_null()); + assert_eq!(asset["gap"], "language_qualification_and_release_pending"); + assert_eq!(asset["source_sha256"].as_str().unwrap().len(), 64); } } diff --git a/crates/codeguard-cli/tests/syntax_worker_candidate.rs b/crates/codeguard-cli/tests/syntax_worker_candidate.rs index 58c7164c..87c3e867 100644 --- a/crates/codeguard-cli/tests/syntax_worker_candidate.rs +++ b/crates/codeguard-cli/tests/syntax_worker_candidate.rs @@ -69,6 +69,35 @@ fn adapted_zig_asset_preserves_candidate_status_and_empty_container_syntax() { assert!(!result.grammar_qualified); } +#[test] +fn dependency_grammars_run_in_worker_without_claiming_clean() { + for (language, path, source) in [ + ( + "objc", + "src/Foo.m", + b"@interface Foo : NSObject\n@end\n".as_slice(), + ), + ( + "solidity", + "src/Vault.sol", + b"pragma solidity ^0.8.20;\ncontract Vault {}\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), + ) + .expect("dependency grammar worker candidate"); + assert!(result.recoveries.is_empty(), "{language}"); + 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-runtime/tests/wasm_grammar_load.rs b/crates/codeguard-runtime/tests/wasm_grammar_load.rs index bb68a06b..dafb5197 100644 --- a/crates/codeguard-runtime/tests/wasm_grammar_load.rs +++ b/crates/codeguard-runtime/tests/wasm_grammar_load.rs @@ -8,6 +8,54 @@ const TYPESCRIPT: &[u8] = include_bytes!("../../../grammars/typescript/parser.wa const TSX: &[u8] = include_bytes!("../../../grammars/tsx/parser.wasm"); const ZIG: &[u8] = include_bytes!("../../../grammars/zig/parser.wasm"); const ZIG_SOURCE: &[u8] = include_bytes!("../../../grammars/zig/source.wasm"); +const OBJC: &[u8] = include_bytes!("../../../grammars/objc/parser.wasm"); +const SOLIDITY: &[u8] = include_bytes!("../../../grammars/solidity/parser.wasm"); + +#[test] +fn dependency_grammars_load_offline_and_parse_basic_fixtures() { + let mut objc = WasmGrammar::load( + "objc", + OBJC, + "2606d4c5809fab61de44d328072d1371d53aa4aff5734436cb2a0ce8db7f2b0c", + 14, + ) + .expect("Objective-C dependency grammar loads in Rust"); + assert!( + !objc + .parse(b"@interface Foo : NSObject\n@end\n") + .unwrap() + .root_node() + .has_error() + ); + assert!( + objc.parse(b"@interface Foo : NSObject\n") + .unwrap() + .root_node() + .has_error() + ); + + let mut solidity = WasmGrammar::load( + "solidity", + SOLIDITY, + "ba02ba3c98c8ce976ed962d727ef48940b3a18dd2243830a8158b558de64b4f2", + 14, + ) + .expect("Solidity dependency grammar loads in Rust"); + assert!( + !solidity + .parse(b"pragma solidity ^0.8.20;\ncontract Vault {}\n") + .unwrap() + .root_node() + .has_error() + ); + assert!( + solidity + .parse(b"contract Vault {\n") + .unwrap() + .root_node() + .has_error() + ); +} #[test] fn pinned_grammars_load_offline_and_parse_valid_sources() { diff --git a/docs/Codeguard-Architecture.md b/docs/Codeguard-Architecture.md index f27a01bd..7435daa2 100644 --- a/docs/Codeguard-Architecture.md +++ b/docs/Codeguard-Architecture.md @@ -28,7 +28,7 @@ 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 five grammars remain unqualified; Zig is a pinned Rust-loadable candidate, not a public lint capability. 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 seven grammars remain unqualified; Zig, Objective-C and Solidity 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. ## 2. Architectural drivers diff --git a/docs/Codeguard-Architecture.zh_CN.md b/docs/Codeguard-Architecture.zh_CN.md index 4c9d8f7a..2544050e 100644 --- a/docs/Codeguard-Architecture.zh_CN.md +++ b/docs/Codeguard-Architecture.zh_CN.md @@ -28,7 +28,7 @@ | [核心聚合](../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 都尚未验收;Zig 仅有经固定字节适配后可加载的候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收、任务的能力匹配关闭及宿主接线仍未完成;设计示例不是当前命令输出。 +WASM 的规范与 19 项实施任务已纳入既有 change;可选 Rust worker 与 Java/TypeScript/TSX 局部单文件反馈路径及 Python Ruff 不可用时的候选路径已存在;七份 grammar 都尚未验收;Zig、Objective-C、Solidity 仅有经固定字节适配后可加载的候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收、任务的能力匹配关闭及宿主接线仍未完成;设计示例不是当前命令输出。 ## 2. 架构驱动 @@ -241,7 +241,7 @@ 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 有 Java、Python、TypeScript、TSX、Zig 五份资产候选。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 有 Java、Objective-C、Python、Solidity、TypeScript、TSX、Zig 七份资产候选。Objective-C 与 Solidity 来自锁定的 `tree-sitter-wasms@0.1.13`,保留原始字节和许可证,并以固定散列的 `dylink` 元数据转换加载;仍未做语言验收与发行。Zig 新版来源 WASM 的导入经固定哈希适配后由 Rust 加载,但仍无公开 `lint zig` 路由,尚无已验收发行能力。Python 已有源码可选构建中的局部 `lint` 兜底,仅覆盖 Ruff 不可用或项目未声明配置的情形;原生结果优先且不能批准交付。已初始化工作区的单文件范围可同步稳定的原生确认任务;候选零恢复节点不会关闭任务。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。尤其 COBOL 来源资产超过当前加载器 8 MiB 限额。 ```text grammars/ # 规划中的发行资产,不是项目状态 diff --git a/docs/Codeguard-Technical-Design.md b/docs/Codeguard-Technical-Design.md index 70e2816a..3290f560 100644 --- a/docs/Codeguard-Technical-Design.md +++ b/docs/Codeguard-Technical-Design.md @@ -14,7 +14,7 @@ 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 five grammars remain unqualified; Zig is only a Rust-loadable candidate. 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 seven grammars remain unqualified; Zig, Objective-C and Solidity 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. ## 2. Technology choices and trade-offs @@ -191,7 +191,7 @@ The opt-in CLI build first checks for a local ESLint 10 package and a single ord 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, five CodeGuard asset candidates (Java, Python, TypeScript, TSX and Zig), 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. The two dependency-provided assets lack pinned bytes, and COBOL exceeds the current 8 MiB loader limit; these remain explicit gaps before any per-language qualification. +Use `codeguard grammar status --format=json` to query the separate source coverage inventory. It reports 32 distinct CodeGraph grammar assets, seven CodeGuard asset candidates (Java, Objective-C, Python, Solidity, TypeScript, TSX and Zig), 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. 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 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. diff --git a/docs/Codeguard-Technical-Design.zh_CN.md b/docs/Codeguard-Technical-Design.zh_CN.md index 7ed8bed0..f8a9c39e 100644 --- a/docs/Codeguard-Technical-Design.zh_CN.md +++ b/docs/Codeguard-Technical-Design.zh_CN.md @@ -14,7 +14,7 @@ 可调用行为以当前源码为准,目标契约明确标注。产品优先级是配置发现 → 原生结果 → 有用的修复指引。内部一致性校验为这个体验服务,不要求用户手工构造执行证明。 -WASM 的规范与 19 项实施任务已纳入既有 change;可选特性下的 Rust worker 与 Java/TypeScript/TSX 局部单文件候选报告及 Python Ruff 不可用时的候选报告已存在;五份 grammar 均未验收;Zig 仅有固定适配后的 Rust 可加载候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 +WASM 的规范与 19 项实施任务已纳入既有 change;可选特性下的 Rust worker 与 Java/TypeScript/TSX 局部单文件候选报告及 Python Ruff 不可用时的候选报告已存在;七份 grammar 均未验收;Zig、Objective-C、Solidity 仅有固定适配后的 Rust 可加载候选资产,尚无公开 lint 路由。项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 ## 2. 技术选型与权衡 @@ -191,7 +191,7 @@ flowchart LR 只引入固定 WASM 字节及上游许可证、提交/补丁来源、SHA-256、ABI、已验证运行时和语言/方言范围、语料引用与已知缺口。逐个验证 CodeGraph 资产与选定 Rust Tree-sitter 运行时兼容,不能复制 TypeScript 提取逻辑或把 CodeGraph 支持等同语法验收。发行清单属于分发资产,不属于可写的 `.codeguard/` 项目状态。 -可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 五份资产候选(Java、Python、TypeScript、TSX、Zig)和零项已发行能力,不运行解析器;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。能力匹配的原生关闭仍未完成。依赖提供的两份资产尚未固定字节,COBOL 超过现有加载器的 8 MiB 限额;每语言验收前仍须解决这些缺口。 +可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 七份资产候选(Java、Objective-C、Python、Solidity、TypeScript、TSX、Zig)和零项已发行能力,不运行解析器;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。能力匹配的原生关闭仍未完成。依赖提供的 Objective-C 与 Solidity 已固定原始和适配后字节、许可证及依赖包完整性,但仍未验收语言版本或公开 lint 路由;COBOL 超过现有加载器的 8 MiB 限额。 由父进程控制解析工作进程,设置总截止时间、单文件输入上限、内存/进程限制及诊断数量上限。按需加载 grammar,不提供通用网络/文件系统导入;终止卡住的进程时保留其它模块的原生结果。宿主约束执行和 Rust MSRV 兼容性须测试,生产数值预算须经测量后确定,不编造性能承诺。 diff --git a/grammars/LICENSE.tree-sitter-wasms b/grammars/LICENSE.tree-sitter-wasms new file mode 100644 index 00000000..fdddb29a --- /dev/null +++ b/grammars/LICENSE.tree-sitter-wasms @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/grammars/codegraph-coverage.json b/grammars/codegraph-coverage.json index e3eb922a..e1323de6 100644 --- a/grammars/codegraph-coverage.json +++ b/grammars/codegraph-coverage.json @@ -127,9 +127,9 @@ { "language": "objc", "provider": "tree_sitter_wasms_dependency", - "source_path": null, - "sha256": null, - "bytes": null + "source_path": "tree-sitter-wasms@0.1.13/out/tree-sitter-objc.wasm", + "sha256": "7c1b5bfdca7e64b6c63b6040bb7ba0afc347df116f9030ca32f8535d7377f6ff", + "bytes": 7708264 }, { "language": "pascal", @@ -183,9 +183,9 @@ { "language": "solidity", "provider": "tree_sitter_wasms_dependency", - "source_path": null, - "sha256": null, - "bytes": null + "source_path": "tree-sitter-wasms@0.1.13/out/tree-sitter-solidity.wasm", + "sha256": "160745e470f234cae903a9ba445d19e758d0b02e1197401fc765976c6254d2b6", + "bytes": 423940 }, { "language": "swift", diff --git a/grammars/manifest.json b/grammars/manifest.json index 459a7aca..b8b6766b 100644 --- a/grammars/manifest.json +++ b/grammars/manifest.json @@ -27,22 +27,24 @@ "release_status": "candidate_unvalidated" }, { - "language": "typescript", - "dialect": "typescript", - "grammar_repository": "https://github.com/tree-sitter/tree-sitter-typescript", - "grammar_commit": "f975a621f4e7f532fe322e13c4f79495e0a7b2e7", - "grammar_version": "v0.23.2", - "path": "typescript/parser.wasm", - "sha256": "3a44d634c9840dccec36f33b99592bd086a2f940e9cd80c64347c45b7dce662f", - "bytes": 1414055, - "license": "typescript/LICENSE", - "license_sha256": "49bf33cf78ef5897e4e161ce1517df7de1ae5042a65b6bcfd44401e0fc606559", + "language": "objc", + "dialect": "objc", + "grammar_repository": "https://github.com/amaanq/tree-sitter-objc", + "grammar_commit": "dea2b2d6a1253c2f0f58b543c10d62edd2f860f2", + "grammar_version": "2.1.0", + "path": "objc/parser.wasm", + "sha256": "2606d4c5809fab61de44d328072d1371d53aa4aff5734436cb2a0ce8db7f2b0c", + "bytes": 7708267, + "source_wasm": "objc/source.wasm", + "source_sha256": "7c1b5bfdca7e64b6c63b6040bb7ba0afc347df116f9030ca32f8535d7377f6ff", + "license": "objc/LICENSE", + "license_sha256": "099c44248f8cf353123211318680e93465587c005a4b3730ce8cb5334de043d6", "abi_version": 14, "codegraph_runtime": "web-tree-sitter 0.25.3", "codeguard_runtime_validation": "rust_loader_smoke_passed", "language_versions": [], "known_limitations": [ - "Rust loader smoke passed; MSRV build, dialect versions, isolation and syntax corpus are not yet validated" + "Rust loader smoke passed after byte-pinned dylink metadata conversion; language versions, corpus differential, resource isolation and release remain unqualified" ], "release_status": "candidate_unvalidated" }, @@ -66,6 +68,28 @@ ], "release_status": "candidate_unvalidated" }, + { + "language": "solidity", + "dialect": "solidity", + "grammar_repository": "https://github.com/JoranHonig/tree-sitter-solidity", + "grammar_commit": "b239a95f94cfcc6e7b3e961bc73a28d55e214f02", + "grammar_version": "1.2.0", + "path": "solidity/parser.wasm", + "sha256": "ba02ba3c98c8ce976ed962d727ef48940b3a18dd2243830a8158b558de64b4f2", + "bytes": 423943, + "source_wasm": "solidity/source.wasm", + "source_sha256": "160745e470f234cae903a9ba445d19e758d0b02e1197401fc765976c6254d2b6", + "license": "solidity/LICENSE", + "license_sha256": "8844f0cc9b76b9c8a9d0251904eb7536b6bb9976e0ec577e8f27ab96d42523ef", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": [ + "Rust loader smoke passed after byte-pinned dylink metadata conversion; language versions, corpus differential, resource isolation and release remain unqualified" + ], + "release_status": "candidate_unvalidated" + }, { "language": "tsx", "dialect": "tsx", @@ -86,6 +110,26 @@ ], "release_status": "candidate_unvalidated" }, + { + "language": "typescript", + "dialect": "typescript", + "grammar_repository": "https://github.com/tree-sitter/tree-sitter-typescript", + "grammar_commit": "f975a621f4e7f532fe322e13c4f79495e0a7b2e7", + "grammar_version": "v0.23.2", + "path": "typescript/parser.wasm", + "sha256": "3a44d634c9840dccec36f33b99592bd086a2f940e9cd80c64347c45b7dce662f", + "bytes": 1414055, + "license": "typescript/LICENSE", + "license_sha256": "49bf33cf78ef5897e4e161ce1517df7de1ae5042a65b6bcfd44401e0fc606559", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": [ + "Rust loader smoke passed; MSRV build, dialect versions, isolation and syntax corpus are not yet validated" + ], + "release_status": "candidate_unvalidated" + }, { "language": "zig", "dialect": "zig", @@ -106,5 +150,8 @@ ], "release_status": "candidate_unvalidated" } - ] + ], + "dependency_package_integrity": "tree-sitter-wasms@0.1.13 sha512-wT+cR6DwaIz80/vho3AvSF0N4txuNx/5bcRKoXouOfClpxh/qqrF4URNLQXbbt8MaAxeksZcZd1j8gcGjc+QxQ==", + "dependency_package_license": "LICENSE.tree-sitter-wasms", + "dependency_package_license_sha256": "6b0382b16279f26ff69014300541967a356a666eb0b91b422f6862f6b7dad17e" } diff --git a/grammars/objc/LICENSE b/grammars/objc/LICENSE new file mode 100644 index 00000000..5af53636 --- /dev/null +++ b/grammars/objc/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Amaan Qureshi + +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/objc/parser.wasm b/grammars/objc/parser.wasm new file mode 100644 index 00000000..2236f9c5 Binary files /dev/null and b/grammars/objc/parser.wasm differ diff --git a/grammars/objc/source.wasm b/grammars/objc/source.wasm new file mode 100644 index 00000000..8a347a6a Binary files /dev/null and b/grammars/objc/source.wasm differ diff --git a/grammars/solidity/LICENSE b/grammars/solidity/LICENSE new file mode 100644 index 00000000..9ced3c1a --- /dev/null +++ b/grammars/solidity/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2020 Joran Honig + +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. \ No newline at end of file diff --git a/grammars/solidity/parser.wasm b/grammars/solidity/parser.wasm new file mode 100644 index 00000000..65b39d29 Binary files /dev/null and b/grammars/solidity/parser.wasm differ diff --git a/grammars/solidity/source.wasm b/grammars/solidity/source.wasm new file mode 100644 index 00000000..42c1ceb6 Binary files /dev/null and b/grammars/solidity/source.wasm differ diff --git a/openspec/changes/introduce-rust-codeguard-cli/tasks.md b/openspec/changes/introduce-rust-codeguard-cli/tasks.md index ff2de78c..98593219 100644 --- a/openspec/changes/introduce-rust-codeguard-cli/tasks.md +++ b/openspec/changes/introduce-rust-codeguard-cli/tasks.md @@ -1028,7 +1028,7 @@ TDD缺自动同步先RED。相关普通:build9、work sync15、next6,共30 状态:逐项实施中,未达到整体验收。统一规格 [syntax-precheck](specs/syntax-precheck/spec.md)。依赖已有 CLI/原生调度/工作台切片,不等待整个 S13;本阶段验收进入 S12、S13。各任务须先失败样本后实现与回归;不改写原生规则。责任为模块维护职责,非已分配人员。 -- [ ] 14.1 资产清单与来源。责任:adapters / 发布。规格:SP04。依赖:无。验收:固定 CodeGraph 来源提交、grammar 版本、许可证、SHA-256、ABI、语言/方言;缺来源、错散列和不兼容样本拒绝加载。进行中:已从固定 CodeGraph 提交复制 Java/Python/TypeScript/TSX WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;四份资产已由 Rust 离线加载并实测 ABI,Python 尚无 lint 路由;见[Python 资产局部验收](../../../tests/acceptance/python-grammar-asset-candidate.md);[局部证据](../../../tests/acceptance/grammar-asset-candidates.md)。新增与批准资产清单分离的[完整来源覆盖库存](../../../grammars/codegraph-coverage.json)及只读 `grammar status`:固定提交中的 30 份随仓 WASM 已逐字节核对,另两种依赖资产标为未固定,COBOL 的 16.4 MB 超出当前 8 MiB 加载限额;[覆盖验收](../../../tests/acceptance/codegraph-grammar-coverage.md)。其余 grammar 的上游许可证/版本、Rust 加载,以及所有候选的语言版本/方言、语料及可发行验收仍缺,不勾选。 Python 资产已接入可选源码构建的 `lint python` 局部候选路径,但版本/方言和发行验收仍缺;见[Python 兜底局部验收](../../../tests/acceptance/python-syntax-fallback-candidate.md)。 2026-09-29 增量:CodeGraph 来源更新至 `1072f82ce24db3d133258d30165cef6b74d108b2`,30/30 随仓字节与新提交一致。新增 Zig 第五份候选:保留新版原始 WASM、许可证和固定哈希;原始模块因 `__main_argc_argv` 不被 Rust `WasmStore` 接受,使用固定输入/输出散列的同签名导入适配后,可解析合法空容器及损坏样例,仍未做完整语料和原生对照;见[Zig 局部验收](../../../tests/acceptance/zig-grammar-candidate.md)。本项及全量语言覆盖仍未完成。 +- [ ] 14.1 资产清单与来源。责任:adapters / 发布。规格:SP04。依赖:无。验收:固定 CodeGraph 来源提交、grammar 版本、许可证、SHA-256、ABI、语言/方言;缺来源、错散列和不兼容样本拒绝加载。进行中:已从固定 CodeGraph 提交复制 Java/Python/TypeScript/TSX WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;四份资产已由 Rust 离线加载并实测 ABI,Python 尚无 lint 路由;见[Python 资产局部验收](../../../tests/acceptance/python-grammar-asset-candidate.md);[局部证据](../../../tests/acceptance/grammar-asset-candidates.md)。新增与批准资产清单分离的[完整来源覆盖库存](../../../grammars/codegraph-coverage.json)及只读 `grammar status`:固定提交中的 30 份随仓 WASM 已逐字节核对,另两种依赖资产标为未固定,COBOL 的 16.4 MB 超出当前 8 MiB 加载限额;[覆盖验收](../../../tests/acceptance/codegraph-grammar-coverage.md)。其余 grammar 的上游许可证/版本、Rust 加载,以及所有候选的语言版本/方言、语料及可发行验收仍缺,不勾选。 Python 资产已接入可选源码构建的 `lint python` 局部候选路径,但版本/方言和发行验收仍缺;见[Python 兜底局部验收](../../../tests/acceptance/python-syntax-fallback-candidate.md)。 2026-09-29 增量:CodeGraph 来源更新至 `1072f82ce24db3d133258d30165cef6b74d108b2`,30/30 随仓字节与新提交一致。新增 Zig 第五份候选:保留新版原始 WASM、许可证和固定哈希;原始模块因 `__main_argc_argv` 不被 Rust `WasmStore` 接受,使用固定输入/输出散列的同签名导入适配后,可解析合法空容器及损坏样例,仍未做完整语料和原生对照;见[Zig 局部验收](../../../tests/acceptance/zig-grammar-candidate.md)。2026-09-29 后续增量:Objective-C 与 Solidity 从 CodeGraph 锁定的 `tree-sitter-wasms@0.1.13` 获取,依赖包完整性、两份原始 WASM、上游许可证及适配后字节均固定;Rust 将旧 `dylink` 元数据转为 `dylink.0`,离线加载、基本正反例及隔离 worker 候选观察通过。候选累计 7,已验收发行仍 0;完整语料、原生对照和公开 lint 路由仍缺,见[依赖 grammar 局部验收](../../../tests/acceptance/dependency-grammar-candidates.md)。本项及全量语言覆盖仍未完成。 - [ ] 14.2 Rust WASM 加载器。责任:runtime。规格:SP04,SP05。依赖:14.1。验收:支持固定资产离线加载;不依赖 Node 解析器、CodeGraph 或用户安装 tree-sitter-cli;通过有效/损坏/错 ABI 样本及 MSRV。进行中:可选 `wasm-precheck` 特性已通过 Java/Python/TypeScript/TSX Rust `WasmStore` 加载与反例测试,并由私有工作进程从 stdin 处理真实源码、父进程核对身份与恢复锚点,见[局部验收](../../../tests/acceptance/syntax-worker-candidate.md);本机无 Rust 1.85,MSRV 实编及正式 `lint/check` 接线尚缺。 - [ ] 14.3 进程资源隔离。责任:runtime。规格:SP05。依赖:14.2。验收:验证超时、内存、输出、取消与崩溃;损坏 grammar 不阻塞其他模块、不遗留进程。进行中:Unix 候选 worker 复用受控进程组内核,输入 1 MiB、输出 64 KiB,父进程有共同截止时间和取消;崩溃后代清理、输出洪泛、运行中取消及随后正常解析均增加真实子进程反例。Linux 2 GiB `RLIMIT_AS`、3 GiB 分配负例与 worker 故障隔离在 [Ubuntu CI](https://github.com/full-stack-plugins/codeguard/actions/runs/36478461118) 真实通过;Wasmtime 虚拟预留缩小。macOS 本机硬限制实测不支持,候选仍不具内存隔离权威;见[局部验收](../../../tests/acceptance/syntax-worker-candidate.md)。其它目标平台、损坏 grammar 隔离及正式调度仍缺,不勾选。 - [ ] 14.4 语言覆盖与源码映射。责任:adapters。规格:SP06。依赖:14.2。验收:识别 ERROR/MISSING,合并恢复节点;测试 Unicode、换行、嵌入语言、新语法和未知版本,不将不支持当源码违规。进行中:Rust 已提取两类原始节点,adapters 核对 UTF-8/CRLF 字节锚点并转换 Unicode 标量列;结构祖先归组保留并列错误,预算截断保持不完整;[局部证据](../../../tests/acceptance/syntax-recovery-candidate.md)。级联归并语料、版本/嵌入语言及原生对照仍缺。 @@ -1046,4 +1046,4 @@ TDD缺自动同步先RED。相关普通:build9、work sync15、next6,共30 - [ ] 14.16 Gemini CLI 实际对话接入。责任:plugin。规格:SP07,SP12。依赖:14.9,14.10。验收:独立验证真实 Gemini 对话反馈、去重、故障和权限边界,不借用其他宿主结果。 - [ ] 14.17 逐语言误报与性能评测。责任:评测/adapters。规格:SP06,SP12。依赖:14.3,14.4,14.11。验收:独立合法/非法 oracle、版本/方言语料、原生对照;分别报告误报、漏报、未知覆盖及冷暖启动/包体/内存;先实测再定预算。 - [ ] 14.18 打包兼容与分阶段发布验收。责任:发布/CLI。规格:SP04,SP11,SP12。依赖:14.12-14.17。验收:每个平台验证内置资产/许可证/散列和离线 npx;保持退出码、统一入口及旧报告读取;同步中英文示例;未验收语言/宿主仍标 gap。 -- [ ] 14.19 CodeGraph 32 种 grammar 全量接入与 Zig 误报回归。责任:adapters/runtime/CLI/发布。规格:SP01,SP04,SP06,SP11,SP12。依赖:14.1-14.18。验收:逐语言固定可再分发来源、许可证、原始和发行字节、真实 ABI、Rust worker 离线加载、合法/非法版本语料、原生工具对照、原生优先统一命令、任务与对话反馈、资源预算及发行包实装;覆盖 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。当前五份候选(Java/Python/TypeScript/TSX/Zig),已验收发行 0;COBOL 超出 8 MiB 上限,Objective-C/Solidity 仅来源依赖包待正式固定,其他 24 种仍无资产清单和执行路由。不得以 `grammar status` 库存、WASM 可加载或未验收候选替代原生 lint 或语言验收。 +- [ ] 14.19 CodeGraph 32 种 grammar 全量接入与 Zig 误报回归。责任:adapters/runtime/CLI/发布。规格:SP01,SP04,SP06,SP11,SP12。依赖:14.1-14.18。验收:逐语言固定可再分发来源、许可证、原始和发行字节、真实 ABI、Rust worker 离线加载、合法/非法版本语料、原生工具对照、原生优先统一命令、任务与对话反馈、资源预算及发行包实装;覆盖 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。当前七份候选(Java/Objective-C/Python/Solidity/TypeScript/TSX/Zig),已验收发行 0;COBOL 超出 8 MiB 上限,其他 25 种仍无资产清单和执行路由。不得以 `grammar status` 库存、WASM 可加载或未验收候选替代原生 lint 或语言验收。 diff --git a/tests/acceptance/codegraph-grammar-coverage.md b/tests/acceptance/codegraph-grammar-coverage.md index f709a872..2b530d30 100644 --- a/tests/acceptance/codegraph-grammar-coverage.md +++ b/tests/acceptance/codegraph-grammar-coverage.md @@ -13,3 +13,5 @@ 再后续的 [Python 资产候选](python-grammar-asset-candidate.md)使当前候选数变为 4;Python 尚未接入 lint,已发行能力仍为 0。上述数值均为各次增量当时的记录。 2026-09-29 增量:来源库存更新到 CodeGraph `1072f82ce24db3d133258d30165cef6b74d108b2`,当前工作树 30/30 份随仓 WASM 的长度与 SHA-256 与新库存一致。Zig 源 WASM 已变更为修复空容器误报的构建;其原始字节与 Rust 适配后的候选资产、加载测试见 [Zig 局部验收](zig-grammar-candidate.md)。当前候选资产为 5,已验收发行仍为 0。`objc` 与 `solidity` 的精确字节可从 CodeGraph 锁定的 `tree-sitter-wasms@0.1.13` 本机 npm 缓存重现,但本增量尚未把它们写入 CodeGuard 资产清单或验收为可加载能力。历史 2/3/4 候选数仅表示各次验收快照。 + +2026-09-29 后续增量:Objective-C 与 Solidity 的依赖包原始字节、上游许可证及可复现的 Rust `dylink` 元数据适配现已入[候选清单](../../grammars/manifest.json);局部加载和隔离 worker 证据见[依赖 grammar 候选验收](dependency-grammar-candidates.md)。当前候选数 7,已验收发行仍为 0。上述 2/3/4/5 候选数是历史快照,旧的 `dependency_bytes_not_pinned` 状态也只适用于当时的库存。 diff --git a/tests/acceptance/dependency-grammar-candidates.md b/tests/acceptance/dependency-grammar-candidates.md new file mode 100644 index 00000000..e7afa356 --- /dev/null +++ b/tests/acceptance/dependency-grammar-candidates.md @@ -0,0 +1,14 @@ +# Objective-C 与 Solidity 依赖 grammar:局部验收 + +CodeGraph 固定提交 `1072f82ce24db3d133258d30165cef6b74d108b2` 的锁文件选用 `tree-sitter-wasms@0.1.13`。本仓固定该 npm 包的 SHA-512 完整性、随附 Unlicense、两份原始 WASM 的 SHA-256 和字节长度,并保留 Objective-C 与 Solidity grammar 的 MIT 许可证。来源包构建时锁定 `tree-sitter-objc@2.1.0` 及 Solidity 提交 `b239a95f94cfcc6e7b3e961bc73a28d55e214f02`。 + +这两份原始 WASM 使用旧 `dylink` 自定义段,当前 Rust Tree-sitter `WasmStore` 要求 `dylink.0`。仓内保留 `source.wasm`,只把四个内存/函数表尺寸参数封入新版动态链接元数据,输出为 `parser.wasm`。Rust 适配器严格校验输入和输出 SHA-256,拒绝额外依赖、未知语言和漂移字节;没有重写 grammar 的代码段。 + +本地实测: + +- `cargo test -p codeguard-adapters --test grammar_asset_manifest`:5 通过,0 失败;包含来源、许可证、适配确定性和篡改拒绝。 +- `cargo test --features wasm-precheck -p codeguard-runtime --test wasm_grammar_load dependency_grammars_load_offline_and_parse_basic_fixtures`:1 通过,0 失败;两份资产均由 Rust 离线加载,合法与未闭合样例给出不同解析结果。 +- `cargo test --features wasm-precheck -p codeguard-cli --test syntax_worker_candidate dependency_grammars_run_in_worker_without_claiming_clean`:1 通过,0 失败;隔离 worker 的合法样例仍返回 `incomplete` 和 `grammar_qualified=false`。 +- `cargo test --features wasm-precheck -p codeguard-cli --test grammar_status_cli`:2 通过,0 失败;32 种来源、7 份候选、0 项已发行。 + +尚未验收 Objective-C/Solidity 的语言版本、方言、真实项目语料、原生 lint 对照、完整资源预算、公开 `lint` 路由及发行包安装。两份资产只是候选观察;原生 lint 缺失时仍须保留环境阻塞,不能把零恢复节点判为 clean 或关闭任务。