Architecture • Security Model
Security Overview
RTQ's security architecture delegates containment to platform isolation tools, computes risk authoritatively, and mandates explicit capability registration. Authorizations are represented as short-lived, single-use, cryptographically-signed tickets.
e179d2b.Pipeline Layers
1. Capability Registry
INV-01Every operation must be explicitly registered before execution. Unregistered capability names return decision: 'denied'.
2. Risk Engine
INV-04RTQ evaluates risk authoritatively. Caller claimedRisk cannot lower declared risk ratings.
3. Policy Rules
INV-03Default-deny evaluation. A missing matching rule evaluates to decision: 'deny'.
4. Clarification
Bounded TurnsWhen a capability requires parameters not provided, RTQ prompts with structured questions rather than guessing.
5. Approval
INV-12Human or device challenge-response via HMAC-SHA256-signed, single-use authorization tickets.
6. Platform Sandbox
INV-07Execution containment is delegated to platform security mechanisms (macOS Seatbelt, Linux bubblewrap, Windows AppContainer).
7. Redacted Audit
INV-08Structured audit events with HMAC integrity. Sensitive environment keys and tokens are stripped.
Tested Core Properties
- •Explicit Surface: Only registered capabilities can execute. Unknown capabilities return code: "capability.not_registered" (INV-01).
- •Default Deny: A missing policy rule is a denial, never an implicit allow (INV-03).
- •Authoritative Risk: Caller claims cannot lower risk in tested authorization paths (INV-04).
- •Single-Use Tickets: HMAC-SHA256, bound to exact operation parameters. Second redemption returns ok: false (INV-09).
- •Fail-Closed Sandbox Initiation: If the platform sandbox backend cannot be initialized, execution halts.
Code Example
rtq.registerCapability({
name: "files.delete",
version: 1,
inputSchema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] },
risk: { base: "high", factors: ["irreversible"] },
execute: async (ctx, input) => {
// Executes inside OS sandbox with verified ticket
await fs.unlink(input.path);
return { ok: true };
},
});