diff --git a/corpus/native-protected-boundaries/README.md b/corpus/native-protected-boundaries/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e45118c5733909412024acf32b83041f8f1a9cba
--- /dev/null
+++ b/corpus/native-protected-boundaries/README.md
@@ -0,0 +1,20 @@
+# Native protected attachment boundaries
+
+Synthetic OneNote 2010 section with an exact known password in
+[manifest.json](manifest.json), including a supplementary Unicode character and a
+combining mark. All pages and attachments were generated by native OneNote.
+[The generator](../../tools/native/external-assets.ps1) accepts the recorded lengths.
+
+The notebook is the native protected image. `read/` contains an independent
+fresh-clone, empty-cache unlock oracle. Its `environment.json` says `cold: false`
+because the read reused the cache that the preceding isolated cold-open and
+unlock step established; that step is recorded separately in the manifest.
+
+Attachment plaintext is reproducible: repeat the 1024-byte block whose byte at
+index `i` is `i % 251`, truncated to the recorded length. Native exported hashes
+are in `read/payloads.json`; no second copy of those generated bytes is retained.
+The zero-length attachment has a zero-length stored payload even when protected.
+
+The initially rejected UI attempt is excluded. Source notebooks and personal
+profiles were never edited. This fixture establishes native 2010 behavior for
+these inputs; its password and contents are deliberately public.
diff --git a/corpus/native-protected-boundaries/manifest.json b/corpus/native-protected-boundaries/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..410335e16225a63efea46b167a61e13e202763a2
--- /dev/null
+++ b/corpus/native-protected-boundaries/manifest.json
@@ -0,0 +1,113 @@
+{
+ "captured_utc": "2026-09-08T03:41:36.733670+00:00",
+ "native_build": "14.0.4763.1000",
+ "password": "native-payloads-🦀-é",
+ "generator": "../../tools/native/external-assets.ps1",
+ "lengths": [
+ 0,
+ 1,
+ 15,
+ 16,
+ 17,
+ 4095,
+ 4096,
+ 4097,
+ 65537,
+ 1048577
+ ],
+ "native_pages": 11,
+ "operations": [
+ "Native generated synthetic attachment pages; clean image retained before protection.",
+ "Set password in OneNote UI on owned clone; native lock and unlock passed.",
+ "Fresh clone and isolated native cache; observed locked section and unlocked with the exact fixture password.",
+ "Native cold-read returned all 11 pages; titles and text matched the pre-protection capture; every attachment matched byte for byte.",
+ "Both owned clones removed."
+ ],
+ "cold_cache": {
+ "pages": 11,
+ "hostname": "ONE-M6-139963EF",
+ "cold": true
+ },
+ "files": [
+ {
+ "path": "notebook/Open Notebook.onetoc2",
+ "bytes": 4936,
+ "sha256": "bc2400e03c8ae5f309ddb2a1640f54a4ed2b02127b99b7599e2899e7f399773a"
+ },
+ {
+ "path": "notebook/synthetic.one",
+ "bytes": 1235272,
+ "sha256": "d490a6f6d27a79e9c726a958ab6cdc70a49a28d27fe8fdd19619d85e622619bd"
+ },
+ {
+ "path": "read/environment.json",
+ "bytes": 165,
+ "sha256": "d2a40090b6074bef02f6b3267436397b37072cd792d070d237451163ec71ae0c"
+ },
+ {
+ "path": "read/hierarchy.xml",
+ "bytes": 2597,
+ "sha256": "dcc0305a7d8c5d1c5873908811399b56af64200c807503c297d236cf74cb4794"
+ },
+ {
+ "path": "read/page-000.xml",
+ "bytes": 1699,
+ "sha256": "88bf95c8482a696571b812bd82773442a2000d05b0dd92772316ae96485c2dfc"
+ },
+ {
+ "path": "read/page-001.xml",
+ "bytes": 1699,
+ "sha256": "c83d007a3bccffd34b5e565b3e09f9f12faf84d934311be876f9c7344b0adc00"
+ },
+ {
+ "path": "read/page-002.xml",
+ "bytes": 1703,
+ "sha256": "7c925ccdb1f84440afb2e7b64beaf93fad8373fad80a71e279c988ac1c7d47f0"
+ },
+ {
+ "path": "read/page-003.xml",
+ "bytes": 1703,
+ "sha256": "fd31e47e9b51a2f02327c220682967d6b2b492787ddaaf1c4af36755d5913532"
+ },
+ {
+ "path": "read/page-004.xml",
+ "bytes": 1703,
+ "sha256": "78b1b2f4fe7cc9ee4f8d3830e3b01e8ae1a58060833d85a33a7e7a017022d7a6"
+ },
+ {
+ "path": "read/page-005.xml",
+ "bytes": 1711,
+ "sha256": "e24344d38c142b640f86ce586cdff9ff7b1fccda019253a76e246bc68cc4ec1f"
+ },
+ {
+ "path": "read/page-006.xml",
+ "bytes": 1711,
+ "sha256": "33e0703d598f63fa6caa2c13429a3a33c7930b1cc5fd84d808f2ade8e8782297"
+ },
+ {
+ "path": "read/page-007.xml",
+ "bytes": 1711,
+ "sha256": "e2c1d3efebba92924533c00f8c1f071c81b4a834e494138c4a26640f7f825c49"
+ },
+ {
+ "path": "read/page-008.xml",
+ "bytes": 1715,
+ "sha256": "73b09d4378e5d31faf07303085a0d2e127f878b35ada88ec6c4d26caa8ef4993"
+ },
+ {
+ "path": "read/page-009.xml",
+ "bytes": 1723,
+ "sha256": "2c06ec16c7f5933d471df036ea4238254e6f537f92c5187f5cb854e45c4f8e3f"
+ },
+ {
+ "path": "read/page-010.xml",
+ "bytes": 1235,
+ "sha256": "54f597866ce44693af9f947f7a2f226c06b326b35f420422083e453d1d6eab6a"
+ },
+ {
+ "path": "read/payloads.json",
+ "bytes": 3280,
+ "sha256": "cfbb46f2a69ad78acf9459826456d23b0c008b8920919a2ccf938df36d4b5701"
+ }
+ ]
+}
diff --git a/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2 b/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2
new file mode 100644
index 0000000000000000000000000000000000000000..26949b307d50fd81e89349e2ffbf15b27898bf6e
Binary files /dev/null and b/corpus/native-protected-boundaries/notebook/Open Notebook.onetoc2 differ
diff --git a/corpus/native-protected-boundaries/notebook/synthetic.one b/corpus/native-protected-boundaries/notebook/synthetic.one
new file mode 100644
index 0000000000000000000000000000000000000000..798ee1d0f1dff352a7602cf1c544744a3525e469
Binary files /dev/null and b/corpus/native-protected-boundaries/notebook/synthetic.one differ
diff --git a/corpus/native-protected-boundaries/read/environment.json b/corpus/native-protected-boundaries/read/environment.json
new file mode 100644
index 0000000000000000000000000000000000000000..4677c0fd9e2d94f924a53259789aba82b7d6dd95
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/environment.json
@@ -0,0 +1,7 @@
+{
+ "powershell": "5.1.14409.1005",
+ "schema": "xs2010",
+ "hostname": "ONE-M6-139963EF",
+ "cold": false,
+ "onenote": "14.0.4763.1000"
+}
diff --git a/corpus/native-protected-boundaries/read/hierarchy.xml b/corpus/native-protected-boundaries/read/hierarchy.xml
new file mode 100644
index 0000000000000000000000000000000000000000..70874a962ab127bf23c44ab28aa08441cc4bef33
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/hierarchy.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-000.xml b/corpus/native-protected-boundaries/read/page-000.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2be7829609d2b467f47723bf1c36209c15f6619b
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-000.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-001.xml b/corpus/native-protected-boundaries/read/page-001.xml
new file mode 100644
index 0000000000000000000000000000000000000000..08f6b1710de0c19774ce1ee3157443a211ad71fc
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-001.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-002.xml b/corpus/native-protected-boundaries/read/page-002.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7402d944b4efc3122cc24cd56d474c3093f32ddd
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-002.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-003.xml b/corpus/native-protected-boundaries/read/page-003.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8280934011f002963d898564374cb8ae4c44cfe3
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-003.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-004.xml b/corpus/native-protected-boundaries/read/page-004.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cad0c3b55a9825fad71fa9bf4d91a24ccfb076fc
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-004.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-005.xml b/corpus/native-protected-boundaries/read/page-005.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f215c5fd5b2d7171fe034b9ab23cbf83a37e5b0a
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-005.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-006.xml b/corpus/native-protected-boundaries/read/page-006.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2ee987370ac710518b3617181352e639a0a380c4
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-006.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-007.xml b/corpus/native-protected-boundaries/read/page-007.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9b791699877156f8f6c93192c17609812541832a
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-007.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-008.xml b/corpus/native-protected-boundaries/read/page-008.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7287b96ebc2c6c0b67481fa3e185d7523dc5875c
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-008.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-009.xml b/corpus/native-protected-boundaries/read/page-009.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fcd1a97a88622f061af0b8fe289efbca84f8ade6
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-009.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/page-010.xml b/corpus/native-protected-boundaries/read/page-010.xml
new file mode 100644
index 0000000000000000000000000000000000000000..508998cce55ffe2ef27dfd50895b93196071856e
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/page-010.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/corpus/native-protected-boundaries/read/payloads.json b/corpus/native-protected-boundaries/read/payloads.json
new file mode 100644
index 0000000000000000000000000000000000000000..d7c8f39c63fc29c2b9fbe1197d07cc7c19ce8cfd
--- /dev/null
+++ b/corpus/native-protected-boundaries/read/payloads.json
@@ -0,0 +1,82 @@
+[
+ {
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "name": "0.bin",
+ "object": "{0B7E4970-D3E3-01A1-25E0-745DEE575203}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{12}{B0}",
+ "bytes": 0
+ },
+ {
+ "sha256": "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
+ "name": "1.bin",
+ "object": "{89F9F232-AB92-07AB-39A0-579A47A5F10A}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{15}{B0}",
+ "bytes": 1
+ },
+ {
+ "sha256": "7071fc3188fde7e7e500d4768f1784bede1a22e991648dcab9dc3219acff1d4c",
+ "name": "15.bin",
+ "object": "{A5CFC542-F990-057E-367A-028A57D773EA}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{18}{B0}",
+ "bytes": 15
+ },
+ {
+ "sha256": "be45cb2605bf36bebde684841a28f0fd43c69850a3dce5fedba69928ee3a8991",
+ "name": "16.bin",
+ "object": "{D01E8920-2805-0083-3721-95BCC8E4167F}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{21}{B0}",
+ "bytes": 16
+ },
+ {
+ "sha256": "3e5718fea51a8f3f5baca61c77afab473c1810f8b9db330273b4011ce92c787e",
+ "name": "17.bin",
+ "object": "{97C3EBA8-DDD3-0A4F-1E9C-683127C71288}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{24}{B0}",
+ "bytes": 17
+ },
+ {
+ "sha256": "925128da639768d0475745fe9a9f64762cde4124250d33eeadfa3fa59ade26ba",
+ "name": "4095.bin",
+ "object": "{741633FC-036D-0C74-320F-8ADC38E0A19E}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{27}{B0}",
+ "bytes": 4095
+ },
+ {
+ "sha256": "d836371f66ce824353fbe3fbcee019fd534c02e3afaf4266d6dacb424acb5ac1",
+ "name": "4096.bin",
+ "object": "{221F2011-02E3-0DFF-30DA-32B887343A0E}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{30}{B0}",
+ "bytes": 4096
+ },
+ {
+ "sha256": "e17ccd8f53701462eeb137b59b9f839b0f1da9b5ed8721ac65540eff10965c91",
+ "name": "4097.bin",
+ "object": "{6FC97252-6851-027D-2C2F-02DD4D1043A5}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{33}{B0}",
+ "bytes": 4097
+ },
+ {
+ "sha256": "dc8608b73169191bf61e580637df32af153784c4e63748134fd4ab85afcc2d40",
+ "name": "65537.bin",
+ "object": "{BB722167-561D-0EB5-282A-227BB9601E32}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{36}{B0}",
+ "bytes": 65537
+ },
+ {
+ "sha256": "e0bf9215397fdc4f1046c58bcbab5e927b5cab719f17ac3a7312a393cd2d5d33",
+ "name": "1048577.bin",
+ "object": "{B986C7A4-513F-086A-093A-A55963EAD509}{19}{B0}",
+ "kind": "InsertedFile",
+ "page": "{29453F44-AA0E-0CBE-13F7-7684DA3DB9EB}{39}{B0}",
+ "bytes": 1048577
+ }
+]
\ No newline at end of file
diff --git a/crates/onestore/tests/document.rs b/crates/onestore/tests/document.rs
index e44ced8614d1c64700372eb7c52af03124e22eaa..997d6b84477bf30521c8a0f4b39bdb89bd7278cc 100644
--- a/crates/onestore/tests/document.rs
+++ b/crates/onestore/tests/document.rs
@@ -438,21 +438,25 @@ fn native_unicode_table_assets_and_coordinates_are_typed() {
#[test]
fn encrypted_content_is_accounted_without_fabricated_plaintext() {
- let bytes =
- fs::read("../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one").unwrap();
- let store = Store::parse(&bytes).unwrap();
- let index = RevisionIndex::parse(&store).unwrap();
- let document = Document::parse(&index).unwrap();
- assert!(!document.spaces.is_empty());
- let nodes: Vec<_> = document
- .spaces
- .values()
- .flat_map(|s| s.revisions.values())
- .flat_map(|r| r.nodes.values())
- .collect();
- assert!(!nodes.is_empty());
- for node in nodes {
- assert!(matches!(node.kind, Kind::Encrypted { ciphertext } if !ciphertext.is_empty()));
+ for path in [
+ "../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one",
+ "../../corpus/native-protected-boundaries/notebook/synthetic.one",
+ ] {
+ let bytes = fs::read(path).unwrap();
+ let store = Store::parse(&bytes).unwrap();
+ let index = RevisionIndex::parse(&store).unwrap();
+ let document = Document::parse(&index).unwrap();
+ assert!(!document.spaces.is_empty());
+ let nodes: Vec<_> = document
+ .spaces
+ .values()
+ .flat_map(|s| s.revisions.values())
+ .flat_map(|r| r.nodes.values())
+ .collect();
+ assert!(!nodes.is_empty());
+ for node in nodes {
+ assert!(matches!(node.kind, Kind::Encrypted { ciphertext } if !ciphertext.is_empty()));
+ }
}
}
diff --git a/crates/onestore/tests/revisions.rs b/crates/onestore/tests/revisions.rs
index 8d49d368c9f9146c1c4008b16e5bc4c22c4b6cf4..b282fd6a8a4c9f2fe64af3ee83ccde9563d30aa0 100644
--- a/crates/onestore/tests/revisions.rs
+++ b/crates/onestore/tests/revisions.rs
@@ -67,31 +67,35 @@ fn persisted_identities_preserve_native_byte_order_and_canonical_form() {
#[test]
fn native_encryption_remains_opaque() {
- let bytes =
- fs::read("../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one").unwrap();
- let store = Store::parse(&bytes).unwrap();
- assert!(store.checksum_mismatches.is_empty());
- let index = RevisionIndex::parse(&store).unwrap();
- let mut encrypted = 0;
- for (osid, space) in &index.spaces {
- for (rid, revision) in &space.revisions {
- let resolved = index.resolve(*osid, *rid).unwrap();
- if revision.encrypted {
- encrypted += 1;
- assert!(
- resolved
- .objects
- .values()
- .any(|object| matches!(object.data, ObjectData::Encrypted(_)))
- );
- assert_eq!(
- resolved.reachable().unwrap_err().message,
- "Encrypted property references are unavailable"
- );
+ for path in [
+ "../../corpus/native-encrypted/encrypted-01/notebook/synthetic.one",
+ "../../corpus/native-protected-boundaries/notebook/synthetic.one",
+ ] {
+ let bytes = fs::read(path).unwrap();
+ let store = Store::parse(&bytes).unwrap();
+ assert!(store.checksum_mismatches.is_empty());
+ let index = RevisionIndex::parse(&store).unwrap();
+ let mut encrypted = 0;
+ for (osid, space) in &index.spaces {
+ for (rid, revision) in &space.revisions {
+ let resolved = index.resolve(*osid, *rid).unwrap();
+ if revision.encrypted {
+ encrypted += 1;
+ assert!(
+ resolved
+ .objects
+ .values()
+ .any(|object| matches!(object.data, ObjectData::Encrypted(_)))
+ );
+ assert_eq!(
+ resolved.reachable().unwrap_err().message,
+ "Encrypted property references are unavailable"
+ );
+ }
}
}
+ assert!(encrypted > 0);
}
- assert!(encrypted > 0);
}
#[test]
diff --git a/crates/onestore/tests/shared_snapshot.rs b/crates/onestore/tests/shared_snapshot.rs
index 2fa337a18d5e384068c67b8cb6fe9a2f345deed9..ba87504a4d63e614baf6d71eb86f48fc2a361bcf 100644
--- a/crates/onestore/tests/shared_snapshot.rs
+++ b/crates/onestore/tests/shared_snapshot.rs
@@ -19,6 +19,7 @@ use trace::{Event, Trace};
fn storage_inspection_preserves_opaque_images_without_claiming_edit_readiness() {
for path in [
"native-encrypted/encrypted-01/notebook/synthetic.one",
+ "native-protected-boundaries/notebook/synthetic.one",
"native-encrypted/cold-encrypted-02/notebook/Open Notebook.one",
"malformed/native-inflight.one",
] {