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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package marketnetwork
import (
"context"
"encoding/json"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
exposurev1alpha1 "github.com/johnandersen777/socialweb-computer-kcp/api/exposure/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/app/compose"
"github.com/johnandersen777/socialweb-computer-kcp/internal/contract/atprotorepo"
"github.com/johnandersen777/socialweb-computer-kcp/internal/devinstance"
"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/fsx"
)
const (
NetworkVouchLabel = "apps.socialweb.computer/network-vouch"
networkVouchLinkSet = "network-vouches"
bidderVouchPrefix = "network-vouch-"
)
func requesterVouchApp(requesterDid string) string {
return "requester-" + compose.Stamp(requesterDid)
}
func RequesterVouchName(requesterDid string) string {
return compose.OperatorVouchPrefix + requesterVouchApp(requesterDid)
}
func BidderVouchName(bidderApp string) string {
return bidderVouchPrefix + bidderApp
}
type operatorOf struct {
app string
did string
at string
}
type networkRequester struct {
ws string
did string
at string
}
type networkBidder struct {
app string
ws string
did string
}
func (ctl *Controller) declareOperatorVouches(ctx context.Context, r compose.Root, apps []v1alpha1.NetworkApp) {
var bidderOps, gatewayOps []operatorOf
var bidders, gateways []string
var bidderApps []networkBidder
var requesters []networkRequester
operator := func(ws, name, app string) (operatorOf, bool) {
id, err := ctl.c.Identity(ctx, ws, name)
if err != nil {
return operatorOf{}, false
}
did := compose.OperatorDID(nil, id)
if did == "" {
return operatorOf{}, false
}
return operatorOf{app: app, did: did, at: id.CreationTimestamp.UTC().Format("2006-01-02T15:04:05Z")}, true
}
for _, app := range apps {
if app.Stopped {
continue
}
ch, err := ctl.child(app)
if err != nil {
continue
}
var rec devinstance.Record
if fsx.ReadJSON(ch.layout.Record, &rec) != nil || rec.BaseWorkspace == "" {
continue
}
switch app.Kind {
case v1alpha1.ApplicationKindMarketBidder:
bidders = append(bidders, rec.BaseWorkspace)
if op, ok := operator(rec.BaseWorkspace, BidderIdentity, app.Name); ok {
bidderOps = append(bidderOps, op)
}
if did := strings.TrimSpace(ctl.c.IdentityDid(ctx, rec.BaseWorkspace, BidderIdentity)); did != "" {
bidderApps = append(bidderApps, networkBidder{app: app.Name, ws: rec.BaseWorkspace, did: did})
}
case v1alpha1.ApplicationKindGateway:
ws := rec.BaseWorkspace + ":" + compose.ComponentWorkspace
gateways = append(gateways, ws)
if op, ok := operator(ws, RequesterIdentity, app.Name); ok {
gatewayOps = append(gatewayOps, op)
}
case v1alpha1.ApplicationKindMarketRequester:
id, err := ctl.c.Identity(ctx, rec.BaseWorkspace, RequesterIdentity)
if err != nil || strings.TrimSpace(id.Status.Did) == "" {
continue
}
requesters = append(requesters, networkRequester{ws: rec.BaseWorkspace, did: strings.TrimSpace(id.Status.Did),
at: id.CreationTimestamp.UTC().Format("2006-01-02T15:04:05Z")})
}
}
declare := func(workspaces []string, ops []operatorOf, what string) {
for _, ws := range workspaces {
for _, op := range ops {
if err := ctl.c.ApplyOperatorVouch(ctx, r, ws, op.app, op.did, op.at); err != nil {
ctl.log().Warn(what, "workspace", ws, "app", op.app, "err", err.Error())
}
}
}
}
declare(gateways, bidderOps, "declaring the gateway operator's vouch for a bidder's operator")
declare(bidders, gatewayOps, "declaring the bidder operator's vouch for a gateway's operator")
for _, req := range requesters {
for _, b := range bidderApps {
if err := ctl.c.ApplyOperatorVouch(ctx, r, b.ws, requesterVouchApp(req.did), req.did, req.at); err != nil {
ctl.log().Warn("declaring the bidder operator's vouch for a network requester", "workspace", b.ws, "requester", req.did, "err", err.Error())
}
}
if err := ctl.applyRequesterVouches(ctx, r, req, bidderApps); err != nil {
ctl.log().Warn("declaring a network requester's vouches for the network bidders", "workspace", req.ws, "requester", req.did, "err", err.Error())
}
}
}
func (ctl *Controller) applyRequesterVouches(ctx context.Context, r compose.Root, req networkRequester, bidders []networkBidder) error {
if len(bidders) == 0 {
return nil
}
repo := commonv1.ObjectRef{Group: v1alpha1.GroupName, Kind: compose.KindAtprotoRepo, Name: atprotorepo.RepoName(req.did), Workspace: req.ws}
records := exposurev1alpha1.ComponentLinkSelector{Group: v1alpha1.GroupName, Kind: "AtprotoRecord", Workspace: req.ws,
MatchLabels: map[string]string{NetworkVouchLabel: "true"}}
link := compose.SelectorLink(compose.LinkName("network-vouches", req.ws), records, repo, compose.Cap(atprotorepo.CapabilityWrite, compose.VouchNSID))
if err := ctl.c.AddLinks(ctx, r, networkVouchLinkSet, []compose.Link{link}); err != nil {
return err
}
for _, b := range bidders {
record, err := json.Marshal(map[string]any{"$type": compose.VouchNSID, "subject": b.did, "createdAt": req.at})
if err != nil {
return err
}
repoRef := repo
repoRef.Workspace = ""
obj := &v1alpha1.AtprotoRecord{ObjectMeta: metav1.ObjectMeta{Name: BidderVouchName(b.app), Labels: map[string]string{NetworkVouchLabel: "true"}},
Spec: v1alpha1.AtprotoRecordSpec{RepoRef: &repoRef, Collection: compose.VouchNSID, Rkey: b.did, Record: record,
DeletionPolicy: v1alpha1.RecordDeletionRetain}}
if err := ctl.c.ApplyTyped(ctx, r, req.ws, compose.AtprotoRecordGVR, v1alpha1.GroupVersion.String(), "AtprotoRecord", obj); err != nil {
return err
}
}
return nil
}