go-gemara
May 4, 2026 ยท View on GitHub
Go SDK for parsing and converting Gemara documents.
Overview
This repository provides Go types and utilities for working with Gemara documents.
The Go types are generated from CUE schemas published in the Gemara CUE module (github.com/gemaraproj/gemara@v0) available in the CUE Central Registry.
Installation
go get github.com/gemaraproj/go-gemara
Usage
CLI Tool
The oscalexport command-line tool converts Gemara documents to OSCAL format.
Building the CLI
make build
This builds binaries to ./bin/ directory.
Converting a Control Catalog
./bin/oscalexport catalog ./path/to/catalog.yaml --output ./catalog.json
Converting a Guidance Catalog
./bin/oscalexport guidance ./path/to/guidance.yaml \
--catalog-output ./guidance.json \
--profile-output ./profile.json
Library Usage
Loading Gemara Documents
package main
import (
"github.com/gemaraproj/go-gemara"
"github.com/gemaraproj/go-gemara/fetcher"
)
func main() {
f := &fetcher.File{}
// Load a Guidance Catalog
guidance, err := gemara.Load[gemara.GuidanceCatalog](f, "path/to/guidance.yaml")
if err != nil {
panic(err)
}
// Load a Control Catalog
catalog, err := gemara.Load[gemara.ControlCatalog](f, "path/to/catalog.yaml")
if err != nil {
panic(err)
}
_ = guidance
_ = catalog
}
Converting to OSCAL
package main
import (
"github.com/gemaraproj/go-gemara"
"github.com/gemaraproj/go-gemara/fetcher"
"github.com/gemaraproj/go-gemara/gemaraconv"
)
func main() {
f := &fetcher.File{}
// Convert Control Catalog to OSCAL
catalog, err := gemara.Load[gemara.ControlCatalog](f, "path/to/catalog.yaml")
if err != nil {
panic(err)
}
oscalCatalog, err := gemaraconv.ControlCatalog(catalog).ToOSCAL()
if err != nil {
panic(err)
}
// Convert Guidance Catalog to OSCAL
guidance, err := gemara.Load[gemara.GuidanceCatalog](f, "path/to/guidance.yaml")
if err != nil {
panic(err)
}
_, oscalProfile, err := gemaraconv.GuidanceCatalog(guidance).ToOSCAL("relative/path/to/catalog.json")
if err != nil {
panic(err)
}
_ = oscalCatalog
_ = oscalProfile
}
Bundling and Distributing Artifacts via OCI
package main
import (
"context"
"os"
"github.com/gemaraproj/go-gemara/bundle"
"github.com/gemaraproj/go-gemara/fetcher"
"oras.land/oras-go/v2"
"oras.land/oras-go/v2/content/oci"
"oras.land/oras-go/v2/registry/remote"
)
func main() {
ctx := context.Background()
data, _ := os.ReadFile("policy.yaml")
src := bundle.File{Name: "policy.yaml", Data: data}
// Assemble the full dependency tree (extends + imports)
m := bundle.Manifest{BundleVersion: "1", GemaraVersion: "v1.0.0"}
asm := bundle.NewAssembler(&fetcher.URI{})
b, _ := asm.Assemble(ctx, m, src)
// Pack into a local OCI layout
layoutStore, _ := oci.New("./bundle-output")
desc, _ := bundle.Pack(ctx, layoutStore, b)
_ = layoutStore.Tag(ctx, desc, "v1.0.0")
// Push to a remote OCI registry
repo, _ := remote.NewRepository("registry.example.com/org/bundle")
tagDesc, _ := layoutStore.Resolve(ctx, "v1.0.0")
_ = oras.CopyGraph(ctx, layoutStore, repo, tagDesc, oras.DefaultCopyGraphOptions)
_ = repo.Tag(ctx, tagDesc, "v1.0.0")
// Unpack from the registry
unpacked, _ := bundle.Unpack(ctx, repo, "v1.0.0")
_ = unpacked
}
Converting to SARIF
package main
import (
"github.com/gemaraproj/go-gemara"
"github.com/gemaraproj/go-gemara/fetcher"
"github.com/gemaraproj/go-gemara/gemaraconv"
)
func main() {
f := &fetcher.File{}
// Load Control Catalog (required for SARIF conversion)
catalog, err := gemara.Load[gemara.ControlCatalog](f, "path/to/catalog.yaml")
if err != nil {
panic(err)
}
// Convert EvaluationLog to SARIF
evaluationLog := gemara.EvaluationLog{
// ... populate evaluation log ...
}
sarifBytes, err := gemaraconv.EvaluationLog(evaluationLog).ToSARIF(gemaraconv.WithArtifactURI("file:///path/to/artifact.md"), gemaraconv.WithCatalog(catalog))
if err != nil {
panic(err)
}
_ = sarifBytes
}
Development
Building
make build
Testing
# Run all tests
make test
# Run tests with coverage
make testcov
# Check coverage threshold
make coverage-check
Linting
make lint
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.