feat(plugins): include rustc version in plugin compatibility gate

OpenCADStudio/plugins#901

- Record the host's rustc --version output in the embedded version_info.json.
- Add rustc_version/rustc_declared/rustc_compatible to plugin manifests and
  release metadata, mirroring the existing acadrust gate.
- Reject API v4+ plugins whose declared rustc differs from the host, with a
  clear one-line error message.
- Propagate the rustc gate through the marketplace, install flow, and UI.
- Update plugin architecture docs to describe the new ABI metadata.
This commit is contained in:
Sebastian committed 2026-08-29 10:34:47 +02:00
1 parent 3024869de0
commit ed3e064a47
7 files changed
+344 -7

No files matched your search

+56 -2
View File
@@ -236,12 +236,32 @@ pub fn fetch_release_info(repo: &str) -> Result<Vec<ReleaseInfo>, String> {
),
}
};
let rustc_version = manifest.rustc_version.clone();
let rustc_declared = manifest.rustc_declared;
let rustc_compatible = if !ocs_plugin_api::version_info::uses_acadrust_gate(
manifest.api_version,
) {
true
} else if !rustc_declared {
true
} else {
match rustc_version.as_deref() {
None | Some("") => false,
Some(version) => ocs_plugin_api::version_info::rustc_versions_compatible(
version,
ocs_plugin_api::version_info::host_rustc_version(),
),
}
};
Ok::<_, String>(ReleaseInfo {
tag: release.tag,
api_version: manifest.api_version,
acadrust_source,
acadrust_declared,
acadrust_compatible,
rustc_version,
rustc_declared,
rustc_compatible,
})
})();
match result {
@@ -251,8 +271,8 @@ pub fn fetch_release_info(repo: &str) -> Result<Vec<ReleaseInfo>, String> {
}
// Once a repo declares a fingerprint, require it on later API versions.
let any_declared = info.iter().any(|r| r.acadrust_declared);
if any_declared {
let any_acadrust_declared = info.iter().any(|r| r.acadrust_declared);
if any_acadrust_declared {
for r in &mut info {
if !r.acadrust_declared
&& ocs_plugin_api::version_info::uses_acadrust_gate(r.api_version)
@@ -261,6 +281,16 @@ pub fn fetch_release_info(repo: &str) -> Result<Vec<ReleaseInfo>, String> {
}
}
}
let any_rustc_declared = info.iter().any(|r| r.rustc_declared);
if any_rustc_declared {
for r in &mut info {
if !r.rustc_declared
&& ocs_plugin_api::version_info::uses_acadrust_gate(r.api_version)
{
r.rustc_compatible = false;
}
}
}
if info.is_empty() {
Err(last_error.unwrap_or_else(|| "no installable releases found".to_string()))
@@ -361,6 +391,30 @@ pub fn install(release: &Release, repository: &str) -> Result<String, String> {
}
}
if ocs_plugin_api::version_info::uses_acadrust_gate(manifest.api_version)
&& manifest.rustc_declared
{
let Some(version) = manifest.rustc_version.as_deref() else {
return Err(
"Release declares rustc metadata but has no version; cannot verify ABI compatibility".to_string(),
);
};
if version.is_empty() {
return Err(
"Release declares rustc metadata but has no version; cannot verify ABI compatibility".to_string(),
);
}
if !ocs_plugin_api::version_info::rustc_versions_compatible(
version,
ocs_plugin_api::version_info::host_rustc_version(),
) {
let host_rustc = ocs_plugin_api::version_info::host_rustc_version();
return Err(format!(
"Plugin built with {version}, host requires {host_rustc} - rebuild required"
));
}
}
let dir = external::plugins_dir()
.ok_or("cannot locate the plugins folder")?
.join(&manifest.id);