Skip to content

feat(blaze): restore sandbox checkpoints - #2475

Merged
casparant merged 1 commit into
alibaba:mainfrom
WeissonHan:feature/blaze/checkpoint-restore-workflow-draft-v1
Aug 18, 2026
Merged

feat(blaze): restore sandbox checkpoints#2475
casparant merged 1 commit into
alibaba:mainfrom
WeissonHan:feature/blaze/checkpoint-restore-workflow-draft-v1

Conversation

@WeissonHan

@WeissonHan WeissonHan commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Why

Blaze can capture and list committed checkpoints, but it cannot yet replace a
running sandbox with a selected checkpoint through the public sandbox API. The
replacement must keep backend, storage, lifecycle, and checkpoint history in
agreement even when a request is cancelled or the daemon stops partway through
the operation.

What changed

  • Add POST /v1/sandboxes/{id}/rollback/{checkpoint_id}.
  • Verify the selected checkpoint, its ancestry, artifact integrity, policy,
    image, backend identity, backend version, and snapshot kind before mutation.
  • Require explicit restore support from both the backend and storage provider;
    unsupported combinations return 501 before stopping the current runtime.
  • Add a backend-neutral restore request and capability contract. The built-in
    mock backend implements it for end-to-end validation. Firecracker-specific
    restore transport remains outside this pull request and will be delivered
    with Firecracker checkpoint support in feat(blaze): capture Firecracker checkpoints #2473.
  • Add a recoverable file-provider transaction that stages a replacement root
    filesystem, retains the predecessor, activates without replacement races,
    and can either commit or roll back after restart.
  • Journal every ownership boundary, retain the sandbox operation lock in a
    detached supervisor after client cancellation, and preserve recovery state
    whenever the result cannot be proven.
  • Move checkpoint HEAD only after the replacement backend is live and ready.
    Restoring an older checkpoint changes only HEAD; it does not delete or
    rewrite later checkpoint history.
  • Document the endpoint, capability checks, durable ordering, failure outcomes,
    and rollback procedure in the English and Chinese README, user guide, and
    component design documents.

No /v1/instances compatibility route is added.

Related issue

Closes #2463

User / Agent impact

Users and agents can select a committed checkpoint and request replacement of a
running sandbox. Success returns the sandbox identifier, selected checkpoint,
restored: true, and the resulting running state.

The generic path currently succeeds with the built-in mock backend and file
storage provider. Other backend or provider combinations fail with 501 before
runtime mutation until they implement the explicit restore contract.

Risk and compatibility

  • Public CLI, API, configuration, or documented behavior changed
  • Privileged or security-sensitive behavior changed
  • Cross-component contract changed
  • Migration or rollback guidance is needed

This adds one HTTP endpoint, new backend and storage capability contracts, new
restore lifecycle journal phases, and file-provider transaction artifacts.
Existing implementations remain fail-closed because both restore capabilities
default to unsupported.

Checkpoint directories and artifacts are retained by open descriptors during
verification and replacement. Storage publication uses private staging files,
identity checks, no-follow opens, durable rename boundaries, and a journal that
restart reconciliation can finish or abort.

Validation

Exact candidate:

Completed for this exact commit:

  • exact-diff and commit-message checks;
  • scope audit confirming one commit, one parent, no /v1/instances route, and
    no Firecracker restore implementation.

An uninterrupted Linux x86_64 run on Rust 1.88.0 completed for the tree above.
It used a fresh source directory, a dedicated Cargo home, and an initially
empty task-exclusive target directory for each stage. Every Cargo stage ran
with --locked --offline.

Stage Result
cargo fmt --all -- --check pass
cargo metadata, default and all features pass
cargo build --workspace --all-targets, default and all features pass
cargo clippy --workspace --all-targets -- -D warnings, default and all features pass, no warnings
cargo test --workspace -- --test-threads=1 382 passed, 0 failed, 0 ignored
cargo test --workspace --all-features -- --test-threads=1 444 passed, 0 failed, 0 ignored
RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps, default and all features pass, no warnings
scripts/docs-lint.sh pass
scripts/docs-link-check.py pass
git diff --check pass
source tree hash before and after the run unchanged

The all-feature run covers 40 focused restore tests. They prove the rollback
route end to end on the built-in mock backend, 501 rejection before any state
or resource change, per-stage cancellation and failure compensation, staging
that keeps the live root filesystem intact, predecessor retention through
activation, transaction reconciliation after an interrupted boundary, HEAD
movement without capture-history rewrite, and restore journal phase rules.

Real virtual-machine backends are unchanged: they still reject restore with
501 until they implement the contract.

This commit is directly based on the merged #2472 in main
(7a8005874e078455e9acde0f4f6981839919489d). The PR consists of one commit.

Documentation and rollback

The English and Chinese Blaze README, runtime user guide, lifecycle consistency
design, and storage synchronization design describe the new API and recovery
contract. No changelog entry is added because Blaze has not been released.

To roll back, stop the Blaze daemon and verify that no sandbox has an unfinished
restore operation or RecoveryRequired state. Revert this commit together with
its API, lifecycle, backend, storage, and documentation changes. Preserve any
restore transaction artifacts for operator inspection until the current binary
has reconciled or explicitly cleaned them.

@github-actions github-actions Bot added component:blaze src/blaze scope:documentation ./docs/|./*.md|./NOTICE labels Aug 13, 2026
@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 1f3b685 to 06a35b2 Compare August 17, 2026 08:22
@WeissonHan
WeissonHan marked this pull request as ready for review August 17, 2026 08:25
@WeissonHan
WeissonHan requested a review from casparant as a code owner August 17, 2026 08:25

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06a35b2bf1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/sandbox/restore.rs Outdated
@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 06a35b2 to c65dc0f Compare August 17, 2026 08:40
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review This PR adds the backend-neutral POST /v1/sandboxes/{id}/rollback/{checkpoint_id} endpoint and restore contract that replaces a running sandbox from a verified full checkpoint, with a recoverable file-provider rootfs transaction and the built-in mock backend as the end-to-end implementation; Firecracker-specific restore stays in #2473.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@kongche-jbw

Copy link
Copy Markdown
Collaborator

@codex review

@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from c65dc0f to 4257e73 Compare August 17, 2026 09:07

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c65dc0f3c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/sandbox/restore.rs Outdated
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Backend-neutral sandbox checkpoint restore: adds POST /v1/sandboxes/{id}/rollback/{checkpoint_id}, the restore capability contract, a recoverable file-provider rootfs transaction, and mock-backend end-to-end restore; the previous P2 finding about the failure-path catalog read is fixed in 4257e736e.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 4257e73 to 2be88b7 Compare August 17, 2026 09:54
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@mathiIdada

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2be88b74a3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/file_provider/restore.rs Outdated
@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 2be88b7 to 3c1dc73 Compare August 17, 2026 12:29
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 3c1dc73 to 7c52ad3 Compare August 17, 2026 13:33
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 871baac to 8bfde2c Compare August 18, 2026 03:01
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Docs-only follow-up: the restore "keeps running" guarantee is now limited to failures strictly before the daemon begins stopping the old backend; a stop-step failure (kill error) and everything after is documented as RecoveryRequired, aligned across all four docs.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8bfde2c8ba

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/docs/design/lifecycle-state-consistency.md Outdated
Comment thread src/blaze/crates/blaze-core/src/lifecycle.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 8bfde2c to 5c7d2f2 Compare August 18, 2026 03:09
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Docs-only follow-up: propagated the restore failure boundary to lifecycle-state-consistency.md/_zh.md, and updated src/blaze/AGENTS.md to describe the lifecycle as 10 states with the Running → Restoring → Running branch.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c7d2f2c67

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/docs/design/lifecycle-state-consistency.md
Add the sandbox rollback endpoint and the backend-neutral restore contract
needed to replace a running sandbox from a verified full checkpoint.

Journal lifecycle ownership, stage and reconcile file-provider root
filesystem replacement, preserve runtime-directory ownership across
replacement startup, and fail unsupported backend adapters before mutation.

Document the route, capability checks, durable ordering, failure boundaries,
and checkpoint-history semantics in the English and Chinese operator
documentation.

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
@WeissonHan
WeissonHan force-pushed the feature/blaze/checkpoint-restore-workflow-draft-v1 branch from 5c7d2f2 to 242120c Compare August 18, 2026 03:14
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Docs-only follow-up: updated the checkpoint-section introductions in lifecycle-state-consistency.md/_zh.md to describe three routes (capture, history, restore) and the restore journal/lifecycle contract, matching the section body.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 242120cde7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@casparant casparant left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed against the baseline we have been applying since #1830.

Review baseline — all met:

  • Unified motivation: clear Why grounded in the post-#2472 main — Blaze can capture and list checkpoints but cannot yet restore a sandbox from one; this PR adds POST /v1/sandboxes/{id}/rollback/{checkpoint_id} with full-lifecycle journaling and transactional storage replacement.
  • No caller-less code: every new pub item (RestoreCapability, RestoreRequest, StorageRestoreTransaction and its five trait methods, begin_restore_operation, advance_restore_phase, read_head_id, BackendSpawner::restore_capability/restore) has a production call site in the restore worker or storage provider; test-only spawners (GuestMockSpawner, TransportDroppingRestoreSpawner) are correctly gated behind #[cfg(test)].
  • Explicit boundary: Firecracker-specific restore transport deferred to #2473; checkpoint deletion/pruning not provided; no /v1/instances compatibility route added — all stated in the PR body.
  • Docs: bilingual user guides, READMEs, and lifecycle-state-consistency / storage-artifact-synchronization design docs updated; AGENTS.md state machine description updated (9→10 states with Restoring).
  • Commits: single atomic commit after multiple revision iterations; CI 8/8 green; all 10 inline threads carry exactly one substantive reply each and fixes are verified present in the final head 242120cde70b.
  • Naming: restore correctly confined to the data-plane checkpoint recovery path; control plane uses journal/phase/operation vocabulary; no misuse of reserved word families.

One non-blocking note:

The file_provider/restore.rs at ~1650 lines is the densest single-file addition in the series — the internal structure (stage/activate/commit/abort/reconcile) is sound, but a future crate-level split would improve navigability.

LGTM.

@casparant
casparant merged commit db0e465 into alibaba:main Aug 18, 2026
27 checks passed
@WeissonHan
WeissonHan deleted the feature/blaze/checkpoint-restore-workflow-draft-v1 branch August 18, 2026 05:13
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request. `BackendInstance` gains
`holds_network_slot`, which the generic transaction probes while the captured
owner is still alive, because that owner's cleanup removes the host device the
snapshot names. Reconstructing the spawn configuration from defaults would have
dropped networking, leaving a restored VM bound to a deleted tap after the
running VM had already been stopped.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

Because the console setting now survives, reopening the console log appends
instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable replaced in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. `PinnedExecutable` holds the file open, the
generic transaction opens it once and hands the same pin to both the capability
check and the launch, and the replacement executes that pinned file rather than
re-resolving the configured path.

Because the console setting now survives, reopening the console log appends
instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 18, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A load's deadline follows the captured
memory image's size, the same way a capture's follows the configured memory. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A load's deadline follows the captured
memory image's size, the same way a capture's follows the configured memory. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. Length and modification time
cannot carry that check alone, because a same-length rewrite can restore both, so
the comparison includes inode change time — the one indicator an ordinary writer
cannot put back. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. Length and modification time
cannot carry that check alone, because a same-length rewrite can restore both, so
the comparison includes inode change time — the one indicator an ordinary writer
cannot put back. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit to WeissonHan/anolisa that referenced this pull request Aug 19, 2026
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. Length and modification time
cannot carry that check alone, because a same-length rewrite can restore both, so
the comparison includes inode change time — the one indicator an ordinary writer
cannot put back. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

The capture-version probe stays fatal on this path, unlike a cold start which keeps
running without capture: a restore must load the snapshot into a VM whose version was
confirmed to match the one that captured it, and an unverified replacement is worse
than a refused restore.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
WeissonHan added a commit that referenced this pull request Aug 19, 2026
* feat(blaze): capture Firecracker checkpoints

This lets Firecracker-backed sandboxes use the checkpoint API that #2472 already
exposes, by pausing the VM, writing full VM-state and guest-memory snapshots
through the Firecracker API socket, and resuming the owned runtime.

The owner resolves its version from the running VM rather than from the
configured binary and freezes it, so a concurrent binary replacement cannot make
a capture claim a version this VM never ran. Firecracker snapshot formats are
tied to that exact version, so a record without one cannot be restored safely;
capture therefore refuses a Firecracker sandbox whose owner reports no version,
and the checkpoint manifest rejects the same shape.

Firecracker writes snapshot files itself from inside a private mount namespace,
so a capture names a scratch directory below the runtime directory the VM
already owns and transfers the artifacts to the destinations the publisher
chose. Scratch is reclaimed only when the outcome is known: a rejected request
never wrote anything, while an unknown outcome may still have a live writer, so
that scratch is retained for reconciliation and reclaimed by destroy or startup
instead of being deleted underneath Firecracker.

Snapshot requests get their own deadline, scaled by guest memory. A control
request such as `/version` or a pause should answer immediately, so a short bound
catches a wedged VMM, but a full snapshot moves the whole guest memory and its
duration scales with memory size and storage speed. Sharing the short bound would
report an unknown outcome and fail a capture that was still making progress: a
512 MiB guest already takes about 29 seconds on real hardware. Guest memory has
no configured upper bound either, so no fixed replacement bound would hold — at
that rate a 16 GiB guest outlives a 15-minute deadline. The deadline is therefore
derived from the memory size against a conservative throughput floor, with a floor
for fixed overhead, and exists only to catch a VMM that never answers.

A VM that answers on its API socket but not for its version stays a usable sandbox
and only loses checkpoint capture: the owner carries no capture context, so it
reports no version, does not advertise the capability, and a later capture is refused
before anything is paused. Treating the probe as fatal would turn a lost checkpoint
capability into a failed sandbox creation.

Only full capture is enabled. Restore stays unavailable until its adapter lands.

The user guides previously stated that Firecracker does not advertise capture
support, which this makes untrue, so both language versions are corrected. They
also now state the operational consequence of freezing the version: a checkpoint
can only be loaded back by the Firecracker build that took it, and capture refuses a
Firecracker sandbox whose monitor reports no version, before the sandbox is paused,
so a checkpoint without a recorded version cannot be produced.

Tests cover the frozen version, a full snapshot over the API socket, scratch
transfer through inherited descriptors, and the retained-scratch boundaries for
rejected requests, uncleanable scratch, and disconnects.

Closes #2470

Signed-off-by: Weisson <Weisson@linux.alibaba.com>

* feat(blaze): restore Firecracker checkpoints

This lets the generic restore workflow from #2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a #2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. Length and modification time
cannot carry that check alone, because a same-length rewrite can restore both, so
the comparison includes inode change time — the one indicator an ordinary writer
cannot put back. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

The capture-version probe stays fatal on this path, unlike a cold start which keeps
running without capture: a restore must load the snapshot into a VM whose version was
confirmed to match the one that captured it, and an unverified replacement is worse
than a refused restore.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes #2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>

---------

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:blaze src/blaze scope:documentation ./docs/|./*.md|./NOTICE

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[blaze] feat: restore sandboxes from checkpoints

4 participants