1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! # LocalGPT Security Module
//!
//! Central security module for LocalGPT. This file is the **front door**
//! for security auditing — all security-critical types, constants, and
//! functions are re-exported here.
//!
//! ## Architecture
//!
//! ```text
//! ┌──────────────────────────────────────────────────────────────────┐
//! │ localgpt.rs (you are here) │
//! │ Public API facade & documentation │
//! ├────────────────┬───────────────┬──────────┬─────────────────────┤
//! │ policy.rs │ signing.rs │ audit.rs │ protected_files.rs │
//! │ Load, verify, │ Device key, │ Append- │ Agent write deny │
//! │ sanitize │ HMAC-SHA256, │ only log │ list for security- │
//! │ pipeline │ manifest │ + hash │ critical files │
//! │ │ │ chain │ │
//! ├────────────────┴───────────────┴──────────┴─────────────────────┤
//! │ suffix.rs — Hardcoded security suffix (always last in context) │
//! └──────────────────────────────────────────────────────────────────┘
//! ```
//!
//! ## Security Model
//!
//! 1. **Additive only**: The user's `LocalGPT.md` policy can tighten
//! restrictions on top of the built-in safety rules. It cannot
//! weaken or override the hardcoded security suffix.
//!
//! 2. **Fail closed**: Any verification failure (unsigned, tampered,
//! corrupted manifest, suspicious content) causes the system to
//! fall back to hardcoded-only security. The agent never operates
//! with a compromised policy.
//!
//! 3. **Tamper-evident**: Policies are signed with HMAC-SHA256 using a
//! device-local key stored outside the workspace. The manifest
//! includes both a quick SHA-256 content hash and the HMAC. An
//! append-only audit log with hash chaining records all security
//! events.
//!
//! 4. **Agent-proof**: A protected files list blocks the agent from
//! writing to `LocalGPT.md`, the manifest, the device key, and
//! the audit log via `write_file`/`edit_file` tools. Bash commands
//! get a best-effort heuristic check (true enforcement requires
//! OS-level sandboxing).
//!
//! 5. **Recency-reinforced**: The hardcoded security suffix is always
//! the last content in the context window, exploiting transformer
//! recency bias to keep security rules in the model's high-attention
//! zone even in long sessions.
//!
//! ## Quick Start
//!
//! ```rust,ignore
//! use localgpt::security::{
//! load_and_verify_policy, PolicyVerification,
//! build_ending_security_block,
//! append_audit_entry, AuditAction,
//! };
//!
//! // At session start — verify the policy:
//! let result = load_and_verify_policy(&workspace_path, &state_dir);
//! let user_policy = match result {
//! PolicyVerification::Valid(content) => Some(content),
//! PolicyVerification::TamperDetected => {
//! eprintln!("⚠ LocalGPT.md tampered. Using defaults.");
//! append_audit_entry(
//! &state_dir, AuditAction::TamperDetected, "", "session_start"
//! ).ok();
//! None
//! }
//! _ => None,
//! };
//!
//! // At context assembly — always append the security block last:
//! let block = build_ending_security_block(user_policy.as_deref());
//! ```
//!
//! ## File Hierarchy
//!
//! ```text
//! ~/.localgpt/ # State directory
//! ├── .device_key # 32-byte HMAC key (0600)
//! ├── .security_audit.jsonl # Append-only audit log
//! └── workspace/
//! ├── LocalGPT.md # User security policy
//! └── .localgpt_manifest.json # HMAC signature manifest
//! ```
//!
//! ## Threat Model
//!
//! | Threat | Defense Layer |
//! |--------|--------------|
//! | Agent writes to `LocalGPT.md` via tool | Protected files deny list |
//! | Agent writes via `bash` | Heuristic check + OS sandbox (separate) |
//! | Injected content in policy file | Sanitization pipeline (blocking) |
//! | Modified policy after signing | HMAC verification |
//! | Attacker modifies manifest too | HMAC requires device key (outside workspace) |
//! | Policy weakens hardcoded rules | Hardcoded suffix always last in context |
//! | Policy floods context window | 4096 char limit |
//! | Audit log tampered | Hash chain + state dir location |
// ── Policy Verification ─────────────────────────────────────────────
pub use ;
// ── Signing & Integrity ─────────────────────────────────────────────
pub use ;
// ── Audit Log ───────────────────────────────────────────────────────
pub use ;
// ── Protected Files ─────────────────────────────────────────────────
pub use ;
// ── Context Window Suffix ───────────────────────────────────────────
pub use ;
// ── Constants ───────────────────────────────────────────────────────
/// The filename for the user-editable security policy.
///
/// This file lives in the workspace alongside `MEMORY.md`, `HEARTBEAT.md`,
/// and other markdown files. It follows the same plain-markdown convention.
pub const POLICY_FILENAME: &str = "LocalGPT.md";