Skip to content

Commit b863f37

Browse files
authored
Merge pull request #42 from puerco/generalize-2
2 parents 6d3f27f + f9f8027 commit b863f37

File tree

15 files changed

+745
-64
lines changed

15 files changed

+745
-64
lines changed

pkg/elements/edge.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright 2025 The Protobom Authors
3+
4+
package elements
5+
6+
import (
7+
"fmt"
8+
"reflect"
9+
10+
"github.com/google/cel-go/cel"
11+
"github.com/google/cel-go/common/types"
12+
"github.com/google/cel-go/common/types/ref"
13+
"github.com/google/cel-go/common/types/traits"
14+
"github.com/protobom/protobom/pkg/sbom"
15+
)
16+
17+
var EdgeType = cel.ObjectType("protobom.protobom.Edge")
18+
19+
type Edge struct {
20+
*sbom.Edge
21+
}
22+
23+
// ConvertToNative implements ref.Val.ConvertToNative.
24+
func (e *Edge) ConvertToNative(typeDesc reflect.Type) (any, error) {
25+
if reflect.TypeOf(e).AssignableTo(typeDesc) {
26+
return e, nil
27+
} else if reflect.TypeOf(e.Edge).AssignableTo(typeDesc) {
28+
return e.Edge, nil
29+
}
30+
31+
return nil, fmt.Errorf("type conversion error from 'Edge' to '%v'", typeDesc)
32+
}
33+
34+
// ConvertToType implements ref.Val.ConvertToType.
35+
func (e *Edge) ConvertToType(typeVal ref.Type) ref.Val {
36+
switch typeVal {
37+
case EdgeType:
38+
return e
39+
// TODO(puerco): Add sbom.Doc type conversion
40+
case types.TypeType:
41+
return DocumentType
42+
}
43+
return types.NewErr("type conversion error from '%s' to '%s'", EdgeType, typeVal)
44+
}
45+
46+
// Equal implements ref.Val.Equal.
47+
func (e *Edge) Equal(other ref.Val) ref.Val {
48+
// TODO(puerco): Implement with e.Edge.Equal()
49+
return types.MaybeNoSuchOverloadErr(other)
50+
}
51+
52+
func (*Edge) Type() ref.Type {
53+
return EdgeType
54+
}
55+
56+
// Value implements ref.Val.Value.
57+
func (e *Edge) Value() any {
58+
return e.Edge
59+
}
60+
61+
var _ traits.Indexer = (*Edge)(nil)
62+
63+
// Get is the getter to implement the indexer trait
64+
func (e *Edge) Get(index ref.Val) ref.Val {
65+
switch v := index.Value().(type) {
66+
case string:
67+
switch v {
68+
case propType:
69+
if _, ok := sbom.Edge_Type_name[int32(e.GetType())]; ok {
70+
return types.String(sbom.Edge_Type_name[int32(e.GetType())])
71+
}
72+
return types.String(sbom.Edge_Type_name[0])
73+
case "from":
74+
return types.String(e.From)
75+
case "to":
76+
return types.NewDynamicList(types.DefaultTypeAdapter, e.To)
77+
default:
78+
return types.NewErr("no such key %v", index)
79+
}
80+
81+
default:
82+
return types.NewErr("no such key %v", index)
83+
}
84+
}

pkg/elements/elements.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright 2025 The Protobom Authors
3+
4+
// Package elements has wrappers of the protobom elements (from the
5+
// main protobuf definition) that implement the ref.Val interface
6+
// used by the CEL runtime. This lets the library expose them natively
7+
// in the CEL evaluation environment.
8+
//
9+
// As of v0.1.0 the elements package has a complete wrappers library
10+
// for the native elements defined in protobom v0.5.x.
11+
package elements
12+
13+
// Constants for common property names
14+
const (
15+
propType = "type"
16+
propHashes = "hashes"
17+
propComment = "comment"
18+
propName = "name"
19+
propVersion = "version"
20+
)

pkg/elements/externalreference.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright 2025 The Protobom Authors
3+
4+
package elements
5+
6+
import (
7+
"fmt"
8+
"reflect"
9+
10+
"github.com/google/cel-go/cel"
11+
"github.com/google/cel-go/common/types"
12+
"github.com/google/cel-go/common/types/ref"
13+
"github.com/google/cel-go/common/types/traits"
14+
"github.com/protobom/protobom/pkg/sbom"
15+
)
16+
17+
var ExternalReferenceType = cel.ObjectType("protobom.protobom.ExternalReference")
18+
19+
type ExternalReference struct {
20+
*sbom.ExternalReference
21+
}
22+
23+
// ConvertToNative implements ref.Val.ConvertToNative.
24+
func (er *ExternalReference) ConvertToNative(typeDesc reflect.Type) (any, error) {
25+
if reflect.TypeOf(er).AssignableTo(typeDesc) {
26+
return er, nil
27+
} else if reflect.TypeOf(er.ExternalReference).AssignableTo(typeDesc) {
28+
return er.ExternalReference, nil
29+
}
30+
31+
return nil, fmt.Errorf("type conversion error from 'ExternalReference' to '%v'", typeDesc)
32+
}
33+
34+
// ConvertToType implements ref.Val.ConvertToType.
35+
func (er *ExternalReference) ConvertToType(typeVal ref.Type) ref.Val {
36+
switch typeVal {
37+
case ExternalReferenceType:
38+
return er
39+
case types.TypeType:
40+
return DocumentType
41+
}
42+
return types.NewErr("type conversion error from '%s' to '%s'", ExternalReferenceType, typeVal)
43+
}
44+
45+
// Equal implements ref.Val.Equal.
46+
func (er *ExternalReference) Equal(other ref.Val) ref.Val {
47+
// TODO(puerco): Implement with e.Edge.Equal()
48+
return types.MaybeNoSuchOverloadErr(other)
49+
}
50+
51+
func (*ExternalReference) Type() ref.Type {
52+
return ExternalReferenceType
53+
}
54+
55+
// Value implements ref.Val.Value.
56+
func (er *ExternalReference) Value() any {
57+
return er.ExternalReference
58+
}
59+
60+
var _ traits.Indexer = (*ExternalReference)(nil)
61+
62+
// Get is the getter to implement the indexer trait
63+
func (er *ExternalReference) Get(index ref.Val) ref.Val {
64+
switch v := index.Value().(type) {
65+
case string:
66+
switch v {
67+
case propType:
68+
if _, ok := sbom.Edge_Type_name[int32(er.GetType())]; ok {
69+
return types.String(sbom.ExternalReference_ExternalReferenceType_name[int32(er.GetType())])
70+
}
71+
return types.String(sbom.ExternalReference_ExternalReferenceType_name[0])
72+
case "url":
73+
return types.String(er.Url)
74+
case propComment:
75+
return types.String(er.Comment)
76+
case "authority":
77+
return types.String(er.Authority)
78+
case propHashes:
79+
ret := map[string]string{}
80+
for a, v := range er.Hashes {
81+
if _, ok := sbom.HashAlgorithm_name[a]; ok {
82+
ret[sbom.HashAlgorithm_name[a]] = v
83+
} else {
84+
ret[sbom.HashAlgorithm_name[0]] = v
85+
}
86+
}
87+
return types.NewDynamicMap(types.DefaultTypeAdapter, ret)
88+
default:
89+
return types.NewErr("no such key %v", index)
90+
}
91+
92+
default:
93+
return types.NewErr("no such key %v", index)
94+
}
95+
}

pkg/elements/metadata.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,34 @@ func (md *Metadata) Get(index ref.Val) ref.Val {
6767
switch v {
6868
case "id":
6969
return types.String(md.Id)
70-
case "name":
70+
case propName:
7171
return types.String(md.Name)
72-
case "version":
72+
case propVersion:
7373
return types.String(md.Version)
7474
case "tools":
75-
return types.NewDynamicList(types.DefaultTypeAdapter, md.Tools)
75+
toolsList := make([]ref.Val, len(md.Tools))
76+
for i, t := range md.Tools {
77+
toolsList[i] = &Tool{
78+
Tool: t,
79+
}
80+
}
81+
return types.NewRefValList(types.DefaultTypeAdapter, toolsList)
82+
case "authors":
83+
authorsList := make([]ref.Val, len(md.Authors))
84+
for i, p := range md.Authors {
85+
authorsList[i] = &Person{
86+
Person: p,
87+
}
88+
}
89+
return types.NewRefValList(types.DefaultTypeAdapter, authorsList)
7690
case "date":
7791
return types.Timestamp{Time: md.Date.AsTime()}
78-
case "comment":
92+
case propComment:
7993
return types.String(md.Comment)
94+
case "source_data":
95+
return &SourceData{
96+
SourceData: md.SourceData,
97+
}
8098
default:
8199
return types.NewErr("no such key %v", index)
82100
}

pkg/elements/node.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,11 @@ func (n *Node) Get(index ref.Val) ref.Val {
8888
switch v {
8989
case "id":
9090
return types.String(n.Id)
91-
case "name":
91+
case propName:
9292
return types.String(n.Name)
93-
case "type":
93+
case propType:
9494
return types.String(n.Node.Type.String())
95-
case "version":
95+
case propVersion:
9696
return types.String(n.Version)
9797
case "file_name":
9898
return types.String(n.FileName)
@@ -110,7 +110,7 @@ func (n *Node) Get(index ref.Val) ref.Val {
110110
return types.String(n.Copyright)
111111
case "source_info":
112112
return types.String(n.SourceInfo)
113-
case "comment":
113+
case propComment:
114114
return types.String(n.Comment)
115115
case "summary":
116116
return types.String(n.Summary)
@@ -157,7 +157,7 @@ func (n *Node) Get(index ref.Val) ref.Val {
157157
}
158158
}
159159
return types.NewDynamicMap(types.DefaultTypeAdapter, ret)
160-
case "hashes":
160+
case propHashes:
161161
ret := map[string]string{}
162162
for a, v := range n.Hashes {
163163
if _, ok := sbom.HashAlgorithm_name[a]; ok {

pkg/elements/nodelist.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,26 @@ var _ traits.Indexer = (*NodeList)(nil)
133133
func (nl *NodeList) Get(index ref.Val) ref.Val {
134134
switch v := index.Value().(type) {
135135
case string:
136-
if v == "nodes" {
137-
nodesList := make([]ref.Val, len(v))
136+
switch v {
137+
case "nodes":
138+
nodesList := make([]ref.Val, len(nl.Nodes))
138139
for i, node := range nl.Nodes {
139140
n := Node{
140141
Node: node,
141142
}
142143
nodesList[i] = n.ConvertToType(NodeType)
143144
}
144145
return types.NewRefValList(types.DefaultTypeAdapter, nodesList)
146+
case "edges":
147+
edgeList := make([]ref.Val, len(nl.Edges))
148+
for i, e := range nl.Edges {
149+
edgeList[i] = &Edge{
150+
Edge: e,
151+
}
152+
}
153+
return types.NewRefValList(types.DefaultTypeAdapter, edgeList)
145154
}
146-
return types.NewErr("no such key %v", index)
155+
return types.NewErr("no such key in edge: %v", index)
147156
default:
148157
return types.NewErr("no such key %v", index)
149158
}

pkg/elements/person.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/google/cel-go/checker/decls"
1212
"github.com/google/cel-go/common/types"
1313
"github.com/google/cel-go/common/types/ref"
14+
"github.com/google/cel-go/common/types/traits"
1415
"github.com/protobom/protobom/pkg/sbom"
1516
)
1617

@@ -57,3 +58,38 @@ func (*Person) Type() ref.Type {
5758
func (p *Person) Value() any {
5859
return p.Person
5960
}
61+
62+
var _ traits.Indexer = (*Person)(nil)
63+
64+
// Get is the getter to implement the indexer trait
65+
func (p *Person) Get(index ref.Val) ref.Val {
66+
switch v := index.Value().(type) {
67+
case string:
68+
switch v {
69+
case propName:
70+
return types.String(p.GetName())
71+
case "is_org":
72+
return types.Bool(p.GetIsOrg())
73+
case "email":
74+
return types.String(p.GetEmail())
75+
case "phone":
76+
return types.String(p.GetPhone())
77+
case "contacts":
78+
personsList := []ref.Val{}
79+
if p.GetContacts() != nil {
80+
for _, person := range p.GetContacts() {
81+
p := &Person{
82+
Person: person,
83+
}
84+
personsList = append(personsList, p)
85+
}
86+
}
87+
return types.NewRefValList(types.DefaultTypeAdapter, personsList)
88+
default:
89+
return types.NewErr("no such key %v", index)
90+
}
91+
92+
default:
93+
return types.NewErr("no such key %v", index)
94+
}
95+
}

0 commit comments

Comments
 (0)