diff --git a/README.md b/README.md index ec895ce8..25545623 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,8 @@ Version output includes `cli_version`, `target`, and protocol information. Disco The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with pinned Java/TypeScript grammar candidates. It currently reaches only single-file `lint java` and `lint typescript` requests without explicit native context; 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 two unqualified candidates and zero released syntax capabilities. 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 On Apple Silicon macOS, the published `0.1.2` package was verified with a fresh npm cache: diff --git a/README.zh-CN.md b/README.zh-CN.md index cbed779f..e223ce3a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -96,6 +96,8 @@ cargo build --locked -p codeguard-cli 工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java/TypeScript grammar 候选资产与有界 Rust worker,为缺少显式原生上下文的 `lint java`、`lint typescript` 单文件请求提供疑似语法观察;公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。 +当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前只有两份未验收候选,已发行语法能力为零。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。 + ### npm 安装与一次性调用 已在 Apple Silicon macOS 上通过全新 npm 缓存验证公开 `0.1.2` 包: diff --git a/crates/codeguard-cli/src/grammar_status_command.rs b/crates/codeguard-cli/src/grammar_status_command.rs new file mode 100644 index 00000000..8cb79ec0 --- /dev/null +++ b/crates/codeguard-cli/src/grammar_status_command.rs @@ -0,0 +1,218 @@ +//! CodeGraph grammar 来源覆盖清单的只读投影;不加载 WASM,也不签发检查结果。 + +use codeguard_adapters::bundled_grammar_candidates; +use serde::Deserialize; +use serde_json::{Value, json}; +use std::collections::BTreeSet; +use std::process::ExitCode; + +const SOURCE_COMMIT: &str = "40f112453583a2304c4b605a3a9d6545919662bd"; +const LANGUAGES: [&str; 32] = [ + "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", +]; + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct CoverageInventory { + schema_version: String, + source_repository: String, + source_commit: String, + scope: String, + note: String, + assets: Vec, +} + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct CoverageAsset { + language: String, + provider: String, + source_path: Option, + sha256: Option, + bytes: Option, +} + +/// 展示 CodeGraph 固定来源与 CodeGuard 已验证候选之间的覆盖差距。 +/// 参数仅接受 `--format human|json`;返回 3 表示仍有未接入或未验收的 grammar。 +pub fn run(args: &[String]) -> ExitCode { + let format = match args { + [] => "human", + [option, value] if option == "--format" && matches!(value.as_str(), "human" | "json") => { + value.as_str() + } + [option] if option == "--format=human" => "human", + [option] if option == "--format=json" => "json", + _ => { + eprintln!("grammar status 仅支持 --format human|json"); + return ExitCode::from(2); + } + }; + let report = match coverage_report() { + Ok(report) => report, + Err(reason) => { + eprintln!("grammar 来源清单未完成:{reason}"); + return ExitCode::from(4); + } + }; + if format == "json" { + println!("{report}"); + } else { + println!( + "CodeGraph grammar 32 种独立资产:随仓固定 30;CodeGuard 候选 {};已验收发行 0。", + report["candidate_count"] + ); + println!("全部语法初检覆盖未完成;原生 lint 义务不变。使用 --format=json 查看逐语言缺口。"); + } + ExitCode::from(3) +} + +fn coverage_report() -> Result { + let raw = include_bytes!("../../../grammars/codegraph-coverage.json"); + let strict = codeguard_adapters::parse_unique_json(raw).map_err(str::to_owned)?; + let inventory: CoverageInventory = + serde_json::from_value(strict).map_err(|error| error.to_string())?; + validate_inventory(&inventory)?; + let candidates = bundled_grammar_candidates()?; + let candidate_languages = candidates + .assets + .iter() + .map(|asset| asset.language.as_str()) + .collect::>(); + let inventory_languages = inventory + .assets + .iter() + .map(|asset| asset.language.as_str()) + .collect::>(); + if !candidate_languages.is_subset(&inventory_languages) { + return Err("CodeGuard 候选不在 CodeGraph 来源清单中".into()); + } + let assets = inventory + .assets + .iter() + .map(|asset| { + let candidate = candidates + .assets + .iter() + .find(|candidate| candidate.language == asset.language); + json!({ + "language":asset.language, + "provider":asset.provider, + "source_path":asset.source_path, + "source_sha256":asset.sha256, + "source_bytes":asset.bytes, + "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"} + else if asset.bytes.is_some_and(|bytes| bytes > 8 * 1024 * 1024) {"current_loader_size_limit"} + else if candidate.is_some() {"language_qualification_and_release_pending"} + else {"asset_provenance_license_and_loader_validation_pending"}, + }) + }) + .collect::>(); + Ok(json!({ + "schema_version":"1.0.0", + "report_type":"grammar_coverage_inventory", + "source_repository":inventory.source_repository, + "source_commit":inventory.source_commit, + "codegraph_grammar_count":inventory.assets.len(), + "codegraph_vendored_count":inventory.assets.iter().filter(|asset| asset.provider == "codegraph_vendored").count(), + "candidate_count":candidates.assets.len(), + "released_count":0, + "authority":"source_inventory_only", + "parser_capability":"unverified", + "gate_effect":"none", + "execution":"not_run", + "delivery_decision":"not_evaluated", + "next_action":"固定各缺口资产的上游来源与许可证,逐语言验证 Rust 加载、版本语料及原生对照;不得凭此库存跳过原生 lint。", + "assets":assets, + })) +} + +fn validate_inventory(inventory: &CoverageInventory) -> Result<(), String> { + if inventory.schema_version != "1.0.0" + || inventory.source_repository != "https://github.com/partme-ai/codegraph" + || inventory.source_commit != SOURCE_COMMIT + || inventory.scope != "CodeGraph grammar file map excluding the jsx alias of javascript" + || inventory.note.is_empty() + || inventory.assets.len() != LANGUAGES.len() + { + return Err("CodeGraph 来源清单版本、来源或范围不符".into()); + } + let mut seen = BTreeSet::new(); + let mut vendored = 0; + for asset in &inventory.assets { + if !seen.insert(asset.language.as_str()) { + return Err("CodeGraph grammar 重复".into()); + } + match asset.provider.as_str() { + "codegraph_vendored" => { + vendored += 1; + let filename = if asset.language == "csharp" { + "c_sharp" + } else { + &asset.language + }; + if asset.source_path.as_deref() + != Some(format!("src/extraction/wasm/tree-sitter-{filename}.wasm").as_str()) + || !asset.sha256.as_deref().is_some_and(valid_sha256) + || asset.bytes.is_none_or(|bytes| bytes < 8) + { + return Err("CodeGraph 随仓资产身份无效".into()); + } + } + "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() + { + return Err("CodeGraph 依赖资产身份无效".into()); + } + } + _ => return Err("CodeGraph 资产来源未知".into()), + } + } + if vendored != 30 || seen != LANGUAGES.into_iter().collect() { + return Err("CodeGraph grammar 覆盖集合不符".into()); + } + Ok(()) +} + +fn valid_sha256(value: &str) -> bool { + value.len() == 64 + && value + .bytes() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) +} diff --git a/crates/codeguard-cli/src/lib.rs b/crates/codeguard-cli/src/lib.rs index 3c96595b..9add0eed 100644 --- a/crates/codeguard-cli/src/lib.rs +++ b/crates/codeguard-cli/src/lib.rs @@ -97,6 +97,7 @@ pub mod git_index_safety; pub mod git_index_safety_command; #[cfg(unix)] pub mod go_lint_command; +pub mod grammar_status_command; #[cfg(unix)] pub mod hook_execute_command; pub mod hook_plan_command; diff --git a/crates/codeguard-cli/src/main.rs b/crates/codeguard-cli/src/main.rs index 0428c5f1..7c146d9b 100644 --- a/crates/codeguard-cli/src/main.rs +++ b/crates/codeguard-cli/src/main.rs @@ -63,6 +63,9 @@ fn main() -> ExitCode { println!( "规则目录:rules list [path] [--format human|json];只读配置声明、候选规则来源及目录缺口,不执行检查或批准白名单。" ); + println!( + "语法资产覆盖:grammar status [--format human|json];只读列出固定 CodeGraph 来源的 32 种独立 grammar、CodeGuard 候选与未接入项;不加载 WASM、不运行 lint。" + ); println!( "检查预算:check all 支持 --jobs 1–64 和 CODEGUARD_JOBS;--timeout 优先于 CODEGUARD_TIMEOUT,默认 30m。项目默认值见 .codeguard/runtime.json 1.1;当前仅原生执行受截止时间约束。" ); @@ -76,6 +79,9 @@ fn main() -> ExitCode { [command, rest @ ..] if command == "init" => codeguard_cli::init_command::run(rest), [command, rest @ ..] if command == "config" => codeguard_cli::config_command::run(rest), [command, rest @ ..] if command == "tools" => codeguard_cli::tools_command::run(rest), + [command, operation, rest @ ..] if command == "grammar" && operation == "status" => { + codeguard_cli::grammar_status_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), diff --git a/crates/codeguard-cli/tests/grammar_status_cli.rs b/crates/codeguard-cli/tests/grammar_status_cli.rs new file mode 100644 index 00000000..70757069 --- /dev/null +++ b/crates/codeguard-cli/tests/grammar_status_cli.rs @@ -0,0 +1,60 @@ +use serde_json::Value; +use std::process::Command; + +#[test] +fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["grammar", "status", "--format=json"]) + .output() + .expect("grammar status"); + assert_eq!(output.status.code(), Some(3)); + let report: Value = serde_json::from_slice(&output.stdout).expect("JSON report"); + 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"], 2); + 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"); + let assets = report["assets"].as_array().unwrap(); + assert_eq!(assets.len(), 32); + for asset in assets { + assert_eq!(asset["released"], false); + assert!(!asset["gap"].as_str().unwrap().is_empty()); + } + for language in ["java", "typescript"] { + let asset = assets + .iter() + .find(|row| row["language"] == language) + .unwrap(); + assert_eq!(asset["integration_status"], "candidate_unvalidated"); + assert_eq!(asset["runtime_observation"], "rust_loader_smoke_passed"); + } + let cobol = assets + .iter() + .find(|row| row["language"] == "cobol") + .unwrap(); + assert_eq!(cobol["gap"], "current_loader_size_limit"); + assert!(cobol["source_bytes"].as_u64().unwrap() > 8 * 1024 * 1024); + for language in ["objc", "solidity"] { + let asset = assets + .iter() + .find(|row| row["language"] == language) + .unwrap(); + assert_eq!(asset["gap"], "dependency_bytes_not_pinned"); + assert!(asset["source_sha256"].is_null()); + } +} + +#[test] +fn grammar_status_rejects_unexpected_arguments_without_scanning() { + let output = Command::new(env!("CARGO_BIN_EXE_codeguard")) + .args(["grammar", "status", "--check"]) + .output() + .expect("invalid grammar command"); + assert_eq!(output.status.code(), Some(2)); + assert!(output.stdout.is_empty()); +} diff --git a/docs/Codeguard-Architecture.md b/docs/Codeguard-Architecture.md index c75ef6d6..19fae3ae 100644 --- a/docs/Codeguard-Architecture.md +++ b/docs/Codeguard-Architecture.md @@ -241,6 +241,8 @@ 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 now projects a [pinned CodeGraph coverage inventory](../grammars/codegraph-coverage.json): 30 vendored WASM files and two dependency-provided grammars, with Java and TypeScript as CodeGuard candidates and none qualified for release. 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. + ```text grammars/ # proposed release assets, not project state ├── manifest.json # immutable source, digest, ABI and capability map diff --git a/docs/Codeguard-Architecture.zh_CN.md b/docs/Codeguard-Architecture.zh_CN.md index 6ffa8855..d6cde4b1 100644 --- a/docs/Codeguard-Architecture.zh_CN.md +++ b/docs/Codeguard-Architecture.zh_CN.md @@ -241,6 +241,8 @@ 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、TypeScript 两份候选,尚无已验收发行能力。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。尤其 COBOL 来源资产超过当前加载器 8 MiB 限额。 + ```text grammars/ # 规划中的发行资产,不是项目状态 ├── manifest.json # 固定来源、摘要、ABI 及能力映射 diff --git a/docs/Codeguard-Technical-Design.md b/docs/Codeguard-Technical-Design.md index d88cb7dd..0b16c872 100644 --- a/docs/Codeguard-Technical-Design.md +++ b/docs/Codeguard-Technical-Design.md @@ -191,6 +191,8 @@ The opt-in CLI build now also emits [ESLint feedback 0.3.0](../schemas/eslint-lo 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, two CodeGuard candidates, and zero released capabilities without running a parser. 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 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. The opt-in Rust CLI now has a private [candidate worker](../crates/codeguard-cli/src/syntax_worker_command.rs) and [parent verifier](../crates/codeguard-cli/src/syntax_worker_runner.rs). On Unix they use the existing process-group runner with a 1 MiB source limit, 64 KiB output limit, caller deadline and cancellation, then recheck source/grammar digests and recovery positions. This is a measured contract slice, not the finished isolation design: a verified memory bound, cross-platform enforcement, formal lint/check routing and release packaging remain open. Candidate grammar observations remain `incomplete` even when parsing finds no recovery nodes. diff --git a/docs/Codeguard-Technical-Design.zh_CN.md b/docs/Codeguard-Technical-Design.zh_CN.md index fa2902ee..9136581f 100644 --- a/docs/Codeguard-Technical-Design.zh_CN.md +++ b/docs/Codeguard-Technical-Design.zh_CN.md @@ -191,6 +191,8 @@ flowchart LR 只引入固定 WASM 字节及上游许可证、提交/补丁来源、SHA-256、ABI、已验证运行时和语言/方言范围、语料引用与已知缺口。逐个验证 CodeGraph 资产与选定 Rust Tree-sitter 运行时兼容,不能复制 TypeScript 提取逻辑或把 CodeGraph 支持等同语法验收。发行清单属于分发资产,不属于可写的 `.codeguard/` 项目状态。 +可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 两份候选和零项已发行能力,不运行解析器。依赖提供的两份资产尚未固定字节,COBOL 超过现有加载器的 8 MiB 限额;每语言验收前仍须解决这些缺口。 + 由父进程控制解析工作进程,设置总截止时间、单文件输入上限、内存/进程限制及诊断数量上限。按需加载 grammar,不提供通用网络/文件系统导入;终止卡住的进程时保留其它模块的原生结果。宿主约束执行和 Rust MSRV 兼容性须测试,生产数值预算须经测量后确定,不编造性能承诺。 可选构建特性下,Rust CLI 现在有私有[候选工作进程](../crates/codeguard-cli/src/syntax_worker_command.rs)与[父进程核验器](../crates/codeguard-cli/src/syntax_worker_runner.rs)。Unix 路径复用现有进程组执行内核,源码输入上限 1 MiB、输出上限 64 KiB,沿用调用方截止时间和取消,并重新核对源码/grammar 摘要与恢复位置。这只是已测试的局部契约:经目标平台实测的内存上限、跨平台强制约束、正式 lint/check 路由与发行打包仍缺;候选 grammar 即使无恢复节点也保持 `incomplete`。 diff --git a/grammars/codegraph-coverage.json b/grammars/codegraph-coverage.json new file mode 100644 index 00000000..e03e3644 --- /dev/null +++ b/grammars/codegraph-coverage.json @@ -0,0 +1,233 @@ +{ + "schema_version": "1.0.0", + "source_repository": "https://github.com/partme-ai/codegraph", + "source_commit": "40f112453583a2304c4b605a3a9d6545919662bd", + "scope": "CodeGraph grammar file map excluding the jsx alias of javascript", + "note": "Coverage inventory only; not an approved grammar manifest or a parser capability claim.", + "assets": [ + { + "language": "arkts", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-arkts.wasm", + "sha256": "db0812971109457d22b3fe9dcdb1cd8e614fba2a338e220670bd254485753623", + "bytes": 4384161 + }, + { + "language": "c", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-c.wasm", + "sha256": "a271e584616c7c3c0ac663f01cd05dd5f1a6c2ce6d4cd23096548985a95d0ccb", + "bytes": 625716 + }, + { + "language": "cfml", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-cfml.wasm", + "sha256": "17aeb294c58dd47045b470fc082ccceac3100c8e548b13764d4f3987a062322f", + "bytes": 2700518 + }, + { + "language": "cfquery", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-cfquery.wasm", + "sha256": "9d4eaaec46eec7e6400d4b8d6c85fac7dfe33867ed5b4e5c218dfa7851c32558", + "bytes": 2411407 + }, + { + "language": "cfscript", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-cfscript.wasm", + "sha256": "e381db5d2b8a7744fc7d8e51b0a14ff03f86c8ff497cdfe32d1da467f19d4096", + "bytes": 2162812 + }, + { + "language": "cobol", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-cobol.wasm", + "sha256": "65b98799f92e831d8b5ed8cd811464c71fac31c4beabf66990a545a4f65e02f1", + "bytes": 16355286 + }, + { + "language": "cpp", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-cpp.wasm", + "sha256": "70f5e2b9976dad56bdcd1fafcb3af8c839c7a92e7beaa437162bcf45f390e83d", + "bytes": 3434644 + }, + { + "language": "csharp", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-c_sharp.wasm", + "sha256": "6f69e1cae44e1c32c1eccc170dc5a9778fb94ff716f71113fe1f8c4299aa2f40", + "bytes": 5350581 + }, + { + "language": "dart", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-dart.wasm", + "sha256": "7f5364e4256cf7e55efd01dd52421ef2663caa8061b82659b7e4bf61064545ec", + "bytes": 984666 + }, + { + "language": "erlang", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-erlang.wasm", + "sha256": "dbab33f03e07b89f4385fcdd48d87d86ba35c82a0a426788d55b8c25410bc491", + "bytes": 421639 + }, + { + "language": "go", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-go.wasm", + "sha256": "4eda5d91c99ca981e88bc7d3d33f0db166b4bab0a84d0021a9abf39b364c78ef", + "bytes": 210013 + }, + { + "language": "java", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-java.wasm", + "sha256": "181a6fbc34d7864a551d91c13882fc33007e923b3c81a4bdbe7fa47492090077", + "bytes": 414653 + }, + { + "language": "javascript", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-javascript.wasm", + "sha256": "7978e62bcc851ab1d1f6dcd4678f9eda79df2b3b3490e75f81dd819d9bccccfa", + "bytes": 411832 + }, + { + "language": "kotlin", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-kotlin.wasm", + "sha256": "c80c88867a589a1a0959bcea89de84b7e9684b3693b2cdb2944812458e62ff48", + "bytes": 4052313 + }, + { + "language": "lua", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-lua.wasm", + "sha256": "6d95607fc7d78964cfdf065ccb1ba76be5ed217c5ec0d0a3cace13c59fa1ae43", + "bytes": 49488 + }, + { + "language": "luau", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-luau.wasm", + "sha256": "f1647052518f2bdfae8e8c0b033ffdeca1193d69d11c78ba20f84c8374fd0fe3", + "bytes": 94204 + }, + { + "language": "nix", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-nix.wasm", + "sha256": "4acffa1c013df751193a21ce429777ca214c7d3a7e3665085b6df00dad8869f0", + "bytes": 80876 + }, + { + "language": "objc", + "provider": "tree_sitter_wasms_dependency", + "source_path": null, + "sha256": null, + "bytes": null + }, + { + "language": "pascal", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-pascal.wasm", + "sha256": "be3634fca99c19f5e1035a1a9c7d93d6ee82b35e6d5024f02be4883b71329c3e", + "bytes": 716886 + }, + { + "language": "php", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-php.wasm", + "sha256": "6545a9a110bc878e26ed329950147e190c83da038bb17e999de646fe6c4d6c82", + "bytes": 1058082 + }, + { + "language": "python", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-python.wasm", + "sha256": "a7fdc587e77bd729b9f5b783c659be23c896e305a2c374472bed7114d9e01fac", + "bytes": 456131 + }, + { + "language": "r", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-r.wasm", + "sha256": "2a8f5acd1c53d91e0ec5c01a6830d8ac7f5a7f96f0ac4b3768c016c8e9d07711", + "bytes": 481163 + }, + { + "language": "ruby", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-ruby.wasm", + "sha256": "4cb5a4b12870876ca864c1e92fe1f5cd47036b2adc083e9306488af88867dbb4", + "bytes": 2106097 + }, + { + "language": "rust", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-rust.wasm", + "sha256": "206031e0f67fb41ecae505868ca3bb917df7375031aebafd2f97314a849713fe", + "bytes": 1114303 + }, + { + "language": "scala", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-scala.wasm", + "sha256": "37d7fe5a91ca98941dc05493b0c05a0df0f36df5035890fa00b02497c68aaac3", + "bytes": 3973559 + }, + { + "language": "solidity", + "provider": "tree_sitter_wasms_dependency", + "source_path": null, + "sha256": null, + "bytes": null + }, + { + "language": "swift", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-swift.wasm", + "sha256": "cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843", + "bytes": 3726622 + }, + { + "language": "terraform", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-terraform.wasm", + "sha256": "0d9ef3ae926acc0411bfecba9b34df4ea659061917b96455570a45a70824e890", + "bytes": 92484 + }, + { + "language": "tsx", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-tsx.wasm", + "sha256": "8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e", + "bytes": 1445641 + }, + { + "language": "typescript", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-typescript.wasm", + "sha256": "3a44d634c9840dccec36f33b99592bd086a2f940e9cd80c64347c45b7dce662f", + "bytes": 1414055 + }, + { + "language": "vbnet", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-vbnet.wasm", + "sha256": "e38a09e1826c7ec06340c0531a98bbb5ee79bdd710bba3d3349b79a19721e844", + "bytes": 6477499 + }, + { + "language": "zig", + "provider": "codegraph_vendored", + "source_path": "src/extraction/wasm/tree-sitter-zig.wasm", + "sha256": "512184b21b9d234b9462f0afaeb6932d508ce7b21ca5247ee47e04ba191fa807", + "bytes": 693809 + } + ] +} 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 c14f32f2..8d31ff60 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 @@ -66,6 +66,13 @@ 引入的 CodeGraph 或上游 grammar MUST 固定源码提交、必要补丁、许可证、WASM SHA-256、ABI/运行时兼容范围、语言/方言版本、语料引用及已知限制。活动工作目录中的未固定字节 MUST NOT 直接作为受认可发行输入。文件存在、Rust 加载成功、语法验收完成 MUST 为独立状态。语法包 MUST 随支持平台发行离线可用;不要求用户安装 CodeGraph、tree-sitter-cli 或 Node 解析运行时。Node 可以继续作为 npm 启动层。额外包升级 MUST 经清单校验,不静默使用 latest。 +CodeGuard MUST 提供只读的来源覆盖清单,区分 CodeGraph 随仓 WASM、由依赖包提供但尚未固定字节的 grammar、CodeGuard 已复制候选及已验收发行能力。覆盖清单或 `grammar status` 的存在 MUST NOT 自动改变原生检查义务、加载未经批准的字节,或把来源资产数量说成已支持语言数量。来源资产超过当前加载预算时 MUST 明示预算缺口,不能静默跳过。 + +#### Scenario: Source grammar exists but CodeGuard has not qualified it + +- **WHEN** 查询固定 CodeGraph 来源中的 grammar 覆盖状态 +- **THEN** 列出其来源身份、CodeGuard 集成状态及下一项缺口;不运行解析器、不签发质量或交付通过 + #### Scenario: CodeGraph can load a copied grammar but Rust cannot - **WHEN** Rust 运行时拒绝 ABI 或外部扫描器组合 - **THEN** 该 grammar 保持不可用并显示兼容原因,不宣称语言初检已支持 diff --git a/openspec/changes/introduce-rust-codeguard-cli/tasks.md b/openspec/changes/introduce-rust-codeguard-cli/tasks.md index 271b5a85..4cf18ec6 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/TypeScript WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;两份资产已由 Rust 离线加载并实测 ABI;[局部证据](../../../tests/acceptance/grammar-asset-candidates.md)。支持版本/方言、语料及可发行验收仍缺,不勾选。 +- [ ] 14.1 资产清单与来源。责任:adapters / 发布。规格:SP04。依赖:无。验收:固定 CodeGraph 来源提交、grammar 版本、许可证、SHA-256、ABI、语言/方言;缺来源、错散列和不兼容样本拒绝加载。进行中:已从固定 CodeGraph 提交复制 Java/TypeScript WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;两份资产已由 Rust 离线加载并实测 ABI;[局部证据](../../../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 加载、语言版本/方言、语料及可发行验收仍缺,不勾选。 - [ ] 14.2 Rust WASM 加载器。责任:runtime。规格:SP04,SP05。依赖:14.1。验收:支持固定资产离线加载;不依赖 Node 解析器、CodeGraph 或用户安装 tree-sitter-cli;通过有效/损坏/错 ABI 样本及 MSRV。进行中:可选 `wasm-precheck` 特性已通过 Java/TypeScript 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)。级联归并语料、版本/嵌入语言及原生对照仍缺。 diff --git a/tests/acceptance/codegraph-grammar-coverage.md b/tests/acceptance/codegraph-grammar-coverage.md new file mode 100644 index 00000000..f631847f --- /dev/null +++ b/tests/acceptance/codegraph-grammar-coverage.md @@ -0,0 +1,9 @@ +# CodeGraph grammar 来源覆盖库存:局部验收 + +固定来源为 `partme-ai/codegraph@40f112453583a2304c4b605a3a9d6545919662bd`。其 `src/extraction/grammars.ts` 映射 33 个语言 ID;`jsx` 与 `javascript` 共用 WASM,因此有 32 份独立 grammar。来源提交的 `src/extraction/wasm/` 有 30 份随仓字节;`objc`、`solidity` 通过 CodeGraph 的 `tree-sitter-wasms` 依赖解析,当前库存不假设其字节摘要。`grammars/codegraph-coverage.json` 是**来源覆盖库存**,不是已批准、可加载或已发行的资产清单;后者仍只有 Java/TypeScript 两份候选。 + +本地从该固定 Git 提交逐项读取 30 份 WASM,重新计算 SHA-256 和字节长度,与覆盖库存全部一致(`pinned_source_bytes_verified 30`)。未使用 CodeGraph 当前工作目录作为字节来源。库存不包含 WASM 本体,也不在运行时装入这些尚未审定的文件。 + +`cargo test --locked -p codeguard-cli --test grammar_status_cli`:2/2 通过。实际调用 `target/debug/codeguard grammar status --format=json` 返回 `grammar_coverage_inventory`、`codegraph_grammar_count=32`、`codegraph_vendored_count=30`、`candidate_count=2`、`released_count=0`、`execution=not_run`、`delivery_decision=not_evaluated`。Java/TypeScript 是 `candidate_unvalidated`;`objc`/`solidity` 为 `dependency_bytes_not_pinned`。COBOL 源文件 16,355,286 字节,超过现有 Rust 加载器 8 MiB 限额,明确显示 `current_loader_size_limit`。 + +未完成:其余 30 份资产的上游版本/许可证、Rust ABI 与真实加载、各语言版本/方言/语料、原生对照、运行时预算和发行打包。此库存不证明任何新增语言已可进行语法初检,不改变原生 lint 或交付门禁。