glove/tests/control/guest_channel_test.cpp
trvon a8137db76b
feat(control): neutral guest channels, quarantine recovery, capability sealing, local-service proxy
Introduce the framed guest_channel_transport with shared deadlines and
std::jthread ownership, metadata-only retired-schema quarantine with
fail-closed integrity, stateless frozen-catalog validators with
capability pinned to zero, and the generic local-service proxy with
descriptor-pinned endpoints, alias-only guest sockets, audit-gated
delivery, and a Linux managed runtime capability derived only from a
registry-bound operational factory. Sage vocabulary is confined to
src/adapters/sage.
2026-08-30 20:28:41 -06:00

124 lines
4.7 KiB
C++

#include "glove/control/guest_channel.hpp"
#include <atomic>
#include <concepts>
#include <cstdio>
#include <string>
#include <thread>
#include <type_traits>
#include <vector>
namespace {
#define REQUIRE(cond) \
do { \
if (!(cond)) { \
std::fprintf(stderr, "REQUIRE failed: %s @ %s:%d\n", #cond, __FILE__, __LINE__); \
return 1; \
} \
} while (0)
auto accepts_observation(const glove::control::glove_observation_body&) noexcept -> bool {
return true;
}
using body_validator = glove::control::channel_descriptor::body_validator_type;
static_assert(std::is_pointer_v<body_validator>);
static_assert(std::is_nothrow_invocable_r_v<
bool,
body_validator,
const glove::control::glove_observation_body&>);
static_assert(std::is_convertible_v<decltype(&accepts_observation), body_validator>);
constexpr auto capturing_validator = [state = 0](
const glove::control::glove_observation_body&
) mutable noexcept { return ++state != 0; };
static_assert(!std::is_convertible_v<decltype(capturing_validator), body_validator>);
constexpr auto captureless_validator = [](const glove::control::glove_observation_body&) noexcept {
return true;
};
static_assert(std::is_convertible_v<decltype(captureless_validator), body_validator>);
template<typename Host>
concept admits_mutable_descriptor = requires(Host& host) {
host.admits("test.observation.v1")->body_validator = &accepts_observation;
};
static_assert(!admits_mutable_descriptor<glove::control::channel_host>);
static_assert(requires(const glove::control::channel_host& host) {
{
host.admits("test.observation.v1")
} -> std::same_as<const glove::control::channel_descriptor*>;
});
auto descriptor(std::string schema_id) -> glove::control::channel_descriptor {
return {
.schema_id = std::move(schema_id),
.body_validator = &accepts_observation,
.bounds = {
.max_items = 4,
.max_body_bytes = 1'024,
.max_ttl_ms = 60'000,
.max_skew_ms = 1'000,
},
};
}
} // namespace
int main() {
glove::control::channel_host empty;
REQUIRE(empty.empty());
REQUIRE(empty.size() == 0U);
REQUIRE(!empty.frozen());
auto empty_freeze = empty.freeze();
REQUIRE(!empty_freeze.has_value());
REQUIRE(!empty.frozen());
auto missing_schema = descriptor("");
REQUIRE(!empty.register_channel(std::move(missing_schema)).has_value());
auto missing_validator = descriptor("test.missing-validator.v1");
missing_validator.body_validator = {};
REQUIRE(!empty.register_channel(std::move(missing_validator)).has_value());
auto invalid_bounds = descriptor("test.invalid-bounds.v1");
invalid_bounds.bounds.max_items = 0;
REQUIRE(!empty.register_channel(std::move(invalid_bounds)).has_value());
REQUIRE(empty.empty());
REQUIRE(empty.register_channel(descriptor("test.observation.v1")).has_value());
REQUIRE(!empty.empty());
REQUIRE(empty.size() == 1U);
REQUIRE(!empty.register_channel(descriptor("test.observation.v1")).has_value());
REQUIRE(empty.size() == 1U);
REQUIRE(empty.freeze().has_value());
REQUIRE(empty.frozen());
REQUIRE(empty.freeze().has_value());
REQUIRE(empty.admits("test.observation.v1") != nullptr);
REQUIRE(empty.admits("test.unknown.v1") == nullptr);
REQUIRE(!empty.register_channel(descriptor("test.second.v1")).has_value());
REQUIRE(empty.size() == 1U);
const glove::control::channel_host& frozen = empty;
const glove::control::glove_observation_body body{};
std::atomic<bool> rejected{false};
std::vector<std::jthread> readers;
readers.reserve(8);
for (std::size_t index = 0; index < 8U; ++index) {
readers.emplace_back([&] {
for (std::size_t attempt = 0; attempt < 10'000U; ++attempt) {
const auto* admitted = frozen.admits("test.observation.v1");
if (admitted == nullptr || !admitted->body_validator(body)) {
rejected.store(true, std::memory_order_relaxed);
return;
}
}
});
}
readers.clear();
REQUIRE(!rejected.load(std::memory_order_relaxed));
REQUIRE(frozen.size() == 1U);
return 0;
}