Skip to content

chore(policy): Bootstrap WASM policy engine#2584

Merged
javirln merged 5 commits intochainloop-dev:mainfrom
javirln:feat/pfm-3817
Nov 28, 2025
Merged

chore(policy): Bootstrap WASM policy engine#2584
javirln merged 5 commits intochainloop-dev:mainfrom
javirln:feat/pfm-3817

Conversation

@javirln
Copy link
Member

@javirln javirln commented Nov 26, 2025

Architecture

The WASM engine is implemented using Extism, a universal plugin system that allows running WebAssembly modules safely across different platforms.

Here's a small video hands on:

showcase-wasm.mov

Key Components

Policy Type Detection

File: pkg/policies/engine/detect.go

Automatically detects policy type by checking for WASM magic bytes (0x00 0x61 0x73 0x6d). Falls back to Rego for text-based policies. Detection happens transparently at runtime.

WASM Engine

File: pkg/policies/engine/wasm/engine.go

Implements the PolicyEngine interface using Extism Go SDK.

Features:

  • Timeout control with configurable execution timeout (default 60 seconds)
  • Logging integration that maps Extism log levels to zerolog
  • HTTP restrictions via AllowedHostnames
  • WASI support enabled
  • Configuration passing via Extism config as JSON

Policy Execution Flow

Material or attestation is passed to PolicyVerifier, which detects the policy type. For WASM policies, the engine creates an Extism plugin, calls the Execute function, and parses JSON output.

Material/Attestation → PolicyVerifier.executeScript()
                           ↓
                    DetectPolicyType()
                           ↓
             ┌─────────────┴─────────────┐
             ↓                           ↓
        PolicyTypeRego              PolicyTypeWASM
             ↓                           ↓
      Rego.NewEngine()            WASM.NewEngine()
             ↓                           ↓
        OPA Evaluation          Extism Plugin Execution
                           ↓
                    Call "Execute" function
                           ↓
                    Parse JSON output

Configuration Options

Common Options

Shared with Rego engine:

  • AllowedHostnames: List of domains for HTTP requests (defaults: www.chainloop.dev, www.cisa.gov)
  • IncludeRawData: Include raw input/output in results
  • EnablePrint: Enable print statements

WASM-Specific Options

  • ExecutionTimeout: Maximum execution time (default 60s)
  • Logger: zerolog logger instance

WASM Policy Contract

WASM policies must export an Execute function.

Input: Raw material bytes as input parameter, with arguments accessible via Extism config under "args" key.

Output: JSON object with violations array, skipped boolean, skip_reason string, and ignore boolean.

Error Handling

File: pkg/policies/engine/wasm/errors.go

Provides sophisticated error parsing for:

  • HTTP Forbidden errors with hostname extraction
  • Timeout detection
  • Out-of-memory conditions
  • Runtime errors with helpful messages
  • User-friendly hints and suggestions

Security Features

  • Sandboxing through WASM memory isolation
  • Network restrictions via allowed hostnames list
  • Timeout protection against infinite loops
  • No custom host functions exposed
  • WASI-only standard interfaces

Integration Points

Policy Loader

File: pkg/policies/policies.go

Automatically selects engine based on detected policy type. For WASM policies, creates engine with logger and common options.

Material Verification

File: pkg/attestation/crafter/crafter.go

WASM policies are evaluated alongside Rego policies with the same violation reporting structure, transparent to users.

Current Limitations

  • MatchesParameters and MatchesEvaluation are stub implementations that always return true
  • No automatic boilerplate injection like Rego policies
  • Must be pre-compiled WASM modules

Implementation Details

File Structure

  • engine.go: Main WASM engine implementation
  • engine_test.go: Engine tests
  • errors.go: Error parsing and handling
  • errors_test.go: Error handling tests

Key Methods

NewEngine creates a new WASM engine with specified options and applies common configuration.

Verify is the main execution method that creates an Extism plugin, configures it, calls the Execute function, and parses results.

MatchesParameters and MatchesEvaluation are stub implementations that delegate to WASM policy internals.

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln self-assigned this Nov 26, 2025
@javirln javirln marked this pull request as draft November 26, 2025 16:04
Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln marked this pull request as ready for review November 27, 2025 06:50
Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
if err != nil {
return nil, fmt.Errorf("failed to inject boilerplate: %w", err)
// Inject boilerplate only for Rego policies, not WASM
if engine.DetectPolicyType(script) == engine.PolicyTypeRego {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if the policy type should be a property of spec. I'm ok if we feel comfortable with this magic detection, but this might not stand in the future if we support more engines (jq or something else), since here ware just detecting that this is NOT WASM, but it might be anything else.

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln
Copy link
Member Author

javirln commented Nov 28, 2025

All comments addressed

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln merged commit d1dea77 into chainloop-dev:main Nov 28, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants