Gunnar

nordisk/heimdall

crates/heimdall-wasm/src/codes.rs

// SPDX-License-Identifier: AGPL-3.0-only
//! Stable refusal codes of the wasm host. A code never changes meaning once
//! published; a new kind of refusal gets a new number. Callers branch on the
//! code, people read the reason. Heimdall is a defensive sandbox.

/// The guest returned `err(refusal)` itself; the reason is the guest's.
pub const GUEST_REFUSED: &str = "heimdall-wasm-1";
/// The guest trapped (unreachable, bad memory access, a bad return value, …).
pub const TRAPPED: &str = "heimdall-wasm-2";
/// Out of fuel.
pub const OUT_OF_FUEL: &str = "heimdall-wasm-3";
/// The wall-clock timeout (epoch interruption) fired.
pub const TIMEOUT: &str = "heimdall-wasm-4";
/// The memory limit fired.
pub const MEMORY_LIMIT: &str = "heimdall-wasm-5";
/// The table limit fired.
pub const TABLE_LIMIT: &str = "heimdall-wasm-6";
/// The stack limit fired (deep recursion).
pub const STACK_OVERFLOW: &str = "heimdall-wasm-7";
/// An instance, table-count or memory-count limit refused instantiation.
pub const INSTANTIATION_LIMIT: &str = "heimdall-wasm-8";
/// `emit-file` was refused (bad name, duplicate, too many, too large).
pub const EMIT_REFUSED: &str = "heimdall-wasm-9";
/// The note or reason the guest returned is over the text limit.
pub const OUTPUT_TOO_LARGE: &str = "heimdall-wasm-10";
/// The guest's `run` export does not have the WIT signature.
pub const INTERFACE_MISMATCH: &str = "heimdall-wasm-11";
/// A fault in the host's own glue, caught and turned into a refusal.
pub const HOST_FAULT: &str = "heimdall-wasm-12";

/// The module file could not be read.
pub const LOAD_UNREADABLE: &str = "heimdall-wasm-20";
/// The module file is over the size cap.
pub const LOAD_TOO_LARGE: &str = "heimdall-wasm-21";
/// No `.wasm.blake3` pin beside the module.
pub const LOAD_DIGEST_MISSING: &str = "heimdall-wasm-22";
/// The blake3 pin (sidecar or caller) does not match.
pub const LOAD_DIGEST_MISMATCH: &str = "heimdall-wasm-23";
/// The `.wasm.p7s` signature check failed.
pub const LOAD_UNTRUSTED: &str = "heimdall-wasm-24";
/// A core module, not a component.
pub const LOAD_NOT_A_COMPONENT: &str = "heimdall-wasm-25";
/// Not a valid component.
pub const LOAD_INVALID: &str = "heimdall-wasm-26";
/// The guest imports something other than `emit-file` (WASI, …).
pub const LOAD_IMPORT_REFUSED: &str = "heimdall-wasm-27";
/// The guest exports no `run`.
pub const LOAD_MISSING_EXPORT: &str = "heimdall-wasm-28";
/// Linking failed (an import with the wrong type).
pub const LOAD_LINK: &str = "heimdall-wasm-29";

/// Every code, for the uniqueness test and for documentation.
pub const ALL: [&str; 22] = [
    GUEST_REFUSED,
    TRAPPED,
    OUT_OF_FUEL,
    TIMEOUT,
    MEMORY_LIMIT,
    TABLE_LIMIT,
    STACK_OVERFLOW,
    INSTANTIATION_LIMIT,
    EMIT_REFUSED,
    OUTPUT_TOO_LARGE,
    INTERFACE_MISMATCH,
    HOST_FAULT,
    LOAD_UNREADABLE,
    LOAD_TOO_LARGE,
    LOAD_DIGEST_MISSING,
    LOAD_DIGEST_MISMATCH,
    LOAD_UNTRUSTED,
    LOAD_NOT_A_COMPONENT,
    LOAD_INVALID,
    LOAD_IMPORT_REFUSED,
    LOAD_MISSING_EXPORT,
    LOAD_LINK,
];

#[cfg(test)]
mod tests {
    #[test]
    fn every_code_is_unique_and_named_heimdall_wasm_n() {
        let mut seen = std::collections::BTreeSet::new();
        for c in super::ALL {
            assert!(seen.insert(c), "{c} twice");
            let n = c.strip_prefix("heimdall-wasm-").expect(c);
            assert!(n.parse::<u32>().is_ok(), "{c}");
        }
    }
}