glove/tests/container/linux_managed_session_test.cpp
0xkite 56e3cbd638
fix(linux): support delegated systemd subgroup
Keep gloved in a systemd-owned supervisor leaf while creating sibling session cgroups under the empty delegated parent. Under mapped-root supervisors, attach blocked children before releasing their existing start gate instead of combining nested UID mapping with CLONE_INTO_CGROUP.
2026-09-01 15:33:03 -06:00

1340 lines
56 KiB
C++

#include "glove/container/digest.hpp"
#include "glove/container/profile.hpp"
#include "glove/container/receipt_chain.hpp"
#include "glove/container/receipt_producer.hpp"
#include "glove/host/runtime_policy.hpp"
#include "glove/supervisor/harness_adoption.hpp"
#include "glove/supervisor/library_bundle.hpp"
#include "glove/supervisor/linux_session_filesystem.hpp"
#include "glove/supervisor/native_skill_runtime_adapter.hpp"
#include "glove/supervisor/path_alias.hpp"
#include "cgroup_v2.hpp"
#include "linux_managed_session.hpp"
#include "linux_resource_lifecycle.hpp"
#include <poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <expected>
#include <filesystem>
#include <fstream>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#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)
using glove::container::profile;
using glove::container::resource_enforcement_receipt;
using glove::container::resource_limits;
using glove::container::resource_termination_cause;
using glove::container::linux_detail::cgroup_v2_root;
using glove::container::linux_detail::linux_resource_lifecycle;
using glove::supervisor::linux_detail::linux_session_filesystem;
constexpr std::string_view controller_plan_digest =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
constexpr std::string_view audit_key =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
struct requested_alias {
std::string alias;
std::filesystem::path source;
std::string target;
glove::supervisor::path_access access = glove::supervisor::path_access::ephemeral_write;
};
class temporary_tree {
public:
temporary_tree() {
std::string pattern = "/tmp/glove-managed-session-test-XXXXXX";
char* created = ::mkdtemp(pattern.data());
if (created != nullptr) {
root_ = created;
}
}
temporary_tree(const temporary_tree&) = delete;
auto operator=(const temporary_tree&) -> temporary_tree& = delete;
temporary_tree(temporary_tree&&) = delete;
auto operator=(temporary_tree&&) -> temporary_tree& = delete;
~temporary_tree() {
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 epoch_ms() -> std::uint64_t {
const auto now = std::chrono::system_clock::now().time_since_epoch();
return static_cast<std::uint64_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(now).count()
);
}
auto make_pi_adoption(const std::filesystem::path& root, std::string_view name)
-> std::expected<glove::supervisor::resolved_native_harness_adoption, std::string> {
const auto fixture_root = root / std::string{name};
const auto settings_path = fixture_root / "source/settings.json";
const auto package_root = fixture_root / "store/example-extension";
std::error_code error;
if (!std::filesystem::create_directories(settings_path.parent_path(), error) || error ||
!std::filesystem::create_directories(package_root, error) || error ||
::chmod(fixture_root.c_str(), 0700) != 0) {
return std::unexpected(std::string{"create Pi adoption fixture"});
}
{
std::ofstream settings{settings_path, std::ios::binary | std::ios::trunc};
std::ofstream package{package_root / "package.json", std::ios::binary | std::ios::trunc};
std::ofstream entry{package_root / "index.js", std::ios::binary | std::ios::trunc};
settings << R"({"packages":["npm:example-extension"]})";
package << R"({"name":"example-extension","dependencies":{}})";
entry << "export default {};\n";
}
if (::chmod(settings_path.c_str(), 0600) != 0 ||
::chmod((package_root / "package.json").c_str(), 0600) != 0 ||
::chmod((package_root / "index.js").c_str(), 0600) != 0) {
return std::unexpected(std::string{"protect Pi adoption fixture"});
}
const auto protected_directory = fixture_root / "protected";
auto generated = glove::host::generate_pi_adoption_manifest({
.settings_path = settings_path,
.package_store_root = fixture_root / "store",
.protected_directory = protected_directory,
.dry_run = false,
});
if (!generated) {
return std::unexpected(generated.error());
}
const auto canonical_root = std::filesystem::canonical(protected_directory, error);
if (error) {
return std::unexpected(std::string{"canonicalize Pi adoption fixture"});
}
return glove::supervisor::resolve_native_harness_adoption(
{
.manifest_root = canonical_root.string(),
.manifest_digest = generated->manifest_digest,
.snapshot_digest = generated->snapshot_digest,
},
"pi"
);
}
auto policy_for(const requested_alias& requested, std::uint64_t quota)
-> glove::supervisor::path_alias_policy {
const bool read_only = requested.access == glove::supervisor::path_access::read;
return {
.alias = requested.alias,
.host_path = requested.source.string(),
.target_path = requested.target,
.max_ttl_secs = 300,
.access = {{
.access = requested.access,
.materialization = read_only ? glove::supervisor::path_materialization::bind
: glove::supervisor::path_materialization::copy,
.create_policy = read_only ? glove::supervisor::path_create_policy::never
: glove::supervisor::path_create_policy::empty_directory,
.cleanup_policy = read_only ? glove::supervisor::path_cleanup_policy::retain
: glove::supervisor::path_cleanup_policy::remove,
.max_bytes = read_only ? 0 : quota,
}},
};
}
auto make_lifecycle(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
std::span<const requested_alias> requested_aliases,
std::string_view session_id,
const resource_limits& limits,
std::vector<glove::supervisor::resolved_library_projection>&& library_projections = {},
std::string_view runtime_id = {},
std::optional<glove::supervisor::resolved_native_harness_adoption>&& adoption = {}
) -> std::expected<std::unique_ptr<linux_resource_lifecycle>, std::string> {
std::vector<glove::supervisor::resolved_path_grant> grants;
if (!requested_aliases.empty()) {
const auto alias_quota = limits.disk_bytes / 4U;
std::vector<glove::supervisor::path_alias_policy> policies;
policies.reserve(requested_aliases.size());
for (const auto& requested : requested_aliases) {
policies.push_back(policy_for(requested, alias_quota));
}
auto registry = glove::supervisor::path_alias_registry::build(std::move(policies));
if (!registry) {
return std::unexpected(registry.error());
}
grants.reserve(requested_aliases.size());
for (const auto& requested : requested_aliases) {
auto grant = registry->resolve({
.alias = requested.alias,
.access = requested.access,
.ttl_secs = 300,
.max_bytes =
requested.access == glove::supervisor::path_access::read ? 0 : alias_quota,
});
if (!grant) {
return std::unexpected(grant.error());
}
grants.push_back(std::move(*grant));
}
}
auto filesystem = linux_session_filesystem::create(
materialization_root.string(),
session_id,
limits.disk_bytes,
std::move(grants),
std::move(library_projections),
runtime_id,
std::move(adoption)
);
if (!filesystem) {
return std::unexpected(filesystem.error());
}
auto cgroup = root.create_session(session_id, limits);
if (!cgroup) {
return std::unexpected(cgroup.error());
}
return linux_resource_lifecycle::create(
std::move(*cgroup), std::move(*filesystem), limits, epoch_ms()
);
}
auto limits_for(std::uint64_t disk_bytes) -> resource_limits {
return {
.cpu_time_ms = 10'000,
.memory_bytes = std::uint64_t{128} * 1024U * 1024U,
.pids = 16,
.wall_time_ms = 5'000,
.disk_bytes = disk_bytes,
.terminal_output_bytes = std::uint64_t{1024} * 1024U,
};
}
auto launch_profile(const resource_limits& limits) -> profile {
profile value;
value.environment = {"PATH=/usr/bin:/bin:/usr/sbin:/sbin"};
value.required_limits = limits;
return value;
}
auto digest_for(std::string_view value) -> std::string {
const auto* bytes = reinterpret_cast<const unsigned char*>(value.data());
return glove::container::sha256_hex(std::span{bytes, value.size()}).value_or("");
}
auto execute_managed(
const profile& prof,
const std::vector<std::string>& argv,
std::unique_ptr<linux_resource_lifecycle> lifecycle
) -> std::expected<resource_enforcement_receipt, std::string> {
if (!lifecycle) {
return std::unexpected(std::string{"test lifecycle is required"});
}
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, *lifecycle, controller_plan_digest
);
if (!binding) {
return std::unexpected(binding.error());
}
return glove::container::linux_detail::exec_managed_session(
prof, argv, *binding, std::move(lifecycle)
);
}
auto inherited_stream_survives_clone_exec_seccomp_test(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
std::uint64_t page,
bool run_native_probe = true
) -> int {
const auto run_probe = [&](std::string_view session_id,
std::optional<std::filesystem::path> node_binary) -> int {
auto limits = limits_for(page * 32U);
limits.wall_time_ms = 60'000;
auto lifecycle = make_lifecycle(root, materialization_root, {}, session_id, limits);
REQUIRE(lifecycle.has_value());
int declared[2] = {-1, -1};
int undeclared[2] = {-1, -1};
REQUIRE(::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, declared) == 0);
REQUIRE(::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, undeclared) == 0);
REQUIRE(::fchmod(declared[0], 0600) == 0);
REQUIRE(::fchmod(declared[1], 0600) == 0);
struct stat child_status{};
struct stat peer_status{};
REQUIRE(::fstat(declared[1], &child_status) == 0);
REQUIRE(::fstat(declared[0], &peer_status) == 0);
const int undeclared_child_fd = undeclared[1];
std::vector<glove::container::linux_detail::inherited_stream_descriptor> descriptors;
descriptors.push_back({
.alias = "status",
.descriptor_fd = std::exchange(declared[1], -1),
.child_fd = 3,
.device = static_cast<std::uint64_t>(child_status.st_dev),
.inode = static_cast<std::uint64_t>(child_status.st_ino),
.uid = static_cast<std::uint32_t>(child_status.st_uid),
.mode = static_cast<std::uint32_t>(child_status.st_mode),
.links = static_cast<std::uint64_t>(child_status.st_nlink),
.peer_device = static_cast<std::uint64_t>(peer_status.st_dev),
.peer_inode = static_cast<std::uint64_t>(peer_status.st_ino),
.peer_uid = static_cast<std::uint32_t>(peer_status.st_uid),
.peer_mode = static_cast<std::uint32_t>(peer_status.st_mode),
.peer_links = static_cast<std::uint64_t>(peer_status.st_nlink),
.manifest_digest = std::string(64U, 'b'),
});
REQUIRE((*lifecycle)->install_inherited_streams(std::move(descriptors)).has_value());
auto prof = launch_profile(limits);
prof.environment.push_back(R"(GLOVE_LOCAL_SERVICE_FDS_V1={"status":3})");
std::vector<std::string> argv;
if (node_binary) {
constexpr std::string_view node_script = R"JS(
const net = require('node:net');
if (process.env.GLOVE_LOCAL_SERVICE_FDS_V1 !== '{"status":3}') process.exit(201);
const socket = new net.Socket({fd: 3, readable: true, writable: true});
let response = Buffer.alloc(0);
const timer = setTimeout(() => process.exit(202), 2000);
socket.on('error', () => process.exit(203));
socket.on('data', (chunk) => {
response = Buffer.concat([response, chunk]);
if (response.length >= 4) {
clearTimeout(timer);
socket.destroy();
process.exit(response.subarray(0, 4).toString() === 'pong' ? 0 : 204);
}
});
socket.write('ping');
)JS";
argv = {node_binary->string(), "-e", std::string{node_script}};
} else {
const std::filesystem::path probe{GLOVE_INHERITED_SOCKET_PROBE_AGENT_BIN};
REQUIRE(!probe.empty());
argv = {probe.string(), std::to_string(undeclared_child_fd)};
}
const auto peer_timeout_ms = static_cast<int>(limits.wall_time_ms + 5'000U);
std::thread peer{[descriptor = declared[0], peer_timeout_ms] {
pollfd readiness{.fd = descriptor, .events = POLLIN, .revents = 0};
std::array<char, 4> request{};
if (::poll(&readiness, 1, peer_timeout_ms) > 0 &&
::recv(descriptor, request.data(), request.size(), MSG_WAITALL) == 4 &&
std::string_view{request.data(), request.size()} == "ping") {
static_cast<void>(::send(descriptor, "pong", 4, MSG_NOSIGNAL));
}
::close(descriptor);
}};
declared[0] = -1;
auto receipt = execute_managed(prof, argv, std::move(*lifecycle));
peer.join();
::close(undeclared[0]);
::close(undeclared[1]);
if (!receipt) {
std::fprintf(stderr, "inherited socket probe failed: %s\n", receipt.error().c_str());
}
REQUIRE(receipt.has_value());
REQUIRE(receipt->termination_cause == resource_termination_cause::exited);
if (receipt->exit_code != 0) {
std::fprintf(
stderr,
"inherited socket introspection probe exit: %d\n",
receipt->exit_code.value_or(-1)
);
}
REQUIRE(receipt->exit_code == 0);
return 0;
};
if (run_native_probe) {
REQUIRE(run_probe("managed-inherited-stream", std::nullopt) == 0);
}
if (const char* node = std::getenv("GLOVE_TEST_NODE_BINARY");
node != nullptr && node[0] != '\0') {
REQUIRE(run_probe("managed-inherited-node", std::filesystem::path{node}) == 0);
return 0;
}
if (!run_native_probe) {
std::fprintf(stderr, "SKIP: Node.js is required for the inherited-node probe\n");
return 77;
}
return 0;
}
// The local REQUIRE macro expands each assertion into branches; the scenario
// itself remains a single linear launch contract.
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
auto mounted_copy_is_isolated_test(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
const std::filesystem::path& source,
const std::filesystem::path& file_source,
const std::filesystem::path& reference_source,
std::uint64_t page
) -> int {
const auto limits = limits_for(page * 64U);
const std::vector aliases = {
requested_alias{"project", source, "/workspace/project"},
requested_alias{"single", file_source, "/workspace/single.txt"},
requested_alias{
"reference",
reference_source,
"/workspace/reference",
glove::supervisor::path_access::read,
},
};
auto lifecycle = make_lifecycle(root, materialization_root, aliases, "managed-copy", limits);
REQUIRE(lifecycle.has_value());
std::string script = "set -eu; ";
script += "test \"$(cat /workspace/project/input.txt)\" = seed; ";
script += "printf child > /workspace/project/output.txt; ";
script += "test \"$(cat /workspace/project/output.txt)\" = child; ";
script += "test \"$(cat /workspace/single.txt)\" = standalone; ";
script += "printf changed > /workspace/single.txt; ";
script += "test \"$(cat /workspace/single.txt)\" = changed; ";
script += "test \"$(cat /workspace/reference/reference.txt)\" = trusted; ";
script += "if (printf denied > /workspace/reference/blocked) 2>/dev/null; then exit 81; fi; ";
script += "test -w /tmp; test -w /var/tmp; ";
script += "test \"$(stat -c %d /tmp)\" = \"$(stat -c %d /var/tmp)\"; ";
script += "test ! -e '" + source.string() + "'; ";
script += "printf alpha; printf beta >&2";
const auto prof = launch_profile(limits);
const std::vector argv = {std::string{"/usr/bin/sh"}, std::string{"-c"}, script};
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
const auto producer_key_path = materialization_root.parent_path() / "managed-audit.key";
const auto producer_journal_path =
materialization_root.parent_path() / "managed-receipts.journal";
{
std::ofstream key{producer_key_path, std::ios::binary | std::ios::trunc};
key << audit_key << '\n';
key.flush();
REQUIRE(key.good());
}
REQUIRE(::chmod(producer_key_path.c_str(), 0600) == 0);
const glove::container::receipt_audit_producer_config producer_config{
.key_path = producer_key_path,
.journal_path = producer_journal_path,
};
auto producer = glove::container::receipt_audit_producer::initialize(producer_config);
REQUIRE(producer.has_value());
const auto producer_genesis = (*producer)->anchor();
REQUIRE((*producer)->acknowledge_bootstrap(producer_genesis).has_value());
auto terminal = glove::container::linux_detail::exec_managed_session_authenticated(
prof, argv, "managed-copy", *binding, std::move(*lifecycle), **producer
);
REQUIRE(terminal.has_value());
const auto durable_anchor = (*producer)->anchor();
REQUIRE(durable_anchor.sequence == 1);
producer->reset();
auto recovered =
glove::container::receipt_audit_producer::recover(producer_config, producer_genesis);
REQUIRE(recovered.has_value());
auto pending = (*recovered)->page_after(producer_genesis, 10);
REQUIRE(pending.has_value());
REQUIRE(pending->envelopes.size() == 1);
REQUIRE(pending->envelopes[0] == *terminal);
REQUIRE(terminal->receipt.profile_digest == binding->profile_digest);
REQUIRE(terminal->receipt.termination_cause == resource_termination_cause::exited);
REQUIRE(terminal->receipt.exit_code == 0);
REQUIRE(terminal->receipt.observed.disk_bytes > 0);
REQUIRE(terminal->receipt.observed.disk_bytes <= limits.disk_bytes);
REQUIRE(terminal->receipt.observed.terminal_output_bytes == 9);
auto anchor = glove::container::receipt_audit_anchor::create(audit_key);
REQUIRE(anchor.has_value());
REQUIRE(
glove::container::verify_receipt_audit_envelope(
*terminal, audit_key, "managed-copy", controller_plan_digest, **anchor
)
.has_value()
);
REQUIRE(
glove::container::validate_resource_enforcement_receipt(
terminal->receipt,
limits,
glove::container::linux_detail::managed_session_capabilities(),
glove::container::sandbox_backend::linux_production,
binding->profile_digest
)
.has_value()
);
auto tampered_digest = terminal->receipt;
tampered_digest.profile_digest[0] = tampered_digest.profile_digest[0] == 'a' ? 'b' : 'a';
REQUIRE(!glove::container::validate_resource_enforcement_receipt(
tampered_digest,
limits,
glove::container::linux_detail::managed_session_capabilities(),
glove::container::sandbox_backend::linux_production,
binding->profile_digest
)
.has_value());
auto tampered_mechanisms = terminal->receipt;
tampered_mechanisms.mechanisms.disk = glove::container::enforcement_mechanism::unavailable;
REQUIRE(!glove::container::validate_resource_enforcement_receipt(
tampered_mechanisms,
limits,
glove::container::linux_detail::managed_session_capabilities(),
glove::container::sandbox_backend::linux_production,
binding->profile_digest
)
.has_value());
auto tampered_limits = terminal->receipt;
++tampered_limits.configured_limits.wall_time_ms;
REQUIRE(!glove::container::validate_resource_enforcement_receipt(
tampered_limits,
limits,
glove::container::linux_detail::managed_session_capabilities(),
glove::container::sandbox_backend::linux_production,
binding->profile_digest
)
.has_value());
auto tampered_envelope = *terminal;
++tampered_envelope.receipt.observed.disk_bytes;
auto tamper_anchor = glove::container::receipt_audit_anchor::create(audit_key);
REQUIRE(tamper_anchor.has_value());
REQUIRE(
!glove::container::verify_receipt_audit_envelope(
tampered_envelope, audit_key, "managed-copy", controller_plan_digest, **tamper_anchor
)
.has_value()
);
REQUIRE(!std::filesystem::exists(source / "output.txt"));
REQUIRE(!std::filesystem::exists(reference_source / "blocked"));
{
std::ifstream original{file_source};
std::string contents;
original >> contents;
REQUIRE(contents == "standalone");
}
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto managed_policy_rejection_test(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
const std::filesystem::path& source,
std::uint64_t page
) -> int {
const auto limits = limits_for(page * 32U);
auto raw_path_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-raw-path", limits);
REQUIRE(raw_path_lifecycle.has_value());
auto raw_path_profile = launch_profile(limits);
raw_path_profile.filesystem.push_back({.path = source.string(), .writable = false});
auto raw_path =
execute_managed(raw_path_profile, {"/usr/bin/true"}, std::move(*raw_path_lifecycle));
REQUIRE(!raw_path.has_value());
REQUIRE(raw_path.error().find("lifecycle mount set") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto runtime_path_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-runtime-path", limits);
REQUIRE(runtime_path_lifecycle.has_value());
auto runtime_path_profile = launch_profile(limits);
runtime_path_profile.runtime_filesystem.push_back({.path = source.string(), .writable = false});
auto runtime_path = execute_managed(
runtime_path_profile,
{"/bin/sh", "-c", "test -f " + (source / "input.txt").string()},
std::move(*runtime_path_lifecycle)
);
REQUIRE(runtime_path.has_value());
REQUIRE(std::filesystem::is_empty(materialization_root));
auto unmanaged_home_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-unbound-home", limits);
REQUIRE(unmanaged_home_lifecycle.has_value());
auto unmanaged_home_profile = launch_profile(limits);
unmanaged_home_profile.managed_home_dir = "/home/agent";
auto unmanaged_home = execute_managed(
unmanaged_home_profile, {"/usr/bin/true"}, std::move(*unmanaged_home_lifecycle)
);
REQUIRE(!unmanaged_home.has_value());
REQUIRE(unmanaged_home.error().find("exact scratch projections") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto mismatched_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-limit-mismatch", limits);
REQUIRE(mismatched_lifecycle.has_value());
auto mismatched_limits = limits;
++mismatched_limits.wall_time_ms;
auto mismatched_profile = launch_profile(mismatched_limits);
auto mismatch =
execute_managed(mismatched_profile, {"/usr/bin/true"}, std::move(*mismatched_lifecycle));
REQUIRE(!mismatch.has_value());
REQUIRE(mismatch.error().find("resource limits mismatch") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto tampered_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-binding-tamper", limits);
REQUIRE(tampered_lifecycle.has_value());
const auto prof = launch_profile(limits);
const std::vector argv = {std::string{"/usr/bin/true"}};
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **tampered_lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
binding->profile_digest[0] = binding->profile_digest[0] == 'a' ? 'b' : 'a';
auto tampered = glove::container::linux_detail::exec_managed_session(
prof, argv, *binding, std::move(*tampered_lifecycle)
);
REQUIRE(!tampered.has_value());
REQUIRE(tampered.error().find("launch binding mismatch") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto codex_runtime_context_test(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
const std::filesystem::path& library_root,
std::uint64_t page
) -> int {
constexpr std::string_view bundle =
R"({"schema_version":1,"source_library_ref":"bafy-codex","source_manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","entries":[{"key":"sage-core","kind":"skill","content_digest":"a8095aa5472d84253e87441d7438235d2b13c13e09de63cbb88609931b8b8947","content":"# Sage core\n"}]})";
const auto bundle_digest = digest_for(bundle);
REQUIRE(bundle_digest.size() == 64U);
const auto bundle_path = library_root / (bundle_digest + ".json");
{
std::ofstream output{bundle_path, std::ios::binary | std::ios::trunc};
output << bundle;
}
REQUIRE(::chmod(bundle_path.c_str(), 0600) == 0);
auto store = glove::supervisor::library_bundle_store::open(library_root);
REQUIRE(store.has_value());
auto projections = store->resolve_projections({{
.projection =
{
.projection_id = "sage-codex",
.content_digest = bundle_digest,
.destination_alias = "libraries",
},
.target_path = "/opt/sage/library-bundles",
}});
REQUIRE(projections.has_value());
const auto limits = limits_for(page * 32U);
auto lifecycle = make_lifecycle(
root,
materialization_root,
{},
"managed-codex-context",
limits,
std::move(*projections),
"codex"
);
REQUIRE(lifecycle.has_value());
auto prof = launch_profile(limits);
prof.environment.push_back("CODEX_HOME=/home/agent/.codex");
prof.managed_home_dir = "/home/agent";
const std::vector argv = {
std::string{"/usr/bin/sh"},
std::string{"-c"},
std::string{"test \"$HOME\" = /home/agent; test \"$CODEX_HOME\" = /home/agent/.codex; "
"test -f /home/agent/.codex/skills/sage-codex-sage-core/SKILL.md; "
"test \"$(cat /home/agent/.codex/skills/sage-codex-sage-core/SKILL.md)\" = '# "
"Sage core'"},
};
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
auto terminal = glove::container::linux_detail::exec_managed_session(
prof, argv, *binding, std::move(*lifecycle)
);
REQUIRE(terminal.has_value());
REQUIRE(terminal->exit_code == 0);
REQUIRE(terminal->profile_digest == binding->profile_digest);
REQUIRE(terminal->library_projections.size() == 1U);
REQUIRE(terminal->library_projections.front().content_digest == bundle_digest);
REQUIRE(std::filesystem::is_empty(materialization_root));
struct native_runtime_case {
std::string_view runtime_id;
std::string_view skill_directory;
std::string_view managed_environment;
};
for (const native_runtime_case runtime : {
native_runtime_case{"claude-code", ".claude/skills", ""},
native_runtime_case{"pi", ".pi/agent/skills", ""},
native_runtime_case{"copilot", ".copilot/skills", "COPILOT_HOME=/home/agent/.copilot"},
native_runtime_case{
"opencode", ".config/opencode/skills", "XDG_CONFIG_HOME=/home/agent/.config"
},
}) {
auto native_projections = store->resolve_projections({{
.projection =
{
.projection_id = "sage-codex",
.content_digest = bundle_digest,
.destination_alias = "libraries",
},
.target_path = "/opt/sage/library-bundles",
}});
REQUIRE(native_projections.has_value());
std::optional<glove::supervisor::resolved_native_harness_adoption> adoption;
if (runtime.runtime_id == "pi") {
auto resolved = make_pi_adoption(materialization_root.parent_path(), "pi-context");
REQUIRE(resolved.has_value());
adoption.emplace(std::move(*resolved));
}
auto native_lifecycle = make_lifecycle(
root,
materialization_root,
{},
std::string{"managed-"} + std::string{runtime.runtime_id} + "-context",
limits,
std::move(*native_projections),
runtime.runtime_id,
std::move(adoption)
);
REQUIRE(native_lifecycle.has_value());
auto native_profile = launch_profile(limits);
native_profile.managed_home_dir = "/home/agent";
if (!runtime.managed_environment.empty()) {
native_profile.environment.push_back(std::string{runtime.managed_environment});
}
std::string command = "test \"$HOME\" = /home/agent; test -f /home/agent/" +
std::string{runtime.skill_directory} +
"/sage-codex-sage-core/SKILL.md";
if (!runtime.managed_environment.empty()) {
const auto separator = runtime.managed_environment.find('=');
command += "; test \"$" +
std::string{runtime.managed_environment.substr(0, separator)} + "\" = \"" +
std::string{runtime.managed_environment.substr(separator + 1)} + "\"";
}
const std::vector native_argv = {
std::string{"/usr/bin/sh"},
std::string{"-c"},
std::move(command),
};
auto native_binding = glove::container::linux_detail::bind_managed_session(
native_profile, native_argv, **native_lifecycle, controller_plan_digest
);
REQUIRE(native_binding.has_value());
auto native_terminal = glove::container::linux_detail::exec_managed_session(
native_profile, native_argv, *native_binding, std::move(*native_lifecycle)
);
REQUIRE(native_terminal.has_value());
REQUIRE(native_terminal->exit_code == 0);
REQUIRE(std::filesystem::is_empty(materialization_root));
}
return 0;
}
struct native_harness_case {
std::string_view runtime_id;
std::string_view executable;
};
constexpr std::array<native_harness_case, 5> native_harnesses{{
{"codex", "codex"},
{"claude-code", "claude"},
{"pi", "pi"},
{"copilot", "copilot"},
{"opencode", "opencode"},
}};
// A test-only image supplies pinned, operator-like harness installations under
// this one read-only runtime root. The regular containment image intentionally
// has no vendor client, so ordinary unit and workflow lanes retain that guard.
auto resolve_native_harness_root() -> std::expected<std::filesystem::path, std::string> {
const char* configured_root = ::getenv("GLOVE_TEST_NATIVE_HARNESS_ROOT");
if (configured_root == nullptr || *configured_root == '\0') {
return std::unexpected("GLOVE_TEST_NATIVE_HARNESS_ROOT is not configured");
}
std::error_code error;
auto harness_root = std::filesystem::canonical(configured_root, error);
if (error || !std::filesystem::is_directory(harness_root)) {
return std::unexpected("GLOVE_TEST_NATIVE_HARNESS_ROOT is not an available directory");
}
const auto bin_directory = harness_root / "node_modules" / ".bin";
for (const auto& harness : native_harnesses) {
const auto executable = bin_directory / harness.executable;
if (!std::filesystem::is_regular_file(executable) ||
::access(executable.c_str(), X_OK) != 0) {
return std::unexpected(
"managed native harness distribution is unavailable (" +
std::string{harness.runtime_id} + ": " + executable.string() + ")"
);
}
}
return harness_root;
}
auto real_native_harness_test(
cgroup_v2_root& root,
const std::filesystem::path& materialization_root,
const std::filesystem::path& library_root,
std::uint64_t page
) -> int {
auto resolved_harness_root = resolve_native_harness_root();
if (!resolved_harness_root) {
std::fprintf(stderr, "SKIP: %s\n", resolved_harness_root.error().c_str());
return 77;
}
const auto& harness_root = *resolved_harness_root;
const auto bin_directory = harness_root / "node_modules" / ".bin";
const auto node_directory = harness_root / "node-runtime" / "bin";
constexpr std::string_view bundle =
R"({"schema_version":1,"source_library_ref":"bafy-native","source_manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","entries":[{"key":"sage-core","kind":"skill","content_digest":"a8095aa5472d84253e87441d7438235d2b13c13e09de63cbb88609931b8b8947","content":"# Sage core\n"}]})";
const auto bundle_digest = digest_for(bundle);
REQUIRE(bundle_digest.size() == 64U);
const auto bundle_path = library_root / (bundle_digest + ".json");
{
std::ofstream output{bundle_path, std::ios::binary | std::ios::trunc};
output << bundle;
}
REQUIRE(::chmod(bundle_path.c_str(), 0600) == 0);
auto store = glove::supervisor::library_bundle_store::open(library_root);
REQUIRE(store.has_value());
auto limits = limits_for(page * 256U);
// Vendor startup shapes differ; this is a conformance ceiling, not the
// low-limit enforcement probe elsewhere in this test suite.
limits.memory_bytes = std::uint64_t{1} * 1024U * 1024U * 1024U;
limits.pids = 64;
limits.wall_time_ms = 20'000;
limits.disk_bytes = std::uint64_t{512} * 1024U * 1024U;
for (const auto& harness : native_harnesses) {
const auto adapter =
glove::supervisor::native_skill_runtime_adapter_for(harness.runtime_id);
REQUIRE(adapter.has_value());
const auto executable = bin_directory / harness.executable;
REQUIRE(std::filesystem::is_regular_file(executable));
REQUIRE(::access(executable.c_str(), X_OK) == 0);
auto projections = store->resolve_projections({{
.projection =
{
.projection_id = "sage-native",
.content_digest = bundle_digest,
.destination_alias = "libraries",
},
.target_path = "/opt/sage/library-bundles",
}});
REQUIRE(projections.has_value());
std::optional<glove::supervisor::resolved_native_harness_adoption> adoption;
if (harness.runtime_id == "pi") {
auto resolved = make_pi_adoption(materialization_root.parent_path(), "pi-real");
REQUIRE(resolved.has_value());
adoption.emplace(std::move(*resolved));
}
auto lifecycle = make_lifecycle(
root,
materialization_root,
{},
std::string{"managed-real-"} + std::string{harness.runtime_id},
limits,
std::move(*projections),
harness.runtime_id,
std::move(adoption)
);
REQUIRE(lifecycle.has_value());
auto prof = launch_profile(limits);
prof.environment = {
"PATH=" + bin_directory.string() + ":" + node_directory.string() + ":/usr/bin:/bin",
"TERM=xterm-256color",
};
for (const auto& variable : adapter->managed_environment) {
prof.environment.push_back(variable);
}
prof.runtime_filesystem.push_back({.path = harness_root.string(), .writable = false});
prof.managed_home_dir = "/home/agent";
const std::vector argv = {executable.string(), std::string{"--version"}};
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
auto session = glove::container::linux_detail::start_managed_pty_session(
prof,
argv,
*binding,
std::move(*lifecycle),
{
.transcript_bytes = 64U * 1024U,
.max_read_bytes = 64U * 1024U,
.max_input_frame_bytes = 64U * 1024U,
.input_timeout_ms = 1'000,
.initial_rows = 24,
.initial_columns = 80,
.refinement_evaluator = nullptr,
},
[](::pid_t) -> std::expected<void, std::string> { return {}; }
);
REQUIRE(session.has_value());
auto output = (*session)->wait_read(0, 64U * 1024U, 5'000);
REQUIRE(output.has_value());
auto terminal = (*session)->wait();
REQUIRE(terminal.has_value());
if (terminal->exit_code != 0) {
std::fprintf(
stderr,
"Glove Linux real native harness probe (%.*s) exited %d: %.*s\n",
static_cast<int>(harness.runtime_id.size()),
harness.runtime_id.data(),
terminal->exit_code.value_or(-1),
static_cast<int>(output->bytes.size()),
output->bytes.data()
);
std::fprintf(
stderr,
" termination=%u peak_memory=%llu peak_pids=%u wall=%llu\n",
static_cast<unsigned int>(terminal->termination_cause),
static_cast<unsigned long long>(terminal->observed.peak_memory_bytes),
terminal->observed.peak_pids,
static_cast<unsigned long long>(terminal->observed.wall_time_ms)
);
return 1;
}
REQUIRE(terminal->termination_cause == resource_termination_cause::exited);
REQUIRE(!output->bytes.empty());
REQUIRE(!output->truncated);
REQUIRE(terminal->profile_digest == binding->profile_digest);
REQUIRE(terminal->library_projections.size() == 1U);
REQUIRE(terminal->library_projections.front().content_digest == bundle_digest);
REQUIRE(std::filesystem::is_empty(materialization_root));
std::fprintf(
stderr,
"Glove Linux real native harness probe (%.*s) passed\n",
static_cast<int>(harness.runtime_id.size()),
harness.runtime_id.data()
);
}
return 0;
}
auto child_release_is_gated_by_durable_callback_test(
cgroup_v2_root& root, const std::filesystem::path& materialization_root, std::uint64_t page
) -> int {
const auto limits = limits_for(page * 16U);
const auto prof = launch_profile(limits);
const std::vector argv = {std::string{"/usr/bin/true"}};
auto denied_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-start-denied", limits);
REQUIRE(denied_lifecycle.has_value());
auto denied_binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **denied_lifecycle, controller_plan_digest
);
REQUIRE(denied_binding.has_value());
bool denied_callback_called = false;
auto denied = glove::container::linux_detail::exec_managed_session(
prof,
argv,
*denied_binding,
std::move(*denied_lifecycle),
[&](::pid_t child) -> std::expected<void, std::string> {
denied_callback_called = child > 0;
return std::unexpected(std::string{"durable running append rejected"});
}
);
REQUIRE(!denied.has_value());
REQUIRE(denied_callback_called);
REQUIRE(denied.error().find("durable running append rejected") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto accepted_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-start-accepted", limits);
REQUIRE(accepted_lifecycle.has_value());
auto accepted_binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **accepted_lifecycle, controller_plan_digest
);
REQUIRE(accepted_binding.has_value());
bool accepted_callback_called = false;
auto accepted = glove::container::linux_detail::exec_managed_session(
prof,
argv,
*accepted_binding,
std::move(*accepted_lifecycle),
[&](::pid_t child) -> std::expected<void, std::string> {
accepted_callback_called = child > 0;
return {};
}
);
REQUIRE(accepted.has_value());
REQUIRE(accepted_callback_called);
REQUIRE(accepted->termination_cause == resource_termination_cause::exited);
REQUIRE(accepted->exit_code == 0);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto child_disk_exhaustion_test(
cgroup_v2_root& root, const std::filesystem::path& materialization_root, std::uint64_t page
) -> int {
const auto limits = limits_for(page * 16U);
auto lifecycle = make_lifecycle(root, materialization_root, {}, "managed-disk", limits);
REQUIRE(lifecycle.has_value());
const std::string script =
"dd if=/dev/urandom of=/tmp/pressure bs=4096 count=100000 status=none 2>/dev/null; "
"sleep 10";
auto terminal = execute_managed(
launch_profile(limits), {"/usr/bin/sh", "-c", script}, std::move(*lifecycle)
);
REQUIRE(terminal.has_value());
REQUIRE(terminal->termination_cause == resource_termination_cause::disk_limit);
REQUIRE(!terminal->exit_code.has_value());
REQUIRE(terminal->observed.disk_bytes > 0);
REQUIRE(terminal->observed.disk_bytes <= limits.disk_bytes);
REQUIRE(terminal->observed.wall_time_ms < limits.wall_time_ms);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto child_output_exhaustion_test(
cgroup_v2_root& root, const std::filesystem::path& materialization_root, std::uint64_t page
) -> int {
auto limits = limits_for(page * 16U);
limits.terminal_output_bytes = 64;
auto lifecycle = make_lifecycle(root, materialization_root, {}, "managed-output", limits);
REQUIRE(lifecycle.has_value());
const std::string script = "printf '%0128d' 0; sleep 10";
auto terminal = execute_managed(
launch_profile(limits), {"/usr/bin/sh", "-c", script}, std::move(*lifecycle)
);
REQUIRE(terminal.has_value());
REQUIRE(terminal->termination_cause == resource_termination_cause::terminal_output_limit);
REQUIRE(!terminal->exit_code.has_value());
REQUIRE(terminal->observed.terminal_output_bytes > limits.terminal_output_bytes);
REQUIRE(terminal->observed.wall_time_ms < limits.wall_time_ms);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto interactive_pty_attach_and_stop_test(
cgroup_v2_root& root, const std::filesystem::path& materialization_root, std::uint64_t page
) -> int {
auto limits = limits_for(page * 16U);
limits.wall_time_ms = 60'000;
const auto prof = launch_profile(limits);
const std::vector argv = {std::string{"/usr/bin/cat"}};
auto ungated_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-pty-ungated", limits);
REQUIRE(ungated_lifecycle.has_value());
auto ungated_binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **ungated_lifecycle, controller_plan_digest
);
REQUIRE(ungated_binding.has_value());
auto ungated = glove::container::linux_detail::start_managed_pty_session(
prof,
argv,
*ungated_binding,
std::move(*ungated_lifecycle),
{},
glove::container::linux_detail::managed_session_start_gate{}
);
REQUIRE(!ungated.has_value());
REQUIRE(ungated.error().find("child-release gate") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto denied_lifecycle =
make_lifecycle(root, materialization_root, {}, "managed-pty-denied", limits);
REQUIRE(denied_lifecycle.has_value());
auto denied_binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **denied_lifecycle, controller_plan_digest
);
REQUIRE(denied_binding.has_value());
auto denied = glove::container::linux_detail::start_managed_pty_session(
prof,
argv,
*denied_binding,
std::move(*denied_lifecycle),
{},
[](::pid_t) -> std::expected<void, std::string> {
return std::unexpected(std::string{"durable PTY running append rejected"});
}
);
REQUIRE(!denied.has_value());
REQUIRE(denied.error().find("durable PTY running append rejected") != std::string::npos);
REQUIRE(std::filesystem::is_empty(materialization_root));
auto lifecycle = make_lifecycle(root, materialization_root, {}, "managed-pty", limits);
REQUIRE(lifecycle.has_value());
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
bool gate_called = false;
auto session = glove::container::linux_detail::start_managed_pty_session(
prof,
argv,
*binding,
std::move(*lifecycle),
{
.transcript_bytes = page,
.max_read_bytes = page,
.max_input_frame_bytes = page,
.input_timeout_ms = 1'000,
.initial_rows = 24,
.initial_columns = 80,
.refinement_evaluator = nullptr,
},
[&](::pid_t child) -> std::expected<void, std::string> {
gate_called = child > 0;
return {};
}
);
REQUIRE(session.has_value());
REQUIRE(gate_called);
REQUIRE((*session)->pid() > 0);
REQUIRE((*session)->write_input("hello from pty\n").has_value());
auto output = (*session)->wait_read(0, page, 1'000);
REQUIRE(output.has_value());
REQUIRE(output->bytes.find("hello from pty") != std::string::npos);
REQUIRE(!output->truncated);
REQUIRE((*session)->resize(48, 132).has_value());
bool stop_gate_called = false;
const glove::container::linux_detail::managed_session_stop_gate before_stop =
[&]() -> std::expected<void, std::string> {
stop_gate_called = true;
return {};
};
REQUIRE((*session)->stop(before_stop).has_value());
REQUIRE(stop_gate_called);
REQUIRE((*session)->stop(before_stop).has_value());
auto terminal = (*session)->wait();
REQUIRE(terminal.has_value());
REQUIRE(terminal->termination_cause == resource_termination_cause::signaled);
REQUIRE(!terminal->exit_code.has_value());
REQUIRE(terminal->observed.terminal_output_bytes >= output->bytes.size());
REQUIRE((*session)->wait() == terminal);
stop_gate_called = false;
REQUIRE((*session)->stop(before_stop).has_value());
REQUIRE(!stop_gate_called);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
auto declarative_refinement_evaluator_test(
cgroup_v2_root& root, const std::filesystem::path& materialization_root, std::uint64_t page
) -> int {
using namespace glove::container;
const auto limits = limits_for(page * 32U);
auto lifecycle = make_lifecycle(root, materialization_root, {}, "managed-refinement", limits);
REQUIRE(lifecycle.has_value());
refinement_execution_binding execution;
execution.schema_version = 1;
execution.variant = refinement_variant::candidate;
execution.fixture = {"fixture", std::string(64, '0'), "fixtures"};
execution.base = {"base", std::string(64, 'b'), "skills"};
execution.candidate = {"candidate", std::string(64, 'c'), "skills"};
execution.matched_context_digest = std::string(64, '0');
execution.plan_context_digest = std::string(64, 'e');
refinement_fixture_manifest fixture{
.schema = std::string{refinement_fixture_schema},
.evaluation_run_id = "run-managed",
.pair_id = "pair-managed",
.session_id = "managed-refinement",
.variant = refinement_variant::candidate,
.proposal_digest = std::string(64, 'a'),
.base_projection_digest = execution.base.content_digest,
.candidate_projection_digest = execution.candidate.content_digest,
.fixture_id = "prompt-managed",
.fixture_digest = std::string(64, 'd'),
.dataset_ref = "fixture:managed",
.dataset_fingerprint = std::string(64, 'f'),
.seed = 42,
.model =
{
.provider = "test",
.model_id = "synthetic",
.model_family = "synthetic",
.model_revision = std::nullopt,
.tier = "local",
.normalizer_version = 1,
},
.harness = "synthetic",
.module = std::nullopt,
.skill_projection_id = execution.candidate.projection_id,
.skill_projection_digest = execution.candidate.content_digest,
.matched_context_digest = std::string(64, '0'),
.assertions = {
.expected_termination = resource_termination_cause::exited,
.expected_exit_code = 0,
.required_transcript_literals = {"alpha beta", "done"},
.forbidden_transcript_literals = {"forbidden"},
.max_latency_ms = 2'000,
},
};
fixture.matched_context_digest =
refinement_fixture_context_digest(fixture, execution.plan_context_digest).value();
execution.matched_context_digest = fixture.matched_context_digest;
const auto encoded = canonical_refinement_fixture_bytes(fixture).value();
const auto encoded_bytes = std::span<const unsigned char>{
reinterpret_cast<const unsigned char*>(encoded.data()), encoded.size()
};
execution.fixture.content_digest = sha256_hex(encoded_bytes).value();
auto evaluator =
refinement_transcript_evaluator::create(encoded_bytes, fixture.session_id, execution);
REQUIRE(evaluator.has_value());
const auto prof = launch_profile(limits);
const std::vector argv = {
std::string{"/usr/bin/sh"},
std::string{"-c"},
std::string{"printf 'alpha '; printf 'beta '; printf done"},
};
auto binding = glove::container::linux_detail::bind_managed_session(
prof, argv, **lifecycle, controller_plan_digest
);
REQUIRE(binding.has_value());
auto session = glove::container::linux_detail::start_managed_pty_session(
prof,
argv,
*binding,
std::move(*lifecycle),
{
.transcript_bytes = page,
.max_read_bytes = page,
.max_input_frame_bytes = page,
.input_timeout_ms = 1'000,
.initial_rows = 24,
.initial_columns = 80,
.refinement_evaluator = *evaluator,
},
[](::pid_t) -> std::expected<void, std::string> { return {}; }
);
REQUIRE(session.has_value());
auto resource = (*session)->wait();
REQUIRE(resource.has_value());
auto refinement = (*session)->wait_refinement();
REQUIRE(refinement.has_value());
REQUIRE(refinement->has_value());
REQUIRE((*refinement)->evaluated_outcome->metrics.at("passed") == 1);
REQUIRE((*refinement)->transcript.byte_count == 15);
REQUIRE(std::filesystem::is_empty(materialization_root));
return 0;
}
enum class managed_test_mode : std::uint8_t {
full,
native_harness_matrix,
inherited_stream,
inherited_node,
systemd_service,
};
auto run(managed_test_mode mode) -> int {
if (mode == managed_test_mode::native_harness_matrix) {
auto harness_root = resolve_native_harness_root();
if (!harness_root) {
std::fprintf(stderr, "SKIP: %s\n", harness_root.error().c_str());
return 77;
}
}
temporary_tree tree;
REQUIRE(!tree.root().empty());
const auto materialization_root = tree.root() / "materializations";
const auto source = tree.root() / "source";
const auto file_source = tree.root() / "single-source.txt";
const auto reference_source = tree.root() / "reference";
const auto library_root = tree.root() / "library";
REQUIRE(std::filesystem::create_directory(materialization_root));
REQUIRE(::chmod(materialization_root.c_str(), 0700) == 0);
REQUIRE(std::filesystem::create_directory(source));
REQUIRE(std::filesystem::create_directory(reference_source));
REQUIRE(std::filesystem::create_directory(library_root));
REQUIRE(::chmod(library_root.c_str(), 0700) == 0);
{
std::ofstream input{source / "input.txt"};
input << "seed\n";
std::ofstream single{file_source};
single << "standalone\n";
std::ofstream reference{reference_source / "reference.txt"};
reference << "trusted\n";
}
const long page_size = ::sysconf(_SC_PAGESIZE);
REQUIRE(page_size > 0);
const auto page = static_cast<std::uint64_t>(page_size);
auto root = cgroup_v2_root::prepare_for_current_process();
if (!root) {
std::fprintf(stderr, "managed-session topology unavailable: %s\n", root.error().c_str());
return 77;
}
if (mode == managed_test_mode::native_harness_matrix) {
return real_native_harness_test(*root, materialization_root, library_root, page);
}
const auto inherited_probe = inherited_stream_survives_clone_exec_seccomp_test(
*root,
materialization_root,
page,
mode != managed_test_mode::inherited_node && mode != managed_test_mode::systemd_service
);
if (inherited_probe != 0) {
return inherited_probe;
}
if (mode == managed_test_mode::inherited_stream || mode == managed_test_mode::inherited_node) {
return 0;
}
if (mode == managed_test_mode::systemd_service) {
return interactive_pty_attach_and_stop_test(*root, materialization_root, page);
}
REQUIRE(
mounted_copy_is_isolated_test(
*root, materialization_root, source, file_source, reference_source, page
) == 0
);
REQUIRE(managed_policy_rejection_test(*root, materialization_root, source, page) == 0);
REQUIRE(codex_runtime_context_test(*root, materialization_root, library_root, page) == 0);
REQUIRE(
child_release_is_gated_by_durable_callback_test(*root, materialization_root, page) == 0
);
REQUIRE(child_disk_exhaustion_test(*root, materialization_root, page) == 0);
REQUIRE(child_output_exhaustion_test(*root, materialization_root, page) == 0);
REQUIRE(interactive_pty_attach_and_stop_test(*root, materialization_root, page) == 0);
REQUIRE(declarative_refinement_evaluator_test(*root, materialization_root, page) == 0);
return 0;
}
} // namespace
auto main(int argc, char* argv[]) -> int {
if (argc == 1) {
return run(managed_test_mode::full);
}
if (argc == 2 && std::string_view{argv[1]} == "--native-harness-matrix") {
return run(managed_test_mode::native_harness_matrix);
}
if (argc == 2 && std::string_view{argv[1]} == "--inherited-stream-only") {
return run(managed_test_mode::inherited_stream);
}
if (argc == 2 && std::string_view{argv[1]} == "--inherited-node-only") {
return run(managed_test_mode::inherited_node);
}
if (argc == 2 && std::string_view{argv[1]} == "--systemd-service-only") {
return run(managed_test_mode::systemd_service);
}
std::fprintf(
stderr,
"usage: %s [--native-harness-matrix|--inherited-stream-only|--inherited-node-only|"
"--systemd-service-only]\n",
argv[0]
);
return 2;
}