Skip to content

Commit 120d0c6

Browse files
committed
Address PR review: deterministic output, type safety, universe validation, and tests
- Fix grammar in ReadersSecurityLabelFromDict godoc - Sort GetReaders and FiniteReaderSet.String output for determinism - Fix godoc example to use UniversalReaders for public label - Panic on unsupported ReaderSet types in Union/Intersection/IsSubset - Add universe mismatch validation in PowersetLattice Join/Meet/Leq - Add comprehensive unit tests for pkg/ifc (lattice laws, serialization, panics)
1 parent ea5af50 commit 120d0c6

2 files changed

Lines changed: 648 additions & 12 deletions

File tree

pkg/ifc/readers_lattice.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
//
1111
// Example usage:
1212
//
13-
// // Create a label readable by everyone
13+
// // Create a label readable by everyone (public)
1414
// universe := UniversalReaders[string]()
15-
// publicReaders := NewFiniteReaderSetFromSlice([]string{"alice", "bob"})
16-
// label, _ := NewPowersetLattice(publicReaders, universe)
15+
// label, _ := NewPowersetLattice(universe, universe)
1716
//
1817
// // Create a label for specific readers only
1918
// finiteUniverse := NewFiniteReaderSetFromSlice([]string{"alice", "bob", "charlie"})
@@ -25,6 +24,7 @@ package ifc
2524
import (
2625
"encoding/json"
2726
"fmt"
27+
"sort"
2828
"strings"
2929
)
3030

@@ -90,7 +90,7 @@ func (f *FiniteReaderSet[T]) IsSubset(other ReaderSet[T]) bool {
9090
}
9191
otherFinite, ok := other.(*FiniteReaderSet[T])
9292
if !ok {
93-
return false
93+
panic(fmt.Sprintf("unsupported ReaderSet implementation: %T", other))
9494
}
9595
for member := range f.members {
9696
if _, exists := otherFinite.members[member]; !exists {
@@ -106,7 +106,7 @@ func (f *FiniteReaderSet[T]) Union(other ReaderSet[T]) ReaderSet[T] {
106106
}
107107
otherFinite, ok := other.(*FiniteReaderSet[T])
108108
if !ok {
109-
return f
109+
panic(fmt.Sprintf("unsupported ReaderSet implementation: %T", other))
110110
}
111111
union := make(map[T]struct{}, len(f.members)+len(otherFinite.members))
112112
for member := range f.members {
@@ -124,7 +124,7 @@ func (f *FiniteReaderSet[T]) Intersection(other ReaderSet[T]) ReaderSet[T] {
124124
}
125125
otherFinite, ok := other.(*FiniteReaderSet[T])
126126
if !ok {
127-
return NewFiniteReaderSet[T](make(map[T]struct{}))
127+
panic(fmt.Sprintf("unsupported ReaderSet implementation: %T", other))
128128
}
129129
intersection := make(map[T]struct{})
130130
for member := range f.members {
@@ -139,15 +139,18 @@ func (f *FiniteReaderSet[T]) String() string {
139139
if len(f.members) == 0 {
140140
return "FiniteReaderSet({})"
141141
}
142+
strs := make([]string, 0, len(f.members))
143+
for member := range f.members {
144+
strs = append(strs, fmt.Sprintf("%v", member))
145+
}
146+
sort.Strings(strs)
142147
var b strings.Builder
143148
b.WriteString("FiniteReaderSet({")
144-
first := true
145-
for member := range f.members {
146-
if !first {
149+
for i, s := range strs {
150+
if i > 0 {
147151
b.WriteString(", ")
148152
}
149-
first = false
150-
fmt.Fprintf(&b, "%v", member)
153+
b.WriteString(s)
151154
}
152155
b.WriteString("})")
153156
return b.String()
@@ -192,23 +195,45 @@ func copySet[T comparable](in map[T]struct{}) map[T]struct{} {
192195
}
193196

194197
func (p *PowersetLattice[T]) Leq(other *PowersetLattice[T]) bool {
198+
p.mustMatchUniverse(other)
195199
return p.subset.IsSubset(other.subset)
196200
}
197201

198202
func (p *PowersetLattice[T]) Join(other *PowersetLattice[T]) *PowersetLattice[T] {
203+
p.mustMatchUniverse(other)
199204
return &PowersetLattice[T]{
200205
subset: p.subset.Union(other.subset),
201206
universe: p.universe,
202207
}
203208
}
204209

205210
func (p *PowersetLattice[T]) Meet(other *PowersetLattice[T]) *PowersetLattice[T] {
211+
p.mustMatchUniverse(other)
206212
return &PowersetLattice[T]{
207213
subset: p.subset.Intersection(other.subset),
208214
universe: p.universe,
209215
}
210216
}
211217

218+
func (p *PowersetLattice[T]) mustMatchUniverse(other *PowersetLattice[T]) {
219+
pUniv := p.universe.IsUniversal()
220+
oUniv := other.universe.IsUniversal()
221+
if pUniv != oUniv {
222+
panic(fmt.Sprintf("universe mismatch: %s vs %s", p.universe, other.universe))
223+
}
224+
if pUniv {
225+
return
226+
}
227+
pFinite, pOK := p.universe.(*FiniteReaderSet[T])
228+
oFinite, oOK := other.universe.(*FiniteReaderSet[T])
229+
if !pOK || !oOK {
230+
panic(fmt.Sprintf("universe mismatch: %T vs %T", p.universe, other.universe))
231+
}
232+
if !pFinite.IsSubset(oFinite) || !oFinite.IsSubset(pFinite) {
233+
panic(fmt.Sprintf("universe mismatch: %s vs %s", p.universe, other.universe))
234+
}
235+
}
236+
212237
func (p *PowersetLattice[T]) String() string {
213238
return fmt.Sprintf("Powerset(%s)", p.subset.String())
214239
}
@@ -318,6 +343,7 @@ func (l ReadersSecurityLabel) GetReaders() []string {
318343
for reader := range finiteSet.members {
319344
readers = append(readers, reader)
320345
}
346+
sort.Strings(readers)
321347
return readers
322348
}
323349

@@ -396,7 +422,7 @@ func (l *ReadersSecurityLabel) UnmarshalJSON(data []byte) error {
396422
return nil
397423
}
398424

399-
// ReadersSecurityLabelFromDict creates an ReadersSecurityLabel from a dictionary format.
425+
// ReadersSecurityLabelFromDict creates a ReadersSecurityLabel from a dictionary format.
400426
func ReadersSecurityLabelFromDict(dict map[string]any) ReadersSecurityLabel {
401427
// Parse integrity
402428
integrityStr := "high"

0 commit comments

Comments
 (0)