fix(plugin): restrict acadrust gate to API v4 and newer
- API v2/v3 plugins bypass the acadrust gate entirely, preserving backwards compatibility. - Marketplace repo-level policy only affects undeclared v4+ releases. - Local load_at_startup only enforces the gate for v4+ plugins.
This commit is contained in:
parent
2e29f6c59e
commit
c358137792
2 changed files with 40 additions and 12 deletions
|
|
@ -73,9 +73,14 @@ impl ExternalPlugin {
|
||||||
|
|
||||||
/// True when the package's `acadrust` fingerprint matches the host.
|
/// True when the package's `acadrust` fingerprint matches the host.
|
||||||
///
|
///
|
||||||
/// If the manifest does not declare `acadrust_source`, the gate is skipped
|
/// The acadrust gate only applies to plugins targeting API v4 or newer;
|
||||||
/// (legacy fallback). If declared but empty or mismatched, incompatible.
|
/// 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 {
|
pub fn acadrust_compatible(&self) -> bool {
|
||||||
|
if self.api_version < ocs_plugin_api::API_VERSION {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if !self.acadrust_declared {
|
if !self.acadrust_declared {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -343,13 +348,13 @@ mod loader {
|
||||||
if !d.lib_present {
|
if !d.lib_present {
|
||||||
continue;
|
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!(
|
eprintln!(
|
||||||
"[plugin] {} declares acadrust metadata but has no fingerprint; cannot verify compatibility",
|
"[plugin] {} declares acadrust metadata but has no fingerprint; cannot verify compatibility",
|
||||||
d.id
|
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 host_src = ocs_plugin_api::version_info::host_acadrust_source();
|
||||||
let plugin_hash = d
|
let plugin_hash = d
|
||||||
.acadrust_source
|
.acadrust_source
|
||||||
|
|
@ -557,6 +562,28 @@ acadrust_source = "{host}"
|
||||||
assert!(p.acadrust_compatible(), "matching acadrust fingerprint should be compatible");
|
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.
|
/// Integration smoke test for the out-of-process plugin path.
|
||||||
/// Set `OCS_TEST_PLUGIN` to the built cdylib path and make sure the
|
/// 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.
|
/// `OpenCADStudio` binary is built; the test uses it as the runner host.
|
||||||
|
|
|
||||||
|
|
@ -221,9 +221,11 @@ pub fn fetch_release_info(repo: &str) -> Result<Vec<ReleaseInfo>, String> {
|
||||||
.ok_or_else(|| format!("release {} plugin.toml is missing an id", release.tag))?;
|
.ok_or_else(|| format!("release {} plugin.toml is missing an id", release.tag))?;
|
||||||
let acadrust_source = manifest.acadrust_source.clone();
|
let acadrust_source = manifest.acadrust_source.clone();
|
||||||
let acadrust_declared = manifest.acadrust_declared;
|
let acadrust_declared = manifest.acadrust_declared;
|
||||||
let acadrust_compatible = if !acadrust_declared {
|
let acadrust_compatible = if manifest.api_version < ocs_plugin_api::API_VERSION {
|
||||||
// Legacy release that predates acadrust metadata: defer the
|
// API versions below v4 predate the acadrust gate.
|
||||||
// decision to the repo-level policy below.
|
true
|
||||||
|
} else if !acadrust_declared {
|
||||||
|
// Legacy v4+ release without metadata: defer to repo-level policy.
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
match acadrust_source.as_deref() {
|
match acadrust_source.as_deref() {
|
||||||
|
|
@ -249,10 +251,9 @@ pub fn fetch_release_info(repo: &str) -> Result<Vec<ReleaseInfo>, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repo-level policy: if any release in this repo declares an acadrust
|
// Repo-level policy: if any release in this repo declares an acadrust
|
||||||
// fingerprint, treat undeclared releases from the same repo as
|
// fingerprint, treat undeclared v4+ releases from the same repo as
|
||||||
// incompatible — but only for releases targeting the current host API
|
// incompatible. API v2/v3 releases predate the gate and are preserved as
|
||||||
// generation (v4 and above). This preserves API v2/v3 backwards
|
// legacy-compatible.
|
||||||
// compatibility for legacy plugins that predate acadrust metadata.
|
|
||||||
let any_declared = info.iter().any(|r| r.acadrust_declared);
|
let any_declared = info.iter().any(|r| r.acadrust_declared);
|
||||||
if any_declared {
|
if any_declared {
|
||||||
for r in &mut info {
|
for r in &mut info {
|
||||||
|
|
@ -333,7 +334,7 @@ pub fn install(release: &Release, repository: &str) -> Result<String, String> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
let Some(source) = manifest.acadrust_source.as_deref() else {
|
||||||
return Err(
|
return Err(
|
||||||
"Release declares acadrust metadata but has no source; cannot verify ABI compatibility".to_string(),
|
"Release declares acadrust metadata but has no source; cannot verify ABI compatibility".to_string(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue