#include "glove/container/digest.hpp" #include "glove/supervisor/codex_runtime_adapter.hpp" #include "glove/supervisor/library_bundle.hpp" #include "glove/supervisor/native_skill_runtime_adapter.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { #define REQUIRE(cond) \ do { \ if (!(cond)) { \ std::fprintf(stderr, "REQUIRE failed: %s @ %s:%d\n", #cond, __FILE__, __LINE__); \ return 1; \ } \ } while (0) class temporary_directory { public: temporary_directory() { std::string pattern = "/tmp/glove-library-bundle-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 digest_for(std::string_view value) -> std::string { const auto* bytes = reinterpret_cast(value.data()); return glove::container::sha256_hex(std::span{bytes, value.size()}).value_or(""); } auto write_bundle(const std::filesystem::path& root, std::string_view contents, mode_t mode = 0600) -> std::filesystem::path { const auto path = root / (digest_for(contents) + ".json"); { std::ofstream output{path, std::ios::binary | std::ios::trunc}; output.write(contents.data(), static_cast(contents.size())); } static_cast(::chmod(path.c_str(), mode)); return path; } auto read_descriptor(int descriptor, std::size_t size) -> std::string { std::string contents(size, '\0'); const auto count = ::pread(descriptor, contents.data(), contents.size(), 0); if (count != static_cast(contents.size())) { return {}; } return contents; } auto run() -> int { temporary_directory temporary; REQUIRE(!temporary.root().empty()); const auto root = temporary.root() / "bundles"; REQUIRE(std::filesystem::create_directory(root)); REQUIRE(::chmod(root.c_str(), 0700) == 0); constexpr std::string_view canonical = R"({"schema_version":1,"source_library_ref":"bafy-test","source_manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","entries":[]})"; const auto digest = digest_for(canonical); REQUIRE(digest.size() == 64U); const auto bundle_path = write_bundle(root, canonical); auto store = glove::supervisor::library_bundle_store::open(root); REQUIRE(store.has_value()); auto resolved = store->resolve(digest); REQUIRE(resolved.has_value()); REQUIRE(resolved->content_digest() == digest); REQUIRE(resolved->size_bytes() == canonical.size()); REQUIRE(read_descriptor(resolved->descriptor_fd(), canonical.size()) == canonical); REQUIRE(resolved->verify_identity().has_value()); std::vector targets; targets.push_back({ .projection = { .projection_id = "sage-core", .content_digest = digest, .destination_alias = "libraries", }, .target_path = "/opt/sage/library-bundles", }); auto projections = store->resolve_projections(targets); REQUIRE(projections.has_value()); REQUIRE(projections->size() == 1U); REQUIRE(projections->front().projection_id == "sage-core"); REQUIRE(projections->front().destination_alias == "libraries"); REQUIRE(projections->front().target_path == "/opt/sage/library-bundles/" + digest + ".json"); REQUIRE(projections->front().bundle.content_digest() == digest); REQUIRE(projections->front().bundle.verify_identity().has_value()); constexpr std::string_view codex_canonical = 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 codex_digest = digest_for(codex_canonical); write_bundle(root, codex_canonical); std::vector codex_targets; codex_targets.push_back({ .projection = { .projection_id = "sage-codex", .content_digest = codex_digest, .destination_alias = "libraries", }, .target_path = "/opt/sage/library-bundles", }); auto codex_projections = store->resolve_projections(codex_targets); REQUIRE(codex_projections.has_value()); auto codex = glove::supervisor::resolve_codex_runtime_projection(*codex_projections); REQUIRE(codex.has_value()); REQUIRE(codex->skills.size() == 1U); REQUIRE(codex->skills.front().projection_id == "sage-codex"); REQUIRE(codex->skills.front().key == "sage-core"); REQUIRE(codex->skills.front().content == "# Sage core\n"); auto codex_projection_digest = glove::supervisor::codex_runtime_projection_digest(*codex); REQUIRE(codex_projection_digest.has_value()); REQUIRE(codex_projection_digest->size() == 64U); auto reordered_codex = *codex; std::ranges::reverse(reordered_codex.skills); REQUIRE( glove::supervisor::codex_runtime_projection_digest(reordered_codex) == codex_projection_digest ); reordered_codex.skills.front().content = "# changed\n"; REQUIRE(!glove::supervisor::codex_runtime_projection_digest(reordered_codex).has_value()); // A skill directory is a single filesystem component. Reject an otherwise // syntactically valid projection before materialization rather than letting // a host filesystem limit decide the launch result. auto oversized_directory = *codex; oversized_directory.skills.front().projection_id = std::string(128U, 'p'); oversized_directory.skills.front().key = std::string(128U, 'k'); REQUIRE(!glove::supervisor::codex_runtime_projection_digest(oversized_directory).has_value()); const auto oversized_home = temporary.root() / "oversized-codex-home"; REQUIRE(std::filesystem::create_directory(oversized_home)); const int oversized_home_fd = ::open(oversized_home.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); REQUIRE(oversized_home_fd >= 0); REQUIRE(!glove::supervisor::materialize_codex_runtime_projection( oversized_home_fd, oversized_directory ) .has_value()); ::close(oversized_home_fd); REQUIRE(std::filesystem::is_empty(oversized_home)); constexpr std::string_view unsupported_codex_canonical = R"({"schema_version":1,"source_library_ref":"bafy-codex","source_manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","entries":[{"key":"selected-prompt","kind":"prompt","content_digest":"3514cf816e5407a39cb7a1c1e1243f176dda121e06398a8934edb1dc426b0b34","content":"ignored"}]})"; const auto unsupported_codex_digest = digest_for(unsupported_codex_canonical); write_bundle(root, unsupported_codex_canonical); std::vector unsupported_codex_targets; unsupported_codex_targets.push_back({ .projection = { .projection_id = "sage-prompt", .content_digest = unsupported_codex_digest, .destination_alias = "libraries", }, .target_path = "/opt/sage/library-bundles", }); auto unsupported_codex_projections = store->resolve_projections(unsupported_codex_targets); REQUIRE(unsupported_codex_projections.has_value()); REQUIRE(!glove::supervisor::resolve_codex_runtime_projection(*unsupported_codex_projections)); // Every built-in harness consumes the same verified Agent Skills bundle, // but receives it in an adapter-owned private-home layout. This proves the // generic adapter is not a Codex-only projection with renamed metadata. const auto native_homes = temporary.root() / "native-homes"; REQUIRE(std::filesystem::create_directory(native_homes)); REQUIRE(::chmod(native_homes.c_str(), 0700) == 0); for (const std::string_view runtime_id : { "codex", "claude-code", "pi", "copilot", "opencode", }) { const auto adapter = glove::supervisor::native_skill_runtime_adapter_for(runtime_id); REQUIRE(adapter.has_value()); if (runtime_id == "codex") { REQUIRE( adapter->managed_arguments == std::vector{"--dangerously-bypass-approvals-and-sandbox"} ); REQUIRE(adapter->managed_configuration.has_value()); REQUIRE(adapter->managed_configuration->filename == "config.toml"); } else { REQUIRE(adapter->managed_arguments.empty()); if (runtime_id != "pi") { REQUIRE(!adapter->managed_configuration); REQUIRE(!adapter->adoption_manifest); } else { REQUIRE(adapter->adoption_manifest.has_value()); REQUIRE(adapter->adoption_manifest->require_snapshot); const std::vector expected_source_artifacts{ "runtime-executable", "runtime-dependency-closure" }; REQUIRE( adapter->adoption_manifest->source_artifact_ids == expected_source_artifacts ); REQUIRE( std::ranges::find( adapter->adoption_manifest->excluded_host_state_ids, "host-auth" ) != adapter->adoption_manifest->excluded_host_state_ids.end() ); auto manifest_digest = glove::supervisor::native_harness_adoption_manifest_digest(*adapter); REQUIRE(manifest_digest.has_value()); REQUIRE(manifest_digest->size() == 64U); } } auto native = glove::supervisor::resolve_native_skill_runtime_projection( *adapter, *codex_projections ); REQUIRE(native.has_value()); auto native_digest = glove::supervisor::native_skill_runtime_projection_digest(*adapter, *native); REQUIRE(native_digest.has_value()); REQUIRE(native_digest->size() == 64U); const auto home = native_homes / std::string{runtime_id}; REQUIRE(std::filesystem::create_directory(home)); const int home_fd = ::open(home.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); REQUIRE(home_fd >= 0); const auto materialized = glove::supervisor::materialize_native_skill_runtime_projection( home_fd, *adapter, *native ); ::close(home_fd); REQUIRE(materialized.has_value()); auto skill_path = home; for (const auto& component : adapter->skill_root_components) { skill_path /= component; } skill_path /= "sage-codex-sage-core"; skill_path /= "SKILL.md"; REQUIRE(std::filesystem::is_regular_file(skill_path)); std::ifstream materialized_skill{skill_path, std::ios::binary}; REQUIRE(static_cast(materialized_skill)); std::string materialized_contents{ std::istreambuf_iterator{materialized_skill}, std::istreambuf_iterator{} }; REQUIRE(materialized_contents == "# Sage core\n"); if (runtime_id == "codex") { std::ifstream managed_config{home / ".codex/config.toml", std::ios::binary}; REQUIRE(static_cast(managed_config)); const std::string config_contents{ std::istreambuf_iterator{managed_config}, std::istreambuf_iterator{}, }; REQUIRE(config_contents.find("[projects.\"/home/agent\"]") != std::string::npos); REQUIRE(config_contents.find("trust_level = \"trusted\"") != std::string::npos); } if (runtime_id == "pi") { std::ifstream managed_config{home / ".pi/agent/settings.json", std::ios::binary}; REQUIRE(static_cast(managed_config)); const std::string config_contents{ std::istreambuf_iterator{managed_config}, std::istreambuf_iterator{}, }; REQUIRE(config_contents == "{\"packages\":[],\"enableSkillCommands\":true}\n"); } } REQUIRE(!glove::supervisor::native_skill_runtime_adapter_for("untrusted-runtime")); auto duplicate_targets = targets; duplicate_targets.push_back({ .projection = { .projection_id = "sage-duplicate", .content_digest = digest, .destination_alias = "libraries", }, .target_path = "/opt/sage/library-bundles", }); REQUIRE(!store->resolve_projections(duplicate_targets).has_value()); auto unavailable_targets = targets; unavailable_targets.front().projection.content_digest = std::string(64U, 'f'); REQUIRE(!store->resolve_projections(unavailable_targets).has_value()); REQUIRE(!store->resolve(std::string(64U, 'A')).has_value()); REQUIRE(!store->resolve(std::string(63U, 'a')).has_value()); REQUIRE(!glove::supervisor::library_bundle_store::open("relative/bundles").has_value()); const auto unsafe_root = temporary.root() / "unsafe"; REQUIRE(std::filesystem::create_directory(unsafe_root)); REQUIRE(::chmod(unsafe_root.c_str(), 0755) == 0); REQUIRE(!glove::supervisor::library_bundle_store::open(unsafe_root).has_value()); const auto symlink_root = temporary.root() / "bundle-link"; REQUIRE(::symlink(root.c_str(), symlink_root.c_str()) == 0); REQUIRE(!glove::supervisor::library_bundle_store::open(symlink_root).has_value()); constexpr std::string_view loose = R"({"schema_version":1,"entries":["loose"]})"; const auto loose_path = write_bundle(root, loose, 0644); REQUIRE(!store->resolve(digest_for(loose)).has_value()); constexpr std::string_view linked = R"({"schema_version":1,"entries":["linked"]})"; const auto linked_path = write_bundle(root, linked); const auto second_link = temporary.root() / "second-link.json"; REQUIRE(::link(linked_path.c_str(), second_link.c_str()) == 0); REQUIRE(!store->resolve(digest_for(linked)).has_value()); constexpr std::string_view redirected = R"({"schema_version":1,"entries":["redirected"]})"; const auto redirected_digest = digest_for(redirected); const auto outside = write_bundle(temporary.root(), redirected); const auto redirected_path = root / (redirected_digest + ".json"); REQUIRE(::symlink(outside.c_str(), redirected_path.c_str()) == 0); REQUIRE(!store->resolve(redirected_digest).has_value()); constexpr std::string_view expected = R"({"schema_version":1,"entries":["expected"]})"; constexpr std::string_view corrupted = R"({"schema_version":1,"entries":["corrupt!"]})"; REQUIRE(expected.size() == corrupted.size()); const auto expected_digest = digest_for(expected); const auto corrupted_path = root / (expected_digest + ".json"); { std::ofstream output{corrupted_path, std::ios::binary | std::ios::trunc}; output.write(corrupted.data(), static_cast(corrupted.size())); } REQUIRE(::chmod(corrupted_path.c_str(), 0600) == 0); REQUIRE(!store->resolve(expected_digest).has_value()); constexpr std::string_view mutable_bundle = R"({"schema_version":1,"entries":["mutable-a"]})"; constexpr std::string_view changed_bundle = R"({"schema_version":1,"entries":["mutable-b"]})"; REQUIRE(mutable_bundle.size() == changed_bundle.size()); const auto mutable_path = write_bundle(root, mutable_bundle); auto mutable_resolved = store->resolve(digest_for(mutable_bundle)); REQUIRE(mutable_resolved.has_value()); { std::ofstream output{mutable_path, std::ios::binary | std::ios::trunc}; output.write(changed_bundle.data(), static_cast(changed_bundle.size())); } REQUIRE(::chmod(mutable_path.c_str(), 0600) == 0); REQUIRE(!mutable_resolved->verify_identity().has_value()); REQUIRE(::chmod(bundle_path.c_str(), 0400) == 0); REQUIRE(!resolved->verify_identity().has_value()); REQUIRE(::chmod(root.c_str(), 0755) == 0); REQUIRE(!store->resolve(digest).has_value()); REQUIRE(::chmod(root.c_str(), 0700) == 0); const auto original_root = temporary.root() / "original-bundles"; std::filesystem::rename(root, original_root); REQUIRE(std::filesystem::is_directory(original_root)); REQUIRE(std::filesystem::create_directory(root)); REQUIRE(::chmod(root.c_str(), 0700) == 0); REQUIRE(!store->resolve(digest).has_value()); static_cast(loose_path); return 0; } } // namespace auto main() -> int { return run(); }