//! Minimal `LocalDatabaseRepository` stand-in (SDD-077). Holds *non-secret* //! state only — bookmarks, in this PoC. Used by the audit tests to prove //! SS-AUD-001 / SS-AUD-002: a secret stored via the secure-storage //! adapter never appears in the SQLite file. use std::path::Path; use rusqlite::{params, Connection}; use thiserror::Error; #[derive(Debug, Error)] pub enum LocalDbError { #[error("sqlite error: {0}")] Sqlite(#[from] rusqlite::Error), } pub struct LocalDatabaseRepository { conn: Connection, } impl LocalDatabaseRepository { pub fn open(path: &Path) -> Result { let conn = Connection::open(path)?; conn.execute_batch( "CREATE TABLE IF NOT EXISTS bookmarks ( id INTEGER PRIMARY KEY AUTOINCREMENT, server_name TEXT NOT NULL, server_host TEXT NOT NULL, identity_ref TEXT NOT NULL );", )?; Ok(Self { conn }) } /// Insert a bookmark. `identity_ref` is a *reference* (e.g. a stable /// secret name like `identity.primary`), **not** the secret itself. /// This is the SAD-067 separation in action. pub fn insert_bookmark( &self, server_name: &str, server_host: &str, identity_ref: &str, ) -> Result { self.conn.execute( "INSERT INTO bookmarks (server_name, server_host, identity_ref) VALUES (?1, ?2, ?3)", params![server_name, server_host, identity_ref], )?; Ok(self.conn.last_insert_rowid()) } /// For the audit: read the raw bytes of the underlying SQLite file /// so a test can grep for forbidden plaintext (SS-AUD-001). pub fn raw_db_bytes(path: &Path) -> std::io::Result> { std::fs::read(path) } }