From bd897c7e871cc4fadbd21369b1802a5ab80b792a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sun, 19 Jul 2026 21:45:10 +0200 Subject: [PATCH] =?UTF-8?q?feat(catalog):=20export=20decodeManifest=20?= =?UTF-8?q?=E2=80=94=20one=20manifest=20validation=20policy=20for=20DSO=20?= =?UTF-8?q?and=20static=20plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A host that registers statically linked plugins has to decode their embedded manifests itself (no DSO scan runs), and a private decoder invited a second, weaker re-implementation host-side — letting a malformed static plugin pass validation the DSO path would reject. decodeManifest(source_path, family, manifest_json) is now part of the pj_plugins/host/plugin_catalog.hpp API: required non-empty id/name/version, typed-field rejection, and the message-parser encoding requirement, identically for both discovery paths. Additive; no ABI or protocol change. Version 0.19.0. --- CHANGELOG.md | 12 ++++++++++++ conanfile.py | 4 ++-- .../include/pj_plugins/host/plugin_catalog.hpp | 10 ++++++++++ pj_plugins/src/plugin_catalog.cpp | 8 ++++---- recipe.yaml | 2 +- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 172f111..d87205a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to `plotjuggler_sdk` are recorded here. Versioning policy is in [`CLAUDE.md`](./CLAUDE.md) → "Release Versioning". +## [0.19.0] + +### Feature: exported manifest decoder — one validation policy for DSO and static plugins (MINOR) + +`decodeManifest(source_path, family, manifest_json)` is now part of the +`pj_plugins/host/plugin_catalog.hpp` API instead of being private to DSO +discovery. A host that registers statically linked plugins (no DSO scan) can +decode their embedded manifests through the exact validation the DSO path +applies — required non-empty `id`/`name`/`version`, typed-field rejection, and +the message-parser `encoding` requirement — instead of re-implementing a +second, weaker decoder. Additive; no ABI or protocol change. + ## [0.18.0] ### Feature: typed table sort keys — numeric columns sort numerically (MINOR) diff --git a/conanfile.py b/conanfile.py index 2b49a87..101aa28 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,7 +6,7 @@ plugin_sdk — umbrella for plugin authors (base + dialog SDK + parser SDK) plugin_host — umbrella for host loaders (data_source/parser/toolbox/dialog) -A consuming Conan recipe declares e.g. `plotjuggler_sdk/0.18.0` and then: +A consuming Conan recipe declares e.g. `plotjuggler_sdk/0.19.0` and then: find_package(plotjuggler_sdk REQUIRED COMPONENTS plugin_sdk) target_link_libraries(my_plugin PRIVATE plotjuggler_sdk::plugin_sdk) @@ -30,7 +30,7 @@ class PlotjugglerSdkConan(ConanFile): name = "plotjuggler_sdk" - version = "0.18.0" + version = "0.19.0" # Apache-2.0 covers the whole SDK (pj_base + pj_plugins). See LICENSE. license = "Apache-2.0" url = "https://github.com/PlotJuggler/plotjuggler_sdk" diff --git a/pj_plugins/include/pj_plugins/host/plugin_catalog.hpp b/pj_plugins/include/pj_plugins/host/plugin_catalog.hpp index e9bca1d..3c2095d 100644 --- a/pj_plugins/include/pj_plugins/host/plugin_catalog.hpp +++ b/pj_plugins/include/pj_plugins/host/plugin_catalog.hpp @@ -64,6 +64,16 @@ struct PluginScanResult { std::vector diagnostics; }; +/// Decode a plugin's embedded manifest JSON into a descriptor, applying the +/// canonical validation both discovery paths share: `id`/`name`/`version` are +/// required non-empty strings, typed fields reject mismatched JSON types, and +/// a message parser must declare a non-empty `encoding` array. `source_path` +/// is recorded as the descriptor's dso_path (for a DSO the file path; a host +/// registering a statically linked plugin passes a synthetic label instead); +/// error strings do not embed it — callers prefix their own source context. +[[nodiscard]] Expected decodeManifest( + const std::filesystem::path& source_path, PluginFamily family, std::string_view manifest_json); + /// Inspect one DSO and return its embedded plugin descriptor. [[nodiscard]] Expected inspectPluginDso(const std::filesystem::path& dso_path); diff --git a/pj_plugins/src/plugin_catalog.cpp b/pj_plugins/src/plugin_catalog.cpp index 60ababb..aff6f50 100644 --- a/pj_plugins/src/plugin_catalog.cpp +++ b/pj_plugins/src/plugin_catalog.cpp @@ -179,8 +179,10 @@ Expected> readStringArray(const nlohmann::json& j, std: return values; } +} // namespace + Expected decodeManifest( - const std::filesystem::path& dso_path, PluginFamily family, std::string_view manifest_json) { + const std::filesystem::path& source_path, PluginFamily family, std::string_view manifest_json) { if (manifest_json.empty()) { return unexpected("plugin embedded manifest is empty"); } @@ -215,7 +217,7 @@ Expected decodeManifest( }; PluginDescriptor d; - d.dso_path = dso_path; + d.dso_path = source_path; d.abi_major = PJ_ABI_VERSION; d.family = family; @@ -275,8 +277,6 @@ Expected decodeManifest( return d; } -} // namespace - std::string_view toString(PluginFamily family) noexcept { switch (family) { case PluginFamily::kDataSource: diff --git a/recipe.yaml b/recipe.yaml index 72ded35..bad0a27 100644 --- a/recipe.yaml +++ b/recipe.yaml @@ -1,7 +1,7 @@ schema_version: 1 context: - version: "0.18.0" + version: "0.19.0" package: name: plotjuggler_sdk