Skip to content

fix(snapshot): make payload integrity opt-in - #1346

Merged
appcypher merged 9 commits into
mainfrom
appcypher/optional-snapshot-integrity
Aug 14, 2026
Merged

fix(snapshot): make payload integrity opt-in#1346
appcypher merged 9 commits into
mainfrom
appcypher/optional-snapshot-integrity

Conversation

@appcypher

@appcypher appcypher commented Aug 14, 2026

Copy link
Copy Markdown
Member

TL;DR

Makes snapshot payload integrity genuinely opt-in and removes the expensive hidden payload scans reported in superradcompany/microsandbox#1220. Ordinary create, open, boot, save, load, and descriptor-upgrade paths remain structural; explicit integrity recording uses a sparse-aware BLAKE3 Merkle tree, while released SHA descriptors keep their exact readers and verifiers.

Description

  • Honor the existing record_integrity / --integrity option. New snapshots write integrity: null by default and do not perform an independent content pass.
  • Add msb-file-merkle-blake3-v1, with fixed 64 KiB leaves, domain-separated leaf/parent/root hashes, deterministic zero padding, and logical size bound into the root.
  • Collapse known sparse holes into precomputed zero subtrees, batch allocated reads, reuse the read buffer, and hash leaf batches in parallel.
  • Preserve exact support for released plain SHA-256 and msb-sparse-sha256-v1 descriptors. Explicit verification continues to execute their original algorithms.
  • Keep archive grammar, confinement, entry-size, descriptor-identity, image-entry, and per-member transport checks mandatory while preserving snapshot payload integrity without executing it implicitly during save or load.
  • Make adjacent descriptor upgrade metadata-only. Explicit downgrade converts current Merkle integrity to the legacy sparse-SHA representation through the already-confined payload handle and refuses to silently discard recorded integrity.
  • Project the optional integrity and not recorded verification result consistently through the CLI and Rust, TypeScript, Python, and Go bindings.
  • Keep Windows archive durability correct by flushing through a write-capable handle before atomic replacement, and keep buffer-heavy save/load futures within Windows worker-stack limits.
  • Update snapshot and SDK documentation to make the default, explicit verification boundary, and released-format compatibility clear.

Sparse Merkle BLAKE3 benchmark

A conservative pre-integration prototype was measured against 64 GiB APFS sparse files on an Apple M5 Max (18 cores, 36 GB RAM), using 64 KiB leaves, BLAKE3 1.8.6, Rayon with 18 workers, Microsandbox's ExtentMap, and release-mode Rust. File creation is excluded; each image was hashed twice.

Image scenario Allocated data Extents First pass Repeat pass
Fully sparse 0 0 <0.001 s <0.001 s
Tiny occupancy 8 MiB 1 0.002 s 0.002 s
~0.1% filled 64 MiB 1 0.006 s 0.004 s
~1% filled 656 MiB 1 0.030 s 0.028 s
~10% filled 6.40 GiB 1 1.159 s 1.159 s
~10% striped 6.40 GiB 819 1.156 s 1.155 s
25% filled 16 GiB 1 2.949 s 3.132 s
50% filled 32 GiB 1 5.789 s 5.880 s
50% striped 32 GiB 4,096 5.836 s 5.839 s
75% filled 48 GiB 1 8.779 s 8.836 s
Fully filled 64 GiB 1 11.858 s 11.972 s

Large allocated images sustained approximately 5.4–5.5 GiB/s. Extent discovery remained below 1 ms for 819 extents and was approximately 4.11 ms for 4,096 extents, so runtime scales with allocated content rather than virtual image size or ordinary fragmentation. The production implementation further batches reads and reuses buffers; these prototype numbers are intentionally not presented as a final performance ceiling.

Test Plan

  • cargo fmt --all -- --check
  • cargo check -p microsandbox-image -p microsandbox -p microsandbox-cli -p microsandbox-node -p microsandbox-py -p microsandbox-go
  • cargo test -p microsandbox-image (203 passed, 3 ignored, including doc tests)
  • macOS: cargo test -p microsandbox --no-default-features --lib snapshot:: (18 passed)
  • macOS: cargo test -p microsandbox --no-default-features --test snapshot_artifact with isolated MSB_HOME (41 passed)
  • cargo clippy -p microsandbox-image --lib -- -D warnings
  • cargo clippy -p microsandbox --lib -- -D warnings
  • TypeScript unit tests (119 passed), build, and typecheck
  • Go build, vet, and tests
  • Native Windows ARM64: Rust library plus Node and Go native bindings compile
  • Native Windows ARM64: cargo test -p microsandbox --lib snapshot:: -- --test-threads=1 (19 passed)
  • Native Windows ARM64: cargo test -p microsandbox --test snapshot_artifact -- --test-threads=1 (40 passed with the normal thread stack)
  • Native Windows ARM64: format check and cargo clippy -p microsandbox --lib -- -D warnings
  • Full CI matrix

Closes #1220

Greptile Summary

The PR makes snapshot payload integrity opt-in while retaining mandatory structural and archive-member validation.

  • Adds sparse-aware BLAKE3 Merkle integrity with fixed-size leaves and explicit verification.
  • Preserves released SHA descriptor compatibility and makes adjacent upgrades metadata-only.
  • Projects optional integrity consistently through the CLI and language SDKs.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
sdk/rust/lib/snapshot/verify.rs Implements explicit legacy SHA verification and the new sparse-aware fixed-leaf BLAKE3 Merkle algorithm.
sdk/rust/lib/snapshot/archive.rs Separates mandatory archive-member validation from optional snapshot payload verification and updates durability behavior.
sdk/rust/lib/snapshot/migration.rs Makes adjacent legacy descriptor upgrades metadata-only while preserving recorded integrity metadata.
crates/image/lib/snapshot/manifest.rs Changes upper integrity to a required nullable field and introduces typed descriptors for released SHA and current Merkle algorithms.
sdk/rust/lib/snapshot/create.rs Records Merkle payload integrity only when explicitly requested.
sdk/rust/lib/snapshot/downgrade.rs Converts current Merkle integrity to a legacy-compatible sparse-SHA representation during explicit downgrade.
sdk/node-ts/src/snapshot.ts Projects absent, legacy SHA, and Merkle integrity shapes into the TypeScript API.
sdk/go/snapshot.go Adds explicit integrity presence and Merkle parameters to the Go snapshot projection.

Sequence Diagram

sequenceDiagram
    participant User
    participant Snapshot
    participant Archive
    participant Payload
    User->>Snapshot: Create (integrity optional)
    alt Integrity requested
        Snapshot->>Payload: Compute sparse BLAKE3 Merkle root
        Snapshot-->>User: Descriptor with recorded integrity
    else Default
        Snapshot-->>User: Descriptor with integrity: null
    end
    User->>Archive: Save or load
    Archive->>Archive: Validate grammar, confinement, sizes, identities, and member transport
    Archive-->>User: Preserve recorded payload integrity
    opt Explicit verify
        User->>Snapshot: verify()
        Snapshot->>Payload: Execute recorded integrity algorithm
        Snapshot-->>User: Verified or mismatch
    end
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into appcypher/optio..." | Re-trigger Greptile

Honor the existing integrity opt-in and remove implicit payload verification from ordinary create, archive, boot, and descriptor migration paths.

Add a sparse-aware fixed-leaf BLAKE3 Merkle representation for explicit verification while preserving released SHA descriptors and adjacent downgrade compatibility.
@appcypher
appcypher requested a review from toksdotdev as a code owner August 14, 2026 08:13
Copilot AI lite review requested due to automatic review settings August 14, 2026 08:13
@mintlify

mintlify Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
microsandbox-staging 🟢 Ready View Preview Aug 14, 2026, 8:14 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Bind archive members to one-pass BLAKE3 digests so payload corruption is
rejected even when persistent snapshot integrity is not recorded. Keep
released inventories readable without another payload scan.

Verify recorded Merkle roots before downgrade projection and pin explicit
verification to a stable file identity. Preserve complete Merkle state in
Node and Go while retaining digest compatibility aliases.

Closes #1220
Copilot AI review requested due to automatic review settings August 14, 2026 15:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Resolve the documentation overlap ahead of the upstream merge. Keep main’s streamlined SDK reference structure while preserving optional-integrity behavior.
Copilot AI review requested due to automatic review settings August 14, 2026 18:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Temporarily align the remaining overlapping sentence with main so GitHub can perform a signed branch update. The corrected optional-integrity wording is restored after the merge.
Copilot AI review requested due to automatic review settings August 14, 2026 18:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 14, 2026 18:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Document that archive loading performs structural and entry checks while preserving recorded payload integrity for an explicit verification request.
Copilot AI review requested due to automatic review settings August 14, 2026 18:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Open the durability handle with write access before FlushFileBuffers and release it before atomic replacement.

Heap-pin buffer-heavy archive entry and staged-cache futures so snapshot save/load fits Windows worker stacks.
Copilot AI review requested due to automatic review settings August 14, 2026 18:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Gate the Unix-only runtime endpoint helper import to Unix test builds and initialize the bind-mount symlink policy in the Windows path fixture. This restores compilation of the full Rust unit-test target on Windows.
Copilot AI review requested due to automatic review settings August 14, 2026 18:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 14, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@appcypher
appcypher merged commit 673b711 into main Aug 14, 2026
53 checks passed
@appcypher
appcypher deleted the appcypher/optional-snapshot-integrity branch August 14, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Snapshot create/save/load each hash the full logical upper size since v0.6.7; docs still describe integrity as opt-in

2 participants