add virtual filesystem with path sandboxing and quotas (milestone 7 complete)
This commit is contained in:
@@ -18,6 +18,7 @@ add_library(mosis-sandbox STATIC
|
||||
../src/main/cpp/sandbox/timer_manager.cpp
|
||||
../src/main/cpp/sandbox/json_api.cpp
|
||||
../src/main/cpp/sandbox/crypto_api.cpp
|
||||
../src/main/cpp/sandbox/virtual_fs.cpp
|
||||
)
|
||||
target_include_directories(mosis-sandbox PUBLIC
|
||||
../src/main/cpp/sandbox
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "timer_manager.h"
|
||||
#include "json_api.h"
|
||||
#include "crypto_api.h"
|
||||
#include "virtual_fs.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -1074,6 +1075,190 @@ bool Test_SecureMathRandom(std::string& error_msg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MILESTONE 7: VIRTUAL FILESYSTEM TESTS
|
||||
//=============================================================================
|
||||
|
||||
bool Test_VirtualFSReadWrite(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Write a file
|
||||
EXPECT_TRUE(vfs.Write("/data/test.txt", "Hello World", err));
|
||||
|
||||
// Read it back
|
||||
auto content = vfs.Read("/data/test.txt", err);
|
||||
EXPECT_TRUE(content.has_value());
|
||||
EXPECT_TRUE(*content == "Hello World");
|
||||
|
||||
// Cleanup
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSBlocksTraversal(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Should reject traversal
|
||||
EXPECT_FALSE(vfs.Write("/data/../../../etc/passwd", "hack", err));
|
||||
EXPECT_TRUE(err.find("traversal") != std::string::npos ||
|
||||
err.find("invalid") != std::string::npos);
|
||||
|
||||
// Should reject paths without valid prefix
|
||||
err.clear();
|
||||
EXPECT_FALSE(vfs.Write("/etc/passwd", "hack", err));
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSEnforcesQuota(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFSLimits limits;
|
||||
limits.max_quota_bytes = 1024; // 1 KB quota for testing
|
||||
mosis::VirtualFS vfs("test.app", test_root, limits);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Write should succeed
|
||||
std::string small_data(500, 'a');
|
||||
EXPECT_TRUE(vfs.Write("/data/file1.txt", small_data, err));
|
||||
|
||||
// Second write should fail (exceeds quota)
|
||||
std::string large_data(600, 'b');
|
||||
EXPECT_FALSE(vfs.Write("/data/file2.txt", large_data, err));
|
||||
EXPECT_TRUE(err.find("quota") != std::string::npos);
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSCleansUpTemp(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Write to temp
|
||||
EXPECT_TRUE(vfs.Write("/temp/session.txt", "temp data", err));
|
||||
EXPECT_TRUE(vfs.Exists("/temp/session.txt"));
|
||||
|
||||
// Clear temp
|
||||
vfs.ClearTemp();
|
||||
|
||||
// Should be gone
|
||||
EXPECT_FALSE(vfs.Exists("/temp/session.txt"));
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSList(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Create some files
|
||||
vfs.Write("/data/file1.txt", "content1", err);
|
||||
vfs.Write("/data/file2.txt", "content2", err);
|
||||
vfs.MakeDir("/data/subdir", err);
|
||||
|
||||
// List directory
|
||||
auto files = vfs.List("/data/", err);
|
||||
EXPECT_TRUE(files.has_value());
|
||||
EXPECT_TRUE(files->size() == 3);
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSStat(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Write a file
|
||||
vfs.Write("/data/test.txt", "Hello", err);
|
||||
|
||||
// Get stat
|
||||
auto stat = vfs.Stat("/data/test.txt", err);
|
||||
EXPECT_TRUE(stat.has_value());
|
||||
EXPECT_TRUE(stat->size == 5);
|
||||
EXPECT_FALSE(stat->is_dir);
|
||||
|
||||
// Directory stat
|
||||
vfs.MakeDir("/data/subdir", err);
|
||||
auto dir_stat = vfs.Stat("/data/subdir", err);
|
||||
EXPECT_TRUE(dir_stat.has_value());
|
||||
EXPECT_TRUE(dir_stat->is_dir);
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSLuaIntegration(std::string& error_msg) {
|
||||
SandboxContext ctx = TestContext();
|
||||
LuaSandbox sandbox(ctx);
|
||||
|
||||
std::string test_root = "test_vfs_lua";
|
||||
mosis::VirtualFS vfs("test.app", test_root);
|
||||
mosis::RegisterVirtualFS(sandbox.GetState(), &vfs);
|
||||
|
||||
std::string script = R"(
|
||||
-- Write and read
|
||||
local ok, err = fs.write("/data/test.txt", "Hello from Lua")
|
||||
assert(ok, "write failed: " .. (err or ""))
|
||||
|
||||
local content, err = fs.read("/data/test.txt")
|
||||
assert(content == "Hello from Lua", "content mismatch: " .. (content or "nil"))
|
||||
|
||||
-- Check exists
|
||||
assert(fs.exists("/data/test.txt"), "file should exist")
|
||||
assert(not fs.exists("/data/nonexistent.txt"), "file should not exist")
|
||||
|
||||
-- Stat
|
||||
local stat = fs.stat("/data/test.txt")
|
||||
assert(stat.size == 14, "size should be 14, got " .. tostring(stat.size))
|
||||
assert(not stat.isDir, "should not be dir")
|
||||
)";
|
||||
|
||||
bool ok = sandbox.LoadString(script, "vfs_test");
|
||||
vfs.ClearAll();
|
||||
|
||||
if (!ok) {
|
||||
error_msg = "Lua test failed: " + sandbox.GetLastError();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Test_VirtualFSMaxFileSize(std::string& error_msg) {
|
||||
std::string test_root = "test_vfs_app";
|
||||
mosis::VirtualFSLimits limits;
|
||||
limits.max_file_size = 100; // 100 bytes max
|
||||
limits.max_quota_bytes = 10000; // Large quota
|
||||
mosis::VirtualFS vfs("test.app", test_root, limits);
|
||||
|
||||
std::string err;
|
||||
|
||||
// Small file should succeed
|
||||
EXPECT_TRUE(vfs.Write("/data/small.txt", std::string(50, 'a'), err));
|
||||
|
||||
// Large file should fail
|
||||
EXPECT_FALSE(vfs.Write("/data/large.txt", std::string(200, 'b'), err));
|
||||
EXPECT_TRUE(err.find("size") != std::string::npos);
|
||||
|
||||
vfs.ClearAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MAIN
|
||||
//=============================================================================
|
||||
@@ -1176,6 +1361,16 @@ int main(int argc, char* argv[]) {
|
||||
harness.AddTest("CryptoHMAC", Test_CryptoHMAC);
|
||||
harness.AddTest("SecureMathRandom", Test_SecureMathRandom);
|
||||
|
||||
// Milestone 7: Virtual Filesystem
|
||||
harness.AddTest("VirtualFSReadWrite", Test_VirtualFSReadWrite);
|
||||
harness.AddTest("VirtualFSBlocksTraversal", Test_VirtualFSBlocksTraversal);
|
||||
harness.AddTest("VirtualFSEnforcesQuota", Test_VirtualFSEnforcesQuota);
|
||||
harness.AddTest("VirtualFSCleansUpTemp", Test_VirtualFSCleansUpTemp);
|
||||
harness.AddTest("VirtualFSList", Test_VirtualFSList);
|
||||
harness.AddTest("VirtualFSStat", Test_VirtualFSStat);
|
||||
harness.AddTest("VirtualFSLuaIntegration", Test_VirtualFSLuaIntegration);
|
||||
harness.AddTest("VirtualFSMaxFileSize", Test_VirtualFSMaxFileSize);
|
||||
|
||||
// Run tests
|
||||
auto results = harness.Run(filter);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user