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
139
140
141
package spec
import (
"context"
"os"
"strings"
"testing"
"time"
commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/policytest"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/runs"
)
func TestMain(m *testing.M) {
path, from, err := policytest.DenoPath()
if err != nil {
os.Stderr.WriteString("policy spec: " + err.Error() + "\n")
os.Exit(1)
}
os.Stderr.WriteString("policy spec: deno " + path + " (" + from + ")\n")
os.Exit(m.Run())
}
type lane string
const (
scope lane = runs.ModeScope
full lane = runs.ModeFull
)
type side string
const (
bidderSide side = "bidder"
requesterSide side = "requester"
)
type decision struct {
verdict runs.Decision
runs []*policytest.Run
}
func (d decision) mustRun(t *testing.T, workflow string) *policytest.Run {
t.Helper()
if len(d.runs) == 0 {
t.Fatalf("no policy run executed for %s; verdict %+v", workflow, d.verdict)
}
for _, run := range d.runs {
if run.Workflow == workflow || run.Spec.WorkflowRef == workflow {
if run.Status.Phase == "" || run.Status.CompletionTime == nil {
t.Fatalf("the policy run %s for %s did not finish: %+v", run.Name, workflow, run.Status)
}
return run
}
}
names := []string{}
for _, run := range d.runs {
names = append(names, run.Workflow)
}
t.Fatalf("no policy run of %s executed; runs: %v", workflow, names)
return nil
}
func (d decision) mustAllow(t *testing.T) {
t.Helper()
if !d.verdict.Allow {
t.Fatalf("want allow, got deny: %s %v", d.verdict.Reason, d.verdict.Violations)
}
}
func (d decision) mustDeny(t *testing.T, reason string) {
t.Helper()
if d.verdict.Allow {
t.Fatalf("want deny (%s), got allow from run %s", reason, d.verdict.Run)
}
text := d.verdict.Reason + " " + strings.Join(d.verdict.Violations, " ")
if strings.TrimSpace(text) == "" {
t.Fatalf("a deny carries no reason")
}
if reason != "" && !strings.Contains(text, reason) {
t.Fatalf("want a deny with %q, got %q", reason, text)
}
}
func (d decision) mustDenyBecause(t *testing.T, cause string) {
t.Helper()
d.mustDeny(t, "")
text := d.verdict.Reason + " " + strings.Join(d.verdict.Violations, " ")
for _, run := range d.runs {
for _, raw := range run.Status.Annotations {
text += " " + string(raw)
}
for _, condition := range run.Status.Conditions {
text += " " + condition.Message
}
text += " " + run.Status.ConsoleOutput
}
if !strings.Contains(text, cause) {
t.Fatalf("the deny does not carry the cause %q: %s", cause, text)
}
}
func actionRan(t *testing.T, run *policytest.Run, policyName string, allow bool) policytest.ActionVerdict {
t.Helper()
for _, verdict := range run.Actions() {
if verdict.Policy == policyName {
if verdict.Allow != allow {
t.Fatalf("the %s action answered allow=%t, want %t", policyName, verdict.Allow, allow)
}
return verdict
}
}
t.Fatalf("the %s action did not run in %s; console:\n%s", policyName, run.Name, run.Status.ConsoleOutput)
return policytest.ActionVerdict{}
}
func evaluate(t *testing.T, h *policytest.Harness, workflow string, perspective side, mode lane, self, counterparty string, rfp *policytest.Ref) decision {
t.Helper()
input := runs.Input{Perspective: string(perspective), Mode: string(mode), SelfDid: self, CounterpartyDid: counterparty}
if mode == full {
input.SubjectDid = counterparty
input.RootRequesterDid = counterparty
if perspective == requesterSide {
input.RootRequesterDid = self
}
}
if rfp != nil {
input.RFP = &commonv1.StrongRef{URI: rfp.URI, CID: rfp.CID}
}
return run(t, h, string(perspective), runs.Request{WorkflowRef: workflow, Input: input})
}
func run(t *testing.T, h *policytest.Harness, role string, req runs.Request) decision {
t.Helper()
mark := h.Runner.Mark()
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
verdict := h.Client(role).Run(ctx, req)
return decision{verdict: verdict, runs: h.Runner.Since(mark)}
}