ComplyPack is a Go library for packing, unpacking, signing, and verifying OCI artifacts containing policy bundles. It provides an evaluator-agnostic format for distributing compliance policies using OCI registries.
- OCI Artifact Packaging - Pack policy content into OCI Image Manifest v1.1 artifacts
- Evaluator-Agnostic - Supports any policy language (OPA, CEL, etc.) via evaluator-id dispatch
- Signing & Verification - Built-in support for keyed and keyless (Sigstore) signing
- Memory-Safe - 100MB content size limit prevents memory exhaustion attacks
- Provenance Tracking - Optional Gemara linkage for generated policies
- Flexible API - Functional options pattern for clean, extensible configuration
go get github.com/complytime/complypackpackage main
import (
"context"
"strings"
"github.com/complytime/complypack/pkg/complypack"
"oras.land/oras-go/v2/content/memory"
)
func main() {
ctx := context.Background()
store := memory.New()
// Configure the artifact
cfg := complypack.Config{
EvaluatorID: "io.complytime.opa",
Version: "1.0.0",
}
// Pack the policy content
content := strings.NewReader("policy content here")
desc, err := complypack.Pack(ctx, store, cfg, content)
if err != nil {
panic(err)
}
// desc.Digest contains the artifact reference
}result, err := complypack.Unpack(ctx, store, desc)
if err != nil {
panic(err)
}
defer result.Content.Close()
// Access configuration
fmt.Printf("Evaluator: %s\n", result.Config.EvaluatorID)
// Read content
content, _ := io.ReadAll(result.Content)// Pack with keyed signing
desc, err := complypack.Pack(ctx, store, cfg, content,
complypack.WithSigning("/path/to/private.key"))
// Pack with keyless signing (OIDC)
desc, err := complypack.Pack(ctx, store, cfg, content,
complypack.WithKeylessSigning("user@example.com", "https://accounts.google.com"))
// Unpack with verification
result, err := complypack.Unpack(ctx, store, desc,
complypack.WithVerification("/path/to/public.key"))cfg := complypack.Config{
EvaluatorID: "io.complytime.opa",
Version: "1.0.0",
Source: &complypack.Provenance{
GemaraContent: "oci://registry/gemara/controls:v1.0.0",
PolicyID: "policy-123",
},
}ComplyPack uses OCI Image Manifest v1.1 with the following structure:
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.complypack.artifact.v1",
"config": {
"mediaType": "application/vnd.complypack.config.v1+json",
"digest": "sha256:...",
"size": 324
},
"layers": [
{
"mediaType": "application/vnd.complypack.content.v1.tar+gzip",
"digest": "sha256:...",
"size": 1024000
}
]
}| Purpose | Media Type |
|---|---|
| Artifact Type | application/vnd.complypack.artifact.v1 |
| Config Layer | application/vnd.complypack.config.v1+json |
| Content Layer | application/vnd.complypack.content.v1.tar+gzip |
The content layer is opaque - the library treats it as raw bytes. For OPA-based policies, this would typically be an OPA bundle tarball. The evaluator-id in the config determines how consumers should interpret the content.
Pack() loads the entire content into memory for digest calculation. Content size is limited to 100MB to prevent memory exhaustion. For larger artifacts, consider alternative approaches or splitting content.
ComplyPack uses sentinel errors for predictable error checking:
import "errors"
_, err := complypack.Pack(ctx, store, cfg, content)
if errors.Is(err, complypack.ErrEmptyContent) {
// Handle empty content
}
if errors.Is(err, complypack.ErrContentTooLarge) {
// Handle content exceeding 100MB limit
}Available sentinel errors:
ErrInvalidConfig- Config validation failedErrEmptyContent- Content reader returned zero bytesErrContentTooLarge- Content exceeds 100MB limitErrSigningFailed- Signing operation failedErrVerificationFailed- Signature verification failedErrInvalidMediaType- Unexpected media type in manifestErrNoContentLayer- Manifest missing content layer
ComplyPack works with any ORAS-compatible storage backend:
// In-memory (for testing)
store := memory.New()
// Filesystem
store, err := file.New("/tmp/oci-store")
defer store.Close()
// Remote registry (via ORAS)
repo, err := remote.NewRepository("ghcr.io/org/repo")
store := repo- Signing/Verification: Validation logic is implemented, but full sigstore-go integration is pending. Signing/verification options will return "not yet implemented" errors.
- Content Size: Maximum 100MB per artifact
- Single Content Layer: Only one content layer per artifact is supported
Contributions are welcome! Please see our contributing guidelines.
Apache License 2.0 - see LICENSE for details.
- ORAS - OCI Registry as Storage
- Sigstore - Keyless signing infrastructure
- Open Policy Agent - Policy-based control
- Gemara - Compliance policy framework