Handle errors from Go in Rego. Support for skipping TL (#47)
* Make TL logging/verification optional * Return errors from go-lang fns * Update pkg/policy/rego.go Co-authored-by: Jonny Stoten <jonny@jonnystoten.com> * Update pkg/attestation/sign.go Co-authored-by: Joel Kamp <joel.kamp@docker.com> * Move public key marshelling until later * Simplify logSignature and pass down opts --------- Co-authored-by: Jonny Stoten <jonny@jonnystoten.com> Co-authored-by: Joel Kamp <joel.kamp@docker.com>
This commit is contained in:
@@ -133,21 +133,42 @@ func jsonGenerator[T any]() func(t *ast.Term, ec *rego.EvalContext) (any, error)
|
||||
}
|
||||
}
|
||||
|
||||
var dynamicObj = types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))
|
||||
var arrayObj = types.NewArray(nil, dynamicObj)
|
||||
var setObj = types.NewSet(dynamicObj)
|
||||
var dynamicObj = types.NewObject(nil, types.NewDynamicProperty(types.A, types.A))
|
||||
|
||||
var verifyDecl = &ast.Builtin{
|
||||
Name: "attestations.verify_envelope",
|
||||
Decl: types.NewFunction(types.Args(dynamicObj, arrayObj), dynamicObj),
|
||||
Name: "attest.verify",
|
||||
Decl: types.NewFunction(types.Args(dynamicObj, dynamicObj), dynamicObj),
|
||||
Nondeterministic: true,
|
||||
}
|
||||
var attestDecl = &ast.Builtin{
|
||||
Name: "attestations.attestation",
|
||||
Decl: types.NewFunction(types.Args(types.S), setObj),
|
||||
Name: "attest.fetch",
|
||||
Decl: types.NewFunction(types.Args(types.S), dynamicObj),
|
||||
Nondeterministic: true,
|
||||
}
|
||||
|
||||
func wrapFunctionResult(value *ast.Term, err error) (*ast.Term, error) {
|
||||
var terms [][2]*ast.Term
|
||||
if err != nil {
|
||||
terms = append(terms, [2]*ast.Term{ast.StringTerm("error"), ast.StringTerm(err.Error())})
|
||||
}
|
||||
if value != nil {
|
||||
terms = append(terms, [2]*ast.Term{ast.StringTerm("value"), value})
|
||||
}
|
||||
return ast.ObjectTerm(terms...), nil
|
||||
}
|
||||
|
||||
func handleErrors1(f func(rCtx rego.BuiltinContext, a *ast.Term) (*ast.Term, error)) rego.Builtin1 {
|
||||
return func(rCtx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
|
||||
return wrapFunctionResult(f(rCtx, a))
|
||||
}
|
||||
}
|
||||
|
||||
func handleErrors2(f func(rCtx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error)) rego.Builtin2 {
|
||||
return func(rCtx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error) {
|
||||
return wrapFunctionResult(f(rCtx, a, b))
|
||||
}
|
||||
}
|
||||
|
||||
func RegoFunctions(resolver oci.AttestationResolver) []*tester.Builtin {
|
||||
return []*tester.Builtin{
|
||||
{
|
||||
@@ -159,7 +180,7 @@ func RegoFunctions(resolver oci.AttestationResolver) []*tester.Builtin {
|
||||
Memoize: true,
|
||||
Nondeterministic: verifyDecl.Nondeterministic,
|
||||
},
|
||||
verifyIntotoEnvelope),
|
||||
handleErrors2(verifyIntotoEnvelope)),
|
||||
},
|
||||
{
|
||||
Decl: attestDecl,
|
||||
@@ -170,12 +191,12 @@ func RegoFunctions(resolver oci.AttestationResolver) []*tester.Builtin {
|
||||
Memoize: true,
|
||||
Nondeterministic: attestDecl.Nondeterministic,
|
||||
},
|
||||
fetchIntotoAttestations(resolver)),
|
||||
handleErrors1(fetchIntotoAttestations(resolver))),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func fetchIntotoAttestations(resolver oci.AttestationResolver) func(rego.BuiltinContext, *ast.Term) (*ast.Term, error) {
|
||||
func fetchIntotoAttestations(resolver oci.AttestationResolver) rego.Builtin1 {
|
||||
return func(rCtx rego.BuiltinContext, predicateTypeTerm *ast.Term) (*ast.Term, error) {
|
||||
predicateTypeStr, ok := predicateTypeTerm.Value.(ast.String)
|
||||
if !ok {
|
||||
@@ -205,22 +226,19 @@ func fetchIntotoAttestations(resolver oci.AttestationResolver) func(rego.Builtin
|
||||
}
|
||||
}
|
||||
|
||||
func verifyIntotoEnvelope(rCtx rego.BuiltinContext, envTerm, keysTerm *ast.Term) (*ast.Term, error) {
|
||||
func verifyIntotoEnvelope(rCtx rego.BuiltinContext, envTerm, optsTerm *ast.Term) (*ast.Term, error) {
|
||||
env := new(att.Envelope)
|
||||
var keys att.Keys
|
||||
opts := new(att.VerifyOptions)
|
||||
err := ast.As(envTerm.Value, env)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to cast envelope: %w", err)
|
||||
}
|
||||
err = ast.As(keysTerm.Value, &keys)
|
||||
err = ast.As(optsTerm.Value, &opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to cast keys: %w", err)
|
||||
return nil, fmt.Errorf("failed to cast verifier options: %w", err)
|
||||
}
|
||||
keysmap := make(map[string]att.KeyMetadata, len(keys))
|
||||
for _, key := range keys {
|
||||
keysmap[key.ID] = key
|
||||
}
|
||||
payload, err := att.VerifyDSSE(rCtx.Context, env, keysmap)
|
||||
|
||||
payload, err := att.VerifyDSSE(rCtx.Context, env, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -242,7 +260,6 @@ func verifyIntotoEnvelope(rCtx rego.BuiltinContext, envTerm, keysTerm *ast.Term)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ast.NewTerm(value), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@ package attest
|
||||
import rego.v1
|
||||
|
||||
keys := [{
|
||||
"id": "a0c296026645799b2a297913878e81b0aefff2a0c301e97232f717e14402f3e4",
|
||||
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgH23D1i2+ZIOtVjmfB7iFvX8AhVN\n9CPJ4ie9axw+WRHozGnRy99U2dRge3zueBBg2MweF0zrToXGig2v3YOrdw==\n-----END PUBLIC KEY-----",
|
||||
"from": "2023-12-15T14:00:00Z",
|
||||
"to": null
|
||||
"id": "a0c296026645799b2a297913878e81b0aefff2a0c301e97232f717e14402f3e4",
|
||||
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgH23D1i2+ZIOtVjmfB7iFvX8AhVN\n9CPJ4ie9axw+WRHozGnRy99U2dRge3zueBBg2MweF0zrToXGig2v3YOrdw==\n-----END PUBLIC KEY-----",
|
||||
"from": "2023-12-15T14:00:00Z",
|
||||
"to": null,
|
||||
}]
|
||||
|
||||
opts := {"keys": keys}
|
||||
|
||||
success if {
|
||||
some env in attestations.attestation("foo")
|
||||
statement := attestations.verify_envelope(env, keys)
|
||||
some env in attest.fetch("foo")
|
||||
statement := attest.verify(env, opts)
|
||||
}
|
||||
|
||||
result := {
|
||||
"success": success
|
||||
}
|
||||
result := {"success": success}
|
||||
|
||||
@@ -3,19 +3,28 @@ package attest
|
||||
import rego.v1
|
||||
|
||||
keys := [{
|
||||
"id": "a0c296026645799b2a297913878e81b0aefff2a0c301e97232f717e14402f3e4",
|
||||
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHyZpSgzvqFqNv7f3x7865OS38rAb\nQMcff55zM2UH/KR3Pr84a8QsGDNgaNGzJQJWjtMSgfV8WnNoffNK+svFNg==\n-----END PUBLIC KEY-----",
|
||||
"from": "2023-12-15T14:00:00Z",
|
||||
"to": null,
|
||||
"id": "a0c296026645799b2a297913878e81b0aefff2a0c301e97232f717e14402f3e4",
|
||||
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHyZpSgzvqFqNv7f3x7865OS38rAb\nQMcff55zM2UH/KR3Pr84a8QsGDNgaNGzJQJWjtMSgfV8WnNoffNK+svFNg==\n-----END PUBLIC KEY-----",
|
||||
"from": "2023-12-15T14:00:00Z",
|
||||
"to": null,
|
||||
}]
|
||||
|
||||
default success := false
|
||||
|
||||
success if {
|
||||
some env in attestations.attestation("foo")
|
||||
statement := attestations.verify_envelope(env, keys)
|
||||
provs(pred) := p if {
|
||||
res := attest.fetch(pred)
|
||||
not res.error
|
||||
p := res.value
|
||||
}
|
||||
|
||||
result := {
|
||||
"success": success
|
||||
atts := union({provs("foo")})
|
||||
|
||||
opts := {"keys": keys}
|
||||
|
||||
success if {
|
||||
some env in atts
|
||||
res := attest.verify(env, opts)
|
||||
not res.error
|
||||
}
|
||||
|
||||
result := {"success": success}
|
||||
|
||||
Reference in New Issue
Block a user