Skip to content

Commit a609d7b

Browse files
authored
Merge pull request #272 from marcelamelara/add-scai-bindings
Add Go and Python bindings for SCAI predicate
2 parents 5944353 + 720d8db commit a609d7b

File tree

2 files changed

+123
-0
lines changed
  • go/predicates/scai/v0
  • python/in_toto_attestation/predicates/scai/v0

2 files changed

+123
-0
lines changed

go/predicates/scai/v0/scai.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Wrapper APIs for SCAI AttributeAssertion and AttributeReport protos.
3+
*/
4+
5+
package v0
6+
7+
import "fmt"
8+
9+
func (a *AttributeAssertion) Validate() error {
10+
// at least the attribute field is required
11+
if a.GetAttribute() == "" {
12+
return fmt.Errorf("The attribute field is required")
13+
}
14+
15+
// check target and evidence are valid ResourceDescriptors
16+
if a.GetTarget() != nil {
17+
if err := a.GetTarget().Validate(); err != nil {
18+
return fmt.Errorf("Target validation failed with an error: %w", err)
19+
}
20+
}
21+
22+
if a.GetEvidence() != nil {
23+
if err := a.GetEvidence().Validate(); err != nil {
24+
return fmt.Errorf("Evidence validation failed with an error: %w", err)
25+
}
26+
}
27+
28+
return nil
29+
}
30+
31+
func (r *AttributeReport) Validate() error {
32+
// at least the attributes field is required
33+
attrs := r.GetAttributes()
34+
if attrs == nil || len(attrs) == 0 {
35+
return fmt.Errorf("At least one AttributeAssertion is required")
36+
}
37+
38+
// ensure all AttributeAssertions are valid
39+
for _, a := range attrs {
40+
if err := a.Validate(); err != nil {
41+
return fmt.Errorf("AttributeAssertion validation failed with an error: %w", err)
42+
}
43+
}
44+
45+
// ensure the producer is a valid ResourceDescriptor
46+
if r.GetProducer() != nil {
47+
if err := r.GetProducer().Validate(); err != nil {
48+
return fmt.Errorf("Producer validation failed with an error: %w", err)
49+
}
50+
}
51+
52+
return nil
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Wrapper class for in-toto attestation SCAI predicate protos.
2+
3+
import in_toto_attestation.predicates.scai.v0.scai_pb2 as scaipb
4+
from in_toto_attestation.v1.resource_descriptor import ResourceDescriptor
5+
6+
SCAI_PREDICATE_TYPE = 'https://in-toto.io/attestation/scai/attribute-report/'
7+
SCAI_PREDICATE_VERSION = 'v0.2'
8+
9+
class AttributeAssertion:
10+
def __init__(self, attribute, target=None, conditions=None, evidence=None) -> None:
11+
self.pb = scaipb.AttributeAssertion()
12+
self.pb.attribute = attribute
13+
if target:
14+
self.pb.target.CopyFrom(target)
15+
if conditions:
16+
self.pb.conditions.update(conditions)
17+
if evidence:
18+
self.pb.evidence.CopyFrom(evidence)
19+
20+
@staticmethod
21+
def copy_from_pb(proto: type[scaipb.AttributeAssertion]) -> 'AttributeAssertion':
22+
assertion = AttributeAssertion('tmp-attr')
23+
assertion.pb.CopyFrom(proto)
24+
return assertion
25+
26+
def validate(self) -> None:
27+
if len(self.pb.attribute) == 0:
28+
raise ValueError('The attribute field is required')
29+
30+
# check any resource descriptors are valid
31+
if self.pb.target.ByteSize() > 0:
32+
rd = ResourceDescriptor.copy_from_pb(self.pb.target)
33+
rd.validate()
34+
35+
if self.pb.evidence.ByteSize() > 0:
36+
rd = ResourceDescriptor.copy_from_pb(self.pb.evidence)
37+
rd.validate()
38+
39+
class AttributeReport:
40+
def __init__(self, attributes: list, producer=None) -> None:
41+
self.pb = scaipb.AttributeReport()
42+
self.pb.attributes.extend(attributes)
43+
if producer:
44+
self.pb.producer.CopyFrom(producer)
45+
46+
@staticmethod
47+
def copy_from_pb(proto: type[scaipb.AttributeReport]) -> 'AttributeReport':
48+
report = AttributeReport([None])
49+
report.pb.CopyFrom(proto)
50+
return report
51+
52+
def validate(self) -> None:
53+
if len(self.pb.attributes) == 0:
54+
raise ValueError('The attributes field is required')
55+
56+
# check any attribute assertions are valid
57+
attributes = self.pb.attributes
58+
for i, attrpb in enumerate(attributes):
59+
assertion = AttributeAssertion.copy_from_pb(attrpb)
60+
61+
try:
62+
assertion.validate()
63+
except ValueError as e:
64+
# return index in the attributes list in case of failure:
65+
# can't assume any other fields in attribute assertion are set
66+
raise ValueError('Invalid attributes field (index: {0})'.format(i)) from e
67+
68+
if self.pb.producer.ByteSize() > 0:
69+
rd = ResourceDescriptor.copy_from_pb(self.pb.producer)
70+
rd.validate()

0 commit comments

Comments
 (0)