glove/tests/run/glove_exec_perimeter_test.cpp
2026-07-19 21:06:11 -04:00

125 lines
3.7 KiB
C++

// Direct-agent defaults must not silently expose the caller's current
// directory, place glove-managed state in the selected workspace, or let an
// agent tamper with its own audit trail.
#include <sys/wait.h>
#include <unistd.h>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#ifndef GLOVE_BIN
# error "GLOVE_BIN must point at the glove executable"
#endif
namespace {
#define REQUIRE(cond) \
do { \
if (!(cond)) { \
std::fprintf(stderr, "REQUIRE failed: %s @ %s:%d\n", #cond, __FILE__, __LINE__); \
return 1; \
} \
} while (0)
auto run_glove(std::vector<std::string> argv_owned) -> int {
std::vector<char*> argv;
argv.reserve(argv_owned.size() + 1);
for (auto& value : argv_owned) {
argv.push_back(value.data());
}
argv.push_back(nullptr);
const ::pid_t child = ::fork();
if (child < 0) {
return -1;
}
if (child == 0) {
::execv(GLOVE_BIN, argv.data());
std::_Exit(127);
}
int status = 0;
if (::waitpid(child, &status, 0) != child) {
return -1;
}
return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
auto run() -> int {
std::error_code ec;
const auto base =
std::filesystem::temp_directory_path() / ("glove_perimeter_" + std::to_string(::getpid()));
const auto workspace = base / "workspace";
const auto marker =
std::filesystem::current_path() / ("glove-caller-secret-" + std::to_string(::getpid()));
std::filesystem::create_directories(workspace, ec);
REQUIRE(!ec);
{
std::ofstream out{marker};
out << "not for the agent\n";
REQUIRE(out.good());
}
// With no --workspace or --read, even an absolute path passed in argv is
// not readable. The command exits 42 if the boundary is too broad.
REQUIRE(
run_glove(
{GLOVE_BIN,
"exec",
"--",
"/bin/sh",
"-c",
"test ! -r \"$1\" || exit 42",
"glove-test",
marker.string()}
) == 0
);
// HOME/TMPDIR are private runtime state, not hidden mutations inside the
// user's project tree.
REQUIRE(
run_glove(
{GLOVE_BIN,
"exec",
"--workspace",
workspace.string(),
"--",
"/bin/sh",
"-c",
"case \"$HOME\" in \"$1\"/*) exit 42;; esac",
"glove-test",
workspace.string()}
) == 0
);
REQUIRE(!std::filesystem::exists(workspace / ".glove-home"));
// An append-only audit destination cannot sit below any path granted to
// the agent, even if the operator names it explicitly.
const auto exposed_audit = workspace / "audit.jsonl";
REQUIRE(
run_glove(
{GLOVE_BIN,
"exec",
"--workspace",
workspace.string(),
"--audit-log",
exposed_audit.string(),
"--",
"/usr/bin/true"}
) == 1
);
REQUIRE(!std::filesystem::exists(exposed_audit));
std::filesystem::remove(marker, ec);
std::filesystem::remove_all(base, ec);
return 0;
}
} // namespace
auto main() -> int {
return run();
}