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
package executor
import (
"context"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/atproto"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/bundled-actions"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/models"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/trust"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/workflow"
)
const (
PolicyGhaLiteNSID = "computer.socialweb.temp.policy.ghalite"
PolicyTypescriptNSID = "computer.socialweb.temp.policy.typescript"
PolicyDenoWorkerNSID = "com.publicdomainrelay.temp.market.policies.denoWorker"
SandboxDeniedPolicyID = "sandbox-denied"
ExpressionDenied = "the policy expression was denied"
NetOnlyRefused = "this evaluator runs gha-lite policies net-only and refuses"
)
type Perspective string
const (
PerspectiveBidder Perspective = "bidder"
PerspectiveRequester Perspective = "requester"
)
type PolicyRecord struct {
URI string `json:"uri"`
CID string `json:"cid"`
Value map[string]any `json:"value,omitempty"`
Payload map[string]any `json:"payload,omitempty"`
}
func (r PolicyRecord) Ref() atproto.StrongRef {
return atproto.StrongRef{URI: r.URI, CID: r.CID}
}
type Violation struct {
Msg string `json:"msg"`
PolicyID any `json:"policyId"`
}
type Verdict struct {
Allow bool `json:"allow"`
Violations []Violation `json:"violations"`
}
func Allow() Verdict {
return Verdict{Allow: true, Violations: []Violation{}}
}
func Deny(msg string, policyID any) Verdict {
return Verdict{Allow: false, Violations: []Violation{{Msg: msg, PolicyID: policyID}}}
}
func RejectionError(verdict Verdict) string {
for _, violation := range verdict.Violations {
if value, ok := violation.PolicyID.(string); ok && value == SandboxDeniedPolicyID {
return "policy sandbox denied"
}
}
return "policy rejected"
}
type EvalContext struct {
PolicyName string
Args map[string]any
Perspective Perspective
SelfDid string
SubjectDid string
RootRequesterDid string
CounterpartyDid string
PolicyRef *atproto.StrongRef
RFP *PolicyRecord
Bid *PolicyRecord
Accept *PolicyRecord
Cache models.Cache
Stack map[string]any
Host trust.Host
}
type ScopeInput struct {
Perspective Perspective
SelfDid string
CounterpartyDid string
Args map[string]any
ResolveOperatorDid func(context.Context, string) (string, bool, error)
ResolveOperatorDidFor func(context.Context, string, string) (string, bool, error)
Vouches func(context.Context, string, string) (bool, error)
}
type Executor interface {
Kind() string
Execute(ctx context.Context, record PolicyRecord, eval *EvalContext, permissions map[string]any) (Verdict, error)
Scope(ctx context.Context, record PolicyRecord, input ScopeInput) (Verdict, bool, error)
}
func RecordType(uri string, value map[string]any) string {
if value != nil {
if kind, ok := value["$type"].(string); ok && kind != "" {
return kind
}
}
_, collection, _ := atproto.SplitURI(uri)
return collection
}
func BundledActions(uses string) (*workflow.Action, error) {
action, err := bundledactions.Lookup(uses)
if err != nil {
return nil, err
}
inputs := make(map[string]string, len(action.Inputs))
for name, def := range action.Inputs {
inputs[name] = def.Default
}
return &workflow.Action{
Uses: action.Uses,
Path: action.Path,
Using: action.Using,
Main: action.Main,
Inputs: inputs,
Source: action.Source,
}, nil
}
func DefaultActionResolver() workflow.ActionResolver {
return BundledActions
}