252 lines
9.6 KiB
C++
252 lines
9.6 KiB
C++
// Live macOS lane: resolve each locally installed, SBPL-vetted native harness
|
|
// through Glove's policy-owned discovery path, then launch `--version`.
|
|
// This deliberately exercises no credentials, network, or resource claims.
|
|
|
|
#include "glove/container/profile.hpp"
|
|
#include "glove/container/spawner.hpp"
|
|
#include "glove/supervisor/path_alias.hpp"
|
|
#include "glove/supervisor/session_plan.hpp"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <array>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#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)
|
|
|
|
class temporary_directory {
|
|
public:
|
|
temporary_directory() {
|
|
std::string pattern = "/tmp/glove-macos-native-harness-test-XXXXXX";
|
|
if (char* created = ::mkdtemp(pattern.data()); created != nullptr) {
|
|
root_ = created;
|
|
}
|
|
}
|
|
|
|
~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_;
|
|
};
|
|
|
|
struct native_runtime {
|
|
std::string_view id;
|
|
std::string_view executable;
|
|
};
|
|
|
|
// The Linux native-harness image verifies the full adapter set. macOS keeps
|
|
// this lane limited to distributions whose complete runtime closure is already
|
|
// represented by a narrow SBPL policy; it must not turn a broad Homebrew or
|
|
// user-home grant into a compatibility shortcut.
|
|
constexpr std::array<native_runtime, 2> native_runtimes{{
|
|
{"codex", "codex"},
|
|
{"copilot", "copilot"},
|
|
}};
|
|
|
|
auto executable_on_service_path(std::string_view executable)
|
|
-> std::optional<std::filesystem::path> {
|
|
const char* path = std::getenv("PATH");
|
|
if (path == nullptr) {
|
|
return std::nullopt;
|
|
}
|
|
std::string_view remaining{path};
|
|
while (true) {
|
|
const auto colon = remaining.find(':');
|
|
const auto entry = remaining.substr(0, colon);
|
|
if (!entry.empty()) {
|
|
const auto candidate = std::filesystem::path{entry} / executable;
|
|
if (::access(candidate.c_str(), X_OK) == 0) {
|
|
return candidate;
|
|
}
|
|
}
|
|
if (colon == std::string_view::npos) {
|
|
return std::nullopt;
|
|
}
|
|
remaining.remove_prefix(colon + 1);
|
|
}
|
|
}
|
|
|
|
auto run_runtime(
|
|
const native_runtime& runtime,
|
|
const std::filesystem::path& executable,
|
|
const std::filesystem::path& workspace,
|
|
const std::filesystem::path& temp_root
|
|
) -> int {
|
|
using namespace glove::supervisor;
|
|
|
|
std::error_code error;
|
|
// Model production discovery with a dedicated, service-owned runtime
|
|
// directory, never an inherited PATH directory.
|
|
const auto runtime_bin = temp_root / ("operator-runtime-bin-" + std::string{runtime.id});
|
|
REQUIRE(std::filesystem::create_directory(runtime_bin, error));
|
|
REQUIRE(!error);
|
|
std::filesystem::create_symlink(executable, runtime_bin / runtime.executable, error);
|
|
REQUIRE(!error);
|
|
|
|
const runtime_launch_template launch{
|
|
.runtime_discovery = std::string{runtime.id},
|
|
.executable_path = "",
|
|
.executable_search_paths = {runtime_bin.string()},
|
|
.arguments = {"--version"},
|
|
.environment = {"PATH=" + runtime_bin.string() + ":/usr/bin:/bin", "TERM=xterm-256color"},
|
|
.read_only_paths = {},
|
|
};
|
|
const auto digest = runtime_launch_template_digest(launch);
|
|
REQUIRE(digest.has_value());
|
|
auto paths = path_alias_registry::build({path_alias_policy{
|
|
.alias = "workspace",
|
|
.host_path = std::filesystem::canonical(workspace).string(),
|
|
.target_path = "/workspace",
|
|
.max_ttl_secs = 60,
|
|
.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 = 1'048'576,
|
|
}},
|
|
}});
|
|
REQUIRE(paths.has_value());
|
|
auto validator = session_plan_validator::build(
|
|
session_plan_policy{
|
|
.revision = 1,
|
|
.max_plan_ttl_ms = 60'000,
|
|
.runtime_templates = {runtime_template_policy{
|
|
.runtime_template_id = std::string{runtime.id} + "-local",
|
|
.runtime_id = std::string{runtime.id},
|
|
.adapter_command_digest = *digest,
|
|
.backend = sandbox_backend::apple_container,
|
|
.allowed_path_aliases = {"workspace"},
|
|
.allowed_projection_destinations = {"libraries"},
|
|
.launch = 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 = 1'048'576,
|
|
.terminal_output_bytes = 1'048'576,
|
|
}},
|
|
.egress_policy_ids = {"no-network"},
|
|
.tool_policy_ids = {"sage-readonly"},
|
|
.secret_handles = {},
|
|
.egress_policies = {},
|
|
.secret_mounts = {},
|
|
},
|
|
std::move(*paths)
|
|
);
|
|
REQUIRE(validator.has_value());
|
|
const std::string plan =
|
|
R"({"schema_version":1,"runtime_id":")" + std::string{runtime.id} +
|
|
R"(","runtime_template_id":")" + std::string{runtime.id} +
|
|
R"(-local","adapter_command_digest":")" + *digest +
|
|
R"(","sandbox_backend":"apple_container","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":[],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":1048576,"terminal_output_bytes":1048576},"policy_revision":1,"expires_at_ms":61000})";
|
|
auto resolved = validator->resolve_runtime_launch_json(plan, 1'000);
|
|
REQUIRE(resolved.has_value());
|
|
REQUIRE(resolved->backend == sandbox_backend::apple_container);
|
|
REQUIRE(std::filesystem::path{resolved->argv.front()}.is_absolute());
|
|
// Harness distributions may resolve to a versioned Mach-O or an entrypoint
|
|
// script. Assert policy resolution, not packaging-specific basenames.
|
|
REQUIRE(resolved->argv.front() != runtime.executable);
|
|
REQUIRE(::access(resolved->argv.front().c_str(), X_OK) == 0);
|
|
|
|
glove::container::profile profile;
|
|
profile.filesystem.push_back({.path = workspace.string(), .writable = true});
|
|
profile.home_dir = workspace.string();
|
|
profile.work_dir = workspace.string();
|
|
profile.environment = resolved->environment;
|
|
auto spawner = glove::container::make_default_spawner();
|
|
REQUIRE(spawner != nullptr);
|
|
REQUIRE(!spawner->resource_capabilities().complete());
|
|
auto handle = spawner->spawn(profile, resolved->argv);
|
|
REQUIRE(handle.has_value());
|
|
auto line = (*handle)->transport().recv();
|
|
const auto exit_code = (*handle)->wait();
|
|
if (!line) {
|
|
std::fprintf(
|
|
stderr,
|
|
"native harness %.*s produced no stdout (exit=%d)\n",
|
|
static_cast<int>(runtime.id.size()),
|
|
runtime.id.data(),
|
|
exit_code ? *exit_code : -1
|
|
);
|
|
return 1;
|
|
}
|
|
REQUIRE(exit_code.has_value());
|
|
REQUIRE(*exit_code == 0);
|
|
REQUIRE(!line->empty());
|
|
std::fprintf(
|
|
stderr,
|
|
"Glove SBPL native harness discovery probe (%.*s): %s\n",
|
|
static_cast<int>(runtime.id.size()),
|
|
runtime.id.data(),
|
|
line->c_str()
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
auto run() -> int {
|
|
temporary_directory temp;
|
|
REQUIRE(!temp.root().empty());
|
|
const auto workspace = temp.root() / "workspace";
|
|
std::error_code error;
|
|
REQUIRE(std::filesystem::create_directories(workspace, error));
|
|
REQUIRE(!error);
|
|
|
|
std::size_t installed = 0;
|
|
std::size_t failed = 0;
|
|
for (const auto& runtime : native_runtimes) {
|
|
const auto executable = executable_on_service_path(runtime.executable);
|
|
if (!executable) {
|
|
std::fprintf(
|
|
stderr,
|
|
"SKIP: %.*s is not installed on this service PATH\n",
|
|
static_cast<int>(runtime.id.size()),
|
|
runtime.id.data()
|
|
);
|
|
continue;
|
|
}
|
|
++installed;
|
|
if (run_runtime(runtime, *executable, workspace, temp.root()) != 0) {
|
|
++failed;
|
|
}
|
|
}
|
|
if (installed == 0) {
|
|
std::fprintf(
|
|
stderr, "SKIP: no supported native harness is installed on this service PATH\n"
|
|
);
|
|
return 77;
|
|
}
|
|
return failed == 0 ? 0 : 1;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
auto main() -> int {
|
|
return run();
|
|
}
|