Documentation Index Fetch the complete documentation index at: https://docs.chainloop.dev/llms.txt
Use this file to discover all available pages before exploring further.
Experimental Feature - WASM Policy Engine This SDK is specifically for writing WASM policies using Chainloop’s experimental WASM policy engine. The WASM policy engine is NOT the default policy engine in Chainloop.
Default engine : Rego-based (recommended for most users)
WASM engine : Experimental alternative for Go/JavaScript policies
Status : Experimental preview - APIs may change in future releases
For the default Rego-based policy engine, see Writing Custom Policies .
Prerequisites
The Chainloop JavaScript SDK for WASM policies is built on top of the Extism JavaScript PDK , which enables JavaScript code to run inside WebAssembly with QuickJS.
Required tools:
For package management and building. # Verify installation
node --version # Should be v16+
Compiles JavaScript to WebAssembly. # Install globally
npm install -g @extism/js-pdk
# Verify installation
extism-js --version
Dependencies:
@chainloop-dev/policy-sdk - Chainloop WASM Policy SDK (npm package)
@extism/js-pdk - Extism JavaScript PDK (auto-installed)
esbuild - JavaScript bundler (dev dependency)
The Extism JS PDK handles JavaScript-to-WASM compilation using QuickJS, while Chainloop’s WASM Policy SDK provides policy-specific APIs for material validation.
Project Setup
Install Dependencies
npm init -y
npm install @chainloop-dev/policy-sdk
npm install --save-dev esbuild
esbuild.js:
const esbuild = require ( 'esbuild' );
esbuild . build ({
entryPoints: [ 'policy.js' ],
outdir: 'dist' ,
bundle: true ,
format: 'cjs' ,
target: [ 'es2020' ],
platform: 'node' ,
}). catch (() => process . exit ( 1 ));
package.json:
{
"name" : "my-policy" ,
"scripts" : {
"build" : "node esbuild.js && extism-js dist/policy.js -i policy.d.ts -o policy.wasm"
},
"dependencies" : {
"@chainloop-dev/policy-sdk" : "^0.1.0"
},
"devDependencies" : {
"esbuild" : "^0.19.0"
}
}
policy.d.ts:
declare module "main" {
export function Execute (): I32 ;
}
policy.yaml:
apiVersion : workflowcontract.chainloop.dev/v1
kind : Policy
metadata :
name : my-js-policy
description : My custom JavaScript policy
spec :
policies :
- kind : EVIDENCE
path : policy.wasm
Complete Example
const {
getMaterialJSON ,
success ,
skip ,
outputResult ,
logInfo ,
logError ,
run
} = require ( '@chainloop-dev/policy-sdk' );
function Execute () {
return run (() => {
// Parse the SBOM material
const sbom = getMaterialJSON ();
if (! sbom . components ) {
outputResult ( skip ( "Not a valid CycloneDX SBOM" ));
return ;
}
logInfo ( `Validating SBOM with ${ sbom . components . length } components` );
const result = success ();
const approved = [ "MIT" , "Apache-2.0" , "BSD-3-Clause" , "ISC" ];
// Validate each component
sbom . components . forEach (( component , index ) => {
// Check version
if (! component . version || component . version === "" ) {
result . addViolation ( `component ' ${ component . name } ' missing version` );
}
// Check licenses
if (! component . licenses || component . licenses . length === 0 ) {
result . addViolation ( `component ' ${ component . name } ' missing license` );
return ;
}
// Validate licenses
component . licenses . forEach ( license => {
const licenseID = license . id || license . name ;
if (! approved . includes ( licenseID )) {
result . addViolation (
`component ' ${ component . name } ' has unapproved license: ${ licenseID } `
);
}
});
});
if ( result . hasViolations ()) {
logError ( `SBOM validation failed with ${ result . violations . length } violations` );
} else {
logInfo ( "SBOM validation passed" );
}
outputResult ( result );
});
}
module . exports = { Execute };
API Quick Reference
The JavaScript SDK provides functions for:
Execution : run() - Entry point wrapper
Material Extraction : getMaterialJSON(), getMaterialString(), getMaterialBytes()
Arguments : getArgs(), getArgString(), getArgStringDefault()
Results : success(), fail(), skip(), outputResult(), addViolation(), hasViolations()
Logging : logInfo(), logDebug(), logWarn(), logError()
HTTP Requests : httpGet(), httpGetJSON(), httpPost(), httpPostJSON()
Artifact Discovery : discover(), discoverByDigest()
Building
This runs:
esbuild - Bundles policy.js and SDK
extism-js - Compiles bundle to WASM
Output:
dist/policy.js - Bundled JavaScript (~7KB)
policy.wasm - Compiled WASM (~2.1MB, includes QuickJS runtime)
Testing
test.sh:
#!/bin/bash
npm run build
echo "Testing valid SBOM..."
chainloop policy devel eval \
--policy policy.yaml \
--material test-data/valid-sbom.json \
--kind SBOM_CYCLONEDX_JSON
echo "Testing invalid SBOM..."
chainloop policy devel eval \
--policy policy.yaml \
--material test-data/invalid-sbom.json \
--kind SBOM_CYCLONEDX_JSON
JavaScript Compatibility
Supported:
✅ ES2020 JavaScript features
✅ JSON parsing and manipulation
✅ String operations and regex
✅ Arrays, objects, and basic types
✅ Synchronous operations
Not Supported:
❌ async/await (no Promise support)
❌ Node.js built-ins (fs, path, http)
❌ ES modules (use CommonJS)
❌ Browser APIs (fetch, localStorage)
❌ setTimeout/setInterval
❌ Symbols and WeakMaps
Recommended:
// ✅ Good: Simple objects
const component = {
name: "lodash" ,
version: "4.17.21"
};
// ✅ Good: Synchronous operations
components . forEach ( comp => {
if (! comp . name ) {
result . addViolation ( "Missing name" );
}
});
// ❌ Avoid: Async operations
// async function validate() { // Not supported
// const data = await fetch(...);
// }
Best Practices
Use simple data structures - Plain objects and arrays
Validate early - Check material format first
Clear violation messages - Include specific details
Use skip appropriately - Don’t fail for wrong material types
Test with real data - Use actual artifacts
Log progress - Aid debugging
Handle errors - Use try-catch for parsing
Next Steps
Examples Explore complete policy examples
Go SDK Compare with the Go SDK