-
Notifications
You must be signed in to change notification settings - Fork 245
/
assertions.go
138 lines (112 loc) · 3.95 KB
/
assertions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package blocks
import (
"encoding/json"
"fmt"
"strings"
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
yamlv3 "gopkg.in/yaml.v3"
"github.com/authzed/spicedb/pkg/spiceerrors"
"github.com/authzed/spicedb/pkg/tuple"
)
// Assertions represents assertions defined in the validation file.
type Assertions struct {
// AssertTrue is the set of relationships to assert true.
AssertTrue []Assertion `yaml:"assertTrue"`
// AssertCaveated is the set of relationships to assert that are caveated.
AssertCaveated []Assertion `yaml:"assertCaveated"`
// AssertFalse is the set of relationships to assert false.
AssertFalse []Assertion `yaml:"assertFalse"`
// SourcePosition is the position of the assertions in the file.
SourcePosition spiceerrors.SourcePosition
}
// Assertion is a parsed assertion.
type Assertion struct {
// RelationshipWithContextString is the string form of the assertion, including optional context.
// Forms:
// `document:firstdoc#view@user:tom`
// `document:seconddoc#view@user:sarah with {"some":"contexthere"}`
RelationshipWithContextString string
// Relationship is the parsed relationship on which the assertion is being
// run.
Relationship *v1.Relationship
// CaveatContext is the caveat context for the assertion, if any.
CaveatContext map[string]any
// SourcePosition is the position of the assertion in the file.
SourcePosition spiceerrors.SourcePosition
}
type internalAssertions struct {
// AssertTrue is the set of relationships to assert true.
AssertTrue []Assertion `yaml:"assertTrue"`
// AssertCaveated is the set of relationships to assert that are caveated.
AssertCaveated []Assertion `yaml:"assertCaveated"`
// AssertFalse is the set of relationships to assert false.
AssertFalse []Assertion `yaml:"assertFalse"`
}
// UnmarshalYAML is a custom unmarshaller.
func (a *Assertions) UnmarshalYAML(node *yamlv3.Node) error {
ia := internalAssertions{}
if err := node.Decode(&ia); err != nil {
return convertYamlError(err)
}
a.AssertTrue = ia.AssertTrue
a.AssertFalse = ia.AssertFalse
a.AssertCaveated = ia.AssertCaveated
a.SourcePosition = spiceerrors.SourcePosition{LineNumber: node.Line, ColumnPosition: node.Column}
return nil
}
// UnmarshalYAML is a custom unmarshaller.
func (a *Assertion) UnmarshalYAML(node *yamlv3.Node) error {
relationshipWithContextString := ""
if err := node.Decode(&relationshipWithContextString); err != nil {
return convertYamlError(err)
}
trimmed := strings.TrimSpace(relationshipWithContextString)
// Check for caveat context.
parts := strings.SplitN(trimmed, " with ", 2)
if len(parts) == 0 {
return spiceerrors.NewErrorWithSource(
fmt.Errorf("error parsing assertion `%s`", trimmed),
trimmed,
uint64(node.Line),
uint64(node.Column),
)
}
tpl := tuple.Parse(strings.TrimSpace(parts[0]))
if tpl == nil {
return spiceerrors.NewErrorWithSource(
fmt.Errorf("error parsing relationship in assertion `%s`", trimmed),
trimmed,
uint64(node.Line),
uint64(node.Column),
)
}
a.Relationship = tuple.MustToRelationship(tpl)
if len(parts) == 2 {
caveatContextMap := make(map[string]any, 0)
err := json.Unmarshal([]byte(parts[1]), &caveatContextMap)
if err != nil {
return spiceerrors.NewErrorWithSource(
fmt.Errorf("error parsing caveat context in assertion `%s`: %w", trimmed, err),
trimmed,
uint64(node.Line),
uint64(node.Column),
)
}
a.CaveatContext = caveatContextMap
}
a.RelationshipWithContextString = relationshipWithContextString
a.SourcePosition = spiceerrors.SourcePosition{LineNumber: node.Line, ColumnPosition: node.Column}
return nil
}
// ParseAssertionsBlock parses the given contents as an assertions block.
func ParseAssertionsBlock(contents []byte) (*Assertions, error) {
a := internalAssertions{}
if err := yamlv3.Unmarshal(contents, &a); err != nil {
return nil, convertYamlError(err)
}
return &Assertions{
AssertTrue: a.AssertTrue,
AssertCaveated: a.AssertCaveated,
AssertFalse: a.AssertFalse,
}, nil
}