glove/tests/control/receipt_audit_protocol_test.cpp
0xkite 5c48e5fd8a
fix(control): report start replay disposition, hard-cap jsonl audit journal, deterministic control tests
MEDIUM 1: session_runtime::start() now returns an explicit
fresh-launch vs replay disposition (session_start_result), and
handle_start_session sets outcome.applied only for a fresh committed
launch. An authenticated idempotent start replay therefore never gains
connection-scoped teardown authority: a broken pipe during a replay can
no longer stop an already-running guest. The control audit event for a
replayed delivery carries the replay disposition
(start_session:replay:<session>).

MEDIUM 2: jsonl_sink truncation now accounts for record delimiters
exactly, so current_bytes_ always tracks the physical file; only
newline-terminated complete records are retained (no blank or partial
lines, bounded read window); the cap is a hard cap (an oversized event
is dropped with a structured operator note; a pre-existing oversized
journal is bounded with a bounded read at construction).

MEDIUM 3: the broken-pipe degrade test now synchronizes through a
mutex-protected condition-variable gate handshake that proves the
dispatch is parked inside the blocked gate before the client resets,
records the start only after the dispatch completes, and the
mark_stopping test destroys every registry lock holder (runtime,
protocol, registry) before the independent registry reopen so the
nonblocking exclusive flock can actually be acquired.
2026-08-31 09:34:45 -06:00

2148 lines
92 KiB
C++

#include "glove/container/digest.hpp"
#include "glove/container/receipt_producer.hpp"
#include "glove/control/guest_channel.hpp"
#include "glove/control/receipt_audit_protocol.hpp"
#include "glove/control/session_registry.hpp"
#include "glove/supervisor/library_bundle.hpp"
#include "glove/supervisor/path_alias.hpp"
#include "glove/supervisor/path_exposure.hpp"
#include "glove/supervisor/session_plan.hpp"
#include "receipt_audit_wire.hpp"
#include "remote_session_runtime.hpp"
#include <glaze/glaze.hpp>
#include <sys/stat.h>
#include <unistd.h>
#include <array>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <system_error>
#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)
constexpr std::string_view audit_key =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
constexpr std::string_view bootstrap_secret =
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
constexpr std::string_view intent_bootstrap_secret =
"9999999999999999999999999999999999999999999999999999999999999999";
constexpr std::string_view plan_digest =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
constexpr std::string_view intent_controller_digest =
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
constexpr std::string_view library_bundle =
R"({"schema_version":1,"source_library_ref":"bafy-test","source_manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","entries":[]})";
class capability_test_runtime final : public glove::control::session_runtime {
public:
explicit capability_test_runtime(bool operational) : operational_{operational} {}
[[nodiscard]] auto backend_id() const noexcept -> std::string_view override {
return "capability-test";
}
[[nodiscard]] auto lifecycle_operational() const noexcept -> bool override {
return operational_;
}
[[nodiscard]] auto agent_runtime_adapter_schema_version() const noexcept
-> std::uint8_t override {
return 0;
}
[[nodiscard]] auto managed_runtime_ids() const -> std::vector<std::string> override {
return {};
}
[[nodiscard]] auto resource_capabilities() const noexcept
-> glove::container::resource_enforcement_capabilities override {
return {};
}
[[nodiscard]] auto start(
glove::container::receipt_audit_producer&,
const glove::control::session_start_authorization&,
std::string_view,
std::uint64_t
) -> std::expected<glove::control::session_start_result, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto reconcile(glove::container::receipt_audit_producer&, std::uint64_t)
-> std::expected<glove::control::session_reconciliation_report, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto list() const
-> std::expected<std::vector<std::string>, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto read(std::string_view, std::uint64_t, std::size_t) const
-> std::expected<glove::control::session_transcript_read, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto wait_read(std::string_view, std::uint64_t, std::size_t, std::uint64_t)
-> std::expected<glove::control::session_transcript_read, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto write_input(std::string_view, std::string_view)
-> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto resize(std::string_view, std::uint16_t, std::uint16_t)
-> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto signal(std::string_view, glove::control::session_signal)
-> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto stop(std::string_view) -> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto stop(std::string_view, std::string_view)
-> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto wait(std::string_view)
-> std::expected<glove::control::session_terminal_record, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
[[nodiscard]] auto cleanup(std::string_view) -> std::expected<void, std::string> override {
return std::unexpected(std::string{"unavailable"});
}
private:
bool operational_ = false;
};
class temporary_directory {
public:
temporary_directory() {
std::string pattern = "/tmp/glove-receipt-protocol-test-XXXXXX";
if (char* created = ::mkdtemp(pattern.data()); created != nullptr) {
root_ = created;
}
}
temporary_directory(const temporary_directory&) = delete;
auto operator=(const temporary_directory&) -> temporary_directory& = delete;
~temporary_directory() {
std::error_code error;
std::filesystem::remove_all(root_, error);
}
[[nodiscard]] auto root() const -> const std::filesystem::path& { return root_; }
private:
std::filesystem::path root_;
};
auto write_owner_only(const std::filesystem::path& path, std::string_view value) -> bool {
std::ofstream output{path, std::ios::binary | std::ios::trunc};
output << value << '\n';
output.flush();
return output.good() && ::chmod(path.c_str(), 0600) == 0;
}
auto receipt() -> glove::container::resource_enforcement_receipt {
using namespace glove::container;
return {
.schema_version = 1,
.profile_digest = std::string(64, 'c'),
.backend = sandbox_backend::linux_production,
.backend_id = "linux-production:cgroup-v2-v1",
.configured_limits =
{
.cpu_time_ms = 60'000,
.memory_bytes = std::uint64_t{512} * 1024U * 1024U,
.pids = 128,
.wall_time_ms = 120'000,
.disk_bytes = std::uint64_t{1024} * 1024U * 1024U,
.terminal_output_bytes = std::uint64_t{16} * 1024U * 1024U,
},
.mechanisms =
{
.cpu_time = enforcement_mechanism::cgroup_v2,
.memory = enforcement_mechanism::cgroup_v2,
.pids = enforcement_mechanism::cgroup_v2,
.wall_time = enforcement_mechanism::watchdog,
.disk = enforcement_mechanism::filesystem_quota,
.terminal_output = enforcement_mechanism::byte_counter,
.receipt_schema_version = 1,
},
.observed =
{
.cpu_time_ms = 500,
.peak_memory_bytes = std::uint64_t{16} * 1024U * 1024U,
.peak_pids = 2,
.wall_time_ms = 750,
.disk_bytes = 4096,
.terminal_output_bytes = 1024,
},
.termination_cause = resource_termination_cause::exited,
.exit_code = 0,
.started_at_ms = 1'000,
.finished_at_ms = 1'750,
.library_projections = {},
.retained_changes = {},
};
}
auto refinement_receipt() -> glove::container::refinement_evaluation_receipt {
using namespace glove::container;
refinement_outcome outcome{
.schema = std::string{refinement_outcome_schema},
.encoding = std::string{refinement_outcome_encoding},
.metrics = {{"failed_assertions", 0}, {"latency_us", 750'000}, {"passed", 1}},
};
const auto outcome_bytes = canonical_refinement_outcome_bytes(outcome).value();
const auto outcome_digest = sha256_hex(
std::span<const unsigned char>{
reinterpret_cast<const unsigned char*>(outcome_bytes.data()), outcome_bytes.size()
}
);
return {
.schema_version = refinement_evaluation_receipt_schema_version,
.runtime_template_id = std::string{refinement_runtime_template_id},
.resource_receipt = receipt(),
.evidence_status = refinement_evidence_status::valid_outcome,
.variant = refinement_variant::candidate,
.fixture = {"fixture", std::string(64, 'f'), "fixtures"},
.base = {"base", std::string(64, 'b'), "skills"},
.candidate = {"candidate", std::string(64, 'c'), "skills"},
.matched_context_digest = std::string(64, 'd'),
.outcome =
{
.schema = outcome.schema,
.encoding = outcome.encoding,
.digest = *outcome_digest,
.byte_length = outcome_bytes.size(),
},
.evaluated_outcome = outcome,
.transcript =
{
.schema = std::string{raw_pty_transcript_schema},
.digest = std::string(64, 'e'),
.byte_count = 1'024,
.complete = true,
},
.evaluator = {
.schema = std::string{refinement_evaluator_schema},
.fixture_complete = true,
.transcript_utf8 = true,
.required_literals = 1,
.forbidden_literals = 1,
},
};
}
} // namespace
namespace wire_test {
struct rpc_error {
std::string code;
std::string message;
};
struct rpc_response {
std::string jsonrpc;
std::string id;
std::optional<glz::raw_json> result;
std::optional<rpc_error> error;
};
struct page_result {
std::uint8_t schema_version = 0;
std::vector<glove::container::authenticated_resource_enforcement_receipt> envelopes;
std::vector<glove::container::authenticated_refinement_evaluation_receipt> refinement_envelopes;
bool has_more = false;
glove::container::receipt_audit_anchor local_anchor;
};
struct acknowledgement_result {
std::uint8_t schema_version = 0;
glove::container::receipt_audit_anchor acknowledged_anchor;
};
struct receipt_audit_capabilities {
std::uint8_t envelope_schema_version = 0;
std::string algorithm;
std::string key_id;
};
struct session_control_capabilities {
bool validate_plan = true;
bool create_session = true;
bool start_session = true;
bool session_status = true;
bool attach = true;
bool resize = true;
bool write_stdin = true;
bool signal = true;
bool detach = true;
bool stop_session = true;
bool cleanup_session = true;
};
struct resource_enforcement_capabilities {
std::string cpu_time;
std::string memory;
std::string pids;
std::string wall_time;
std::string disk;
std::string terminal_output;
std::uint8_t receipt_schema_version = 1;
};
struct backend_capabilities {
std::string backend;
resource_enforcement_capabilities resource_enforcement;
};
struct supervisor_capabilities {
std::uint8_t schema_version = 0;
receipt_audit_capabilities receipt_audit;
session_control_capabilities session_control;
std::uint8_t agent_runtime_adapter_schema_version = 0;
std::vector<std::string> managed_runtime_ids;
std::uint8_t path_exposure_admin_schema_version = 0;
std::uint8_t path_exposure_catalog_schema_version = 0;
std::uint8_t retained_write_schema_version = 0;
std::uint8_t change_manifest_schema_version = 0;
std::uint8_t change_apply_authorization_schema_version = 0;
std::uint8_t refinement_evaluation_protocol_schema_version = 0;
std::uint8_t observation_intent_channel_schema_version = 0;
std::vector<backend_capabilities> backends;
};
struct supervisor_health {
std::uint8_t schema_version = 0;
std::string status;
};
struct path_exposure_mode {
std::string access;
std::string materialization;
std::uint64_t max_bytes = 0;
std::string cleanup_policy;
};
struct path_exposure_projection {
std::uint8_t schema_version = 0;
std::string exposure_id;
std::uint64_t generation = 0;
std::string scope_digest;
std::string display_label;
std::vector<path_exposure_mode> allowed_modes;
std::uint64_t expires_at_ms = 0;
std::vector<std::string> allowed_runtime_template_ids;
std::string state;
};
struct path_exposure_result {
std::uint8_t schema_version = 0;
path_exposure_projection exposure;
};
struct path_exposure_list_result {
std::uint8_t schema_version = 0;
std::vector<path_exposure_projection> exposures;
};
struct session_plan_validation {
std::uint8_t schema_version = 0;
std::uint64_t policy_revision = 0;
};
struct observation_intent_body_wire {
std::string schema;
std::string intent_id;
std::string observation;
std::string value_digest;
std::uint64_t item_count = 0;
};
struct observation_intent_context_wire {
std::string session_id;
std::string controller_plan_digest;
std::string profile_digest;
std::string runtime_id;
std::string projection_digest;
std::uint64_t policy_revision = 0;
std::string channel_id;
std::uint64_t channel_generation = 0;
std::uint64_t issued_at_ms = 0;
std::uint64_t expires_at_ms = 0;
};
struct observation_intent_queue_item_wire {
std::uint64_t sequence = 0;
observation_intent_body_wire body;
observation_intent_context_wire context;
std::string intent_digest;
std::string disposition;
std::uint64_t decided_at_ms = 0;
};
struct page_observation_intents_result {
std::uint8_t schema_version = 0;
std::vector<observation_intent_queue_item_wire> items;
std::optional<std::uint64_t> next_after_sequence;
};
struct observation_intent_disposition_result {
std::uint8_t schema_version = 0;
observation_intent_queue_item_wire item;
};
struct session_record_result {
std::uint8_t schema_version = 0;
std::string session_id;
std::string controller_plan_digest;
std::string plan_content_digest;
std::string state;
std::uint64_t policy_revision = 0;
std::uint64_t expires_at_ms = 0;
std::uint64_t created_at_ms = 0;
std::optional<std::string> profile_digest;
};
} // namespace wire_test
namespace {
using wire_test::acknowledgement_result;
using wire_test::page_result;
using wire_test::rpc_error;
using wire_test::rpc_response;
using wire_test::supervisor_capabilities;
using wire_test::supervisor_health;
auto valid_plan() -> std::string {
return R"({"schema_version":1,"runtime_id":"codex","runtime_template_id":"codex-safe","adapter_command_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","sandbox_backend":"linux_production","egress_policy_id":"no-network","tool_policy_id":"sage-readonly","path_grants":[{"alias":"workspace","access":"ephemeral_write","materialization":"copy","max_bytes":1048576,"ttl_secs":60,"cleanup_policy":"remove"}],"library_projections":[{"projection_id":"sage-core","content_digest":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","destination_alias":"libraries"}],"secret_handles":["codex-token"],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576},"policy_revision":7,"expires_at_ms":61000})";
}
auto plan_validator_for(const std::filesystem::path& source)
-> glove::supervisor::result<glove::supervisor::session_plan_validator> {
using namespace glove::supervisor;
auto paths = path_alias_registry::build({
path_alias_policy{
.alias = "workspace",
.host_path = std::filesystem::canonical(source).string(),
.target_path = "/workspace",
.max_ttl_secs = 120,
.access = {
path_access_policy{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.create_policy = path_create_policy::empty_directory,
.cleanup_policy = path_cleanup_policy::remove,
.max_bytes = 2'097'152,
},
},
},
});
if (!paths) {
return std::unexpected(paths.error());
}
return session_plan_validator::build(
session_plan_policy{
.revision = 7,
.max_plan_ttl_ms = 120'000,
.runtime_templates =
{
runtime_template_policy{
.runtime_template_id = "codex-safe",
.runtime_id = "codex",
.adapter_command_digest = std::string(64, 'a'),
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = {},
.adoption = std::nullopt,
},
},
.library_projection_destinations =
{
library_projection_destination_policy{
.alias = "libraries",
.target_path = "/opt/sage/library-bundles",
},
},
.resource_profiles =
{
resource_limits{
.cpu_time_ms = 1'000,
.memory_bytes = 67'108'864,
.pids = 16,
.wall_time_ms = 2'000,
.disk_bytes = 2'097'152,
.terminal_output_bytes = 1'048'576,
},
},
.egress_policy_ids = {"no-network"},
.tool_policy_ids = {"sage-readonly"},
.secret_handles = {"codex-token"},
.egress_policies = {},
.secret_mounts = {},
},
std::move(*paths)
);
}
auto decode_response(std::string_view frame) -> std::optional<rpc_response> {
rpc_response response;
constexpr glz::opts strict{.error_on_unknown_keys = true};
if (glz::read<strict>(response, frame)) {
return std::nullopt;
}
return response;
}
auto make_request(
std::string_view id,
std::string_view method,
std::string_view secret,
std::string_view payload,
std::optional<std::string_view> idempotency_key = std::nullopt,
std::uint64_t deadline_ms = 2'000
) -> std::string {
std::string request = "{\"jsonrpc\":\"2.0\",\"id\":\"" + std::string{id} + "\",\"method\":\"" +
std::string{method} +
"\",\"params\":{\"schema_version\":1,\"bootstrap_secret\":\"" +
std::string{secret} + "\",\"deadline_ms\":" + std::to_string(deadline_ms);
if (idempotency_key) {
request += ",\"idempotency_key\":\"" + std::string{*idempotency_key} + "\"";
}
request += ",\"payload\":" + std::string{payload} + "}}";
return request;
}
auto observation_capability(
glove::control::receipt_audit_protocol& protocol, std::string_view request_id
) -> std::optional<std::uint8_t> {
auto frame = protocol.handle_frame(
make_request(request_id, "capabilities", bootstrap_secret, "null"), 1'000
);
if (!frame) {
return std::nullopt;
}
auto response = decode_response(*frame);
if (!response || !response->result) {
return std::nullopt;
}
wire_test::supervisor_capabilities capabilities;
if (glz::read<glz::opts{.error_on_unknown_keys = true}>(capabilities, response->result->str)) {
return std::nullopt;
}
return capabilities.observation_intent_channel_schema_version;
}
auto library_bundle_digest() -> std::string {
const auto* bytes = reinterpret_cast<const unsigned char*>(library_bundle.data());
return glove::container::sha256_hex(std::span{bytes, library_bundle.size()}).value_or("");
}
auto intent_launch_template() -> glove::supervisor::runtime_launch_template {
return {
.runtime_discovery = {},
.executable_path = "/usr/bin/true",
.executable_search_paths = {},
.arguments = {"--version"},
.environment = {"PATH=/usr/bin:/bin", "TERM=xterm-256color"},
.read_only_paths = {},
};
}
auto intent_runtime_digest() -> std::string {
return glove::supervisor::runtime_launch_template_digest(intent_launch_template()).value_or("");
}
// Registration example (test fixture): the host owns payload semantics.
auto intent_channel_host() -> std::shared_ptr<const glove::control::channel_host> {
auto host = std::make_shared<glove::control::channel_host>();
if (!host->register_channel({
.schema_id = "test.observation.v1",
.body_validator =
[](const glove::control::glove_observation_body&) noexcept { return true; },
.bounds =
{
.max_items = 4'096,
.max_body_bytes = 8'192,
.max_ttl_ms = 600'000,
.max_skew_ms = 30'000,
},
}) ||
!host->freeze()) {
return {};
}
return host;
}
auto intent_valid_plan_at(std::uint64_t now_ms) -> std::string {
return R"({"schema_version":1,"runtime_id":"codex","runtime_template_id":"codex-safe","adapter_command_digest":")" +
intent_runtime_digest() +
R"(","sandbox_backend":"linux_production","egress_policy_id":"no-network","tool_policy_id":"sage-readonly","path_grants":[{"alias":"workspace","access":"ephemeral_write","materialization":"copy","max_bytes":1048576,"ttl_secs":60,"cleanup_policy":"remove"}],"library_projections":[{"projection_id":"sage-core","content_digest":")" +
library_bundle_digest() +
R"(","destination_alias":"libraries"}],"secret_handles":["codex-token"],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576},"policy_revision":7,"expires_at_ms":)" +
std::to_string(now_ms + 120'000) + "}";
}
auto intent_sage_guest_plan_at(std::uint64_t now_ms) -> std::string {
auto plan = intent_valid_plan_at(now_ms);
for (const auto& [from, to] : {
std::pair{
std::string_view{"\"runtime_id\":\"codex\""},
std::string_view{"\"runtime_id\":\"sage-guest\""}
},
std::pair{
std::string_view{"\"runtime_template_id\":\"codex-safe\""},
std::string_view{"\"runtime_template_id\":\"sage-guest-safe\""}
},
std::pair{
std::string_view{"\"secret_handles\":[\"codex-token\"]"},
std::string_view{"\"secret_handles\":[]"}
},
}) {
const auto offset = plan.find(from);
if (offset != std::string::npos) {
plan.replace(offset, from.size(), to);
}
}
return plan;
}
auto intent_validator_for(const std::filesystem::path& source)
-> glove::supervisor::result<glove::supervisor::session_plan_validator> {
using namespace glove::supervisor;
auto paths = path_alias_registry::build({
path_alias_policy{
.alias = "workspace",
.host_path = std::filesystem::canonical(source).string(),
.target_path = "/workspace",
.max_ttl_secs = 120,
.access = {
path_access_policy{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.create_policy = path_create_policy::empty_directory,
.cleanup_policy = path_cleanup_policy::remove,
.max_bytes = 2'097'152,
},
},
},
});
if (!paths) {
return std::unexpected(paths.error());
}
return session_plan_validator::build(
session_plan_policy{
.revision = 7,
.max_plan_ttl_ms = 120'000,
.runtime_templates =
{
runtime_template_policy{
.runtime_template_id = "codex-safe",
.runtime_id = "codex",
.adapter_command_digest = intent_runtime_digest(),
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = intent_launch_template(),
.adoption = std::nullopt,
},
runtime_template_policy{
.runtime_template_id = "sage-guest-safe",
.runtime_id = "sage-guest",
.adapter_command_digest = intent_runtime_digest(),
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = intent_launch_template(),
.adoption = std::nullopt,
},
},
.library_projection_destinations =
{
library_projection_destination_policy{
.alias = "libraries",
.target_path = "/opt/sage/library-bundles",
},
},
.resource_profiles =
{
resource_limits{
.cpu_time_ms = 1'000,
.memory_bytes = 67'108'864,
.pids = 16,
.wall_time_ms = 2'000,
.disk_bytes = 2'097'152,
.terminal_output_bytes = 1'048'576,
},
},
.egress_policy_ids = {"no-network"},
.tool_policy_ids = {"sage-readonly"},
.secret_handles = {"codex-token"},
.egress_policies = {},
.secret_mounts = {},
},
std::move(*paths)
);
}
auto intent_cgroup_identity(std::uint32_t pid) -> glove::control::linux_cgroup_recovery_identity {
return {
.schema_version = 1,
.device = 42,
.inode = 20'000U + pid,
};
}
auto intent_filesystem_identity() -> glove::control::linux_filesystem_recovery_identity {
return {
.schema_version = 1,
.disk_limit_bytes = 2'097'152,
.partitions = {{.alias = "workspace", .quota_bytes = 1'048'576}},
};
}
auto intent_process_identity(std::uint32_t pid) -> glove::control::linux_process_identity {
return {
.schema_version = 1,
.pid = pid,
.boot_id = "12345678-1234-1234-1234-123456789abc",
.start_time_ticks = 10'000U + pid,
.cgroup_device = 42,
.cgroup_inode = 20'000U + pid,
.cgroup_path_digest = std::string(64, 'd'),
};
}
auto response_excludes_sensitive_material(std::string_view frame) -> bool {
return frame.find("codex-token") == std::string_view::npos &&
frame.find("\"secret_handles\"") == std::string_view::npos &&
frame.find("\"path_grants\"") == std::string_view::npos &&
frame.find("\"bootstrap_secret\"") == std::string_view::npos &&
frame.find(intent_bootstrap_secret) == std::string_view::npos &&
frame.find("\"runtime_template_id\"") == std::string_view::npos &&
frame.find("\"plan\"") == std::string_view::npos &&
frame.find("intent-source") == std::string_view::npos;
}
auto run_observation_intent_control_contract() -> int {
using wire_test::observation_intent_disposition_result;
using wire_test::page_observation_intents_result;
using wire_test::supervisor_capabilities;
constexpr std::uint64_t intent_deadline_ms = 60'000;
const auto intent_request = [](std::string_view id,
std::string_view method,
std::string_view payload,
std::optional<std::string_view> idempotency_key = std::nullopt) {
return make_request(
id, method, intent_bootstrap_secret, payload, idempotency_key, intent_deadline_ms
);
};
temporary_directory temp;
REQUIRE(!temp.root().empty());
const auto source = temp.root() / "intent-source";
REQUIRE(std::filesystem::create_directory(source));
auto validator = intent_validator_for(source);
REQUIRE(validator.has_value());
auto shared_validator =
std::make_shared<const glove::supervisor::session_plan_validator>(std::move(*validator));
const auto bundle_root = temp.root() / "library-bundles";
REQUIRE(std::filesystem::create_directory(bundle_root));
REQUIRE(::chmod(bundle_root.c_str(), 0700) == 0);
const auto bundle_path = bundle_root / (library_bundle_digest() + ".json");
{
std::ofstream output{bundle_path, std::ios::binary};
output.write(library_bundle.data(), static_cast<std::streamsize>(library_bundle.size()));
}
REQUIRE(::chmod(bundle_path.c_str(), 0600) == 0);
auto opened_bundle_store = glove::supervisor::library_bundle_store::open(bundle_root);
REQUIRE(opened_bundle_store.has_value());
auto shared_bundle_store = std::make_shared<const glove::supervisor::library_bundle_store>(
std::move(*opened_bundle_store)
);
const auto intent_key_path = temp.root() / "intent-receipt.key";
REQUIRE(write_owner_only(intent_key_path, audit_key));
auto intent_producer = glove::container::receipt_audit_producer::initialize({
.key_path = intent_key_path,
.journal_path = temp.root() / "intent-receipts.journal",
});
REQUIRE(intent_producer.has_value());
REQUIRE((*intent_producer)->acknowledge_bootstrap((*intent_producer)->anchor()).has_value());
auto registry = glove::control::session_registry::open_or_create(
temp.root() / "intent-sessions.journal",
shared_validator,
shared_bundle_store,
glove::control::default_session_registry_bytes,
intent_channel_host()
);
REQUIRE(registry.has_value());
auto shared_sessions = std::shared_ptr<glove::control::session_registry>{std::move(*registry)};
auto intent_protocol = glove::control::receipt_audit_protocol::create(
intent_bootstrap_secret, *intent_producer, shared_validator, shared_sessions
);
REQUIRE(intent_protocol.has_value());
auto capabilities_frame =
(*intent_protocol)
->handle_frame(intent_request("intent-capabilities", "capabilities", "null"), 50'000);
REQUIRE(capabilities_frame.has_value());
auto capabilities_response = decode_response(*capabilities_frame);
REQUIRE(capabilities_response.has_value());
REQUIRE(capabilities_response->result.has_value());
supervisor_capabilities capability_set;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
capability_set, capabilities_response->result->str
));
REQUIRE(capability_set.observation_intent_channel_schema_version == 0);
auto unauthorized_page = (*intent_protocol)
->handle_frame(
make_request(
"intent-page-unauthorized",
"page_observation_intents",
std::string(64, 'f'),
"{\"after_sequence\":0,\"limit\":1}",
std::nullopt,
intent_deadline_ms
),
50'000
);
REQUIRE(unauthorized_page.has_value());
auto unauthorized_page_response = decode_response(*unauthorized_page);
REQUIRE(unauthorized_page_response.has_value());
REQUIRE(unauthorized_page_response->error.has_value());
REQUIRE(unauthorized_page_response->error->code == "unauthorized");
auto keyed_page = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-keyed",
"page_observation_intents",
"{\"after_sequence\":0,\"limit\":1}",
"page-must-be-read-only"
),
50'000
);
REQUIRE(keyed_page.has_value());
auto keyed_page_response = decode_response(*keyed_page);
REQUIRE(keyed_page_response.has_value());
REQUIRE(keyed_page_response->error.has_value());
REQUIRE(keyed_page_response->error->code == "invalid_request");
auto missing_limit = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-missing-limit",
"page_observation_intents",
"{\"after_sequence\":0}"
),
50'000
);
REQUIRE(missing_limit.has_value());
auto missing_limit_response = decode_response(*missing_limit);
REQUIRE(missing_limit_response.has_value());
REQUIRE(missing_limit_response->error.has_value());
REQUIRE(missing_limit_response->error->code == "invalid_request");
auto missing_after_sequence =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-page-missing-after", "page_observation_intents", "{\"limit\":1}"
),
50'000
);
REQUIRE(missing_after_sequence.has_value());
auto missing_after_sequence_response = decode_response(*missing_after_sequence);
REQUIRE(missing_after_sequence_response.has_value());
REQUIRE(missing_after_sequence_response->error.has_value());
REQUIRE(missing_after_sequence_response->error->code == "invalid_request");
auto unknown_page_field = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-unknown",
"page_observation_intents",
"{\"after_sequence\":0,\"limit\":1,\"now_ms\":1}"
),
50'000
);
REQUIRE(unknown_page_field.has_value());
auto unknown_page_field_response = decode_response(*unknown_page_field);
REQUIRE(unknown_page_field_response.has_value());
REQUIRE(unknown_page_field_response->error.has_value());
REQUIRE(unknown_page_field_response->error->code == "invalid_request");
auto zero_limit = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-zero",
"page_observation_intents",
"{\"after_sequence\":0,\"limit\":0}"
),
50'000
);
REQUIRE(zero_limit.has_value());
auto zero_limit_response = decode_response(*zero_limit);
REQUIRE(zero_limit_response.has_value());
REQUIRE(zero_limit_response->error.has_value());
REQUIRE(zero_limit_response->error->code == "invalid_request");
auto oversize_limit =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-page-oversize",
"page_observation_intents",
std::string{"{\"after_sequence\":0,\"limit\":"} +
std::to_string(glove::control::max_pending_intent_page_size + 1U) + "}"
),
50'000
);
REQUIRE(oversize_limit.has_value());
auto oversize_limit_response = decode_response(*oversize_limit);
REQUIRE(oversize_limit_response.has_value());
REQUIRE(oversize_limit_response->error.has_value());
REQUIRE(oversize_limit_response->error->code == "invalid_request");
auto missing_disposition_key =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-no-key",
"set_observation_intent_disposition",
"{\"session_id\":\"missing\",\"channel_generation\":1,\"intent_id\":\"intent-"
"1\","
"\"intent_digest\":\"" +
std::string(64, 'a') +
"\",\"disposition\":\"accepted\",\"decided_at_ms\":50000}"
),
50'000
);
REQUIRE(missing_disposition_key.has_value());
auto missing_disposition_key_response = decode_response(*missing_disposition_key);
REQUIRE(missing_disposition_key_response.has_value());
REQUIRE(missing_disposition_key_response->error.has_value());
REQUIRE(missing_disposition_key_response->error->code == "invalid_request");
auto timestamped_disposition =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-timestamp",
"set_observation_intent_disposition",
"{\"session_id\":\"missing\",\"channel_generation\":1,\"intent_id\":\"intent-"
"1\","
"\"intent_digest\":\"" +
std::string(64, 'a') +
"\",\"disposition\":\"accepted\",\"decided_at_ms\":50001}",
"intent-disposition-timestamp"
),
50'000
);
REQUIRE(timestamped_disposition.has_value());
auto timestamped_disposition_response = decode_response(*timestamped_disposition);
REQUIRE(timestamped_disposition_response.has_value());
REQUIRE(timestamped_disposition_response->error.has_value());
REQUIRE(timestamped_disposition_response->error->code == "invalid_request");
const std::string session_id = "intent-session";
const std::uint64_t start_ms = 50'000;
auto created = shared_sessions->create(
session_id,
intent_controller_digest,
intent_sage_guest_plan_at(start_ms),
"create-intent-session",
start_ms
);
REQUIRE(created.has_value());
const glove::control::session_start_authorization authorization{
.schema_version = 1,
.authorization_id = "approval-intent-session",
.session_id = session_id,
.controller_plan_digest = std::string{intent_controller_digest},
.plan_content_digest = created->plan_content_digest,
.approved_at_ms = start_ms + 1U,
.expires_at_ms = start_ms + 60'000U,
};
auto reserved =
shared_sessions->reserve_start(authorization, "reserve-intent-session", start_ms + 2U);
REQUIRE(reserved.has_value());
const glove::control::session_execution_binding binding{
.schema_version = 1,
.session_id = session_id,
.controller_plan_digest = std::string{intent_controller_digest},
.plan_content_digest = created->plan_content_digest,
.authorization_id = authorization.authorization_id,
.profile_digest = std::string(64, 'a'),
.cgroup_identity = intent_cgroup_identity(6001),
.filesystem_identity = intent_filesystem_identity(),
};
auto reservation =
(*intent_producer)
->reserve_terminal(
binding.session_id, binding.controller_plan_digest, binding.profile_digest
);
REQUIRE(reservation.has_value());
auto starting = shared_sessions->mark_starting(
binding, *reservation, "starting-intent-session", start_ms + 3U
);
REQUIRE(starting.has_value());
glove::control::session_running_commitment running{
.schema_version = 1,
.session_id = session_id,
.controller_plan_digest = binding.controller_plan_digest,
.plan_content_digest = binding.plan_content_digest,
.authorization_id = binding.authorization_id,
.profile_digest = binding.profile_digest,
.process_identity = intent_process_identity(6001),
.filesystem_identity = binding.filesystem_identity,
};
auto marked_running = shared_sessions->mark_running(
running, *reservation, "running-intent-session", start_ms + 4U
);
REQUIRE(marked_running.has_value());
const glove::control::glove_observation_body body{
.schema = "test.observation.v1",
.intent_id = "intent-1",
.observation = "guest-capability-inventory",
.value_digest = std::string(64, 'd'),
.item_count = 4,
};
const glove::control::observation_intent_context context{
.session_id = session_id,
.controller_plan_digest = running.controller_plan_digest,
.profile_digest = running.profile_digest,
.runtime_id = "sage-guest",
.projection_digest = std::string(64, 'c'),
.policy_revision = 7,
.channel_id = "intent-session-observation-v1",
.channel_generation = 1,
.issued_at_ms = 50'010,
.expires_at_ms = 50'110,
};
auto enqueued = shared_sessions->enqueue_observation_intent(body, context, 50'010);
REQUIRE(enqueued.has_value());
auto second_body = body;
second_body.intent_id = "intent-2";
second_body.value_digest = std::string(64, 'e');
auto second_context = context;
second_context.issued_at_ms = 50'011;
second_context.expires_at_ms = 50'111;
auto second = shared_sessions->enqueue_observation_intent(second_body, second_context, 50'011);
REQUIRE(second.has_value());
auto expiring_body = body;
expiring_body.intent_id = "intent-expired";
expiring_body.value_digest = std::string(64, 'f');
auto expiring_context = context;
expiring_context.issued_at_ms = 50'012;
expiring_context.expires_at_ms = 50'020;
auto expiring =
shared_sessions->enqueue_observation_intent(expiring_body, expiring_context, 50'012);
REQUIRE(expiring.has_value());
auto first_page_frame = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-first",
"page_observation_intents",
"{\"after_sequence\":0,\"limit\":1}"
),
50'015
);
REQUIRE(first_page_frame.has_value());
REQUIRE(response_excludes_sensitive_material(*first_page_frame));
auto first_page_response = decode_response(*first_page_frame);
REQUIRE(first_page_response.has_value());
REQUIRE(first_page_response->result.has_value());
page_observation_intents_result first_page;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
first_page, first_page_response->result->str
));
REQUIRE(first_page.schema_version == 1);
REQUIRE(first_page.items.size() == 1U);
REQUIRE(first_page.items.front().body.intent_id == "intent-1");
REQUIRE(first_page.items.front().disposition == "pending");
REQUIRE(first_page.next_after_sequence.has_value());
REQUIRE(*first_page.next_after_sequence == first_page.items.front().sequence);
auto second_page_frame =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-page-second",
"page_observation_intents",
std::string{"{\"after_sequence\":"} +
std::to_string(*first_page.next_after_sequence) + ",\"limit\":1}"
),
50'015
);
REQUIRE(second_page_frame.has_value());
auto second_page_response = decode_response(*second_page_frame);
REQUIRE(second_page_response.has_value());
REQUIRE(second_page_response->result.has_value());
page_observation_intents_result second_page;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
second_page, second_page_response->result->str
));
REQUIRE(second_page.items.size() == 1U);
REQUIRE(second_page.items.front().body.intent_id == "intent-2");
REQUIRE(second_page.items.front().sequence > first_page.items.front().sequence);
REQUIRE(second_page.next_after_sequence.has_value());
REQUIRE(*second_page.next_after_sequence == second_page.items.front().sequence);
const std::string disposition_payload =
std::string{"{\"session_id\":\""} + session_id +
"\",\"channel_generation\":1,\"intent_id\":\"intent-1\",\"intent_digest\":\"" +
enqueued->intent_digest + "\",\"disposition\":\"accepted\",\"decided_at_ms\":50020}";
auto accepted_frame = (*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-accepted",
"set_observation_intent_disposition",
disposition_payload,
"intent-disposition-accepted"
),
50'020
);
REQUIRE(accepted_frame.has_value());
REQUIRE(response_excludes_sensitive_material(*accepted_frame));
auto accepted_response = decode_response(*accepted_frame);
REQUIRE(accepted_response.has_value());
REQUIRE(accepted_response->result.has_value());
observation_intent_disposition_result accepted_result;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
accepted_result, accepted_response->result->str
));
REQUIRE(accepted_result.schema_version == 1);
REQUIRE(accepted_result.item.disposition == "accepted");
REQUIRE(accepted_result.item.decided_at_ms == 50'020);
auto accepted_replay = (*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-replay",
"set_observation_intent_disposition",
disposition_payload,
"intent-disposition-accepted"
),
50'021
);
REQUIRE(accepted_replay.has_value());
auto accepted_replay_response = decode_response(*accepted_replay);
REQUIRE(accepted_replay_response.has_value());
REQUIRE(accepted_replay_response->result.has_value());
REQUIRE(accepted_replay_response->result->str == accepted_response->result->str);
auto restarted_protocol = glove::control::receipt_audit_protocol::create(
intent_bootstrap_secret, *intent_producer, shared_validator, shared_sessions
);
REQUIRE(restarted_protocol.has_value());
auto accepted_restart_replay = (*restarted_protocol)
->handle_frame(
intent_request(
"intent-disposition-restart-replay",
"set_observation_intent_disposition",
disposition_payload,
"intent-disposition-accepted"
),
50'022
);
REQUIRE(accepted_restart_replay.has_value());
auto accepted_restart_response = decode_response(*accepted_restart_replay);
REQUIRE(accepted_restart_response.has_value());
REQUIRE(accepted_restart_response->result.has_value());
REQUIRE(accepted_restart_response->result->str == accepted_response->result->str);
auto disposition_conflict =
(*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-conflict",
"set_observation_intent_disposition",
std::string{"{\"session_id\":\""} + session_id +
"\",\"channel_generation\":1,\"intent_id\":\"intent-1\",\"intent_digest\":"
"\"" +
enqueued->intent_digest +
"\",\"disposition\":\"rejected\",\"decided_at_ms\":50020}",
"intent-disposition-accepted"
),
50'022
);
REQUIRE(disposition_conflict.has_value());
auto disposition_conflict_response = decode_response(*disposition_conflict);
REQUIRE(disposition_conflict_response.has_value());
REQUIRE(disposition_conflict_response->error.has_value());
REQUIRE(disposition_conflict_response->error->code == "idempotency_conflict");
REQUIRE(response_excludes_sensitive_material(*disposition_conflict));
auto missing_intent_payload =
std::string{"{\"session_id\":\""} + session_id +
"\",\"channel_generation\":1,\"intent_id\":\"missing-intent\",\"intent_digest\":\"" +
std::string(64, 'b') + "\",\"disposition\":\"accepted\",\"decided_at_ms\":50023}";
auto missing_intent = (*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-missing",
"set_observation_intent_disposition",
missing_intent_payload,
"intent-disposition-missing"
),
50'023
);
REQUIRE(missing_intent.has_value());
auto missing_intent_response = decode_response(*missing_intent);
REQUIRE(missing_intent_response.has_value());
REQUIRE(missing_intent_response->error.has_value());
REQUIRE(missing_intent_response->error->code == "observation_intent_not_found");
REQUIRE(missing_intent_response->error->message == "observation intent was not found");
REQUIRE(response_excludes_sensitive_material(*missing_intent));
auto expired_disposition_payload =
std::string{"{\"session_id\":\""} + session_id +
"\",\"channel_generation\":1,\"intent_id\":\"intent-expired\",\"intent_digest\":\"" +
expiring->intent_digest + "\",\"disposition\":\"accepted\",\"decided_at_ms\":50030}";
auto expired_disposition = (*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-expired",
"set_observation_intent_disposition",
expired_disposition_payload,
"intent-disposition-expired"
),
50'030
);
REQUIRE(expired_disposition.has_value());
auto expired_disposition_response = decode_response(*expired_disposition);
REQUIRE(expired_disposition_response.has_value());
REQUIRE(expired_disposition_response->error.has_value());
REQUIRE(expired_disposition_response->error->code == "invalid_request");
REQUIRE(expired_disposition_response->error->message == "invalid observation intent request");
REQUIRE(response_excludes_sensitive_material(*expired_disposition));
auto expired_page = (*intent_protocol)
->handle_frame(
intent_request(
"intent-page-after-expiry",
"page_observation_intents",
"{\"after_sequence\":0,\"limit\":16}"
),
50'030
);
REQUIRE(expired_page.has_value());
auto expired_page_response = decode_response(*expired_page);
REQUIRE(expired_page_response.has_value());
REQUIRE(expired_page_response->result.has_value());
page_observation_intents_result expired_page_result;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
expired_page_result, expired_page_response->result->str
));
REQUIRE(std::ranges::any_of(expired_page_result.items, [](const auto& item) {
return item.body.intent_id == "intent-expired";
}));
const std::string expire_payload =
std::string{"{\"session_id\":\""} + session_id +
"\",\"channel_generation\":1,\"intent_id\":\"intent-expired\",\"intent_digest\":\"" +
expiring->intent_digest + "\",\"disposition\":\"expired\",\"decided_at_ms\":50020}";
auto expire_frame = (*intent_protocol)
->handle_frame(
intent_request(
"intent-disposition-mark-expired",
"set_observation_intent_disposition",
expire_payload,
"intent-disposition-mark-expired"
),
50'030
);
REQUIRE(expire_frame.has_value());
auto expire_response = decode_response(*expire_frame);
REQUIRE(expire_response.has_value());
REQUIRE(expire_response->result.has_value());
observation_intent_disposition_result expire_result;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
expire_result, expire_response->result->str
));
REQUIRE(expire_result.item.disposition == "expired");
REQUIRE(expire_result.item.decided_at_ms == 50'020);
return 0;
}
auto run() -> int {
temporary_directory temp;
REQUIRE(!temp.root().empty());
const auto key_path = temp.root() / "audit.key";
const auto journal_path = temp.root() / "receipts.journal";
REQUIRE(write_owner_only(key_path, audit_key));
const glove::container::receipt_audit_producer_config config{
.key_path = key_path,
.journal_path = journal_path,
};
auto producer = glove::container::receipt_audit_producer::initialize(config);
REQUIRE(producer.has_value());
const auto genesis = (*producer)->anchor();
REQUIRE((*producer)->acknowledge_bootstrap(genesis).has_value());
std::vector<glove::container::authenticated_resource_enforcement_receipt> terminals;
for (std::size_t index = 1; index <= 16; ++index) {
auto reservation = (*producer)->reserve_terminal();
REQUIRE(reservation.has_value());
auto terminal = (*producer)->commit_terminal(
std::move(*reservation), "session-" + std::to_string(index), plan_digest, receipt()
);
REQUIRE(terminal.has_value());
terminals.push_back(std::move(*terminal));
}
auto refinement_reservation = (*producer)->reserve_terminal();
REQUIRE(refinement_reservation.has_value());
auto refinement_terminal = (*producer)->commit_refinement_terminal(
std::move(*refinement_reservation), "session-refinement", plan_digest, refinement_receipt()
);
REQUIRE(refinement_terminal.has_value());
const auto terminal_anchor = (*producer)->anchor();
producer->reset();
auto recovered = glove::container::receipt_audit_producer::recover(config, genesis);
REQUIRE(recovered.has_value());
REQUIRE(!(*recovered)->bootstrap_reconciled());
auto protocol = glove::control::receipt_audit_protocol::create(bootstrap_secret, *recovered);
REQUIRE(protocol.has_value());
auto health_frame = (*protocol)->handle_frame(
make_request("health-1", "health", bootstrap_secret, "null"), 1'000
);
REQUIRE(health_frame.has_value());
auto health_response = decode_response(*health_frame);
REQUIRE(health_response.has_value());
REQUIRE(health_response->result.has_value());
REQUIRE(!health_response->error.has_value());
supervisor_health health;
REQUIRE(
!glz::read<glz::opts{.error_on_unknown_keys = true}>(health, health_response->result->str)
);
REQUIRE(health.schema_version == 1);
REQUIRE(health.status == "ready");
auto invalid_health = (*protocol)->handle_frame(
make_request("invalid-health", "health", bootstrap_secret, "{}"), 1'000
);
REQUIRE(invalid_health.has_value());
auto invalid_health_response = decode_response(*invalid_health);
REQUIRE(invalid_health_response.has_value());
REQUIRE(invalid_health_response->error.has_value());
REQUIRE(invalid_health_response->error->code == "invalid_request");
auto keyed_health = (*protocol)->handle_frame(
make_request(
"keyed-health", "health", bootstrap_secret, "null", "health-must-be-read-only"
),
1'000
);
REQUIRE(keyed_health.has_value());
auto keyed_health_response = decode_response(*keyed_health);
REQUIRE(keyed_health_response.has_value());
REQUIRE(keyed_health_response->error.has_value());
REQUIRE(keyed_health_response->error->code == "invalid_request");
auto capabilities_frame = (*protocol)->handle_frame(
make_request("capabilities-1", "capabilities", bootstrap_secret, "null"), 1'000
);
REQUIRE(capabilities_frame.has_value());
auto capabilities_response = decode_response(*capabilities_frame);
REQUIRE(capabilities_response.has_value());
REQUIRE(capabilities_response->result.has_value());
REQUIRE(!capabilities_response->error.has_value());
supervisor_capabilities capabilities;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
capabilities, capabilities_response->result->str
));
REQUIRE(capabilities.schema_version == 1);
REQUIRE(capabilities.receipt_audit.envelope_schema_version == 1);
REQUIRE(capabilities.receipt_audit.algorithm == "hmac_sha256");
REQUIRE(capabilities.receipt_audit.key_id == genesis.key_id);
REQUIRE(!capabilities.session_control.validate_plan);
REQUIRE(!capabilities.session_control.create_session);
REQUIRE(!capabilities.session_control.start_session);
REQUIRE(!capabilities.session_control.session_status);
REQUIRE(!capabilities.session_control.attach);
REQUIRE(!capabilities.session_control.resize);
REQUIRE(!capabilities.session_control.write_stdin);
REQUIRE(!capabilities.session_control.signal);
REQUIRE(!capabilities.session_control.detach);
REQUIRE(!capabilities.session_control.stop_session);
REQUIRE(!capabilities.session_control.cleanup_session);
REQUIRE(capabilities.agent_runtime_adapter_schema_version == 0);
REQUIRE(capabilities.managed_runtime_ids.empty());
REQUIRE(capabilities.path_exposure_admin_schema_version == 0);
REQUIRE(capabilities.path_exposure_catalog_schema_version == 0);
REQUIRE(capabilities.retained_write_schema_version == 0);
REQUIRE(capabilities.change_manifest_schema_version == 0);
REQUIRE(capabilities.change_apply_authorization_schema_version == 0);
REQUIRE(capabilities.refinement_evaluation_protocol_schema_version == 0);
REQUIRE(capabilities.observation_intent_channel_schema_version == 0);
REQUIRE(capabilities.backends.size() == 2);
for (const auto& backend : capabilities.backends) {
REQUIRE(backend.resource_enforcement.cpu_time == "unavailable");
REQUIRE(backend.resource_enforcement.memory == "unavailable");
REQUIRE(backend.resource_enforcement.pids == "unavailable");
REQUIRE(backend.resource_enforcement.wall_time == "unavailable");
REQUIRE(backend.resource_enforcement.disk == "unavailable");
REQUIRE(backend.resource_enforcement.terminal_output == "unavailable");
REQUIRE(backend.resource_enforcement.receipt_schema_version == 0);
}
REQUIRE(capabilities.backends[0].backend == "linux_production");
REQUIRE(capabilities.backends[1].backend == "apple_container");
constexpr std::array<std::string_view, 11> unavailable_session_methods{
"validate_plan",
"create_session",
"start_session",
"session_status",
"attach",
"resize",
"write_stdin",
"signal",
"detach",
"stop_session",
"cleanup_session",
};
for (const auto method : unavailable_session_methods) {
auto unavailable = (*protocol)->handle_frame(
make_request(
std::string{"unavailable-"} + std::string{method},
method,
bootstrap_secret,
"null",
std::string{"unavailable-"} + std::string{method}
),
1'000
);
REQUIRE(unavailable.has_value());
auto unavailable_response = decode_response(*unavailable);
REQUIRE(unavailable_response.has_value());
REQUIRE(unavailable_response->error.has_value());
REQUIRE(unavailable_response->error->code == "method_not_found");
}
constexpr std::array<std::string_view, 2> unavailable_intent_methods{
"page_observation_intents",
"set_observation_intent_disposition",
};
for (const auto method : unavailable_intent_methods) {
auto unavailable = (*protocol)->handle_frame(
make_request(
std::string{"unavailable-intent-"} + std::string{method},
method,
bootstrap_secret,
method == "page_observation_intents" ? "{\"after_sequence\":0,\"limit\":1}"
: "{\"session_id\":\"missing\","
"\"channel_generation\":1,"
"\"intent_id\":\"intent-1\","
"\"intent_digest\":\"" +
std::string(64, 'a') +
"\",\"disposition\":\"accepted\","
"\"decided_at_ms\":1000}",
method == "set_observation_intent_disposition"
? std::optional<std::string_view>{"unavailable-intent-key"}
: std::nullopt
),
1'000
);
REQUIRE(unavailable.has_value());
auto unavailable_response = decode_response(*unavailable);
REQUIRE(unavailable_response.has_value());
REQUIRE(unavailable_response->error.has_value());
REQUIRE(unavailable_response->error->code == "method_not_found");
}
const auto exposure_root = temp.root() / "exposure-root";
const auto exposure_source = exposure_root / "sage-protocol";
REQUIRE(std::filesystem::create_directories(exposure_source));
const auto canonical_exposure_root = std::filesystem::canonical(exposure_root);
const auto canonical_exposure_source = std::filesystem::canonical(exposure_source);
auto exposure_registry = glove::supervisor::path_exposure_registry::open(
{
glove::supervisor::path_exposure_root_policy{
.root_id = "projects",
.host_root = canonical_exposure_root.string(),
.allowed_modes =
{
glove::supervisor::path_exposure_mode{
.access = glove::supervisor::path_access::read,
.materialization = glove::supervisor::path_materialization::bind,
.max_bytes = 0,
.cleanup_policy = glove::supervisor::path_cleanup_policy::retain,
},
glove::supervisor::path_exposure_mode{
.access = glove::supervisor::path_access::retained_write,
.materialization = glove::supervisor::path_materialization::copy,
.max_bytes = 67'108'864,
.cleanup_policy = glove::supervisor::path_cleanup_policy::retain,
},
},
.max_ttl_secs = 7'200,
.allowed_runtime_template_ids = {"codex-safe"},
},
},
temp.root() / "path-exposures.journal",
std::uint64_t{8} * 1024U * 1024U
);
REQUIRE(exposure_registry.has_value());
auto shared_exposures =
std::make_shared<glove::supervisor::path_exposure_registry>(std::move(*exposure_registry));
auto exposure_protocol = glove::control::receipt_audit_protocol::create(
bootstrap_secret, *recovered, {}, {}, {}, shared_exposures
);
REQUIRE(exposure_protocol.has_value());
auto exposure_capabilities =
(*exposure_protocol)
->handle_frame(
make_request("exposure-capabilities", "capabilities", bootstrap_secret, "null"),
1'000
);
REQUIRE(exposure_capabilities.has_value());
auto exposure_capabilities_response = decode_response(*exposure_capabilities);
REQUIRE(exposure_capabilities_response.has_value());
REQUIRE(exposure_capabilities_response->result.has_value());
supervisor_capabilities exposure_capability_set;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
exposure_capability_set, exposure_capabilities_response->result->str
));
REQUIRE(exposure_capability_set.path_exposure_admin_schema_version == 1);
REQUIRE(exposure_capability_set.path_exposure_catalog_schema_version == 1);
REQUIRE(exposure_capability_set.retained_write_schema_version == 0);
REQUIRE(exposure_capability_set.change_manifest_schema_version == 0);
REQUIRE(exposure_capability_set.change_apply_authorization_schema_version == 0);
REQUIRE(exposure_capability_set.refinement_evaluation_protocol_schema_version == 0);
const auto exposure_payload =
std::string{
"{\"exposure_id\":\"sage-workspace\",\"root_id\":\"projects\",\"host_path\":\""
} +
canonical_exposure_source.string() +
"\",\"display_label\":\"Sage "
"protocol\",\"allowed_modes\":[{\"access\":\"read\",\"materialization\":\"bind\",\"max_"
"bytes\":0,\"cleanup_policy\":\"retain\"},{\"access\":\"retained_write\","
"\"materialization\":\"copy\",\"max_bytes\":33554432,\"cleanup_policy\":\"retain\"}],\"ttl_"
"secs\":3600,\"allowed_runtime_template_ids\":[\"codex-safe\"]}";
auto exposure_created = (*exposure_protocol)
->handle_frame(
make_request(
"exposure-create",
"create_path_exposure",
bootstrap_secret,
exposure_payload,
"exposure-create-1"
),
1'000
);
REQUIRE(exposure_created.has_value());
REQUIRE(exposure_created->find(canonical_exposure_source.string()) == std::string::npos);
auto exposure_created_response = decode_response(*exposure_created);
REQUIRE(exposure_created_response.has_value());
REQUIRE(exposure_created_response->result.has_value());
wire_test::path_exposure_result created_exposure;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
created_exposure, exposure_created_response->result->str
));
REQUIRE(created_exposure.exposure.exposure_id == "sage-workspace");
REQUIRE(created_exposure.exposure.generation == 1);
REQUIRE(created_exposure.exposure.scope_digest.size() == 64U);
REQUIRE(created_exposure.exposure.state == "active");
auto exposure_listed =
(*exposure_protocol)
->handle_frame(
make_request("exposure-list", "list_path_exposures", bootstrap_secret, "null"),
2'000
);
REQUIRE(exposure_listed.has_value());
auto exposure_listed_response = decode_response(*exposure_listed);
REQUIRE(exposure_listed_response.has_value());
REQUIRE(exposure_listed_response->result.has_value());
wire_test::path_exposure_list_result listed_exposures;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
listed_exposures, exposure_listed_response->result->str
));
REQUIRE(listed_exposures.exposures.size() == 1U);
const std::string revoke_payload = R"({"exposure_id":"sage-workspace","generation":1})";
auto exposure_revoked = (*exposure_protocol)
->handle_frame(
make_request(
"exposure-revoke",
"revoke_path_exposure",
bootstrap_secret,
revoke_payload,
"exposure-revoke-1",
4'000
),
3'000
);
REQUIRE(exposure_revoked.has_value());
auto exposure_revoked_response = decode_response(*exposure_revoked);
REQUIRE(exposure_revoked_response.has_value());
if (exposure_revoked_response->error) {
std::fprintf(
stderr,
"exposure revoke failed: %s: %s\n",
exposure_revoked_response->error->code.c_str(),
exposure_revoked_response->error->message.c_str()
);
}
REQUIRE(exposure_revoked_response->result.has_value());
wire_test::path_exposure_result revoked_exposure;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
revoked_exposure, exposure_revoked_response->result->str
));
REQUIRE(revoked_exposure.exposure.state == "revoked");
auto revoke_replay = (*exposure_protocol)
->handle_frame(
make_request(
"exposure-revoke-replay",
"revoke_path_exposure",
bootstrap_secret,
revoke_payload,
"exposure-revoke-1",
4'000
),
3'001
);
REQUIRE(revoke_replay.has_value());
auto revoke_replay_response = decode_response(*revoke_replay);
REQUIRE(revoke_replay_response.has_value());
REQUIRE(revoke_replay_response->result.has_value());
const auto plan_source = temp.root() / "plan-source";
REQUIRE(std::filesystem::create_directory(plan_source));
std::ofstream{plan_source / "tracked.txt"} << "host-owned\n";
auto validator = plan_validator_for(plan_source);
REQUIRE(validator.has_value());
auto shared_validator =
std::make_shared<const glove::supervisor::session_plan_validator>(std::move(*validator));
auto session_registry = glove::control::session_registry::open_or_create(
temp.root() / "sessions.journal", shared_validator
);
REQUIRE(session_registry.has_value());
auto shared_sessions =
std::shared_ptr<glove::control::session_registry>{std::move(*session_registry)};
REQUIRE(!glove::control::receipt_audit_protocol::create(
bootstrap_secret, *recovered, {}, shared_sessions
)
.has_value());
auto planned_protocol = glove::control::receipt_audit_protocol::create(
bootstrap_secret, *recovered, shared_validator, shared_sessions
);
REQUIRE(planned_protocol.has_value());
auto planned_capabilities =
(*planned_protocol)
->handle_frame(
make_request("planned-capabilities", "capabilities", bootstrap_secret, "null"),
1'000
);
REQUIRE(planned_capabilities.has_value());
auto planned_capabilities_response = decode_response(*planned_capabilities);
REQUIRE(planned_capabilities_response.has_value());
REQUIRE(planned_capabilities_response->result.has_value());
supervisor_capabilities planned_capability_set;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
planned_capability_set, planned_capabilities_response->result->str
));
REQUIRE(planned_capability_set.session_control.validate_plan);
REQUIRE(planned_capability_set.session_control.create_session);
REQUIRE(planned_capability_set.session_control.session_status);
REQUIRE(!planned_capability_set.session_control.start_session);
REQUIRE(planned_capability_set.observation_intent_channel_schema_version == 0);
auto operational_runtime = std::make_shared<capability_test_runtime>(true);
auto operational_protocol = glove::control::receipt_audit_protocol::create(
bootstrap_secret,
*recovered,
shared_validator,
shared_sessions,
operational_runtime,
{},
temp.root().string()
);
REQUIRE(operational_protocol.has_value());
REQUIRE(observation_capability(**operational_protocol, "operational-capabilities") == 0);
auto remote_runtime = glove::control::remote_session_runtime::create({
.ssh_argv = {"/usr/bin/ssh", "-F", "/tmp/glove-remote/config", "glove-remote"},
.executor_digest = "sha256:" + std::string(64U, 'a'),
.container_image = "registry.example.test/glove/runtime@sha256:" + std::string(64U, 'b'),
.container_image_digest = "sha256:" + std::string(64U, 'b'),
.channel_timeout_ms = 5'000,
.max_clock_skew_ms = 250,
.max_sessions = 4,
.staging_root = "/var/lib/glove-remote/staging",
});
REQUIRE(remote_runtime.has_value());
auto remote_control = glove::control::receipt_audit_protocol::create(
bootstrap_secret, *recovered, shared_validator, shared_sessions, *remote_runtime, {}, {}
);
REQUIRE(remote_control.has_value());
auto remote_capabilities =
(*remote_control)
->handle_frame(
make_request("remote-capabilities", "capabilities", bootstrap_secret, "null"), 1'000
);
REQUIRE(remote_capabilities.has_value());
auto remote_capabilities_response = decode_response(*remote_capabilities);
REQUIRE(remote_capabilities_response.has_value());
REQUIRE(remote_capabilities_response->result.has_value());
supervisor_capabilities remote_capability_set;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
remote_capability_set, remote_capabilities_response->result->str
));
REQUIRE(remote_capability_set.session_control.create_session);
REQUIRE(remote_capability_set.session_control.session_status);
REQUIRE(!remote_capability_set.session_control.start_session);
REQUIRE(!remote_capability_set.session_control.attach);
REQUIRE(!remote_capability_set.session_control.resize);
REQUIRE(!remote_capability_set.session_control.write_stdin);
REQUIRE(!remote_capability_set.session_control.signal);
REQUIRE(!remote_capability_set.session_control.detach);
REQUIRE(!remote_capability_set.session_control.stop_session);
REQUIRE(!remote_capability_set.session_control.cleanup_session);
REQUIRE(remote_capability_set.agent_runtime_adapter_schema_version == 0);
REQUIRE(remote_capability_set.managed_runtime_ids.empty());
REQUIRE(remote_capability_set.refinement_evaluation_protocol_schema_version == 0);
REQUIRE(remote_capability_set.observation_intent_channel_schema_version == 0);
REQUIRE(remote_capability_set.backends.size() == 2);
for (const auto& backend : remote_capability_set.backends) {
REQUIRE(backend.resource_enforcement.cpu_time == "unavailable");
REQUIRE(backend.resource_enforcement.receipt_schema_version == 0);
}
constexpr std::array<std::string_view, 8> remote_unavailable_methods{
"start_session",
"attach",
"resize",
"write_stdin",
"signal",
"detach",
"stop_session",
"cleanup_session",
};
for (const auto method : remote_unavailable_methods) {
auto unavailable = (*remote_control)
->handle_frame(
make_request(
std::string{"remote-unavailable-"} + std::string{method},
method,
bootstrap_secret,
"null",
"remote-unavailable"
),
1'000
);
REQUIRE(unavailable.has_value());
auto response = decode_response(*unavailable);
REQUIRE(response.has_value());
REQUIRE(response->error.has_value());
REQUIRE(response->error->code == "method_not_found");
}
auto validated =
(*planned_protocol)
->handle_frame(
make_request("validate-plan", "validate_plan", bootstrap_secret, valid_plan()),
1'000
);
REQUIRE(validated.has_value());
auto validated_response = decode_response(*validated);
REQUIRE(validated_response.has_value());
REQUIRE(validated_response->result.has_value());
wire_test::session_plan_validation validation;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
validation, validated_response->result->str
));
REQUIRE(validation.schema_version == 1);
REQUIRE(validation.policy_revision == 7);
auto invalid_plan = (*planned_protocol)
->handle_frame(
make_request(
"invalid-plan",
"validate_plan",
bootstrap_secret,
"{\"schema_version\":1,\"argv\":[\"/bin/sh\"]}"
),
1'000
);
REQUIRE(invalid_plan.has_value());
auto invalid_plan_response = decode_response(*invalid_plan);
REQUIRE(invalid_plan_response.has_value());
REQUIRE(invalid_plan_response->error.has_value());
REQUIRE(invalid_plan_response->error->code == "invalid_plan");
auto keyed_validation =
(*planned_protocol)
->handle_frame(
make_request(
"keyed-plan", "validate_plan", bootstrap_secret, valid_plan(), "read-only-plan"
),
1'000
);
REQUIRE(keyed_validation.has_value());
auto keyed_validation_response = decode_response(*keyed_validation);
REQUIRE(keyed_validation_response.has_value());
REQUIRE(keyed_validation_response->error.has_value());
REQUIRE(keyed_validation_response->error->code == "invalid_request");
const auto create_payload = "{\"session_id\":\"session-17\",\"controller_plan_digest\":\"" +
std::string{plan_digest} + "\",\"plan\":" + valid_plan() + "}";
auto missing_create_idempotency =
(*planned_protocol)
->handle_frame(
make_request(
"create-without-key", "create_session", bootstrap_secret, create_payload
),
1'000
);
REQUIRE(missing_create_idempotency.has_value());
auto missing_create_response = decode_response(*missing_create_idempotency);
REQUIRE(missing_create_response.has_value());
REQUIRE(missing_create_response->error.has_value());
REQUIRE(missing_create_response->error->code == "invalid_request");
auto created = (*planned_protocol)
->handle_frame(
make_request(
"create-session",
"create_session",
bootstrap_secret,
create_payload,
"create-session-17"
),
1'000
);
REQUIRE(created.has_value());
auto created_response = decode_response(*created);
REQUIRE(created_response.has_value());
REQUIRE(created_response->result.has_value());
wire_test::session_record_result created_record;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
created_record, created_response->result->str
));
REQUIRE(created_record.schema_version == 1);
REQUIRE(created_record.session_id == "session-17");
REQUIRE(created_record.controller_plan_digest == plan_digest);
REQUIRE(created_record.plan_content_digest.size() == 64);
REQUIRE(created_record.state == "created");
REQUIRE(created_record.policy_revision == 7);
auto create_replay = (*planned_protocol)
->handle_frame(
make_request(
"create-replay",
"create_session",
bootstrap_secret,
create_payload,
"create-session-17"
),
1'001
);
REQUIRE(create_replay.has_value());
auto create_replay_response = decode_response(*create_replay);
REQUIRE(create_replay_response.has_value());
REQUIRE(create_replay_response->result.has_value());
REQUIRE(create_replay_response->result->str == created_response->result->str);
auto status = (*planned_protocol)
->handle_frame(
make_request(
"status-session",
"session_status",
bootstrap_secret,
"{\"session_id\":\"session-17\"}"
),
1'001
);
REQUIRE(status.has_value());
auto status_response = decode_response(*status);
REQUIRE(status_response.has_value());
REQUIRE(status_response->result.has_value());
REQUIRE(status_response->result->str == created_response->result->str);
auto keyed_status = (*planned_protocol)
->handle_frame(
make_request(
"keyed-status",
"session_status",
bootstrap_secret,
"{\"session_id\":\"session-17\"}",
"status-is-read-only"
),
1'001
);
REQUIRE(keyed_status.has_value());
auto keyed_status_response = decode_response(*keyed_status);
REQUIRE(keyed_status_response.has_value());
REQUIRE(keyed_status_response->error.has_value());
REQUIRE(keyed_status_response->error->code == "invalid_request");
const auto genesis_json = glz::write_json(genesis);
REQUIRE(genesis_json.has_value());
const auto page_payload = "{\"sage_anchor\":" + *genesis_json + ",\"limit\":1000}";
auto page_frame = (*protocol)->handle_frame(
make_request("page-1", "verify_audit_chain", bootstrap_secret, page_payload), 1'000
);
REQUIRE(page_frame.has_value());
auto page_response = decode_response(*page_frame);
REQUIRE(page_response.has_value());
REQUIRE(page_response->result.has_value());
REQUIRE(!page_response->error.has_value());
page_result page;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(page, page_response->result->str));
REQUIRE(page.schema_version == 1);
REQUIRE(page.envelopes.size() == 15);
REQUIRE(page.envelopes.front() == terminals.front());
REQUIRE(page.envelopes.back() == terminals[14]);
REQUIRE(page.has_more);
REQUIRE(page.local_anchor == terminal_anchor);
REQUIRE(!(*recovered)->bootstrap_reconciled());
const glove::container::receipt_audit_anchor first_page_anchor{
.key_id = page.envelopes.back().key_id,
.sequence = page.envelopes.back().sequence,
.head_hmac = page.envelopes.back().this_hmac,
};
const auto first_page_anchor_json = glz::write_json(first_page_anchor);
REQUIRE(first_page_anchor_json.has_value());
const auto final_page_payload =
"{\"sage_anchor\":" + *first_page_anchor_json + ",\"limit\":1000}";
auto final_page_frame = (*protocol)->handle_frame(
make_request("page-2", "verify_audit_chain", bootstrap_secret, final_page_payload), 1'000
);
REQUIRE(final_page_frame.has_value());
auto final_page_response = decode_response(*final_page_frame);
REQUIRE(final_page_response.has_value());
REQUIRE(final_page_response->result.has_value());
page_result final_page;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
final_page, final_page_response->result->str
));
REQUIRE(final_page.envelopes.size() == 1);
REQUIRE(final_page.envelopes.front() == terminals.back());
REQUIRE(final_page.refinement_envelopes.size() == 1);
REQUIRE(final_page.refinement_envelopes.front() == *refinement_terminal);
REQUIRE(!final_page.has_more);
REQUIRE(final_page.local_anchor == terminal_anchor);
REQUIRE(!(*recovered)->bootstrap_reconciled());
auto denied = (*protocol)->handle_frame(
make_request(
"ack-denied",
"acknowledge_audit_chain",
std::string(64, 'e'),
"{}",
"receipt-ack-denied"
),
1'000
);
REQUIRE(denied.has_value());
auto denied_response = decode_response(*denied);
REQUIRE(denied_response.has_value());
REQUIRE(denied_response->error.has_value());
REQUIRE(denied_response->error->code == "unauthorized");
REQUIRE(!(*recovered)->bootstrap_reconciled());
const auto terminal_anchor_json = glz::write_json(terminal_anchor);
REQUIRE(terminal_anchor_json.has_value());
const auto ack_payload = "{\"anchor\":" + *terminal_anchor_json + "}";
const auto ack_request = make_request(
"ack-1", "acknowledge_audit_chain", bootstrap_secret, ack_payload, "receipt-ack-1"
);
auto ack_frame = (*protocol)->handle_frame(ack_request, 1'000);
REQUIRE(ack_frame.has_value());
auto ack_response = decode_response(*ack_frame);
REQUIRE(ack_response.has_value());
REQUIRE(ack_response->result.has_value());
acknowledgement_result acknowledgement;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
acknowledgement, ack_response->result->str
));
REQUIRE(acknowledgement.acknowledged_anchor == terminal_anchor);
REQUIRE((*recovered)->bootstrap_reconciled());
const auto replay_request = make_request(
"ack-2", "acknowledge_audit_chain", bootstrap_secret, ack_payload, "receipt-ack-1"
);
auto replay = (*protocol)->handle_frame(replay_request, 1'001);
REQUIRE(replay.has_value());
auto replay_response = decode_response(*replay);
REQUIRE(replay_response.has_value());
REQUIRE(replay_response->id == "ack-2");
REQUIRE(replay_response->result.has_value());
REQUIRE(replay_response->result->str == ack_response->result->str);
const auto conflicting_payload = "{\"anchor\":" + *genesis_json + "}";
auto conflict = (*protocol)->handle_frame(
make_request(
"ack-conflict",
"acknowledge_audit_chain",
bootstrap_secret,
conflicting_payload,
"receipt-ack-1"
),
1'001
);
REQUIRE(conflict.has_value());
auto conflict_response = decode_response(*conflict);
REQUIRE(conflict_response.has_value());
REQUIRE(conflict_response->error.has_value());
REQUIRE(conflict_response->error->code == "idempotency_conflict");
auto expired = (*protocol)->handle_frame(
make_request(
"expired", "verify_audit_chain", bootstrap_secret, page_payload, std::nullopt, 999
),
1'000
);
REQUIRE(expired.has_value());
auto expired_response = decode_response(*expired);
REQUIRE(expired_response.has_value());
REQUIRE(expired_response->error.has_value());
REQUIRE(expired_response->error->code == "deadline_exceeded");
auto fresh_config = config;
fresh_config.journal_path = temp.root() / "fresh-receipts.journal";
auto fresh_protocol =
glove::control::receipt_audit_protocol::create(bootstrap_secret, fresh_config);
REQUIRE(fresh_protocol.has_value());
auto fresh_capabilities =
(*fresh_protocol)
->handle_frame(
make_request("fresh-capabilities", "capabilities", bootstrap_secret, "null"), 1'000
);
REQUIRE(fresh_capabilities.has_value());
auto fresh_capabilities_response = decode_response(*fresh_capabilities);
REQUIRE(fresh_capabilities_response.has_value());
REQUIRE(fresh_capabilities_response->result.has_value());
REQUIRE(!std::filesystem::exists(fresh_config.journal_path));
auto invalid_capabilities = (*fresh_protocol)
->handle_frame(
make_request(
"invalid-capabilities",
"capabilities",
bootstrap_secret,
"null",
"capabilities-must-be-read-only"
),
1'000
);
REQUIRE(invalid_capabilities.has_value());
auto invalid_capabilities_response = decode_response(*invalid_capabilities);
REQUIRE(invalid_capabilities_response.has_value());
REQUIRE(invalid_capabilities_response->error.has_value());
REQUIRE(invalid_capabilities_response->error->code == "invalid_request");
REQUIRE(!std::filesystem::exists(fresh_config.journal_path));
const auto genesis_ack_payload = "{\"anchor\":" + *genesis_json + "}";
auto premature_ack = (*fresh_protocol)
->handle_frame(
make_request(
"fresh-ack-before-page",
"acknowledge_audit_chain",
bootstrap_secret,
genesis_ack_payload,
"fresh-receipt-ack"
),
1'000
);
REQUIRE(premature_ack.has_value());
auto premature_ack_response = decode_response(*premature_ack);
REQUIRE(premature_ack_response.has_value());
REQUIRE(premature_ack_response->error.has_value());
REQUIRE(premature_ack_response->error->code == "audit_reconciliation_failed");
REQUIRE(!std::filesystem::exists(fresh_config.journal_path));
auto fresh_page =
(*fresh_protocol)
->handle_frame(
make_request("fresh-page", "verify_audit_chain", bootstrap_secret, page_payload),
1'000
);
REQUIRE(fresh_page.has_value());
auto fresh_page_response = decode_response(*fresh_page);
REQUIRE(fresh_page_response.has_value());
REQUIRE(fresh_page_response->result.has_value());
page_result empty_page;
REQUIRE(!glz::read<glz::opts{.error_on_unknown_keys = true}>(
empty_page, fresh_page_response->result->str
));
REQUIRE(empty_page.envelopes.empty());
REQUIRE(empty_page.refinement_envelopes.empty());
REQUIRE(!empty_page.has_more);
REQUIRE(empty_page.local_anchor == genesis);
REQUIRE(std::filesystem::exists(fresh_config.journal_path));
auto fresh_ack = (*fresh_protocol)
->handle_frame(
make_request(
"fresh-ack",
"acknowledge_audit_chain",
bootstrap_secret,
genesis_ack_payload,
"fresh-receipt-ack"
),
1'000
);
REQUIRE(fresh_ack.has_value());
auto fresh_ack_response = decode_response(*fresh_ack);
REQUIRE(fresh_ack_response.has_value());
REQUIRE(fresh_ack_response->result.has_value());
REQUIRE(run_observation_intent_control_contract() == 0);
return 0;
}
} // namespace
auto main() -> int {
return run();
}