-
Notifications
You must be signed in to change notification settings - Fork 0
security: fail generic cleanup closed without object-bound recycle #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
79c6e4e
test: expose generic cleanup recycle race
seonghobae 99baa11
fix: fail generic cleanup closed without object-bound recycle
seonghobae 7497329
fix: route generic cleanup through fail-closed authority
seonghobae 04bdb50
Merge protected main into generic cleanup security line
seonghobae 033c433
fix: avoid duplicate Tauri clean_paths command symbol
seonghobae 50b1076
merge: converge generic cleanup authority with protected main
seonghobae d29f3fc
merge: converge generic cleanup authority with current main
seonghobae 5919c44
merge: converge generic cleanup authority with protected main
seonghobae b32eb8d
test: preserve object-bound dev artifact cleanup route
seonghobae 9bccaae
fix: preserve object-bound dev artifact cleanup route
seonghobae a20c4f3
merge: converge generic cleanup authority with current main
seonghobae e2ffab7
merge: converge generic cleanup authority with current main
seonghobae 8250b3d
merge: converge generic cleanup with current main
seonghobae 034e29c
merge: converge generic cleanup authority with current main
seonghobae 844520c
merge: converge generic cleanup authority with current main
seonghobae 8d88051
merge: converge generic cleanup authority with current main
seonghobae dc5ce7f
merge: converge generic cleanup authority onto current main
seonghobae a54159e
security: converge generic cleanup fail-closed authority onto current…
seonghobae a875e97
test: keep generic cleanup handler coverage-visible
seonghobae 6421098
fix: keep generic cleanup fail-closed handler coverage-visible
seonghobae 3864a8d
merge: converge fail-closed generic cleanup onto current main
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| use crate::commands::CleanResult; | ||
|
|
||
| const IDENTITY_BOUND_RECYCLE_UNAVAILABLE: &str = | ||
| "generic-cleanup-identity-bound-recycle-unavailable"; | ||
|
|
||
| fn clean_paths_inner(paths: &[String]) -> Vec<CleanResult> { | ||
| paths | ||
| .iter() | ||
| .map(|path| CleanResult { | ||
| path: path.clone(), | ||
| ok: false, | ||
| error: IDENTITY_BOUND_RECYCLE_UNAVAILABLE.into(), | ||
| }) | ||
| .collect() | ||
| } | ||
|
|
||
| /// Fail generic cleanup closed until the final reversible recycle primitive can remain bound to | ||
| /// the exact filesystem object that was authorized. Path revalidation cannot close a same-user | ||
| /// rename/symlink replacement window when the operating-system trash API consumes a pathname. | ||
| /// | ||
| /// The Rust function name is intentionally distinct from the legacy command wrapper. Tauri 2.11+ | ||
| /// maps this handler back to the stable external `clean_paths` IPC name without generating the | ||
| /// duplicate command macro symbol that the former same-named Rust function produced. The handler | ||
| /// remains compiled in coverage builds so instrumentation measures the same fail-closed command | ||
| /// surface that ships to customers. | ||
| #[tauri::command(rename = "clean_paths")] | ||
| pub fn fail_closed_clean_paths(paths: Vec<String>) -> Result<Vec<CleanResult>, String> { | ||
| Ok(clean_paths_inner(&paths)) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
| use std::fs; | ||
|
|
||
| #[test] | ||
| fn refusal_is_stable_for_every_requested_path() { | ||
| let paths = vec!["first".to_string(), "second".to_string()]; | ||
|
|
||
| let results = clean_paths_inner(&paths); | ||
|
|
||
| assert_eq!(results.len(), 2); | ||
| assert_eq!(results[0].path, "first"); | ||
| assert!(!results[0].ok); | ||
| assert_eq!(results[0].error, IDENTITY_BOUND_RECYCLE_UNAVAILABLE); | ||
| assert_eq!(results[1].path, "second"); | ||
| assert!(!results[1].ok); | ||
| assert_eq!(results[1].error, IDENTITY_BOUND_RECYCLE_UNAVAILABLE); | ||
| } | ||
|
|
||
| #[test] | ||
| fn public_handler_returns_the_same_fail_closed_results() { | ||
| let results = fail_closed_clean_paths(vec!["customer-file".to_string()]).unwrap(); | ||
|
|
||
| assert_eq!(results.len(), 1); | ||
| assert_eq!(results[0].path, "customer-file"); | ||
| assert!(!results[0].ok); | ||
| assert_eq!(results[0].error, IDENTITY_BOUND_RECYCLE_UNAVAILABLE); | ||
| } | ||
|
|
||
| #[test] | ||
| fn refusal_does_not_mutate_the_named_filesystem_object() { | ||
| let tmp = tempfile::tempdir().unwrap(); | ||
| let victim = tmp.path().join("keep.bin"); | ||
| fs::write(&victim, b"keep").unwrap(); | ||
| let paths = vec![victim.to_string_lossy().into_owned()]; | ||
|
|
||
| let results = clean_paths_inner(&paths); | ||
|
|
||
| assert_eq!(results.len(), 1); | ||
| assert!(!results[0].ok); | ||
| assert_eq!(results[0].error, IDENTITY_BOUND_RECYCLE_UNAVAILABLE); | ||
| assert_eq!(fs::read(&victim).unwrap(), b"keep"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn empty_request_is_a_noop() { | ||
| assert!(clean_paths_inner(&[]).is_empty()); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| use std::fs; | ||
| use std::path::PathBuf; | ||
|
|
||
| fn source(path: &str) -> String { | ||
| let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
| fs::read_to_string(root.join(path)).expect("repository source must be readable") | ||
| } | ||
|
|
||
| #[test] | ||
| fn generic_cleanup_route_must_fail_closed_before_path_consuming_recycle() { | ||
| let lib = source("src/lib.rs"); | ||
| let cleanup = source("src/generic_cleanup.rs"); | ||
|
|
||
| assert!( | ||
| lib.contains("mod generic_cleanup;"), | ||
| "the cleanup authority must live in its own fail-closed module" | ||
| ); | ||
| assert!( | ||
| lib.contains("generic_cleanup::fail_closed_clean_paths,"), | ||
| "the Tauri clean_paths route must use the fail-closed authority" | ||
| ); | ||
| assert!( | ||
| !lib.contains("commands::clean_paths,"), | ||
| "the path-consuming legacy cleanup route must not be registered" | ||
| ); | ||
| assert!( | ||
| cleanup.contains("#[tauri::command(rename = \"clean_paths\")]"), | ||
| "the fail-closed Rust handler must preserve the stable clean_paths IPC command name" | ||
| ); | ||
| assert!( | ||
| cleanup.contains("pub fn fail_closed_clean_paths("), | ||
| "the fail-closed Rust handler name must remain distinct from the legacy command macro" | ||
| ); | ||
| assert!( | ||
| !cleanup.contains( | ||
| "#[cfg(not(coverage))]\n#[tauri::command(rename = \"clean_paths\")]" | ||
| ), | ||
| "coverage builds must retain the shipped fail-closed clean_paths handler instead of compiling a different command surface" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn generic_cleanup_repair_must_not_unregister_identity_bound_dev_artifact_cleanup() { | ||
| let lib = source("src/lib.rs"); | ||
|
|
||
| assert!( | ||
| lib.contains("commands::clean_dev_artifacts,"), | ||
| "generic clean_paths hardening must preserve the separately object-bound clean_dev_artifacts IPC route" | ||
| ); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.