Files
NotesAgentic/frontend/src-tauri/tests/core_process.rs
T

124 lines
4.2 KiB
Rust

//! Executes the real worktree Core, with no personal data or external Provider.
use notesagent_host::core::CoreSupervisor;
use notesagent_host::credentials::{CredentialBroker, CredentialId, Scope};
use std::path::Path;
use std::sync::{Arc, Mutex};
use zeroize::Zeroizing;
#[test]
fn real_python_core_authenticates_and_rotates_generation() {
let backend = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../backend")
.canonicalize()
.unwrap();
let python = backend.join(if cfg!(windows) {
".venv/Scripts/python.exe"
} else {
".venv/bin/python"
});
assert!(
python.is_file(),
"Create the isolated backend environment with uv sync --frozen"
);
let temp = tempfile::tempdir().unwrap();
let mut first = CoreSupervisor::new(
python.clone(),
vec!["-m".into(), "app.sidecar".into()],
backend.clone(),
temp.path().join("one"),
);
let request = first.request_session("/health").unwrap();
assert!(first.available());
assert!(request.url.starts_with("http://127.0.0.1:"));
assert!(!request.url.contains(request.authorization.as_str()));
let mut second = CoreSupervisor::new(
python,
vec!["-m".into(), "app.sidecar".into()],
backend,
temp.path().join("two"),
);
let other = second.request_session("/health").unwrap();
assert_ne!(request.generation, other.generation);
assert_ne!(request.authorization.as_str(), other.authorization.as_str());
drop(first);
let endpoint = request
.url
.trim_start_matches("http://")
.trim_end_matches("/health");
assert!(std::net::TcpStream::connect(endpoint).is_err());
}
#[test]
fn real_core_credential_api_uses_host_stronghold_without_plaintext_response() {
use std::io::{Read, Write};
let backend = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../backend")
.canonicalize()
.unwrap();
let python = backend.join(if cfg!(windows) {
".venv/Scripts/python.exe"
} else {
".venv/bin/python"
});
let temp = tempfile::tempdir().unwrap();
let broker = Arc::new(Mutex::new(CredentialBroker::new(
temp.path().join("stronghold.v1"),
)));
broker
.lock()
.unwrap()
.unlock(Zeroizing::new(b"controlled-fixture-password".to_vec()))
.unwrap();
let handler = broker.clone();
let mut core = CoreSupervisor::new(
python,
vec!["-m".into(), "app.sidecar".into()],
backend,
temp.path().join("core"),
)
.with_broker(Arc::new(move |request| {
handler.lock().unwrap().dispatch(request)
}));
let session = core
.request_session("/api/credentials/fixture-provider")
.unwrap();
let endpoint = session
.url
.trim_start_matches("http://")
.split('/')
.next()
.unwrap();
let body = r#"{"api_key":"fixture-credential-via-host-pipe"}"#;
let mut socket = std::net::TcpStream::connect(endpoint).unwrap();
socket
.set_read_timeout(Some(std::time::Duration::from_secs(30)))
.unwrap();
write!(socket, "PUT /api/credentials/fixture-provider HTTP/1.1\r\nHost: {endpoint}\r\nAuthorization: {}\r\nX-Core-Generation: {}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", session.authorization.as_str(), session.generation, body.len()).unwrap();
let mut response = String::new();
socket.read_to_string(&mut response).unwrap();
assert!(
response.starts_with("HTTP/1.1 200"),
"credential API did not succeed"
);
assert!(!response.contains("fixture-credential-via-host-pipe"));
let id = CredentialId {
scope: Scope::Provider,
id: "fixture-provider".into(),
};
assert_eq!(
broker
.lock()
.unwrap()
.resolve(&Scope::Provider, &id)
.unwrap()
.as_deref()
.map(|s| s.as_slice()),
Some(b"fixture-credential-via-host-pipe".as_slice())
);
assert!(!temp.path().join("core/credentials/master.key").exists());
assert!(!temp
.path()
.join("core/credentials/credentials.json")
.exists());
}