#include "glove/container/profile.hpp" #include "glove/container/spawner.hpp" #include "glove/supervisor/linux_session_filesystem.hpp" #include "linux_managed_session.hpp" #include "linux_resource_lifecycle.hpp" #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) using glove::container::profile; using glove::container::resource_limits; using glove::container::linux_detail::managed_launch_binding; using glove::supervisor::linux_detail::session_mount; constexpr std::string_view controller_digest = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; auto limits() -> resource_limits { return { .cpu_time_ms = 10'000, .memory_bytes = std::uint64_t{128} * 1024U * 1024U, .pids = 16, .wall_time_ms = 20'000, .disk_bytes = std::uint64_t{16} * 1024U * 1024U, .terminal_output_bytes = std::uint64_t{1024} * 1024U, }; } auto launch_profile() -> profile { profile result; result.environment = {"TERM=xterm-256color", "PATH=/usr/bin:/bin"}; result.required_limits = limits(); return result; } auto mounts() -> std::vector { const auto scratch_quota = limits().disk_bytes * 3U / 4U; const auto project_quota = limits().disk_bytes - scratch_quota; return { { .descriptor_fd = 12, .target_path = "/var/tmp", .alias = "__scratch_var_tmp", .quota_partition = "__scratch", .quota_bytes = scratch_quota, .source_identity = std::nullopt, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = true, }, { .descriptor_fd = 11, .target_path = "/tmp", .alias = "__scratch_tmp", .quota_partition = "__scratch", .quota_bytes = scratch_quota, .source_identity = std::nullopt, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = true, }, { .descriptor_fd = 13, .target_path = "/workspace/project", .alias = "project", .quota_partition = "project", .quota_bytes = project_quota, .source_identity = glove::supervisor::path_identity{ .device = 7, .inode = 11, .mode = static_cast(S_IFDIR | 0700), }, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = true, }, { .descriptor_fd = 14, .target_path = "/workspace/reference", .alias = "reference", .quota_partition = "", .quota_bytes = 0, .source_identity = glove::supervisor::path_identity{ .device = 7, .inode = 12, .mode = static_cast(S_IFDIR | 0755), }, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = false, .directory = true, }, }; } auto make_binding( const profile& prof, const std::vector& argv, const std::vector& projection, std::string_view plan_digest = controller_digest, std::span streams = {} ) -> std::expected { return glove::container::linux_detail::bind_managed_launch_projection( prof, argv, projection, plan_digest, streams ); } auto run() -> int { auto first_profile = launch_profile(); const std::vector argv = {std::string{"/usr/bin/true"}, std::string{"--version"}}; auto first_mounts = mounts(); auto first = make_binding(first_profile, argv, first_mounts); REQUIRE(first.has_value()); REQUIRE(first->controller_plan_digest == controller_digest); REQUIRE(first->profile_digest.size() == 64); REQUIRE(first->library_projections.empty()); REQUIRE(!first->service_proxy_manifest_digest); auto service_profile = first_profile; service_profile.environment.push_back("GLOVE_LOCAL_SERVICE_DIR=/run/glove-services/local"); auto service_mounts = first_mounts; service_mounts.push_back({ .descriptor_fd = 15, .target_path = "/run/glove-services/local", .alias = "local-services", .quota_partition = "", .quota_bytes = 0, .source_identity = glove::supervisor::path_identity{ .device = 7, .inode = 13, .mode = static_cast(S_IFDIR | 0700), }, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::string(64U, 'b'), .writable = false, .directory = true, }); auto service_binding = make_binding(service_profile, argv, service_mounts); REQUIRE(service_binding.has_value()); REQUIRE(service_binding->service_proxy_manifest_digest == std::string(64U, 'b')); REQUIRE(service_binding->profile_digest != first->profile_digest); REQUIRE(!make_binding(first_profile, argv, service_mounts).has_value()); REQUIRE(!make_binding(service_profile, argv, first_mounts).has_value()); int stream_pair[2] = {-1, -1}; REQUIRE(::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, stream_pair) == 0); REQUIRE(::fchmod(stream_pair[0], 0600) == 0); REQUIRE(::fchmod(stream_pair[1], 0600) == 0); struct stat stream_status{}; struct stat peer_status{}; REQUIRE(::fstat(stream_pair[0], &stream_status) == 0); REQUIRE(::fstat(stream_pair[1], &peer_status) == 0); const glove::container::linux_detail::inherited_stream_descriptor stream{ .alias = "status", .descriptor_fd = stream_pair[0], .child_fd = 3, .device = static_cast(stream_status.st_dev), .inode = static_cast(stream_status.st_ino), .uid = static_cast(stream_status.st_uid), .mode = static_cast(stream_status.st_mode), .links = static_cast(stream_status.st_nlink), .peer_device = static_cast(peer_status.st_dev), .peer_inode = static_cast(peer_status.st_ino), .peer_uid = static_cast(peer_status.st_uid), .peer_mode = static_cast(peer_status.st_mode), .peer_links = static_cast(peer_status.st_nlink), .manifest_digest = std::string(64U, 'e'), }; auto inherited_profile = first_profile; inherited_profile.environment.push_back(R"(GLOVE_LOCAL_SERVICE_FDS_V1={"status":3})"); const std::vector inherited_streams = {stream}; auto inherited_binding = make_binding(inherited_profile, argv, first_mounts, controller_digest, inherited_streams); REQUIRE(inherited_binding.has_value()); REQUIRE(inherited_binding->service_proxy_manifest_digest == std::string(64U, 'e')); REQUIRE(inherited_binding->profile_digest != first->profile_digest); REQUIRE( !make_binding(inherited_profile, argv, service_mounts, controller_digest, inherited_streams) .has_value() ); auto drifted_streams = inherited_streams; ++drifted_streams[0].inode; REQUIRE(!make_binding(inherited_profile, argv, first_mounts, controller_digest, drifted_streams) .has_value()); auto reserved_streams = inherited_streams; reserved_streams[0].child_fd = 2; REQUIRE( !make_binding(inherited_profile, argv, first_mounts, controller_digest, reserved_streams) .has_value() ); auto duplicate_source_streams = inherited_streams; auto duplicate_source = stream; duplicate_source.alias = "z-status"; duplicate_source.child_fd = 4; duplicate_source_streams.push_back(duplicate_source); auto duplicate_source_profile = first_profile; duplicate_source_profile.environment.push_back( R"(GLOVE_LOCAL_SERVICE_FDS_V1={"status":3,"z-status":4})" ); REQUIRE(!make_binding( duplicate_source_profile, argv, first_mounts, controller_digest, duplicate_source_streams ) .has_value()); auto duplicate_alias_streams = duplicate_source_streams; duplicate_alias_streams[1].alias = "status"; REQUIRE(!make_binding( duplicate_source_profile, argv, first_mounts, controller_digest, duplicate_alias_streams ) .has_value()); auto missing_environment = first_profile; REQUIRE( !make_binding(missing_environment, argv, first_mounts, controller_digest, inherited_streams) .has_value() ); ::close(stream_pair[0]); ::close(stream_pair[1]); auto changed_service = service_mounts; changed_service.back().service_proxy_manifest_digest = std::string(64U, 'c'); auto changed_service_binding = make_binding(service_profile, argv, changed_service); REQUIRE(changed_service_binding.has_value()); REQUIRE(changed_service_binding->profile_digest != service_binding->profile_digest); auto invalid_service = service_mounts; invalid_service.back().alias = "__local_services"; REQUIRE(!make_binding(service_profile, argv, invalid_service).has_value()); invalid_service = service_mounts; invalid_service.back().target_path = "/tmp/local-services"; REQUIRE(!make_binding(service_profile, argv, invalid_service).has_value()); invalid_service = service_mounts; invalid_service.back().service_proxy_manifest_digest = "not-a-digest"; REQUIRE(!make_binding(service_profile, argv, invalid_service).has_value()); invalid_service = service_mounts; invalid_service.push_back(service_mounts.back()); REQUIRE(!make_binding(service_profile, argv, invalid_service).has_value()); std::ranges::reverse(first_profile.environment); std::ranges::reverse(first_mounts); auto reordered = make_binding(first_profile, argv, first_mounts); REQUIRE(reordered == first); auto changed_argv = argv; changed_argv.push_back("different"); auto argv_binding = make_binding(first_profile, changed_argv, first_mounts); REQUIRE(argv_binding.has_value()); REQUIRE(argv_binding->profile_digest != first->profile_digest); auto workspace_profile = first_profile; workspace_profile.work_dir = "/workspace"; auto workspace_binding = make_binding(workspace_profile, argv, first_mounts); REQUIRE(workspace_binding.has_value()); REQUIRE(workspace_binding->profile_digest != first->profile_digest); auto invalid_work_dir = first_profile; invalid_work_dir.work_dir = "/tmp"; REQUIRE(!make_binding(invalid_work_dir, argv, first_mounts).has_value()); auto unbacked_work_dir_mounts = first_mounts; for (auto& mount : unbacked_work_dir_mounts) { if (mount.target_path == "/workspace/project") { mount.target_path = "/project"; } else if (mount.target_path == "/workspace/reference") { mount.target_path = "/reference"; } } REQUIRE(!make_binding(workspace_profile, argv, unbacked_work_dir_mounts).has_value()); auto changed_mounts = first_mounts; changed_mounts[0].target_path = "/workspace/tmp"; auto mount_binding = make_binding(first_profile, argv, changed_mounts); REQUIRE(mount_binding.has_value()); REQUIRE(mount_binding->profile_digest != first->profile_digest); auto writable_reference = first_mounts; const auto writable_reference_entry = std::ranges::find(writable_reference, std::string{"reference"}, &session_mount::alias); REQUIRE(writable_reference_entry != writable_reference.end()); writable_reference_entry->writable = true; REQUIRE(!make_binding(first_profile, argv, writable_reference).has_value()); auto quota_bearing_reference = first_mounts; const auto quota_bearing_reference_entry = std::ranges::find(quota_bearing_reference, std::string{"reference"}, &session_mount::alias); REQUIRE(quota_bearing_reference_entry != quota_bearing_reference.end()); quota_bearing_reference_entry->quota_partition = "reference"; quota_bearing_reference_entry->quota_bytes = 4096U; REQUIRE(!make_binding(first_profile, argv, quota_bearing_reference).has_value()); auto changed_quota = first_mounts; for (auto& mount : changed_quota) { if (mount.quota_partition == "__scratch") { mount.quota_bytes -= 4096U; } else if (mount.writable) { mount.quota_bytes += 4096U; } } auto quota_binding = make_binding(first_profile, argv, changed_quota); REQUIRE(quota_binding.has_value()); REQUIRE(quota_binding->profile_digest != first->profile_digest); auto library_mounts = first_mounts; const std::string library_digest(64U, 'd'); library_mounts.push_back({ .descriptor_fd = 15, .target_path = "/opt/sage/library-bundles/" + library_digest + ".json", .alias = "library:sage-core", .quota_partition = "", .quota_bytes = 0, .source_identity = glove::supervisor::path_identity{ .device = 7, .inode = 13, .mode = static_cast(S_IFREG | 0600), }, .source_content_digest = library_digest, .projection_id = "sage-core", .projection_destination_alias = "libraries", .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = false, .directory = false, }); auto library_binding = make_binding(first_profile, argv, library_mounts); REQUIRE(library_binding.has_value()); REQUIRE(library_binding->profile_digest != first->profile_digest); REQUIRE(library_binding->library_projections.size() == 1U); REQUIRE(library_binding->library_projections.front().projection_id == "sage-core"); REQUIRE(library_binding->library_projections.front().destination_alias == "libraries"); REQUIRE(library_binding->library_projections.front().content_digest == library_digest); REQUIRE( library_binding->library_projections.front().target_path == "/opt/sage/library-bundles/" + library_digest + ".json" ); library_mounts.back().source_content_digest = std::string(64U, 'e'); REQUIRE(!make_binding(first_profile, argv, library_mounts).has_value()); auto inconsistent_quota = first_mounts; ++inconsistent_quota[0].quota_bytes; REQUIRE(!make_binding(first_profile, argv, inconsistent_quota).has_value()); auto changed_plan = make_binding( first_profile, argv, first_mounts, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" ); REQUIRE(changed_plan.has_value()); REQUIRE(changed_plan->profile_digest != first->profile_digest); auto online_profile = first_profile; online_profile.proxy = glove::container::proxy_settings{ .port = 43117, .url = "http://glove:ephemeral-a@127.0.0.1:43117", }; auto online_binding = make_binding(online_profile, argv, first_mounts); REQUIRE(online_binding.has_value()); REQUIRE(online_binding->profile_digest != first->profile_digest); online_profile.proxy->url = "http://glove:ephemeral-b@127.0.0.1:43117"; auto changed_egress_capability = make_binding(online_profile, argv, first_mounts); REQUIRE(changed_egress_capability.has_value()); REQUIRE(changed_egress_capability->profile_digest != online_binding->profile_digest); auto credentialed_profile = first_profile; credentialed_profile.managed_home_dir = "/home/agent"; auto credentialed_mounts = first_mounts; credentialed_mounts.push_back({ .descriptor_fd = 16, .target_path = "/home/agent", .alias = "__runtime_home_codex", .quota_partition = "__scratch", .quota_bytes = limits().disk_bytes * 3U / 4U, .source_identity = std::nullopt, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = "codex", .runtime_context_digest = std::string(64U, 'c'), .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = true, }); credentialed_mounts.push_back({ .descriptor_fd = 17, .target_path = "/home/agent/.codex/auth.json", .alias = "secret:codex-auth", .quota_partition = "", .quota_bytes = 0, .source_identity = glove::supervisor::path_identity{ .device = 7, .inode = 14, .mode = static_cast(S_IFREG | 0600), }, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = std::nullopt, .runtime_context_digest = std::nullopt, .runtime_adoption_manifest_digest = std::nullopt, .runtime_adoption_snapshot_digest = std::nullopt, .secret_handle = "codex-auth", .secret_runtime_id = "codex", .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = false, }); auto credentialed_binding = make_binding(credentialed_profile, argv, credentialed_mounts); REQUIRE(credentialed_binding.has_value()); REQUIRE(credentialed_binding->profile_digest != first->profile_digest); credentialed_profile.work_dir = "/home/agent"; auto private_home_binding = make_binding(credentialed_profile, argv, credentialed_mounts); REQUIRE(private_home_binding.has_value()); REQUIRE(private_home_binding->profile_digest != credentialed_binding->profile_digest); auto adopted_profile = first_profile; adopted_profile.managed_home_dir = "/home/agent"; auto adopted_mounts = first_mounts; adopted_mounts.push_back({ .descriptor_fd = 18, .target_path = "/home/agent", .alias = "__runtime_home_pi", .quota_partition = "__scratch", .quota_bytes = limits().disk_bytes * 3U / 4U, .source_identity = std::nullopt, .source_content_digest = std::nullopt, .projection_id = std::nullopt, .projection_destination_alias = std::nullopt, .runtime_adapter_id = "pi", .runtime_context_digest = std::string(64U, 'c'), .runtime_adoption_manifest_digest = std::string(64U, 'a'), .runtime_adoption_snapshot_digest = std::string(64U, 'b'), .secret_handle = std::nullopt, .secret_runtime_id = std::nullopt, .service_proxy_manifest_digest = std::nullopt, .writable = true, .directory = true, }); auto adopted_binding = make_binding(adopted_profile, argv, adopted_mounts); REQUIRE(adopted_binding.has_value()); adopted_mounts.back().runtime_adoption_snapshot_digest = std::string(64U, 'd'); auto changed_adoption = make_binding(adopted_profile, argv, adopted_mounts); REQUIRE(changed_adoption.has_value()); REQUIRE(changed_adoption->profile_digest != adopted_binding->profile_digest); adopted_mounts.back().runtime_adoption_snapshot_digest = std::nullopt; REQUIRE(!make_binding(adopted_profile, argv, adopted_mounts).has_value()); credentialed_profile.work_dir = "/tmp"; REQUIRE(!make_binding(credentialed_profile, argv, credentialed_mounts).has_value()); auto mismatched_secret = credentialed_mounts; mismatched_secret.back().secret_runtime_id = "claude"; REQUIRE(!make_binding(credentialed_profile, argv, mismatched_secret).has_value()); auto secret_outside_home = credentialed_mounts; secret_outside_home.back().target_path = "/run/secrets/codex-auth"; REQUIRE(!make_binding(credentialed_profile, argv, secret_outside_home).has_value()); std::string executable_pattern = "/tmp/glove-launch-binding-exec-XXXXXX"; const int executable_fd = ::mkstemp(executable_pattern.data()); REQUIRE(executable_fd >= 0); REQUIRE(::fchmod(executable_fd, 0700) == 0); REQUIRE(::write(executable_fd, "first", 5) == 5); const std::vector executable_argv = {executable_pattern}; auto executable_before = make_binding(first_profile, executable_argv, first_mounts); REQUIRE(executable_before.has_value()); REQUIRE(::write(executable_fd, "-changed", 8) == 8); auto executable_after = make_binding(first_profile, executable_argv, first_mounts); REQUIRE(executable_after.has_value()); REQUIRE(executable_after->profile_digest != executable_before->profile_digest); auto pinned_before = glove::container::linux_detail::bind_managed_launch_projection_from_fd( first_profile, executable_argv, first_mounts, controller_digest, executable_fd ); REQUIRE(pinned_before.has_value()); const std::string original_path = executable_pattern + "-original"; REQUIRE(::rename(executable_pattern.c_str(), original_path.c_str()) == 0); auto pinned_after_rename = glove::container::linux_detail::bind_managed_launch_projection_from_fd( first_profile, executable_argv, first_mounts, controller_digest, executable_fd ); REQUIRE(pinned_after_rename.has_value()); const int replacement_fd = ::open(executable_pattern.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0700); REQUIRE(replacement_fd >= 0); REQUIRE(::write(replacement_fd, "replacement", 11) == 11); REQUIRE(::close(replacement_fd) == 0); auto pinned_after = glove::container::linux_detail::bind_managed_launch_projection_from_fd( first_profile, executable_argv, first_mounts, controller_digest, executable_fd ); REQUIRE(pinned_after.has_value()); // Rename updates ctime, which is deliberately committed by the binding. // Replacing the old path must not affect a descriptor pinned after rename. REQUIRE(pinned_after == pinned_after_rename); auto pinned_repeated = glove::container::linux_detail::bind_managed_launch_projection_from_fd( first_profile, executable_argv, first_mounts, controller_digest, executable_fd ); REQUIRE(pinned_repeated == pinned_after); auto replacement = make_binding(first_profile, executable_argv, first_mounts); REQUIRE(replacement.has_value()); REQUIRE(replacement->profile_digest != pinned_after->profile_digest); REQUIRE(::close(executable_fd) == 0); REQUIRE(::unlink(executable_pattern.c_str()) == 0); REQUIRE(::unlink(original_path.c_str()) == 0); REQUIRE(!make_binding(first_profile, argv, first_mounts, "not-a-digest").has_value()); REQUIRE(glove::container::linux_detail::managed_session_capabilities().complete()); auto public_spawner = glove::container::make_default_spawner(); REQUIRE(public_spawner != nullptr); REQUIRE(!public_spawner->resource_capabilities().complete()); return 0; } } // namespace auto main() -> int { return run(); }