implement Milestone 20: Kernel Integration with LuaSandboxManager (149 tests)

This commit is contained in:
2026-01-18 16:54:02 +01:00
parent 1b163891e0
commit 9805bdf175
6 changed files with 907 additions and 13 deletions

View File

@@ -0,0 +1,310 @@
// sandbox_manager.cpp - Multi-app sandbox orchestrator implementation
// Milestone 20: Kernel Integration
#include "sandbox_manager.h"
#include <lua.hpp>
#include <filesystem>
namespace mosis {
LuaSandboxManager::LuaSandboxManager(const std::string& data_root)
: m_data_root(data_root)
, m_audit_log()
, m_rate_limiter()
, m_message_bus()
, m_timer_manager()
{
// Set reasonable default limits
m_default_limits.memory_bytes = 50 * 1024 * 1024; // 50MB per app
m_default_limits.instructions_per_call = 1000000; // 1M instructions
m_default_limits.stack_depth = 200; // 200 recursion depth
m_default_limits.max_string_size = 10 * 1024 * 1024; // 10MB strings
}
LuaSandboxManager::~LuaSandboxManager() {
// Stop all running apps
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& [app_id, app] : m_apps) {
if (app && app->is_running) {
CleanupApp(*app);
}
}
m_apps.clear();
}
bool LuaSandboxManager::StartApp(const std::string& app_id,
const std::string& app_path,
const std::vector<std::string>& permissions,
bool is_system_app) {
std::lock_guard<std::mutex> lock(m_mutex);
// Check if already running
if (m_apps.count(app_id) && m_apps[app_id]->is_running) {
return false; // Already running
}
// Create sandbox context
SandboxContext ctx;
ctx.app_id = app_id;
ctx.app_path = app_path;
ctx.permissions = permissions;
ctx.is_system_app = is_system_app;
// Create app sandbox
auto app = CreateAppSandbox(ctx);
if (!app) {
m_audit_log.Log(AuditEvent::AppStart, app_id,
"FAILED", "Failed to create sandbox");
return false;
}
// Register all APIs
RegisterAPIs(*app);
// Mark as running
app->is_running = true;
// Store in map
m_apps[app_id] = std::move(app);
// Log successful start
m_audit_log.Log(AuditEvent::AppStart, app_id, "SUCCESS", "");
return true;
}
bool LuaSandboxManager::StopApp(const std::string& app_id) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it == m_apps.end() || !it->second->is_running) {
return false; // Not running
}
// Clean up resources
CleanupApp(*it->second);
// Mark as stopped
it->second->is_running = false;
// Log stop
m_audit_log.Log(AuditEvent::AppStop, app_id, "SUCCESS", "");
// Remove from map
m_apps.erase(it);
return true;
}
bool LuaSandboxManager::IsAppRunning(const std::string& app_id) const {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
return it != m_apps.end() && it->second->is_running;
}
AppSandbox* LuaSandboxManager::GetApp(const std::string& app_id) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it != m_apps.end() && it->second->is_running) {
return it->second.get();
}
return nullptr;
}
const AppSandbox* LuaSandboxManager::GetApp(const std::string& app_id) const {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it != m_apps.end() && it->second->is_running) {
return it->second.get();
}
return nullptr;
}
bool LuaSandboxManager::ExecuteCode(const std::string& app_id,
const std::string& code,
const std::string& source_name) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it == m_apps.end() || !it->second->is_running) {
return false;
}
return it->second->lua->LoadString(code, source_name);
}
bool LuaSandboxManager::LoadFile(const std::string& app_id,
const std::string& path) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it == m_apps.end() || !it->second->is_running) {
return false;
}
return it->second->lua->LoadFile(path);
}
void LuaSandboxManager::RecordUserGesture(const std::string& app_id) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_apps.find(app_id);
if (it != m_apps.end() && it->second->is_running) {
it->second->permissions->RecordUserGesture();
}
}
void LuaSandboxManager::UpdateTimers() {
// Fire all ready timers
m_timer_manager.ProcessTimers();
}
std::vector<std::string> LuaSandboxManager::GetRunningApps() const {
std::lock_guard<std::mutex> lock(m_mutex);
std::vector<std::string> result;
for (const auto& [app_id, app] : m_apps) {
if (app && app->is_running) {
result.push_back(app_id);
}
}
return result;
}
size_t LuaSandboxManager::GetRunningAppCount() const {
std::lock_guard<std::mutex> lock(m_mutex);
size_t count = 0;
for (const auto& [app_id, app] : m_apps) {
if (app && app->is_running) {
count++;
}
}
return count;
}
std::unique_ptr<AppSandbox> LuaSandboxManager::CreateAppSandbox(
const SandboxContext& ctx) {
auto app = std::make_unique<AppSandbox>();
app->context = ctx;
// Create core sandbox
app->lua = std::make_unique<LuaSandbox>(ctx, m_default_limits);
// Create permission gate
app->permissions = std::make_unique<PermissionGate>(ctx);
for (const auto& perm : ctx.permissions) {
if (!ctx.is_system_app) {
// Normal apps need explicit grants for dangerous permissions
auto cat = app->permissions->GetCategory(perm);
if (cat == PermissionCategory::Normal) {
app->permissions->GrantPermission(perm);
}
} else {
// System apps get all declared permissions
app->permissions->GrantPermission(perm);
}
}
// Create storage path
std::string app_data_path = m_data_root + "/apps/" + ctx.app_id;
std::filesystem::create_directories(app_data_path + "/data");
std::filesystem::create_directories(app_data_path + "/cache");
std::filesystem::create_directories(app_data_path + "/db");
// Create virtual filesystem
app->filesystem = std::make_unique<VirtualFS>(ctx.app_id, app_data_path);
// Create database manager
app->database = std::make_unique<DatabaseManager>(ctx.app_id, app_data_path + "/db");
// Create network components
app->network = std::make_unique<NetworkManager>(ctx.app_id);
app->websocket = std::make_unique<WebSocketManager>(ctx.app_id);
// Create hardware interfaces
app->camera = std::make_unique<CameraInterface>(ctx.app_id, app->permissions.get());
app->microphone = std::make_unique<MicrophoneInterface>(ctx.app_id, app->permissions.get());
app->audio = std::make_unique<AudioOutputInterface>(ctx.app_id);
app->location = std::make_unique<LocationInterface>(ctx.app_id);
app->sensors = std::make_unique<SensorInterface>(ctx.app_id);
app->bluetooth = std::make_unique<BluetoothInterface>(ctx.app_id);
app->contacts = std::make_unique<ContactsInterface>(ctx.app_id);
return app;
}
void LuaSandboxManager::RegisterAPIs(AppSandbox& app) {
lua_State* L = app.lua->GetState();
if (!L) return;
// Register JSON API
RegisterJsonAPI(L);
// Register crypto API
RegisterCryptoAPI(L);
// Register timer APIs with the shared timer manager
// Note: Individual API registration would be done here if we
// were exposing these to Lua. For now, the timer manager
// provides the backend and apps use it via registered functions.
// Store app context in registry for API callbacks
lua_pushlightuserdata(L, &app);
lua_setfield(L, LUA_REGISTRYINDEX, "__app_sandbox");
// Store manager reference for cross-app operations
lua_pushlightuserdata(L, this);
lua_setfield(L, LUA_REGISTRYINDEX, "__sandbox_manager");
}
void LuaSandboxManager::CleanupApp(AppSandbox& app) {
// Clear timers for this app
m_timer_manager.ClearAppTimers(app.context.app_id);
// Close WebSocket connections
if (app.websocket) {
app.websocket->CloseAll();
}
// Stop camera/microphone sessions
if (app.camera) {
app.camera->Shutdown();
}
if (app.microphone) {
app.microphone->Shutdown();
}
// Stop audio
if (app.audio) {
app.audio->Shutdown();
}
// Stop location watching
if (app.location) {
app.location->Shutdown();
}
// Stop sensors
if (app.sensors) {
app.sensors->Shutdown();
}
// Stop bluetooth
if (app.bluetooth) {
app.bluetooth->Shutdown();
}
// Clean up temp files in filesystem
if (app.filesystem) {
app.filesystem->ClearTemp();
}
// Close database connections
if (app.database) {
app.database->CloseAll();
}
// Unregister from message bus
m_message_bus.UnregisterApp(app.context.app_id);
}
} // namespace mosis

View File

@@ -0,0 +1,127 @@
// sandbox_manager.h - Multi-app sandbox orchestrator
// Milestone 20: Kernel Integration
#pragma once
#include "lua_sandbox.h"
#include "permission_gate.h"
#include "audit_log.h"
#include "rate_limiter.h"
#include "timer_manager.h"
#include "virtual_fs.h"
#include "database_manager.h"
#include "network_manager.h"
#include "websocket_manager.h"
#include "camera_interface.h"
#include "microphone_interface.h"
#include "audio_output.h"
#include "location_interface.h"
#include "sensor_interface.h"
#include "bluetooth_interface.h"
#include "contacts_interface.h"
#include "message_bus.h"
#include "json_api.h"
#include "crypto_api.h"
#include <memory>
#include <unordered_map>
#include <string>
#include <mutex>
#include <functional>
namespace mosis {
// Per-app sandbox instance with all components
struct AppSandbox {
std::unique_ptr<LuaSandbox> lua;
std::unique_ptr<PermissionGate> permissions;
std::unique_ptr<VirtualFS> filesystem;
std::unique_ptr<DatabaseManager> database;
std::unique_ptr<NetworkManager> network;
std::unique_ptr<WebSocketManager> websocket;
std::unique_ptr<CameraInterface> camera;
std::unique_ptr<MicrophoneInterface> microphone;
std::unique_ptr<AudioOutputInterface> audio;
std::unique_ptr<LocationInterface> location;
std::unique_ptr<SensorInterface> sensors;
std::unique_ptr<BluetoothInterface> bluetooth;
std::unique_ptr<ContactsInterface> contacts;
SandboxContext context;
bool is_running = false;
};
// Callback for recording user gestures (from UI events)
using UserGestureCallback = std::function<void(const std::string& app_id)>;
class LuaSandboxManager {
public:
explicit LuaSandboxManager(const std::string& data_root = ".");
~LuaSandboxManager();
// Prevent copying
LuaSandboxManager(const LuaSandboxManager&) = delete;
LuaSandboxManager& operator=(const LuaSandboxManager&) = delete;
// App lifecycle
bool StartApp(const std::string& app_id, const std::string& app_path,
const std::vector<std::string>& permissions,
bool is_system_app = false);
bool StopApp(const std::string& app_id);
bool IsAppRunning(const std::string& app_id) const;
// Get app sandbox for direct access
AppSandbox* GetApp(const std::string& app_id);
const AppSandbox* GetApp(const std::string& app_id) const;
// Execute Lua code in app context
bool ExecuteCode(const std::string& app_id, const std::string& code,
const std::string& source_name = "script");
bool LoadFile(const std::string& app_id, const std::string& path);
// User gesture tracking (for permission-sensitive operations)
void RecordUserGesture(const std::string& app_id);
// Timer management - called from main loop
void UpdateTimers();
// Get all running app IDs
std::vector<std::string> GetRunningApps() const;
// Shared components
AuditLog& GetAuditLog() { return m_audit_log; }
RateLimiter& GetRateLimiter() { return m_rate_limiter; }
MessageBus& GetMessageBus() { return m_message_bus; }
TimerManager& GetTimerManager() { return m_timer_manager; }
// Configuration
void SetDefaultLimits(const SandboxLimits& limits) { m_default_limits = limits; }
const SandboxLimits& GetDefaultLimits() const { return m_default_limits; }
// Stats
size_t GetRunningAppCount() const;
private:
// Create and configure a new app sandbox
std::unique_ptr<AppSandbox> CreateAppSandbox(const SandboxContext& ctx);
// Register all Lua APIs with sandbox
void RegisterAPIs(AppSandbox& app);
// Clean up app resources
void CleanupApp(AppSandbox& app);
// Data storage
std::string m_data_root;
mutable std::mutex m_mutex;
std::unordered_map<std::string, std::unique_ptr<AppSandbox>> m_apps;
// Shared components across all apps
AuditLog m_audit_log;
RateLimiter m_rate_limiter;
MessageBus m_message_bus;
TimerManager m_timer_manager;
// Default limits for new sandboxes
SandboxLimits m_default_limits;
};
} // namespace mosis