Experimental Feature - WASM Policy EngineThese examples are 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
- Currently supported languages: Go and JavaScript only
- Status: Experimental preview - APIs may change in future releases
Common Patterns
Required Fields Validation
Ensure critical fields are present and non-empty.Copy
func validateRequiredFields(comp Component) chainloop.Result {
result := chainloop.Success()
if comp.Name == "" {
result.AddViolation("name is required")
}
if comp.Version == "" {
result.AddViolation("version is required")
}
return result
}
Allowlist/Blocklist Validation
Check values against approved or forbidden lists.Copy
func validateLicense(license string, approved, forbidden []string) chainloop.Result {
result := chainloop.Success()
// Check blocklist first
for _, blocked := range forbidden {
if license == blocked {
result.AddViolationf("%s is forbidden", license)
return result
}
}
// Check allowlist
if len(approved) > 0 {
found := false
for _, allowed := range approved {
if license == allowed {
found = true
break
}
}
if !found {
result.AddViolationf("%s not approved", license)
}
}
return result
}
Nested Structure Validation
Validate arrays of objects (SBOM components, attestation subjects).Copy
func validateComponents(components []Component) chainloop.Result {
result := chainloop.Success()
if len(components) == 0 {
result.AddViolation("must contain at least one component")
}
for i, comp := range components {
if comp.Name == "" {
result.AddViolationf("component %d missing name", i)
}
if comp.Version == "" {
result.AddViolationf("component %d missing version", i)
}
}
return result
}
External API Validation
Verify data against external sources.Copy
func validateWithAPI(name, version string) chainloop.Result {
url := fmt.Sprintf("https://registry.npmjs.org/%s", name)
var data RegistryResponse
err := chainloop.HTTPGetJSON(url, &data)
if err != nil {
return chainloop.Skipf("API unavailable: %v", err)
}
result := chainloop.Success()
if _, exists := data.Versions[version]; !exists {
result.AddViolationf("version %s not found", version)
}
return result
}
Important HTTP Request Notes:
- Always use
skip()when external APIs are unavailable - don’t fail policies due to network issues - All domains are blocked by default except
www.chainloop.devandwww.cisa.gov - Use
--allowed-hostnamesflag to allowlist domains:--allowed-hostnames registry.npmjs.org
Complete Examples
SBOM License Validation
Validate component licenses in a CycloneDX SBOM.Copy
package main
import (
"fmt"
chainloop "github.com/chainloop-dev/chainloop/labs/wasm-policy-sdk/go"
"github.com/extism/go-pdk"
)
type SBOM struct {
Components []Component `json:"components"`
}
type Component struct {
Name string `json:"name"`
Version string `json:"version"`
Licenses []License `json:"licenses"`
}
type License struct {
ID string `json:"id"`
}
//export Execute
func Execute() int32 {
return chainloop.Run(validate)
}
func validate() error {
var sbom SBOM
if err := chainloop.GetMaterialJSON(&sbom); err != nil {
return chainloop.Skip("Not a valid CycloneDX SBOM")
}
approved := []string{"MIT", "Apache-2.0", "BSD-3-Clause"}
forbidden := []string{"GPL-3.0", "AGPL-3.0"}
result := chainloop.Success()
for _, comp := range sbom.Components {
for _, lic := range comp.Licenses {
// Check forbidden
for _, f := range forbidden {
if lic.ID == f {
result.AddViolationf("component '%s' uses forbidden license: %s",
comp.Name, lic.ID)
}
}
// Check approved
approved := false
for _, a := range approved {
if lic.ID == a {
approved = true
}
}
if !approved {
result.AddViolationf("component '%s' license not approved: %s",
comp.Name, lic.ID)
}
}
}
return chainloop.OutputResult(result)
}
func main() {}
sbom.json):
Copy
{
"components": [
{
"name": "lodash",
"version": "4.17.21",
"licenses": [{ "id": "MIT" }]
},
{
"name": "gpl-package",
"version": "1.0.0",
"licenses": [{ "id": "GPL-3.0" }]
}
]
}
Copy
chainloop policy devel eval \
--policy policy.yaml \
--material sbom.json \
--kind SBOM_CYCLONEDX_JSON
Attestation Signature Validation
Validate in-toto attestation has git commit subjects.Copy
package main
import (
chainloop "github.com/chainloop-dev/chainloop/labs/wasm-policy-sdk/go"
"github.com/extism/go-pdk"
)
type Attestation struct {
Subject []Subject `json:"subject"`
}
type Subject struct {
Name string `json:"name"`
}
//export Execute
func Execute() int32 {
return chainloop.Run(validate)
}
func validate() error {
var att Attestation
if err := chainloop.GetMaterialJSON(&att); err != nil {
return chainloop.Skip("Not a valid attestation")
}
result := chainloop.Success()
if len(att.Subject) == 0 {
result.AddViolation("attestation must have at least one subject")
}
for _, subj := range att.Subject {
if subj.Name == "" {
result.AddViolation("subject missing name field")
}
}
return chainloop.OutputResult(result)
}
func main() {}
HTTP API Integration
Verify package version exists in npm registry.Domain Allowlisting RequiredBy default, all HTTP requests are blocked except for:In production, configure allowed hostnames in your policy engine settings.
www.chainloop.devwww.cisa.gov
--allowed-hostnames flag:Copy
chainloop policy devel eval \
--policy policy.yaml \
--material data.json \
--kind EVIDENCE \
--allowed-hostnames registry.npmjs.org,api.example.com
Copy
package main
import (
"fmt"
chainloop "github.com/chainloop-dev/chainloop/labs/wasm-policy-sdk/go"
"github.com/extism/go-pdk"
)
type PackageData struct {
Name string `json:"name"`
Version string `json:"version"`
}
type RegistryResponse struct {
Versions map[string]interface{} `json:"versions"`
}
//export Execute
func Execute() int32 {
return chainloop.Run(validate)
}
func validate() error {
var pkg PackageData
if err := chainloop.GetMaterialJSON(&pkg); err != nil {
return chainloop.Skip("Invalid JSON")
}
url := fmt.Sprintf("https://registry.npmjs.org/%s", pkg.Name)
var registry RegistryResponse
if err := chainloop.HTTPGetJSON(url, ®istry); err != nil {
return chainloop.Skipf("npm registry unavailable: %v", err)
}
result := chainloop.Success()
if _, exists := registry.Versions[pkg.Version]; !exists {
result.AddViolationf("version %s not found in registry", pkg.Version)
}
return chainloop.OutputResult(result)
}
func main() {}
Copy
chainloop policy devel eval \
--policy policy.yaml \
--material package.json \
--kind EVIDENCE \
--allowed-hostnames registry.npmjs.org
Artifact Discovery
Check if related attestations have policy violations.Copy
package main
import (
"fmt"
chainloop "github.com/chainloop-dev/chainloop/labs/wasm-policy-sdk/go"
"github.com/extism/go-pdk"
)
type ContainerImage struct {
ChainloopMetadata struct {
Digest struct {
SHA256 string `json:"sha256"`
} `json:"digest"`
} `json:"chainloop_metadata"`
}
//export Execute
func Execute() int32 {
return chainloop.Run(validate)
}
func validate() error {
var img ContainerImage
if err := chainloop.GetMaterialJSON(&img); err != nil {
return chainloop.Skip("Not a container image")
}
digest := fmt.Sprintf("sha256:%s", img.ChainloopMetadata.Digest.SHA256)
discoverResult, err := chainloop.Discover(digest, "")
if err != nil {
return chainloop.Skipf("Discovery unavailable: %v", err)
}
result := chainloop.Success()
for _, ref := range discoverResult.References {
if ref.Kind == "ATTESTATION" {
if ref.Metadata["hasPolicyViolations"] == "true" {
result.AddViolationf(
"attestation %s contains policy violations", ref.Digest)
}
}
}
return chainloop.OutputResult(result)
}
func main() {}
