Skip to content

Commit df8fd44

Browse files
SecAI-Hubclaude
andcommitted
Add agent mode service: policy-bound local autopilot (Phase 1)
New Python service on :8476 implementing supervised agent layer with deny-by-default policy engine, capability tokens, hard budgets, and storage gateway. Includes systemd sandboxing, UI proxy endpoints, OpenAPI schema, and 82 tests (all passing). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f54a285 commit df8fd44

23 files changed

Lines changed: 3603 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ jobs:
6767
python -m py_compile services/common/audit_chain.py
6868
python -m py_compile services/common/auth.py
6969
python -m py_compile services/common/mlock_helper.py
70+
python -m py_compile services/agent/agent/app.py
71+
python -m py_compile services/agent/agent/models.py
72+
python -m py_compile services/agent/agent/policy.py
73+
python -m py_compile services/agent/agent/planner.py
74+
python -m py_compile services/agent/agent/executor.py
75+
python -m py_compile services/agent/agent/storage.py
76+
python -m py_compile services/agent/agent/capabilities.py
7077
7178
- name: Test
7279
run: python -m pytest tests/ -v

docs/api.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,79 @@ Proxy an outbound request through the Airlock.
111111

112112
---
113113

114+
## Agent API (port 8476)
115+
116+
### POST /v1/task
117+
118+
Submit a new task for the agent to plan and execute.
119+
120+
- **Request body:**
121+
```json
122+
{
123+
"intent": "summarize the documents in my workspace",
124+
"mode": "standard",
125+
"workspace": ["/vault/user_docs/project"],
126+
"preferences": { "read_file": "always" }
127+
}
128+
```
129+
- **Response:** `201 Created` -- task with planned steps
130+
- **Error:** `400 Bad Request` -- missing intent or invalid mode
131+
132+
### GET /v1/task/{id}
133+
134+
Get task status and step details.
135+
136+
- **Response:** `200 OK` -- task object with steps
137+
- **Error:** `404 Not Found` -- task not found
138+
139+
### POST /v1/task/{id}/approve
140+
141+
Approve pending steps that require user confirmation.
142+
143+
- **Request body:**
144+
```json
145+
{
146+
"step_ids": ["abc123"],
147+
"approve_all": false
148+
}
149+
```
150+
- **Response:** `200 OK` -- updated task
151+
152+
### POST /v1/task/{id}/deny
153+
154+
Deny pending steps.
155+
156+
- **Request body:**
157+
```json
158+
{
159+
"step_ids": ["abc123"],
160+
"deny_all": false
161+
}
162+
```
163+
- **Response:** `200 OK` -- updated task
164+
165+
### POST /v1/task/{id}/cancel
166+
167+
Cancel a running or pending task.
168+
169+
- **Response:** `200 OK` -- task cancelled
170+
- **Error:** `409 Conflict` -- task already completed/failed/cancelled
171+
172+
### GET /v1/tasks
173+
174+
List all tasks (most recent first).
175+
176+
- **Query params:** `limit` (default 50, max 200)
177+
- **Response:** `200 OK` -- array of task objects
178+
179+
### GET /v1/modes
180+
181+
List available operating modes with descriptions.
182+
183+
- **Response:** `200 OK` -- array of mode objects (offline_only, standard, online_assisted, sensitive)
184+
185+
---
186+
114187
## UI API (port 8480)
115188

116189
### Model Management

docs/architecture.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ A 7-stage verification pipeline that every model must pass before promotion. Che
2222

2323
The active inference environment. llama-server runs promoted models from the trusted registry. The Tool Firewall gates all tool invocations through a default-deny policy. The Search Mediator (disabled by default) provides sanitized, Tor-routed web search.
2424

25-
### 5. Airlock
25+
### 5. Agent Layer
26+
27+
A policy-bound local autopilot that orchestrates bounded local workflows. The Agent (:8476) decomposes user intent into steps, evaluates each step against a deny-by-default policy engine with capability tokens and sensitivity labels, then executes approved steps through the storage gateway and tool firewall. Low-risk local actions (search, summarize, draft) run automatically; high-risk actions (outbound requests, exports, trust changes) require explicit approval. See [Agent Mode](components/agent.md) for full details.
28+
29+
### 6. Airlock
2630

2731
The controlled boundary between the appliance and the external network. Disabled by default because it represents the largest privacy risk surface. When enabled, it enforces destination allowlists, PII scanning, credential scanning, rate limiting, and HTTPS-only connections.
2832

@@ -62,6 +66,13 @@ The controlled boundary between the appliance and the external network. Disabled
6266
+--------+---------+
6367
|
6468
+--------v---------+
69+
| Agent Autopilot |
70+
| :8476 (Py) |
71+
| (planner, policy, |
72+
| storage gateway) |
73+
+--------+---------+
74+
|
75+
+--------v---------+
6576
| UI (Flask) |
6677
| :8480 (Py) |
6778
+--------+---------+
@@ -85,6 +96,11 @@ The controlled boundary between the appliance and the external network. Disabled
8596

8697
```
8798
UI (:8480)
99+
|-- Agent (:8476) [task orchestration, policy enforcement]
100+
| |-- Inference Worker [planning via LLM]
101+
| |-- Tool Firewall (:8475) [tool invocation gating]
102+
| |-- Storage Gateway [mediated file access]
103+
| +-- Airlock (:8490) [outbound requests, if enabled]
88104
|-- Inference Worker (llama-server)
89105
| |-- Registry (:8470) [model loading]
90106
| |-- Tool Firewall (:8475) [tool invocation]

docs/components/agent.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Agent Mode
2+
3+
Policy-bound local autopilot for SecAI_OS. Automates bounded local
4+
workflows while preserving the project's security and privacy posture.
5+
6+
## Design
7+
8+
The agent is a **supervised local autopilot**, not a free-roaming autonomous
9+
agent. It runs low-risk local tasks automatically and interrupts only at
10+
high-risk boundaries such as outbound requests, export actions, destructive
11+
operations, or trust-state changes.
12+
13+
### Architecture (5 components)
14+
15+
```
16+
User Intent
17+
18+
┌──────────┐
19+
│ Planner │ Decomposes intent into steps (via inference worker or heuristic)
20+
└────┬─────┘
21+
22+
┌──────────────┐
23+
│ Policy Engine│ Deny-by-default. Evaluates each step against capabilities,
24+
│ │ workspace scope, sensitivity labels, and session mode.
25+
└────┬─────────┘
26+
↓ allow / ask / deny
27+
┌──────────────┐
28+
│ Executor │ Runs approved steps with budget enforcement.
29+
│ │ Dispatches to storage gateway, tool firewall, or airlock.
30+
└────┬─────────┘
31+
32+
┌──────────────┐ ┌────────────────┐
33+
│ Storage GW │ │ Tool Firewall │
34+
│ (file access)│ │ (:8475) │
35+
└──────────────┘ └────────────────┘
36+
```
37+
38+
### Operating modes
39+
40+
| Mode | Network | File scope | Approval style |
41+
|------|---------|-----------|----------------|
42+
| **Offline-only** | Blocked | Approved workspaces | Auto for low-risk |
43+
| **Standard** (default) | Disabled unless enabled | Approved workspaces | Auto + ask |
44+
| **Online-assisted** | Airlock-mediated | Approved workspaces | Always ask for online |
45+
| **Sensitive** | Blocked | Explicitly scoped | Tighter budgets, aggressive recycling |
46+
47+
### Allow / deny matrix
48+
49+
- **Allow by default (auto)**: local search, summarize, draft, classify, report, explain security decisions
50+
- **Configurable (user preference: always / ask / never)**: file reads, file writes, tool invocations
51+
- **Hard approval required**: outbound requests, data export, trust changes, batch deletes, scope widening, new tools
52+
- **Always denied**: security setting changes
53+
54+
## Service details
55+
56+
| Property | Value |
57+
|----------|-------|
58+
| Port | 8476 |
59+
| Language | Python (Flask) |
60+
| Bind | 127.0.0.1 (loopback only) |
61+
| Systemd unit | `secure-ai-agent.service` |
62+
| Policy file | `/etc/secure-ai/policy/agent.yaml` |
63+
| Audit log | `/var/lib/secure-ai/logs/agent-audit.jsonl` |
64+
| Depends on | registry, tool-firewall, inference |
65+
66+
## API endpoints
67+
68+
| Method | Path | Description |
69+
|--------|------|-------------|
70+
| POST | `/v1/task` | Submit a new task |
71+
| GET | `/v1/task/<id>` | Get task status |
72+
| POST | `/v1/task/<id>/approve` | Approve pending steps |
73+
| POST | `/v1/task/<id>/deny` | Deny pending steps |
74+
| POST | `/v1/task/<id>/cancel` | Cancel a task |
75+
| GET | `/v1/tasks` | List tasks |
76+
| GET | `/v1/modes` | List operating modes |
77+
| GET | `/health` | Health check |
78+
79+
## Capability tokens
80+
81+
Every task run receives a scoped capability token defining:
82+
- **Readable paths**: which directories the agent may read
83+
- **Writable paths**: where the agent may write output
84+
- **Allowed tools**: which tools may be invoked through the tool firewall
85+
- **Online access**: whether outbound requests are even possible
86+
- **Sensitivity ceiling**: maximum data sensitivity level (low / medium / high)
87+
88+
## Hard budgets
89+
90+
Each task is constrained by:
91+
- Max plan steps (default: 30)
92+
- Max tool calls (default: 80)
93+
- Max tokens (default: 32,000)
94+
- Max wall-clock time (default: 600s)
95+
- Max files touched (default: 20)
96+
- Max output size (default: 1 MB)
97+
98+
Sensitive mode uses tighter limits (10 steps, 120s, 5 files).
99+
100+
## Storage gateway
101+
102+
All file access goes through the storage gateway, which:
103+
- Validates paths against the capability token scope
104+
- Blocks access to sensitive system files (`/etc/shadow`, service tokens, etc.)
105+
- Classifies file sensitivity (heuristic: SSN, email, credit card, credential patterns)
106+
- Enforces sensitivity ceiling (high-sensitivity files blocked in low-ceiling sessions)
107+
- Redacts sensitive content before any outbound use
108+
- Enforces file size limits (2 MB read, 1 MB write)
109+
110+
## Sandboxing
111+
112+
The agent systemd service uses the same defense-in-depth as other services:
113+
- `DynamicUser=yes`, `ProtectSystem=strict`, `ProtectHome=yes`
114+
- `PrivateTmp=yes`, `PrivateDevices=yes`, `NoNewPrivileges=yes`
115+
- `MemoryDenyWriteExecute=yes`, `RestrictNamespaces=yes`
116+
- `SystemCallFilter=@system-service @network-io`
117+
- `MemoryMax=512M`, `CPUQuota=50%`, `TasksMax=64`
118+
- Read-only access to vault user docs; read-write only to outputs and logs
119+
120+
## Implementation phases
121+
122+
1. **Phase 1** (current): Safe local autopilot — planner, policy engine, storage gateway, tool-firewall mediation, capability tokens, automatic low-risk workflows, UI approval flow
123+
2. **Phase 2**: Security explainability — detailed explanations for quarantine/registry/airlock decisions, per-workspace permissions, sensitivity labels, audit views
124+
3. **Phase 3**: Online-assisted mode — airlock-mediated outbound, search mediation, redaction flows, approval UX for online steps
125+
4. **Phase 4**: Stronger isolation — adversarial testing, signed releases, additional sandboxing profiles, policy bypass regression tests

files/scripts/build-services.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ for scanner in modelscan fickling garak modelaudit; do
120120
echo " WARNING: ${scanner} install failed — scanner will be skipped at runtime"
121121
done
122122

123+
# --- Agent service (policy-bound local autopilot) ---
124+
echo "Building: agent"
125+
pip3 install --prefix=/usr --no-cache-dir /tmp/services/agent 2>/dev/null || \
126+
pip3 install --prefix=/usr --break-system-packages --no-cache-dir /tmp/services/agent
127+
cat > "${INSTALL_DIR}/agent" <<'WRAPPER'
128+
#!/usr/bin/env python3
129+
from agent.app import main
130+
main()
131+
WRAPPER
132+
chmod +x "${INSTALL_DIR}/agent"
133+
echo " -> ${INSTALL_DIR}/agent"
134+
123135
# Web UI
124136
echo "Building: ui"
125137
pip3 install --prefix=/usr --no-cache-dir /tmp/services/ui 2>/dev/null || \

files/system/etc/secure-ai/config/appliance.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ services:
4242
bind: "127.0.0.1:8470"
4343
tool_firewall:
4444
bind: "127.0.0.1:8475"
45+
agent:
46+
bind: "127.0.0.1:8476"
4547
ui:
4648
bind: "127.0.0.1:8480"
4749
airlock:
@@ -55,6 +57,18 @@ services:
5557
tor:
5658
socks: "127.0.0.1:9050"
5759

60+
# Agent mode configuration (spec: SecAI_OS Agent Mode Specification)
61+
# The agent is a supervised local autopilot — not an autonomous agent.
62+
# It automates bounded local workflows and treats every online action
63+
# as a policy-gated exception routed through the airlock.
64+
agent:
65+
# Whether agent mode is available (default: true, per spec §1)
66+
enabled: true
67+
# Default operating mode: offline_only | standard | online_assisted | sensitive
68+
default_mode: "standard"
69+
# Policy file for agent-specific rules
70+
policy_path: "/etc/secure-ai/policy/agent.yaml"
71+
5872
traffic_analysis_protection:
5973
# Network traffic analysis countermeasures (M19).
6074
# Query timing randomization: random 0.5–3s delay before each search.

0 commit comments

Comments
 (0)