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
package bidder
import (
"context"
"errors"
"time"
"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/atproto/market"
"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/trust"
)
const AssociationExpiryGrace = 10 * time.Minute
func (b *Bidder) associationExpiry(ctx context.Context, requesterDID, acceptedAt string) string {
if b.records == nil || requesterDID == "" {
return ""
}
skip := func(reason string, args ...any) string {
b.log.Info("bidder_association_expiry_skipped", append([]any{"requester", requesterDID, "reason", reason}, args...)...)
return ""
}
refuse := func(reason string, args ...any) string {
b.log.Warn("bidder_association_expiry_refused", append([]any{"requester", requesterDID, "reason", reason}, args...)...)
return ""
}
mirror, err := b.records.GetRecord(ctx, requesterDID, trust.BadgeBlueKeysNSID, trust.MirrorRKey)
if errors.Is(err, market.ErrNotFound) {
return skip("the requester has no keys mirror")
}
if err != nil {
return refuse("the keys mirror is unread", "err", err.Error())
}
proof, _ := mirror.Value["proof"].(map[string]any)
uri, _ := proof["uri"].(string)
cid, _ := proof["cid"].(string)
if uri == "" && cid == "" {
return skip("the keys mirror names no proof")
}
if uri == "" || cid == "" || market.NSIDFromURI(uri) != market.AssociationNSID {
return refuse("the keys mirror proof is no association strongRef", "proof", uri)
}
authority := market.ATURIAuthority(uri)
if authority == "" || authority == requesterDID {
return refuse("the proof is not in an authority's repo", "proof", uri)
}
record, err := b.records.Resolve(ctx, market.RecordRef{URI: uri, CID: cid})
if err != nil {
return refuse("the proof is unread", "proof", uri, "err", err.Error())
}
if record.CID != cid {
return refuse("the proof cid changed", "proof", uri)
}
assoc, err := market.ParseAssociation(record.Value)
if err != nil {
return refuse("the proof is no association", "proof", uri, "err", err.Error())
}
if assoc.Contract == nil {
return skip("the proof is not contract-scoped", "proof", uri)
}
if assoc.Subject != requesterDID {
return refuse("the proof names another subject", "proof", uri, "subject", assoc.Subject)
}
if market.ATURIAuthority(assoc.Contract.URI) != authority {
return refuse("the proof's contract is not the authority's accept", "proof", uri, "contract", assoc.Contract.URI)
}
expiresAt, err := market.ParseTime(assoc.ExpiresAt)
if err != nil {
return refuse("the proof expiresAt is no datetime", "proof", uri, "expiresAt", assoc.ExpiresAt)
}
start := b.now()
if at, err := market.ParseTime(acceptedAt); err == nil && at.Before(start) {
start = at
}
if bound := start.Add(market.ContractAssociationLifetime); bound.Before(expiresAt) {
b.log.Info("bidder_association_expiry_capped", "requester", requesterDID, "proof", uri, "expiresAt", assoc.ExpiresAt, "cap", market.FormatTime(bound))
expiresAt = bound
}
out := market.FormatTime(expiresAt)
b.log.Info("bidder_association_expiry", "requester", requesterDID, "proof", uri, "authority", authority, "expiresAt", out)
return out
}
func (b *Bidder) releaseAtAssociationExpiry(ctx context.Context, vm *v1alpha1.ComputeVM) time.Duration {
raw := vm.Spec.AssociationExpiresAt
if raw == "" || vm.Spec.Release != nil || vm.DeletionTimestamp != nil || b.guests.Ended(vm) {
return 0
}
expiresAt, err := time.Parse(time.RFC3339Nano, raw)
if err != nil {
return 0
}
deadline := expiresAt.Add(AssociationExpiryGrace)
if wait := deadline.Sub(b.now()); wait > 0 {
return wait
}
release := v1alpha1.ComputeVMRelease{RequestedAt: b.now().UTC().Format(time.RFC3339)}
if err := b.intents.ApplyComputeVMRelease(ctx, vm.Name, release); err != nil {
b.log.Warn("bidder_association_expired_release_failed", "computevm", vm.Name, "err", err.Error())
return time.Minute
}
b.log.Info("bidder_association_expired_release", "computevm", vm.Name, "requester", vm.Spec.Requester.Did, "associationExpiresAt", raw)
return 0
}