glove/tests/supervisor/session_plan_test.cpp
0xkite 2bba117d2a
fix(supervisor): harden bundle projection admission
Preserve known non-skill metadata in projection commitments, reject duplicate and oversized bundles, close Codex exec grammar ambiguity, and keep raw-bundle requirements explicit. Keep layer-2 Sage materialization tests out of this layer.

Validated by the exact layer-1 build and 75-test suite; Apple lifecycle remains a separately skipped layer-2 concern.

Signed-off-by: 0xkite <me@hack4kitesdev.dev>
2026-08-29 09:02:55 -06:00

857 lines
41 KiB
C++

#include "glove/supervisor/path_alias.hpp"
#include "glove/supervisor/path_exposure.hpp"
#include "glove/supervisor/session_plan.hpp"
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <system_error>
#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)
class temporary_directory {
public:
temporary_directory() {
std::string pattern = "/tmp/glove-session-plan-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 replace_once(std::string input, std::string_view before, std::string_view after)
-> std::string {
const auto offset = input.find(before);
if (offset != std::string::npos) {
input.replace(offset, before.size(), after);
}
return input;
}
auto launch_template() -> glove::supervisor::runtime_launch_template {
return {
.runtime_discovery = "",
.executable_path = "/usr/bin/true",
.executable_search_paths = {},
.arguments = {"--version"},
.environment = {"PATH=/usr/bin:/bin", "TERM=xterm-256color"},
.read_only_paths = {},
};
}
auto launch_digest() -> std::string {
auto digest = glove::supervisor::runtime_launch_template_digest(launch_template());
return digest.value_or("launch-template-digest-failed");
}
auto valid_plan() -> std::string {
return R"({"schema_version":1,"runtime_id":"codex","runtime_template_id":"codex-safe","adapter_command_digest":")" +
launch_digest() +
R"(","sandbox_backend":"linux_production","egress_policy_id":"no-network","tool_policy_id":"sage-readonly","path_grants":[{"alias":"workspace","access":"ephemeral_write","materialization":"copy","max_bytes":1048576,"ttl_secs":60,"cleanup_policy":"remove"}],"library_projections":[{"projection_id":"sage-core","content_digest":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","destination_alias":"libraries"}],"secret_handles":["codex-token"],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576},"policy_revision":7,"expires_at_ms":61000})";
}
auto policy_json(const std::filesystem::path& source) -> std::string {
return R"({"schema_version":1,"revision":7,"max_plan_ttl_ms":120000,"runtime_templates":[{"runtime_template_id":"codex-safe","runtime_id":"codex","adapter_command_digest":")" +
launch_digest() +
R"(","sandbox_backend":"linux_production","allowed_path_aliases":["workspace"],"allowed_projection_destinations":["libraries"],"launch":{"executable_path":"/usr/bin/true","arguments":["--version"],"environment":["PATH=/usr/bin:/bin","TERM=xterm-256color"]}}],"path_aliases":[{"alias":"workspace","host_path":")" +
std::filesystem::canonical(source).string() +
R"(","target_path":"/workspace","max_ttl_secs":120,"access":[{"access":"ephemeral_write","materialization":"copy","create_policy":"empty_directory","cleanup_policy":"remove","max_bytes":2097152}]}],"library_projection_destinations":[{"alias":"libraries","target_path":"/opt/sage/library-bundles"}],"resource_profiles":[{"profile_id":"small","cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576}],"egress_policy_ids":["no-network"],"tool_policy_ids":["sage-readonly"],"secret_handles":["codex-token"],"egress_policies":[{"policy_id":"no-network","targets":[]}],"secret_mounts":[{"handle":"codex-token","runtime_id":"codex","source_path":"/tmp/codex-auth.json","target_path":"/home/agent/.codex/auth.json"}]})";
}
auto validator_for(
const std::filesystem::path& source,
bool with_launch = true,
std::shared_ptr<const glove::supervisor::path_exposure_registry> exposures = {},
std::optional<glove::supervisor::runtime_launch_template> launch_override = std::nullopt
) -> glove::supervisor::result<glove::supervisor::session_plan_validator> {
using namespace glove::supervisor;
const auto selected_launch = launch_override.value_or(launch_template());
auto selected_launch_digest = runtime_launch_template_digest(selected_launch);
if (!selected_launch_digest) {
return std::unexpected(selected_launch_digest.error());
}
path_alias_policy path{
.alias = "workspace",
.host_path = std::filesystem::canonical(source).string(),
.target_path = "/workspace",
.max_ttl_secs = 120,
.access = {
path_access_policy{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.create_policy = path_create_policy::empty_directory,
.cleanup_policy = path_cleanup_policy::remove,
.max_bytes = 2'097'152,
},
},
};
auto paths = path_alias_registry::build({std::move(path)});
if (!paths) {
return std::unexpected(paths.error());
}
return session_plan_validator::build(
session_plan_policy{
.revision = 7,
.max_plan_ttl_ms = 120'000,
.runtime_templates =
{
runtime_template_policy{
.runtime_template_id = "codex-safe",
.runtime_id = "codex",
.adapter_command_digest = *selected_launch_digest,
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = with_launch
? std::optional<runtime_launch_template>{selected_launch}
: std::nullopt,
.adoption = std::nullopt,
},
},
.library_projection_destinations =
{
library_projection_destination_policy{
.alias = "libraries",
.target_path = "/opt/sage/library-bundles",
},
},
.resource_profiles =
{
resource_limits{
.cpu_time_ms = 1'000,
.memory_bytes = 67'108'864,
.pids = 16,
.wall_time_ms = 2'000,
.disk_bytes = 2'097'152,
.terminal_output_bytes = 1'048'576,
},
},
.egress_policy_ids = {"no-network"},
.tool_policy_ids = {"sage-readonly"},
.secret_handles = {"codex-token"},
.egress_policies = {egress_policy{.policy_id = "no-network", .targets = {}}},
.secret_mounts = {secret_mount_policy{
.handle = "codex-token",
.runtime_id = "codex",
.source_path = "/tmp/codex-auth.json",
.target_path = "/home/agent/.codex/auth.json",
}},
},
std::move(*paths),
std::move(exposures)
);
}
auto run() -> int {
using namespace glove::supervisor;
temporary_directory temp;
REQUIRE(!temp.root().empty());
const auto source = temp.root() / "source";
REQUIRE(std::filesystem::create_directory(source));
std::ofstream{source / "tracked.txt"} << "immutable source\n";
auto validator = validator_for(std::filesystem::canonical(source));
if (!validator) {
std::fprintf(stderr, "validator build failed: %s\n", validator.error().c_str());
}
REQUIRE(validator.has_value());
// Fixed-size storage exercises the public parser boundary without a
// trailing std::string sentinel. Malformed plans must fail closed.
constexpr std::string_view malformed_plan =
"{\"schema_version\":1,\"runtime_id\":\"codex\",\"runtime_template_id\":\"codex-safe\"";
std::array<char, malformed_plan.size()> unterminated{};
std::ranges::copy(malformed_plan, unterminated.begin());
REQUIRE(!validator
->validate_json(std::string_view{unterminated.data(), unterminated.size()}, 1'000)
.has_value());
REQUIRE(launch_digest().size() == 64U);
REQUIRE(launch_digest() == "0129a3a97cacbef9bd8a2df44ea3b1e01ae8dad706cbe0c27c2237881b5107e7");
auto changed_launch = launch_template();
changed_launch.arguments.push_back("changed");
auto changed_launch_digest = glove::supervisor::runtime_launch_template_digest(changed_launch);
REQUIRE(changed_launch_digest.has_value());
REQUIRE(*changed_launch_digest != launch_digest());
auto runtime_paths_launch = launch_template();
runtime_paths_launch.read_only_paths = {"/opt/glove/codex-runtime"};
auto runtime_paths_digest =
glove::supervisor::runtime_launch_template_digest(runtime_paths_launch);
REQUIRE(runtime_paths_digest.has_value());
REQUIRE(*runtime_paths_digest != launch_digest());
auto relative_launch = launch_template();
relative_launch.executable_path = "usr/bin/true";
REQUIRE(!glove::supervisor::runtime_launch_template_digest(relative_launch).has_value());
auto relative_runtime_path = launch_template();
relative_runtime_path.read_only_paths = {"opt/glove/codex-runtime"};
REQUIRE(!glove::supervisor::runtime_launch_template_digest(relative_runtime_path).has_value());
auto overlapping_runtime_path = launch_template();
overlapping_runtime_path.read_only_paths = {"/usr/bin"};
// Immutable interpreter/package closure may intentionally contain the
// separately identity-pinned executable.
REQUIRE(
glove::supervisor::runtime_launch_template_digest(overlapping_runtime_path).has_value()
);
auto unsorted_environment = launch_template();
std::ranges::reverse(unsorted_environment.environment);
REQUIRE(!glove::supervisor::runtime_launch_template_digest(unsorted_environment).has_value());
auto duplicate_environment = launch_template();
duplicate_environment.environment = {"PATH=first", "PATH=second"};
REQUIRE(!glove::supervisor::runtime_launch_template_digest(duplicate_environment).has_value());
const auto harness_bin = temp.root() / "operator-harnesses";
REQUIRE(std::filesystem::create_directory(harness_bin));
const auto codex = harness_bin / "codex";
std::ofstream{codex} << "#!/bin/sh\nexit 0\n";
REQUIRE(::chmod(codex.c_str(), 0700) == 0);
const runtime_launch_template inherited_path_discovery{
.runtime_discovery = "codex",
.executable_path = "",
.executable_search_paths = {},
.arguments = {"--version"},
.environment = {"PATH=/usr/bin:/bin", "TERM=xterm-256color"},
.read_only_paths = {},
};
// A service PATH must never become launch authority. Discovery is bounded
// by explicit, digest-bound directories only.
REQUIRE(!runtime_launch_template_digest(inherited_path_discovery).has_value());
auto discovered_codex = inherited_path_discovery;
discovered_codex.executable_search_paths = {harness_bin.string()};
const auto discovered_digest = runtime_launch_template_digest(discovered_codex);
REQUIRE(discovered_digest.has_value());
REQUIRE(*discovered_digest != launch_digest());
for (const std::string_view runtime_id : {"claude-code", "pi", "copilot", "opencode"}) {
auto native_discovery = discovered_codex;
native_discovery.runtime_discovery = std::string{runtime_id};
REQUIRE(runtime_launch_template_digest(native_discovery).has_value());
}
const auto alternate_harness_bin = temp.root() / "operator-harnesses-alternate";
REQUIRE(std::filesystem::create_directory(alternate_harness_bin));
auto alternate_search_path = discovered_codex;
alternate_search_path.executable_search_paths = {alternate_harness_bin.string()};
const auto alternate_search_digest = runtime_launch_template_digest(alternate_search_path);
REQUIRE(alternate_search_digest.has_value());
REQUIRE(*alternate_search_digest != *discovered_digest);
auto unknown_discovery = discovered_codex;
unknown_discovery.runtime_discovery = "shell";
REQUIRE(!runtime_launch_template_digest(unknown_discovery).has_value());
auto discovery_paths = path_alias_registry::build({path_alias_policy{
.alias = "workspace",
.host_path = std::filesystem::canonical(source).string(),
.target_path = "/workspace",
.max_ttl_secs = 120,
.access = {path_access_policy{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.create_policy = path_create_policy::empty_directory,
.cleanup_policy = path_cleanup_policy::remove,
.max_bytes = 2'097'152,
}},
}});
REQUIRE(discovery_paths.has_value());
auto discovery_validator = session_plan_validator::build(
session_plan_policy{
.revision = 7,
.max_plan_ttl_ms = 120'000,
.runtime_templates = {runtime_template_policy{
.runtime_template_id = "codex-safe",
.runtime_id = "codex",
.adapter_command_digest = *discovered_digest,
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = discovered_codex,
.adoption = std::nullopt,
}},
.library_projection_destinations = {library_projection_destination_policy{
.alias = "libraries",
.target_path = "/opt/sage/library-bundles",
}},
.resource_profiles = {resource_limits{
.cpu_time_ms = 1'000,
.memory_bytes = 67'108'864,
.pids = 16,
.wall_time_ms = 2'000,
.disk_bytes = 2'097'152,
.terminal_output_bytes = 1'048'576,
}},
.egress_policy_ids = {"no-network"},
.tool_policy_ids = {"sage-readonly"},
.secret_handles = {"codex-token"},
.egress_policies = {egress_policy{.policy_id = "no-network", .targets = {}}},
.secret_mounts = {secret_mount_policy{
.handle = "codex-token",
.runtime_id = "codex",
.source_path = "/tmp/codex-auth.json",
.target_path = "/home/agent/.codex/auth.json",
}},
},
std::move(*discovery_paths)
);
REQUIRE(discovery_validator.has_value());
const auto discovery_plan = replace_once(valid_plan(), launch_digest(), *discovered_digest);
auto discovered_launch =
discovery_validator->resolve_runtime_launch_json(discovery_plan, 1'000);
REQUIRE(discovered_launch.has_value());
REQUIRE(
discovered_launch->argv == std::vector<std::string>({
std::filesystem::canonical(codex).string(),
"--version",
"--dangerously-bypass-approvals-and-sandbox",
})
);
REQUIRE(::chmod(harness_bin.c_str(), 0777) == 0);
REQUIRE(!discovery_validator->resolve_runtime_launch_json(discovery_plan, 1'000).has_value());
REQUIRE(::chmod(harness_bin.c_str(), 0700) == 0);
REQUIRE(discovery_validator->resolve_runtime_launch_json(discovery_plan, 1'000).has_value());
const auto discovery_policy_path = temp.root() / "discovery-session-policy.json";
{
std::ofstream output{discovery_policy_path};
auto encoded = replace_once(policy_json(source), launch_digest(), *discovered_digest);
encoded = replace_once(
std::move(encoded),
R"("launch":{"executable_path":"/usr/bin/true","arguments":["--version"],"environment":["PATH=/usr/bin:/bin","TERM=xterm-256color"]})",
"\"launch\":{\"runtime_discovery\":\"codex\",\"executable_path\":\"\",\"executable_"
"search_paths\":[\"" +
harness_bin.string() +
"\"],\"arguments\":[\"--version\"],\"environment\":[\"PATH=/usr/bin:/"
"bin\",\"TERM=xterm-256color\"]}"
);
output << encoded;
}
REQUIRE(::chmod(discovery_policy_path.c_str(), 0600) == 0);
auto loaded_discovery = session_plan_validator::load(discovery_policy_path);
REQUIRE(loaded_discovery.has_value());
auto loaded_discovery_launch =
loaded_discovery->resolve_runtime_launch_json(discovery_plan, 1'000);
REQUIRE(loaded_discovery_launch.has_value());
REQUIRE(loaded_discovery_launch->argv == discovered_launch->argv);
auto accepted = validator->validate_json(valid_plan(), 1'000);
REQUIRE(accepted.has_value());
REQUIRE(accepted->schema_version == 1);
REQUIRE(accepted->policy_revision == 7);
auto launch = validator->resolve_runtime_launch_json(valid_plan(), 1'000);
REQUIRE(launch.has_value());
REQUIRE(launch->runtime_id == "codex");
REQUIRE(launch->runtime_template_id == "codex-safe");
REQUIRE(launch->adapter_command_digest == launch_digest());
REQUIRE(
launch->argv == std::vector<std::string>({
"/usr/bin/true",
"--version",
"--dangerously-bypass-approvals-and-sandbox",
})
);
const auto resolve_codex_arguments =
[&](std::vector<std::string> arguments,
std::string executable = "/usr/bin/true") -> result<std::vector<std::string>> {
auto custom_launch = launch_template();
custom_launch.executable_path = std::move(executable);
custom_launch.arguments = std::move(arguments);
auto custom_digest = runtime_launch_template_digest(custom_launch);
if (!custom_digest) {
return std::unexpected(custom_digest.error());
}
auto custom_validator = validator_for(source, true, {}, custom_launch);
if (!custom_validator) {
return std::unexpected(custom_validator.error());
}
const auto custom_plan = replace_once(valid_plan(), launch_digest(), *custom_digest);
auto custom_projection = custom_validator->resolve_runtime_launch_json(custom_plan, 1'000);
if (!custom_projection) {
return std::unexpected(custom_projection.error());
}
return custom_projection->argv;
};
const auto exec_launch = resolve_codex_arguments({"exec", "PROMPT"});
REQUIRE(exec_launch.has_value());
REQUIRE(
*exec_launch == std::vector<std::string>({
"/usr/bin/true",
"exec",
"--dangerously-bypass-approvals-and-sandbox",
"PROMPT",
})
);
const auto global_exec_launch =
resolve_codex_arguments({"--model", "gpt-5", "--cd=/workspace", "exec", "PROMPT"});
REQUIRE(global_exec_launch.has_value());
REQUIRE(
*global_exec_launch == std::vector<std::string>({
"/usr/bin/true",
"--model",
"gpt-5",
"--cd=/workspace",
"exec",
"--dangerously-bypass-approvals-and-sandbox",
"PROMPT",
})
);
REQUIRE(!resolve_codex_arguments({"--model", "gpt-5"}).has_value());
REQUIRE(!resolve_codex_arguments({"exec", "PROMPT", "exec"}).has_value());
REQUIRE(!resolve_codex_arguments({"--cd", "exec", "exec", "PROMPT"}).has_value());
REQUIRE(!resolve_codex_arguments({"--cd=exec", "exec", "PROMPT"}).has_value());
REQUIRE(!resolve_codex_arguments({"--", "exec", "PROMPT"}).has_value());
REQUIRE(
!resolve_codex_arguments({"exec", "--dangerously-bypass-approvals-and-sandbox", "PROMPT"})
.has_value()
);
const auto legacy_info_launch = resolve_codex_arguments({"--version"});
REQUIRE(legacy_info_launch.has_value());
REQUIRE(
*legacy_info_launch == std::vector<std::string>({
"/usr/bin/true",
"--version",
"--dangerously-bypass-approvals-and-sandbox",
})
);
const auto wrapped_info_launch =
resolve_codex_arguments({"/opt/codex/bin/codex.js", "--version"}, "/usr/bin/node");
REQUIRE(wrapped_info_launch.has_value());
REQUIRE(
*wrapped_info_launch == std::vector<std::string>({
"/usr/bin/node",
"/opt/codex/bin/codex.js",
"--version",
"--dangerously-bypass-approvals-and-sandbox",
})
);
const auto wrapped_exec_launch =
resolve_codex_arguments({"/opt/codex/bin/codex.js", "exec", "PROMPT"}, "/usr/bin/node");
REQUIRE(wrapped_exec_launch.has_value());
REQUIRE(
*wrapped_exec_launch == std::vector<std::string>({
"/usr/bin/node",
"/opt/codex/bin/codex.js",
"exec",
"--dangerously-bypass-approvals-and-sandbox",
"PROMPT",
})
);
REQUIRE(
!resolve_codex_arguments({"relative/codex.js", "--version"}, "/usr/bin/node").has_value()
);
REQUIRE(!resolve_codex_arguments({"/opt/codex/bin/other.js", "--version"}, "/usr/bin/node")
.has_value());
REQUIRE(!resolve_codex_arguments({"exec", "PROMPT"}, "/usr/bin/node").has_value());
REQUIRE(!resolve_codex_arguments({"--future-global", "exec", "PROMPT"}).has_value());
REQUIRE(!resolve_codex_arguments({"resume", "session-id"}).has_value());
REQUIRE(launch->environment == launch_template().environment);
REQUIRE(launch->limits.cpu_time_ms == 1'000);
REQUIRE(launch->egress_policy_id == "no-network");
REQUIRE(launch->egress_targets.empty());
REQUIRE(launch->secret_mounts.size() == 1U);
REQUIRE(launch->secret_mounts.front().handle == "codex-token");
REQUIRE(launch->secret_mounts.front().source_path == "/tmp/codex-auth.json");
REQUIRE(launch->secret_mounts.front().target_path == "/home/agent/.codex/auth.json");
const auto online_policy_path = temp.root() / "online-session-policy.json";
{
auto online_policy = replace_once(
policy_json(source),
R"("egress_policy_ids":["no-network"])",
R"("egress_policy_ids":["openai"])"
);
online_policy = replace_once(
std::move(online_policy),
R"("egress_policies":[{"policy_id":"no-network","targets":[]}])",
R"("egress_policies":[{"policy_id":"openai","targets":[{"host":"api.openai.com","port":443,"allow_private":false}]}])"
);
std::ofstream{online_policy_path} << online_policy;
}
REQUIRE(::chmod(online_policy_path.c_str(), 0600) == 0);
auto online_validator = session_plan_validator::load(online_policy_path);
REQUIRE(online_validator.has_value());
const auto online_plan = replace_once(
valid_plan(), R"("egress_policy_id":"no-network")", R"("egress_policy_id":"openai")"
);
auto online_launch = online_validator->resolve_runtime_launch_json(online_plan, 1'000);
REQUIRE(online_launch.has_value());
REQUIRE(online_launch->egress_policy_id == "openai");
REQUIRE(online_launch->egress_targets.size() == 1U);
REQUIRE(online_launch->egress_targets.front().host == "api.openai.com");
REQUIRE(online_launch->egress_targets.front().port == 443);
REQUIRE(!online_launch->egress_targets.front().allow_private);
auto libraries = validator->resolve_library_projections_json(valid_plan(), 1'000);
REQUIRE(libraries.has_value());
REQUIRE(libraries->size() == 1U);
REQUIRE(libraries->front().projection_id == "sage-core");
REQUIRE(
libraries->front().content_digest ==
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
);
REQUIRE(libraries->front().destination_alias == "libraries");
auto library_targets = validator->resolve_library_projection_targets_json(valid_plan(), 1'000);
REQUIRE(library_targets.has_value());
REQUIRE(library_targets->size() == 1U);
REQUIRE(library_targets->front().projection == libraries->front());
REQUIRE(library_targets->front().target_path == "/opt/sage/library-bundles");
auto exposure_registry = path_exposure_registry::build({
path_exposure_root_policy{
.root_id = "projects",
.host_root = std::filesystem::canonical(temp.root()).string(),
.allowed_modes =
{
path_exposure_mode{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.max_bytes = 2'097'152,
.cleanup_policy = path_cleanup_policy::remove,
},
},
.max_ttl_secs = 120,
.allowed_runtime_template_ids = {"codex-safe"},
},
});
REQUIRE(exposure_registry.has_value());
auto shared_exposures = std::make_shared<path_exposure_registry>(std::move(*exposure_registry));
auto exposure = shared_exposures->create(
path_exposure_create_request{
.request_id = "create-worktree",
.exposure_id = "worktree",
.root_id = "projects",
.host_path = std::filesystem::canonical(source).string(),
.display_label = "Worktree",
.allowed_modes =
{
path_exposure_mode{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.max_bytes = 2'097'152,
.cleanup_policy = path_cleanup_policy::remove,
},
},
.ttl_secs = 120,
.allowed_runtime_template_ids = {"codex-safe"},
},
1'000
);
REQUIRE(exposure.has_value());
auto v2_validator = validator_for(source, true, shared_exposures);
REQUIRE(v2_validator.has_value());
const auto v2_plan =
R"({"schema_version":2,"runtime_id":"codex","runtime_template_id":"codex-safe","adapter_command_digest":")" +
launch_digest() +
R"(","sandbox_backend":"linux_production","egress_policy_id":"no-network","tool_policy_id":"sage-readonly","path_grants":[{"exposure_id":"worktree","generation":1,"scope_digest":")" +
exposure->scope_digest +
R"(","access":"ephemeral_write","materialization":"copy","max_bytes":1048576,"ttl_secs":60,"cleanup_policy":"remove"}],"library_projections":[{"projection_id":"sage-core","content_digest":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","destination_alias":"libraries"}],"secret_handles":["codex-token"],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576},"policy_revision":7,"expires_at_ms":61000})";
auto accepted_v2 = v2_validator->validate_json(v2_plan, 1'000);
REQUIRE(accepted_v2.has_value());
REQUIRE(accepted_v2->schema_version == 2);
auto launch_v2 = v2_validator->resolve_runtime_launch_json(v2_plan, 1'000);
REQUIRE(launch_v2.has_value());
REQUIRE(launch_v2->validation.schema_version == 2);
REQUIRE(!launch_v2->requires_direct_write_approval);
auto canonical_v2 = v2_validator->canonicalize_json(v2_plan, 1'000);
REQUIRE(canonical_v2.has_value());
REQUIRE(canonical_v2->canonical_json == v2_plan);
auto resolved_v2 = v2_validator->resolve_path_grants_json(v2_plan, 1'000);
REQUIRE(resolved_v2.has_value());
REQUIRE(resolved_v2->size() == 1U);
REQUIRE(resolved_v2->front().alias() == "worktree");
REQUIRE(resolved_v2->front().target_path() == "/workspace/exposures/worktree");
auto short_exposure = shared_exposures->create(
path_exposure_create_request{
.request_id = "create-short-window",
.exposure_id = "short-window",
.root_id = "projects",
.host_path = std::filesystem::canonical(source).string(),
.display_label = "Short Window",
.allowed_modes =
{
path_exposure_mode{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.max_bytes = 2'097'152,
.cleanup_policy = path_cleanup_policy::remove,
},
},
.ttl_secs = 60,
.allowed_runtime_template_ids = {"codex-safe"},
},
1'000
);
REQUIRE(short_exposure.has_value());
const auto v2_subsecond_boundary_rejected =
R"({"schema_version":2,"runtime_id":"codex","runtime_template_id":"codex-safe","adapter_command_digest":")" +
launch_digest() +
R"(","sandbox_backend":"linux_production","egress_policy_id":"no-network","tool_policy_id":"sage-readonly","path_grants":[{"exposure_id":"short-window","generation":1,"scope_digest":")" +
short_exposure->scope_digest +
R"(","access":"ephemeral_write","materialization":"copy","max_bytes":1048576,"ttl_secs":60,"cleanup_policy":"remove"}],"library_projections":[{"projection_id":"sage-core","content_digest":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","destination_alias":"libraries"}],"secret_handles":["codex-token"],"limits":{"cpu_time_ms":1000,"memory_bytes":67108864,"pids":16,"wall_time_ms":2000,"disk_bytes":2097152,"terminal_output_bytes":1048576},"policy_revision":7,"expires_at_ms":60999})";
REQUIRE(!v2_validator->validate_json(v2_subsecond_boundary_rejected, 1'000).has_value());
REQUIRE(
!v2_validator->resolve_path_grants_json(v2_subsecond_boundary_rejected, 1'000).has_value()
);
const auto v2_subsecond_boundary_accepted =
replace_once(v2_subsecond_boundary_rejected, "\"ttl_secs\":60", "\"ttl_secs\":59");
REQUIRE(v2_validator->validate_json(v2_subsecond_boundary_accepted, 1'000).has_value());
auto resolved_v2_subsecond =
v2_validator->resolve_path_grants_json(v2_subsecond_boundary_accepted, 1'000);
REQUIRE(resolved_v2_subsecond.has_value());
REQUIRE(resolved_v2_subsecond->size() == 1U);
REQUIRE(resolved_v2_subsecond->front().alias() == "short-window");
REQUIRE(resolved_v2_subsecond->front().target_path() == "/workspace/exposures/short-window");
REQUIRE(shared_exposures->revoke("revoke-worktree", "worktree", exposure->generation, 2'000)
.has_value());
REQUIRE(!v2_validator->validate_json(v2_plan, 2'000).has_value());
REQUIRE(resolved_v2->front().verify_identity().has_value());
const auto changed_library = replace_once(valid_plan(), "sage-core", "sage-other");
auto changed_libraries = validator->resolve_library_projections_json(changed_library, 1'000);
REQUIRE(changed_libraries.has_value());
REQUIRE(changed_libraries->front().projection_id == "sage-other");
auto invalid_destination_policy = session_plan_policy{
.revision = 7,
.max_plan_ttl_ms = 120'000,
.runtime_templates =
{
runtime_template_policy{
.runtime_template_id = "codex-safe",
.runtime_id = "codex",
.adapter_command_digest = launch_digest(),
.backend = sandbox_backend::linux_production,
.allowed_path_aliases = {"workspace"},
.allowed_projection_destinations = {"libraries"},
.launch = launch_template(),
.adoption = std::nullopt,
},
},
.library_projection_destinations =
{
library_projection_destination_policy{
.alias = "libraries",
.target_path = "relative/library-bundles",
},
},
.resource_profiles =
{
resource_limits{
.cpu_time_ms = 1'000,
.memory_bytes = 67'108'864,
.pids = 16,
.wall_time_ms = 2'000,
.disk_bytes = 2'097'152,
.terminal_output_bytes = 1'048'576,
},
},
.egress_policy_ids = {"no-network"},
.tool_policy_ids = {"sage-readonly"},
.secret_handles = {"codex-token"},
.egress_policies = {},
.secret_mounts = {},
};
path_alias_policy invalid_destination_path{
.alias = "workspace",
.host_path = std::filesystem::canonical(source).string(),
.target_path = "/workspace",
.max_ttl_secs = 120,
.access = {
path_access_policy{
.access = path_access::ephemeral_write,
.materialization = path_materialization::copy,
.create_policy = path_create_policy::empty_directory,
.cleanup_policy = path_cleanup_policy::remove,
.max_bytes = 2'097'152,
},
},
};
auto invalid_destination_paths =
path_alias_registry::build({std::move(invalid_destination_path)});
REQUIRE(invalid_destination_paths.has_value());
REQUIRE(!session_plan_validator::build(
std::move(invalid_destination_policy), std::move(*invalid_destination_paths)
)
.has_value());
auto plan_only_validator = validator_for(std::filesystem::canonical(source), false);
REQUIRE(plan_only_validator.has_value());
REQUIRE(plan_only_validator->validate_json(valid_plan(), 1'000).has_value());
REQUIRE(!plan_only_validator->resolve_runtime_launch_json(valid_plan(), 1'000).has_value());
const auto policy_path = temp.root() / "session-policy.json";
{
std::ofstream output{policy_path};
output << policy_json(source);
}
REQUIRE(::chmod(policy_path.c_str(), 0600) == 0);
auto loaded = glove::supervisor::session_plan_validator::load(policy_path);
REQUIRE(loaded.has_value());
REQUIRE(loaded->validate_json(valid_plan(), 1'000).has_value());
REQUIRE(loaded->resolve_runtime_launch_json(valid_plan(), 1'000).has_value());
auto no_adoption = loaded->resolve_native_harness_adoption_json(valid_plan(), 1'000);
REQUIRE(no_adoption.has_value());
REQUIRE(!no_adoption->has_value());
const auto remote_policy_path = temp.root() / "remote-session-policy.json";
{
std::ofstream output{remote_policy_path};
output << replace_once(
policy_json(source),
"\"sandbox_backend\":\"linux_production\"",
"\"sandbox_backend\":\"remote_linux_container\""
);
}
REQUIRE(::chmod(remote_policy_path.c_str(), 0600) == 0);
auto remote_validator = session_plan_validator::load(remote_policy_path);
REQUIRE(remote_validator.has_value());
const auto remote_plan = replace_once(
valid_plan(),
"\"sandbox_backend\":\"linux_production\"",
"\"sandbox_backend\":\"remote_linux_container\""
);
REQUIRE(!remote_validator->validate_json(remote_plan, 1'000).has_value());
const auto remote_without_secrets =
replace_once(remote_plan, "\"secret_handles\":[\"codex-token\"]", "\"secret_handles\":[]");
REQUIRE(remote_validator->validate_json(remote_without_secrets, 1'000).has_value());
const auto remote_direct = replace_once(
remote_without_secrets, "\"access\":\"ephemeral_write\"", "\"access\":\"direct_write\""
);
REQUIRE(!remote_validator->validate_json(remote_direct, 1'000).has_value());
const auto remote_retained = replace_once(
remote_without_secrets, "\"access\":\"ephemeral_write\"", "\"access\":\"retained_write\""
);
REQUIRE(!remote_validator->validate_json(remote_retained, 1'000).has_value());
const auto invalid_adoption_policy_path = temp.root() / "invalid-adoption-policy.json";
{
std::ofstream output{invalid_adoption_policy_path};
output << replace_once(
policy_json(source),
R"("launch":{"executable_path":"/usr/bin/true")",
R"("adoption":{"manifest_root":"relative","manifest_digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","snapshot_digest":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"launch":{"executable_path":"/usr/bin/true")"
);
}
REQUIRE(::chmod(invalid_adoption_policy_path.c_str(), 0600) == 0);
REQUIRE(
!glove::supervisor::session_plan_validator::load(invalid_adoption_policy_path).has_value()
);
const auto unbound_destination_policy_path = temp.root() / "unbound-destination-policy.json";
{
std::ofstream output{unbound_destination_policy_path};
output << replace_once(
policy_json(source),
R"("library_projection_destinations":[{"alias":"libraries","target_path":"/opt/sage/library-bundles"}])",
R"("library_projection_destinations":[])"
);
}
REQUIRE(::chmod(unbound_destination_policy_path.c_str(), 0600) == 0);
REQUIRE(!glove::supervisor::session_plan_validator::load(unbound_destination_policy_path)
.has_value());
const auto unnamed_resource_policy_path = temp.root() / "unnamed-resource-policy.json";
{
std::ofstream output{unnamed_resource_policy_path};
output << replace_once(
policy_json(source), "\"profile_id\":\"small\"", "\"profile_id\":\"\""
);
}
REQUIRE(::chmod(unnamed_resource_policy_path.c_str(), 0600) == 0);
REQUIRE(
!glove::supervisor::session_plan_validator::load(unnamed_resource_policy_path).has_value()
);
const auto mismatched_policy_path = temp.root() / "mismatched-session-policy.json";
{
std::ofstream output{mismatched_policy_path};
output << replace_once(policy_json(source), "/usr/bin/true", "/usr/bin/false");
}
REQUIRE(::chmod(mismatched_policy_path.c_str(), 0600) == 0);
REQUIRE(!glove::supervisor::session_plan_validator::load(mismatched_policy_path).has_value());
REQUIRE(::chmod(policy_path.c_str(), 0644) == 0);
REQUIRE(!glove::supervisor::session_plan_validator::load(policy_path).has_value());
REQUIRE(::chmod(policy_path.c_str(), 0600) == 0);
const auto unknown_runtime = replace_once(valid_plan(), "codex-safe", "shell");
REQUIRE(!validator->validate_json(unknown_runtime, 1'000).has_value());
const auto stale_policy =
replace_once(valid_plan(), "\"policy_revision\":7", "\"policy_revision\":6");
REQUIRE(!validator->validate_json(stale_policy, 1'000).has_value());
const auto raw_authority = replace_once(
valid_plan(), "\"expires_at_ms\":61000", "\"expires_at_ms\":61000,\"argv\":[\"/bin/sh\"]"
);
REQUIRE(!validator->validate_json(raw_authority, 1'000).has_value());
const auto excessive_quota =
replace_once(valid_plan(), "\"max_bytes\":1048576", "\"max_bytes\":4194304");
REQUIRE(!validator->validate_json(excessive_quota, 1'000).has_value());
const auto wrong_materialization =
replace_once(valid_plan(), "\"materialization\":\"copy\"", "\"materialization\":\"bind\"");
REQUIRE(!validator->validate_json(wrong_materialization, 1'000).has_value());
const auto receipt_named_cleanup = replace_once(
valid_plan(), "\"cleanup_policy\":\"remove\"", "\"cleanup_policy\":\"retain_receipt\""
);
REQUIRE(!validator->validate_json(receipt_named_cleanup, 1'000).has_value());
const auto expired =
replace_once(valid_plan(), "\"expires_at_ms\":61000", "\"expires_at_ms\":1000");
REQUIRE(!validator->validate_json(expired, 1'000).has_value());
const auto excessive_ttl =
replace_once(valid_plan(), "\"expires_at_ms\":61000", "\"expires_at_ms\":200000");
REQUIRE(!validator->validate_json(excessive_ttl, 1'000).has_value());
const auto grant_outlives_plan =
replace_once(valid_plan(), "\"ttl_secs\":60", "\"ttl_secs\":120");
REQUIRE(!validator->validate_json(grant_outlives_plan, 1'000).has_value());
const auto unsorted_secrets = replace_once(
valid_plan(),
"\"secret_handles\":[\"codex-token\"]",
"\"secret_handles\":[\"z-token\",\"codex-token\"]"
);
REQUIRE(!validator->validate_json(unsorted_secrets, 1'000).has_value());
return 0;
}
} // namespace
int main() {
return run();
}