Engine: pasting only formats from a file leaves the destination's trust alone

Paste Special › Formats copies cell styles and merged areas. It copies no conditional formats,
formulas or validation, so it carries nothing that runs. It still marked the destination
FromFile: copying a formula cell from an opened file and pasting its formats into a new workbook
made that workbook ask before running its own active content.

Formats pastes now count as passive, like values, column widths and notes. The comment and
docs/architecture.md no longer say that pasted formats carry trust.
This commit is contained in:
prxnvt
2026-10-21 17:27:20 -04:00
parent ab27d35386
commit 0457f102a0
3 changed files with 10 additions and 6 deletions
+5 -4
View File
@@ -1183,10 +1183,11 @@ fn paste_special(s: &mut Session, p: &Json) -> Result<Json> {
*cx.sel = crate::Selection { active: at, anchor: at, ranges: vec![RangeRef::new(at, end)] };
Ok(())
})?;
// Formulas, formats (conditional formats hold formulas) and validation from an untrusted file
// leave the destination untrusted; plain values, column widths and notes carry nothing active
// (a linked paste of values still writes formulas).
let passive = matches!(what, What::ColumnWidths | What::Comments) || (!link && matches!(what, What::Values | What::ValuesAndNumberFormats));
// Formulas and validation from an untrusted file leave the destination untrusted; plain values,
// formats (cell styles and merged areas, no conditional formats), column widths and notes
// carry nothing active (a linked paste of values still writes formulas).
let passive =
matches!(what, What::Formats | What::ColumnWidths | What::Comments) || (!link && matches!(what, What::Values | What::ValuesAndNumberFormats));
if !same_doc && !passive {
let d = s.doc_mut()?;
d.trust = d.trust.receive(clip.trust);
+3
View File
@@ -472,6 +472,9 @@ fn pasting_from_a_file_carries_its_trust() {
// Values carry nothing that runs.
s.execute("edit.pasteSpecial", json!({"what": "values", "at": "B1"})).unwrap();
assert_eq!(trust(&s), Trust::Local);
// Formats carry cell styles and merged areas, nothing that runs.
s.execute("edit.pasteSpecial", json!({"what": "formats", "at": "B3"})).unwrap();
assert_eq!(trust(&s), Trust::Local);
// A linked paste of values still writes formulas.
s.execute("edit.pasteSpecial", json!({"what": "values", "link": true, "at": "B2"})).unwrap();
assert_eq!(trust(&s), Trust::FromFile);
+2 -2
View File
@@ -59,8 +59,8 @@ Actions made of many commands (macros, a debugger that runs one step per call) u
Commands run by other commands are not recorded, and the buffer is independent of the journal
(Automate › Record Actions still records through the journal).
- **Document trust.** `DocState::trust` is `Local` for workbooks made in the session and
`FromFile` for workbooks opened from a file, and for workbooks that received formulas, formats
or validation pasted from one. Active content in a `FromFile` workbook asks before it runs.
`FromFile` for workbooks opened from a file, and for workbooks that received formulas or
validation pasted from one. Active content in a `FromFile` workbook asks before it runs.
- **Workbook data in hidden names** (`cmd/stash.rs`). An item is split over hidden
workbook-scope names `_gc_<key>_0`, `_gc_<key>_1`, … of string literals within Excel's 255- and
8,192-character limits, so it survives an xlsx round trip. The older single-name `_sc_<key>`