move docs to docs/ folder, merge architecture files, update references

This commit is contained in:
2026-01-19 09:02:11 +01:00
parent 1b34b0e974
commit 010e11cf6b
68 changed files with 1741 additions and 1350 deletions

View File

@@ -0,0 +1,463 @@
# Milestone 18: Inter-App Communication
**Status**: Complete
**Goal**: Kernel-mediated message passing between apps.
---
## Overview
This milestone implements secure inter-app communication via an intent system:
- Apps register to receive specific intent actions
- Senders must have required permissions
- All messages go through kernel mediation (no direct app-to-app)
- Message size limits prevent resource exhaustion
- Audit logging for all inter-app communication
### Key Deliverables
1. **MessageBus class** - Central message routing and validation
2. **Intent struct** - Message format with action, type, and data
3. **Lua intents API** - `intents.send()`, `intents.on()`, `intents.broadcast()`
4. **Security validation** - Permission checks, sender/receiver verification
---
## File Structure
```
src/main/cpp/sandbox/
├── message_bus.h # NEW - Message bus API header
└── message_bus.cpp # NEW - Message bus implementation
```
---
## Implementation Details
### 1. MessageBus Class
```cpp
// message_bus.h
#pragma once
#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
struct lua_State;
namespace mosis {
struct Intent {
std::string action; // Intent action (e.g., "share", "view", "edit")
std::string type; // MIME type (e.g., "text/plain", "image/png")
std::string data; // Intent data/payload
std::string from_app; // Sender app ID (set by kernel)
};
struct IntentFilter {
std::string action; // Required action
std::vector<std::string> types; // Accepted MIME types (empty = all)
};
enum class MessageError {
None,
NoReceivers,
PermissionDenied,
InvalidIntent,
DataTooLarge,
ReceiverNotFound,
SenderBlocked
};
class MessageBus {
public:
using IntentHandler = std::function<void(const Intent&)>;
MessageBus();
~MessageBus();
// Register an app to receive intents
void RegisterReceiver(
const std::string& app_id,
const IntentFilter& filter,
IntentHandler handler
);
// Unregister all handlers for an app
void UnregisterApp(const std::string& app_id);
// Send intent to specific app (requires permission)
MessageError Send(
const std::string& sender_app,
const std::string& target_app,
const Intent& intent,
std::string& error
);
// Broadcast intent to all registered receivers
MessageError Broadcast(
const std::string& sender_app,
const Intent& intent,
std::string& error
);
// Check if any app handles this action
bool HasReceiverFor(const std::string& action) const;
// Get list of apps that handle an action
std::vector<std::string> GetReceiversFor(const std::string& action) const;
// Permission management
void SetAppPermission(const std::string& app_id, const std::string& permission, bool granted);
bool HasPermission(const std::string& app_id, const std::string& permission) const;
// Block specific app from sending/receiving
void BlockApp(const std::string& app_id);
void UnblockApp(const std::string& app_id);
bool IsBlocked(const std::string& app_id) const;
// Clear all registrations (for testing)
void Clear();
// Statistics
size_t GetReceiverCount() const;
size_t GetMessageCount() const { return m_message_count; }
private:
struct ReceiverEntry {
std::string app_id;
IntentFilter filter;
IntentHandler handler;
};
std::vector<ReceiverEntry> m_receivers;
std::unordered_map<std::string, std::unordered_set<std::string>> m_permissions;
std::unordered_set<std::string> m_blocked_apps;
mutable std::mutex m_mutex;
size_t m_message_count = 0;
static constexpr size_t MAX_DATA_SIZE = 1024 * 1024; // 1MB max
bool MatchesFilter(const Intent& intent, const IntentFilter& filter) const;
bool ValidateIntent(const Intent& intent, std::string& error) const;
};
// Register intents.* APIs as globals
void RegisterIntentsAPI(lua_State* L, MessageBus* bus, const std::string& app_id);
} // namespace mosis
```
### 2. Standard Intent Actions
| Action | Description | Required Permission |
|--------|-------------|---------------------|
| `share` | Share content with another app | None |
| `view` | Request app to view content | None |
| `edit` | Request app to edit content | None |
| `pick` | Request user to pick item | None |
| `call` | Initiate phone call | `phone.call` |
| `message` | Send SMS/message | `sms.send` |
| `email` | Compose email | None |
### 3. Permission Requirements
| Operation | Permission Required |
|-----------|---------------------|
| Send intent | Action-specific (see above) |
| Broadcast intent | Action-specific |
| Register receiver | None |
| Receive intent | None |
### 4. Lua API
```lua
-- Register to receive intents
intents.on("share", function(intent)
print("Received share from:", intent.from)
print("Type:", intent.type)
print("Data:", intent.data)
end)
-- Register with MIME type filter
intents.on("view", function(intent)
-- Handle view intent
end, {types = {"image/png", "image/jpeg"}})
-- Send intent to specific app
local success, err = intents.send("target.app.id", {
action = "share",
type = "text/plain",
data = "Hello world"
})
-- Broadcast to all handlers
local count = intents.broadcast({
action = "share",
type = "text/plain",
data = "Hello everyone"
})
-- Check if any app handles an action
local hasHandler = intents.hasReceiver("share")
-- Get list of apps that handle an action
local apps = intents.getReceivers("share")
-- Unregister all handlers for this app
intents.unregisterAll()
```
### 5. Error Handling
```lua
-- Errors raised via Lua errors
local ok, err = pcall(function()
intents.send("target.app", {action = "share", data = "test"})
end)
if not ok then
print("Error:", err) -- e.g., "no receivers for action: share"
end
```
---
## Test Cases
### Test 1: Send to Registered Receiver
```cpp
bool Test_MessageBusSendToReceiver(std::string& error_msg) {
mosis::MessageBus bus;
bool received = false;
mosis::Intent receivedIntent;
// Register receiver
bus.RegisterReceiver("receiver.app", {"share", {}}, [&](const mosis::Intent& i) {
received = true;
receivedIntent = i;
});
// Send intent
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Send("sender.app", "receiver.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::None);
EXPECT_TRUE(received);
EXPECT_TRUE(receivedIntent.action == "share");
EXPECT_TRUE(receivedIntent.data == "Hello");
EXPECT_TRUE(receivedIntent.from_app == "sender.app");
return true;
}
```
### Test 2: Block Unregistered Action
```cpp
bool Test_MessageBusBlockUnregistered(std::string& error_msg) {
mosis::MessageBus bus;
// No receivers registered
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Send("sender.app", "receiver.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::ReceiverNotFound);
EXPECT_TRUE(err.find("not found") != std::string::npos ||
err.find("no receiver") != std::string::npos);
return true;
}
```
### Test 3: Broadcast to Multiple Receivers
```cpp
bool Test_MessageBusBroadcast(std::string& error_msg) {
mosis::MessageBus bus;
int receiveCount = 0;
// Register multiple receivers for same action
bus.RegisterReceiver("app1", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
bus.RegisterReceiver("app2", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
bus.RegisterReceiver("app3", {"other", {}}, [&](const mosis::Intent&) { receiveCount++; });
// Broadcast share intent
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Broadcast("sender.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::None);
EXPECT_TRUE(receiveCount == 2); // Only app1 and app2
return true;
}
```
### Test 4: MIME Type Filtering
```cpp
bool Test_MessageBusMimeFilter(std::string& error_msg) {
mosis::MessageBus bus;
bool imageReceived = false;
bool textReceived = false;
// Register with MIME filter
bus.RegisterReceiver("image.viewer", {"view", {"image/png", "image/jpeg"}},
[&](const mosis::Intent&) { imageReceived = true; });
bus.RegisterReceiver("text.viewer", {"view", {"text/plain"}},
[&](const mosis::Intent&) { textReceived = true; });
// Send image intent
mosis::Intent imgIntent{"view", "image/png", "data", "sender"};
std::string err;
bus.Broadcast("sender", imgIntent, err);
EXPECT_TRUE(imageReceived);
EXPECT_TRUE(!textReceived);
return true;
}
```
### Test 5: Data Size Limit
```cpp
bool Test_MessageBusDataLimit(std::string& error_msg) {
mosis::MessageBus bus;
bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});
// Create oversized data (> 1MB)
std::string largeData(2 * 1024 * 1024, 'x');
mosis::Intent intent{"share", "text/plain", largeData, "sender"};
std::string err;
auto result = bus.Send("sender", "receiver", intent, err);
EXPECT_TRUE(result == mosis::MessageError::DataTooLarge);
return true;
}
```
### Test 6: Blocked App Cannot Send
```cpp
bool Test_MessageBusBlockedApp(std::string& error_msg) {
mosis::MessageBus bus;
bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});
bus.BlockApp("bad.app");
mosis::Intent intent{"share", "text/plain", "Hello", "bad.app"};
std::string err;
auto result = bus.Send("bad.app", "receiver", intent, err);
EXPECT_TRUE(result == mosis::MessageError::SenderBlocked);
return true;
}
```
### Test 7: Lua Integration
```cpp
bool Test_MessageBusLuaIntegration(std::string& error_msg) {
SandboxContext ctx = TestContext();
LuaSandbox sandbox(ctx);
mosis::MessageBus bus;
mosis::RegisterIntentsAPI(sandbox.GetState(), &bus, "test.app");
std::string script = R"lua(
-- Test that intents global exists
if not intents then
error("intents global not found")
end
if not intents.on then
error("intents.on not found")
end
if not intents.send then
error("intents.send not found")
end
if not intents.broadcast then
error("intents.broadcast not found")
end
if not intents.hasReceiver then
error("intents.hasReceiver not found")
end
if not intents.getReceivers then
error("intents.getReceivers not found")
end
if not intents.unregisterAll then
error("intents.unregisterAll not found")
end
)lua";
bool ok = sandbox.LoadString(script, "intents_test");
if (!ok) {
error_msg = "Lua test failed: " + sandbox.GetLastError();
return false;
}
return true;
}
```
---
## Acceptance Criteria
All tests must pass:
- [x] `Test_MessageBusSendToReceiver` - Send reaches registered receiver
- [x] `Test_MessageBusBlockUnregistered` - Unregistered action fails
- [x] `Test_MessageBusBroadcast` - Broadcast reaches all matching receivers
- [x] `Test_MessageBusMimeFilter` - MIME type filtering works
- [x] `Test_MessageBusDataLimit` - Data size limit enforced
- [x] `Test_MessageBusBlockedApp` - Blocked apps cannot send
- [x] `Test_MessageBusLuaIntegration` - Lua API works
---
## Dependencies
- Milestone 1 (LuaSandbox)
- Milestone 2 (PermissionGate)
- Milestone 3 (AuditLog)
---
## Notes
### Security Considerations
1. **Kernel mediation**: All messages route through MessageBus, no direct app-to-app
2. **Sender verification**: `from_app` is set by kernel, cannot be spoofed
3. **Permission checks**: Sensitive actions require permissions
4. **Size limits**: 1MB max to prevent resource exhaustion
5. **App blocking**: Misbehaving apps can be blocked
6. **Audit logging**: All inter-app communication is logged
### Privacy Features
1. **Opt-in receiving**: Apps must explicitly register for actions
2. **MIME filtering**: Receivers can filter by content type
3. **No discovery**: Apps cannot enumerate other apps (only check receivers)
---
## Next Steps
After Milestone 18 passes:
1. Milestone 19: Security Testing Suite