Documentation
¶
Overview ¶
Package wasmmod — AOCR push for §4.8.1 WASM snapshot artifacts (D2).
Index ¶
- Constants
- Variables
- func DeleteSnapshotRef(ctx context.Context, cfg ORASPushConfig, registryRef string) error
- func PullModuleArtifact(ctx context.Context, a ModuleAuth, registryRef, dstDir string, maxBytes int64) (wasmPath string, err error)
- func PullSnapshotArtifact(ctx context.Context, cfg ORASPullConfig, registryRef, dstDir string) error
- func PushModuleArtifact(ctx context.Context, a ModuleAuth, wasmPath, registryRef string) (digest string, err error)
- func PushSnapshotArtifact(ctx context.Context, cfg ORASPushConfig, memSnapDir, registryRef string) (digest string, err error)
- func ResolveModuleManifestDigest(ctx context.Context, a ModuleAuth, registryRef string) (string, error)
- func ValidateFile(path string) error
- func WasmCheckpointDigestTag(digest string) string
- func WasmCheckpointRef(host, clusterID, sandboxID string) string
- func WasmCheckpointRefTagged(host, clusterID, sandboxID, tag string) string
- func WriteCheckpointWasm(t *testing.T, dir, name string) string
- func WriteMinimalWasm(t *testing.T, dir, name string) string
- type ModuleAuth
- type ModuleResolver
- func (r *ModuleResolver) Resolve(ctx context.Context, ref string) (*ResolvedModule, error)
- func (r *ModuleResolver) ResolveByDigest(digest string) (*ResolvedModule, bool)
- func (r *ModuleResolver) ResolveWithAuth(ctx context.Context, ref string, authOverride *ModuleAuth) (*ResolvedModule, error)
- func (r *ModuleResolver) SetDigestMode(mode string)
- type ORASPullConfig
- type ORASPushConfig
- type ResolvedModule
- type Resolver
Constants ¶
const CheckpointWasmHex = "0061736d01000000010401600000030201000503010001071302066d656d6f72790200065f737461727400000a040102000b"
CheckpointWasmHex is a minimal module with exported linear memory for snapshot tests.
const MinimalWasmHex = "0061736d0100000001040160000003020100070a01065f737461727400000a040102000b"
MinimalWasmHex is a valid wasm module: (module (func) (export "_start" (func 0))). Used by pkg/wasm and pkg/wasmmod tests — the export name length must be 6, not 4.
Variables ¶
var ( // ErrModuleNotFound: the ref named no reserved keyword, catalogue id, or // local file. The service surfaces the valid reserved keywords alongside. ErrModuleNotFound = errors.New("wasm module not found") // ErrRegistryNotAllowed: an oci:// ref named a host outside // SB_WASM_REGISTRY_ALLOWLIST. This is the SSRF guard — never relax it to // a warning. ErrRegistryNotAllowed = errors.New("wasm module registry not allowed") // ErrRegistryAuth: the registry rejected our credentials (bad/expired PAT). // Terminal — retrying without fixing the token will not help. ErrRegistryAuth = errors.New("wasm module registry authentication failed") ErrRegistryUnavailable = errors.New("wasm module registry unavailable") // ErrModuleTooLarge: the artifact exceeded the size cap mid-stream. We // abort the pull rather than buffer an unbounded body. ErrModuleTooLarge = errors.New("wasm module exceeds size cap") // ErrModuleDigestMismatch: a sandbox pinned digest X at create, but the // alias/tag it referenced now resolves to different bytes and the frozen // copy is gone. We fail loudly rather than silently boot different code on // restart/failover (codex C2). ErrModuleDigestMismatch = errors.New("wasm module digest drift") )
Module-resolution error taxonomy. The service layer maps these to HTTP status via apihttp.WriteStoreAwareError so the SDK can tell a terminal failure (fix your ref / token) from a transient one (retry the pull).
ErrComponentModelUnsupported (validate.go) is the sixth member of this set; it is mapped to 422 the same way.
var ErrComponentModelUnsupported = errors.New("wasm component model not supported")
ErrComponentModelUnsupported flags a WASI Component Model artifact. Neither engine in this repo (wazero, nor wasmtime-go which has no component API) can instantiate a component — both run core wasip1 modules only. Detecting it here turns a cryptic deep parse failure into a directed, actionable error.
Functions ¶
func DeleteSnapshotRef ¶
func DeleteSnapshotRef(ctx context.Context, cfg ORASPushConfig, registryRef string) error
DeleteSnapshotRef removes a tagged WASM checkpoint manifest from AOCR. Missing refs are treated as success so SQLite prune can proceed after manual cleanup.
func PullModuleArtifact ¶
func PullModuleArtifact(ctx context.Context, a ModuleAuth, registryRef, dstDir string, maxBytes int64) (wasmPath string, err error)
PullModuleArtifact downloads a single-layer .wasm artifact from registryRef into dstDir and returns the unpacked file path. The caller is responsible for validation (ValidateFile) and content-addressed publishing — this function only does the transport. dstDir should be a caller-owned temp dir.
maxBytes (>0) bounds the download: the manifest is resolved and its layer sizes summed BEFORE any layer blob is fetched, so an oversized artifact is rejected without buffering it. This is the DoS/SSRF size guard — a malicious registry cannot make us pull an unbounded body.
func PullSnapshotArtifact ¶
func PullSnapshotArtifact(ctx context.Context, cfg ORASPullConfig, registryRef, dstDir string) error
PullSnapshotArtifact downloads a §4.8.1 mem.snap directory from AOCR into dstDir.
func PushModuleArtifact ¶
func PushModuleArtifact(ctx context.Context, a ModuleAuth, wasmPath, registryRef string) (digest string, err error)
PushModuleArtifact uploads a single local .wasm file to registryRef as a one-layer OCI artifact. Returns the manifest digest. wasmPath must already be a validated core module (caller runs ValidateFile).
func PushSnapshotArtifact ¶
func PushSnapshotArtifact(ctx context.Context, cfg ORASPushConfig, memSnapDir, registryRef string) (digest string, err error)
PushSnapshotArtifact uploads a local mem.snap directory to an OCI registry.
func ResolveModuleManifestDigest ¶
func ResolveModuleManifestDigest(ctx context.Context, a ModuleAuth, registryRef string) (string, error)
ResolveModuleManifestDigest performs a credentialed manifest HEAD/GET and returns the manifest content digest WITHOUT downloading any layer blob. It is the cheap, per-caller authorization + cache-key step the resolver runs before a full pull: every caller still authenticates to the registry here (so a cache shortcut never bypasses registry authz), but only ONE of N concurrent duplicate creates goes on to download the blobs (codex P0 single-flight).
func ValidateFile ¶
ValidateFile checks the WASM magic header, the core-vs-component layer, and the size bounds. A WASM binary's 8-byte preamble is 4 magic bytes + a 4-byte version/layer field: core modules carry layer 0x0000 (version u32 = 1), components carry layer 0x0001 (bytes 6–7 == 0x01 0x00). We reject the latter.
func WasmCheckpointDigestTag ¶
WasmCheckpointDigestTag normalizes a manifest digest for use as an OCI tag.
func WasmCheckpointRef ¶
WasmCheckpointRef is the AOCR destination for a durable WASM checkpoint (:latest).
func WasmCheckpointRefTagged ¶
WasmCheckpointRefTagged builds an AOCR ref with an explicit tag (digest or latest).
func WriteCheckpointWasm ¶
WriteCheckpointWasm writes a module with exported memory for checkpoint tests.
Types ¶
type ModuleAuth ¶
ModuleAuth carries the registry credentials for a BYO module pull/push. Username is the AOCR login.
Two credential sources, by design:
- PAT: an inline token. This is the PER-TENANT path — the token rides the create/push request (req.Registry.Password) and is never persisted in plaintext. Thousands of tenants each supply their own; nothing is configured globally.
- PATPath: a token file. This is the SYSTEM path — the operator's identity for pulling the curated standard modules. Set once, re-read each call so rotation needs no restart.
PAT wins when both are set.
type ModuleResolver ¶
type ModuleResolver struct {
// CacheDir holds pulled oci:// modules as <digest>.wasm. Distinct from the
// checkpoint root so eviction never walks a passivated sandbox's mem.snap.
CacheDir string
// Reserved maps a standard keyword to its staged filename under ModulesDir
// (e.g. "python" -> "python.wasm"). Provisioned by Ansible, identical fleet
// wide; never DB-backed (codex C1).
Reserved map[string]string
// Allowlist is the set of registry hosts an oci:// ref may target. Empty
// means "deny all remote pulls" — the safe default until configured.
Allowlist map[string]struct{}
// PullTimeout bounds a single oci:// pull so it cannot stall sandbox boot.
PullTimeout time.Duration
// MaxBytes caps a pulled artifact (mirrors ValidateFile's 256MiB).
MaxBytes int64
// Auth carries the default registry credentials for oci:// pulls. A
// per-tenant override can be passed to ResolveWithAuth (failover, BYO).
Auth ModuleAuth
// CatalogueLookup resolves a BYO catalogue id to an already-local path +
// digest. Optional; nil disables step 3.
CatalogueLookup func(ctx context.Context, id string) (path, digest string, ok bool)
// contains filtered or unexported fields
}
ModuleResolver is the single resolution chokepoint for every module_ref shape. ALL callers (sandbox create, CreateWasmModule, start/rehydrate by pinned digest, failover) go through Resolve so that allowlist enforcement, core-wasip1 validation, digest computation, and atomic cache publishing happen in exactly one place. Splitting this logic across call sites is how the SSRF allowlist or the validation gets silently skipped on one path.
Resolution precedence (a single ref grammar with explicit ordering — see codex C3, the alias/bare-file collision):
- reserved keyword ("python") -> ModulesDir/<staged filename>
- oci:// ref ("oci://h/r:t") -> allowlist -> pull -> cache/<digest>.wasm
- catalogue id (BYO digest id) -> CatalogueLookup -> local path
- file:// / abs / bare filename -> ModulesDir (legacy Resolver)
Reserved keywords win over a same-named bare file on disk, so a stray ModulesDir/python file can never shadow the standard "python" runtime.
func NewModuleResolver ¶
func NewModuleResolver(modulesDir, cacheDir string) *ModuleResolver
NewModuleResolver builds a chokepoint over modulesDir. cacheDir defaults to modulesDir/cache when empty.
func (*ModuleResolver) Resolve ¶
func (r *ModuleResolver) Resolve(ctx context.Context, ref string) (*ResolvedModule, error)
Resolve resolves ref using the default Auth.
func (*ModuleResolver) ResolveByDigest ¶
func (r *ModuleResolver) ResolveByDigest(digest string) (*ResolvedModule, bool)
ResolveByDigest returns the content-addressed cached module for digest, if a frozen copy exists in CacheDir. start/rehydrate use this to boot the EXACT bytes pinned at create rather than re-resolving a mutable alias/tag (codex C2). Reports ok=false on a cache miss; the caller then falls back to ref resolution with a digest-match assertion.
func (*ModuleResolver) ResolveWithAuth ¶
func (r *ModuleResolver) ResolveWithAuth(ctx context.Context, ref string, authOverride *ModuleAuth) (*ResolvedModule, error)
ResolveWithAuth resolves ref, using authOverride for an oci:// pull when non-nil (failover hands the original tenant's sealed creds here so a private module re-pulls on the new owner — codex C4).
func (*ModuleResolver) SetDigestMode ¶ added in v0.5.5
func (r *ModuleResolver) SetDigestMode(mode string)
SetDigestMode switches verify-once vs always-hash for local file resolves.
type ORASPullConfig ¶
ORASPullConfig wires AOCR auth for WASM checkpoint pull (failover-from-snapshot).
func (ORASPullConfig) Validate ¶
func (c ORASPullConfig) Validate() error
Validate enforces required fields when pull is requested.
type ORASPushConfig ¶
ORASPushConfig wires AOCR auth for WASM checkpoint push. Mirrors the snapshot-push PAT file semantics: token is re-read on every call.
func (ORASPushConfig) Validate ¶
func (c ORASPushConfig) Validate() error
Validate enforces required fields when push is requested.
type ResolvedModule ¶
ResolvedModule is a validated local .wasm artifact ready for the engine.
type Resolver ¶
type Resolver struct {
ModulesDir string
// DigestMode controls per-resolve hashing: once (default) or always.
DigestMode string
// contains filtered or unexported fields
}
Resolver maps a module reference to a local .wasm path under modulesDir.
func NewResolver ¶
NewResolver constructs a resolver. modulesDir is the host cache root (SB_WASM_MODULES_DIR).
func (*Resolver) InvalidateDigestCache ¶ added in v0.5.5
InvalidateDigestCache drops verify-once entries for path after module delete/replace.
func (*Resolver) Resolve ¶
Resolve turns ref into a local file path. Phase 2 accepts:
- absolute paths to .wasm files
- file:// URLs
- bare filenames or relative paths under modulesDir
func (*Resolver) SetDigestMode ¶ added in v0.5.5
SetDigestMode switches verify-once vs always-hash behavior (SB_WASM_MODULE_DIGEST_MODE).