fix(gateway): keep httplib out of plugin-facing headers + add build-farm purity gate#411
Merged
Merged
Conversation
The typed DTO contract made dto/operations.hpp pull http/alternate_status.hpp -> http/typed_router.hpp -> <httplib.h>, leaking httplib into every plugin that includes a provider interface (e.g. operation_provider.hpp). Plugins built against the installed gateway (build-farm / Docker topology, where the vendored httplib is not on the include path) then failed with 'httplib.h: No such file'. Extract the httplib-free handler-result vocabulary (Result, NoContent, Forwarded, ValidatorResult, ResponseAttachments) into a new leaf header http/handler_result.hpp; typed_router.hpp re-exports it and keeps only TypedRequest (the sole httplib-dependent type); alternate_status.hpp includes the leaf. Plugins are now httplib-free across the .so boundary. No ABI, wire, or behaviour change.
g++ -M -MG dependency scan over the provider interfaces and plugin base headers; fails if any reaches <httplib.h>. Registered as the gateway_plugin_header_purity linter ctest. Fast and distro-independent.
Build the gateway into a throwaway prefix, then build each plugin library against the installed gateway with httplib withheld (poisoned -isystem shadow header + -DBUILD_TESTING=OFF). Plugins overlay into one isolated prefix so deps resolve; parallelism is capped (override MEDKIT_ISO_JOBS) to avoid OOM on high-core hosts.
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request fixes a transitive public-header leak of #include <httplib.h> into plugin-facing interfaces by extracting the httplib-free handler result vocabulary into a new leaf header, and adds guardrails to prevent the regression in build-farm (“installed gateway”) topologies.
Changes:
- Introduces
http/handler_result.hppand updatestyped_router.hpp/alternate_status.hppso provider/DTO headers no longer pull in cpp-httplib. - Adds a CTest linter (
gateway_plugin_header_purity) plus a pre-push pre-commit hook to enforce “no<httplib.h>in plugin-facing public headers”. - Adds an end-to-end isolated build script to locally reproduce the build-farm scenario (plugins built against an installed gateway with
httplibintentionally poisoned/withheld) and documents the contract.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/ros2_medkit_gateway/scripts/check_headers_httplib_free.sh |
Adds a preprocessor dependency scan to detect any transitive httplib.h dependency from plugin-facing public headers. |
src/ros2_medkit_gateway/README.md |
Documents the new plugin header purity contract and how it’s enforced. |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/typed_router.hpp |
Re-exports the handler-result markers from the new leaf header while keeping TypedRequest (and httplib) localized here. |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handler_result.hpp |
New httplib-free header defining Result, NoContent, Forwarded, ValidatorResult, and ResponseAttachments. |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/alternate_status.hpp |
Switches include from typed_router.hpp to handler_result.hpp to avoid pulling httplib via DTO/provider chains. |
src/ros2_medkit_gateway/design/dto_contract.rst |
Adds design/contract documentation for “no httplib across the plugin boundary” and the enforcement mechanisms. |
src/ros2_medkit_gateway/CMakeLists.txt |
Registers the new gateway_plugin_header_purity linter CTest. |
scripts/check_isolated_build.sh |
Adds an isolated “installed gateway + poisoned httplib” build reproducer for local verification. |
.pre-commit-config.yaml |
Adds a pre-push hook to run the header purity check automatically. |
bburda
added a commit
that referenced
this pull request
Jun 8, 2026
PRs #408 (gateway config_file launch argument), #411 (httplib-free plugin-facing headers), and #405 (cpp-httplib <0.20 cap + ROS 2 Lyrical / Ubuntu 26.04 support) merged after the 0.5.0 changelogs were finalized. Add their entries to the gateway and cmake changelogs and credit @evTessellate. Set the 0.5.0 release date to 2026-06-08 across all 15 package changelogs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Summary
Plugin libraries failed to build against the installed gateway with
fatal error: httplib.h: No such file or directory. A provider-facing public header chain leaked<httplib.h>:core/providers/operation_provider.hpp->dto/operations.hpp->http/alternate_status.hpp->http/typed_router.hpp-><httplib.h>Plugins implement provider interfaces and exchange JSON / typed DTOs /
tl::expected/ the opaquePluginRequest/PluginResponseshim - they never usehttplibtypes across the.soboundary, so cpp-httplib should stay a gateway-internal detail. Normal CI masked this (systemlibcpp-httplib-devinstalled + single-overlay build); it only surfaced when a plugin was built against the installed gateway with cpp-httplib withheld (build-farm / Docker topology).http/typed_router.hppmixed httplib-free handler-result markers (Result,NoContent,Forwarded,ValidatorResult,ResponseAttachments) with the only httplib-dependent type (TypedRequest). This PR:http/handler_result.hpp;typed_router.hppre-exports them and keeps onlyTypedRequest;alternate_status.hppincludes the leaf. The provider/DTO chain is now httplib-free. No ABI, wire, or behaviour change (markers moved verbatim).g++ -M -MGheader-purity scan (gateway_plugin_header_puritylinter ctest + pre-push hook) that fails if any plugin-facing public header reaches<httplib.h>.scripts/check_isolated_build.sh, which reproduces the build-farm topology locally (each plugin built against the installed gateway with cpp-httplib withheld via a poisoned-isystemshadow header).Issue
Type
Testing
scripts/check_isolated_build.shpasses end-to-end on Jazzy: gateway installed, thenros2_medkit_graph_provider,ros2_medkit_sovd_service_interface, andros2_medkit_opcuaall build against the installed gateway with cpp-httplib withheld.Reviewers can verify the contract with
colcon test --packages-select ros2_medkit_gateway --ctest-args -L linter -R gateway_plugin_header_purity, or runscripts/check_isolated_build.sh.Checklist
Out of scope: the gateway still pins cpp-httplib
< 0.20for its own multipart handling (tracked in #409); that is orthogonal to this header leak and not required to make plugins build.