docs: terminal file viewer structure and capability census
Add CLAUDE.md structure notes for the viewer/ frontend and file_viewer/ backend, plus a Key Conventions reminder that a new local window needs its own capability file and lib.rs's on_window_event guard. Extend default.json's threat-model census to name file-viewer.json and its allow-destroy grant. Tighten the capability test in file_viewer/mod.rs from a substring check to a parsed serde_json assertion of the exact windows list and permission set for both capability files, per Task 12's controller ruling. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -45,7 +45,53 @@ mod tests {
|
||||
assert!(!html.contains("<style"), "an inline <style> makes Tauri add a style nonce, which disables 'unsafe-inline' and breaks CodeMirror");
|
||||
let vite = std::fs::read_to_string(app_dir.join("vite.config.ts")).expect("vite.config.ts");
|
||||
assert!(vite.contains("viewer.html"), "vite.config.ts must list viewer.html in build.rollupOptions.input");
|
||||
let cap = std::fs::read_to_string(app_dir.join("src-tauri/capabilities/file-viewer.json")).expect("capability");
|
||||
assert!(cap.contains("\"file-viewer-*\"") && cap.contains("core:window:allow-destroy"));
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct Capability {
|
||||
windows: Vec<String>,
|
||||
permissions: Vec<String>,
|
||||
}
|
||||
|
||||
/// Task 12: a substring check on the capability JSON (the form this test used to take)
|
||||
/// only proves a permission string appears *somewhere* in the file — it would not catch
|
||||
/// `windows` widened past `file-viewer-*`, nor an extra grant slipped in beside the ones
|
||||
/// this window actually needs. Parse both capability files and pin `windows`/`permissions`
|
||||
/// exactly, so a later widening of either file is a failing test, not a silent threat-model
|
||||
/// drift — this file *is* the reviewed threat model of record (see its own description).
|
||||
#[test]
|
||||
fn the_viewer_capability_grants_exactly_the_reviewed_windows_and_permissions() {
|
||||
let app_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("..");
|
||||
let raw = std::fs::read_to_string(app_dir.join("src-tauri/capabilities/file-viewer.json"))
|
||||
.expect("capabilities/file-viewer.json");
|
||||
let cap: Capability = serde_json::from_str(&raw).expect("file-viewer.json must be valid JSON");
|
||||
|
||||
assert_eq!(cap.windows, vec!["file-viewer-*"]);
|
||||
|
||||
let mut permissions = cap.permissions;
|
||||
permissions.sort();
|
||||
assert_eq!(
|
||||
permissions,
|
||||
vec![
|
||||
"core:event:allow-listen",
|
||||
"core:event:allow-unlisten",
|
||||
"core:webview:allow-internal-toggle-devtools",
|
||||
"core:window:allow-destroy",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// The main window's capability file must stay scoped to `main` — a `windows` list that
|
||||
/// grew to include `file-viewer-*` would hand every viewer window the dialog/store surface
|
||||
/// `default.json` grants `main`, which is a much larger IPC surface than the one
|
||||
/// `file-viewer.json` was deliberately kept small.
|
||||
#[test]
|
||||
fn the_default_capability_is_scoped_to_the_main_window_only() {
|
||||
let app_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("..");
|
||||
let raw = std::fs::read_to_string(app_dir.join("src-tauri/capabilities/default.json"))
|
||||
.expect("capabilities/default.json");
|
||||
let cap: Capability = serde_json::from_str(&raw).expect("default.json must be valid JSON");
|
||||
|
||||
assert_eq!(cap.windows, vec!["main"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user