wasm-capability-contract 0.3.0

Generic, domain-agnostic capability pattern: CapabilityEngine/CapabilityRegistry/CapabilityDispatcher trait shapes + component/capability types. Trait definitions only -- see wasm-capability-core for this pattern's own default implementation, extracted from agent-runtime's ADR-001 (agent-runtime#31, ADR-011).
Documentation
//! Real-implementation tests for the `ComponentValidator` trait, via a
//! real, hand-written test double (not a mocking-library mock). See
//! `wasm-capability-system`'s own
//! `wasm-capability-wasmparser-spi/tests/component_validator_int_test.rs`
//! for the real `DefaultComponentValidator` behavioral tests.

use wasm_capability_contract::{
    ArtifactProvenance, CapabilityError, ComponentManifest, ComponentValidator, ResourceLimits,
    ValidateComponentRequest,
};

/// A real `ComponentValidator` that rejects any manifest whose
/// `contract_version` isn't exactly the one it accepts — the same real
/// first gate `DefaultComponentValidator` itself checks.
struct ContractVersionOnlyValidator;

impl ComponentValidator for ContractVersionOnlyValidator {
    fn validate(&self, req: ValidateComponentRequest) -> Result<(), CapabilityError> {
        if req.manifest.contract_version != "swe:edge-handler@0.2.0" {
            return Err(CapabilityError::UnsupportedContractVersion(
                req.manifest.contract_version,
            ));
        }
        if req.component_bytes.is_empty() {
            return Err(CapabilityError::InvalidManifest(
                "component_bytes must not be empty".to_string(),
            ));
        }
        Ok(())
    }
}

fn manifest(contract_version: &str) -> ComponentManifest {
    ComponentManifest {
        component_id: "echo".to_string(),
        route_id: "/echo".to_string(),
        contract_version: contract_version.to_string(),
        handler_export: "echo".to_string(),
        resource_limits: ResourceLimits {
            max_memory_bytes: 1024,
            invoke_timeout_ms: 1000,
            max_concurrency: 1,
            max_payload_bytes: 1024,
        },
        capabilities: vec![],
        artifact_provenance: ArtifactProvenance {
            source: "test".to_string(),
            checksum_sha256: "a".repeat(64),
            built_at: "2026-08-30T00:00:00Z".to_string(),
        },
    }
}

/// @covers: ComponentValidator
/// The trait must be object-safe — `Arc<dyn ComponentValidator>` is how
/// every real consumer (the wasmtime component engine) is expected to
/// hold one.
fn _accept(_validator: &dyn ComponentValidator) {}

/// @covers: ComponentValidator::validate
/// Paired with its negative counterpart in the same test: a supported
/// contract version succeeds, an unsupported one — otherwise identical —
/// fails, proving the check is real and not a stub that always passes.
#[test]
fn test_validate_supported_contract_version_happy() {
    let supported = ContractVersionOnlyValidator.validate(ValidateComponentRequest {
        manifest: manifest("swe:edge-handler@0.2.0"),
        component_bytes: vec![1],
        granted_capabilities: vec![],
    });
    assert!(supported.is_ok(), "expected a supported version to pass");

    let unsupported = ContractVersionOnlyValidator.validate(ValidateComponentRequest {
        manifest: manifest("swe:edge-handler@99.0.0"),
        component_bytes: vec![1],
        granted_capabilities: vec![],
    });
    assert!(
        unsupported.is_err(),
        "expected an unsupported version to fail"
    );
}

/// @covers: ComponentValidator::validate
#[test]
fn test_validate_unsupported_contract_version_error() {
    let result = ContractVersionOnlyValidator.validate(ValidateComponentRequest {
        manifest: manifest("swe:edge-handler@99.0.0"),
        component_bytes: vec![1],
        granted_capabilities: vec![],
    });
    assert!(matches!(
        result,
        Err(CapabilityError::UnsupportedContractVersion(_))
    ));
}

/// @covers: ComponentValidator::validate
/// The empty-bytes boundary: a supported contract version with zero
/// component bytes must still be rejected, not accepted just because the
/// version check passed.
#[test]
fn test_validate_empty_component_bytes_edge() {
    let result = ContractVersionOnlyValidator.validate(ValidateComponentRequest {
        manifest: manifest("swe:edge-handler@0.2.0"),
        component_bytes: vec![],
        granted_capabilities: vec![],
    });
    assert!(matches!(result, Err(CapabilityError::InvalidManifest(_))));
}