Skip to content

Commit

Permalink
Implement custom rego functions for PURL handling
Browse files Browse the repository at this point in the history
Signed-off-by: Mark Bestavros <[email protected]>
  • Loading branch information
mbestavros committed Nov 21, 2023
1 parent eed552c commit 4a48180
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/package-url/packageurl-go v0.1.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/peterh/liner v1.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,8 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.3.0 h1:XtuXmOLIXLjiU2XduuWREDT0LOKtSgos/g7i7RYyoZQ=
github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ=
github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4=
github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
Expand Down
74 changes: 72 additions & 2 deletions internal/evaluator/rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ import (
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"github.com/package-url/packageurl-go"
log "github.com/sirupsen/logrus"

"github.com/enterprise-contract/ec-cli/internal/fetchers/oci"
)

const ociBlobName = "ec.oci.blob"
const purlIsValidName = "ec.purl.is_valid"
const purlParseName = "ec.purl.parse"

func registerOCIBlob() {
decl := rego.Function{
Expand All @@ -49,15 +52,51 @@ func registerOCIBlob() {
types.Named("blob", types.S).Description("the OCI blob"),
),
// As per the documentation, enable memoization to ensure function evaluation is
// deterministic. But also mark it as non-deterministic because it does rely on external
// entities, i.e. OCI registry. https://www.openpolicyagent.org/docs/latest/extensions/
// deterministic.
Memoize: true,
Nondeterministic: true,
}

rego.RegisterBuiltin1(&decl, ociBlob)
}

func registerPURLIsValid() {
decl := rego.Function{
Name: purlIsValidName,
Decl: types.NewFunction(
types.Args(
types.Named("purl", types.S).Description("the PURL"),
),
types.Named("result", types.S).Description("PURL validity"),
),
// As per the documentation, enable memoization to ensure function evaluation is
// deterministic.
Memoize: true,
Nondeterministic: false,
}

rego.RegisterBuiltin1(&decl, purlIsValid)
}

func registerPURLParse() {
decl := rego.Function{
Name: purlParseName,
Decl: types.NewFunction(
types.Args(
types.Named("purl", types.S).Description("the PURL"),
),
types.Named("object", types.S).Description("the parsed PURL object"),
),
// As per the documentation, enable memoization to ensure function evaluation is
// deterministic. But also mark it as non-deterministic because it does rely on external
// entities, i.e. OCI registry. https://www.openpolicyagent.org/docs/latest/extensions/
Memoize: true,
Nondeterministic: false,
}

rego.RegisterBuiltin1(&decl, purlParse)
}

const maxBytes = 10 * 1024 * 1024 // 10 MB

func ociBlob(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
Expand Down Expand Up @@ -118,6 +157,37 @@ func ociBlob(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
return ast.StringTerm(blob.String()), nil
}

func purlIsValid(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
uri, ok := a.Value.(ast.String)
if !ok {
return ast.BooleanTerm(false), nil
}
_, err := packageurl.FromString(uri.String())
if err != nil {
log.Errorf("Parsing PURL %s failed: %s", uri, err)
return ast.BooleanTerm(false), nil
}
return ast.BooleanTerm(true), nil
}

func purlParse(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
uri, ok := a.Value.(ast.String)
if !ok {
return nil, nil
}
instance, err := packageurl.FromString(uri.String())
if err != nil {
log.Errorf("Parsing PURL %s failed: %s", uri, err)
return nil, nil
}
value, err := ast.InterfaceToValue(instance)
if err != nil {
log.Errorf("Converting PURL %s to rego value failed: %s", uri, err)
return nil, nil
}
return ast.NewTerm(value), nil
}

func init() {
registerOCIBlob()
}

0 comments on commit 4a48180

Please sign in to comment.