diff --git a/src/plugin/external.rs b/src/plugin/external.rs index 33924d8c2..355aac93a 100644 --- a/src/plugin/external.rs +++ b/src/plugin/external.rs @@ -73,9 +73,14 @@ impl ExternalPlugin { /// True when the package's `acadrust` fingerprint matches the host. /// - /// If the manifest does not declare `acadrust_source`, the gate is skipped - /// (legacy fallback). If declared but empty or mismatched, incompatible. + /// The acadrust gate only applies to plugins targeting API v4 or newer; + /// older API versions predate the gate and are treated as compatible. + /// If the manifest does not declare `acadrust_source`, the gate is skipped. + /// If declared but empty or mismatched, incompatible. pub fn acadrust_compatible(&self) -> bool { + if self.api_version < ocs_plugin_api::API_VERSION { + return true; + } if !self.acadrust_declared { return true; } @@ -343,13 +348,13 @@ mod loader { if !d.lib_present { continue; } - if d.acadrust_declared && d.acadrust_source.is_none() { + if d.api_version >= ocs_plugin_api::API_VERSION && d.acadrust_declared && d.acadrust_source.is_none() { eprintln!( "[plugin] {} declares acadrust metadata but has no fingerprint; cannot verify compatibility", d.id ); } - if !d.acadrust_compatible() { + if d.api_version >= ocs_plugin_api::API_VERSION && !d.acadrust_compatible() { let host_src = ocs_plugin_api::version_info::host_acadrust_source(); let plugin_hash = d .acadrust_source @@ -557,6 +562,28 @@ acadrust_source = "{host}" assert!(p.acadrust_compatible(), "matching acadrust fingerprint should be compatible"); } + #[test] + fn acadrust_gate_only_applies_to_api_v4_and_newer() { + let toml = r#" +[plugin] +id = "opencad.test" +name = "Test" +version = "0.1.0" +api_version = 2 + +[opencad] +acadrust_source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=0908da7#0908da7b6e4f702a6c78359a57f53e2b79cf39eb" +"#; + let mut p = parse_plugin_toml(toml).expect("parsed"); + p.lib_present = true; + assert!(p.acadrust_declared); + assert!( + p.acadrust_compatible(), + "API v2 plugin should bypass acadrust gate" + ); + assert!(p.loadable()); + } + /// Integration smoke test for the out-of-process plugin path. /// Set `OCS_TEST_PLUGIN` to the built cdylib path and make sure the /// `OpenCADStudio` binary is built; the test uses it as the runner host. diff --git a/src/plugin/marketplace.rs b/src/plugin/marketplace.rs index 7976cd46b..b6e5069a8 100644 --- a/src/plugin/marketplace.rs +++ b/src/plugin/marketplace.rs @@ -221,9 +221,11 @@ pub fn fetch_release_info(repo: &str) -> Result, String> { .ok_or_else(|| format!("release {} plugin.toml is missing an id", release.tag))?; let acadrust_source = manifest.acadrust_source.clone(); let acadrust_declared = manifest.acadrust_declared; - let acadrust_compatible = if !acadrust_declared { - // Legacy release that predates acadrust metadata: defer the - // decision to the repo-level policy below. + let acadrust_compatible = if manifest.api_version < ocs_plugin_api::API_VERSION { + // API versions below v4 predate the acadrust gate. + true + } else if !acadrust_declared { + // Legacy v4+ release without metadata: defer to repo-level policy. true } else { match acadrust_source.as_deref() { @@ -249,10 +251,9 @@ pub fn fetch_release_info(repo: &str) -> Result, String> { } // Repo-level policy: if any release in this repo declares an acadrust - // fingerprint, treat undeclared releases from the same repo as - // incompatible — but only for releases targeting the current host API - // generation (v4 and above). This preserves API v2/v3 backwards - // compatibility for legacy plugins that predate acadrust metadata. + // fingerprint, treat undeclared v4+ releases from the same repo as + // incompatible. API v2/v3 releases predate the gate and are preserved as + // legacy-compatible. let any_declared = info.iter().any(|r| r.acadrust_declared); if any_declared { for r in &mut info { @@ -333,7 +334,7 @@ pub fn install(release: &Release, repository: &str) -> Result { )); } - if manifest.acadrust_declared { + if manifest.api_version >= ocs_plugin_api::API_VERSION && manifest.acadrust_declared { let Some(source) = manifest.acadrust_source.as_deref() else { return Err( "Release declares acadrust metadata but has no source; cannot verify ABI compatibility".to_string(),