pub async fn snapshot_save(
__arg0: State<Arc<AppState>>,
tenant: Option<Extension<TenantId>>,
auth: Option<Extension<AuthContext>>,
payload: Result<Json<SnapshotSaveRequest>, JsonRejection>,
) -> ApiResult<Json<SnapshotSaveResponse>>Expand description
POST /snapshot/save — capture a deployed function into a signed
snapshot blob.
§Auth posture
Mounted on the protected stack (bearer auth + tenant scope + rate limit + audit), exactly like the function-mutating routes. The handler runs the same two-stage tenant gate the other resource handlers use:
authorize_tenantagainst the bearer token’s scope — an out-of-scope token sees403 tenant_scope_deniedbefore any registry lookup, so it cannot probe function-id existence via a 403-vs-404 split.- a per-resource owner check against the looked-up
FunctionRecord::tenant_id— a wildcard-scoped caller from another tenant cannot snapshot tenant A’s function.
§HMAC wiring (M5)
The snapshot blob is signed with the operator-configured
TENSOR_WASM_API_SNAPSHOT_HMAC_KEY (threaded in via
AppState::app_config). When no key is configured the route returns
503 snapshot_signing_not_configured, mirroring the kernel-registry
posture — the gateway will not silently emit an unsigned blob under a
route that promises a signed one.
§What is captured
The function’s deployed Wasm module bytes are captured into the
snapshot’s wasm_memory blob via
tensor_wasm_snapshot::writer::SnapshotWriter. This is the working
save/restore-of-bytes layer with end-to-end HMAC signing. Capturing a
live running instance’s linear / GPU memory needs a
TensorWasmExecutor capture hook that does not exist yet; that
capability is intentionally out of scope here (see the module status in
crate::config). The blob produced here round-trips through
/snapshot/restore.