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
|
package db
import (
"context"
"errors"
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/authzed-go/v1"
"github.com/xlgmokha/x/pkg/x"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain"
"gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls"
)
type authorization[T domain.Entity] struct {
client *authzed.Client
repository domain.Repository[T]
}
func WithAuthorization[T domain.Entity](client *authzed.Client) x.Option[domain.Repository[T]] {
return func(repository domain.Repository[T]) domain.Repository[T] {
return &authorization[T]{
client: client,
repository: repository,
}
}
}
func (r *authorization[T]) All(ctx context.Context) []T {
allItems := r.repository.All(ctx)
if len(allItems) == 0 {
return allItems
}
response, err := r.client.CheckBulkPermissions(ctx, &v1.CheckBulkPermissionsRequest{
Items: x.Map(allItems, func(item T) *v1.CheckBulkPermissionsRequestItem {
return &v1.CheckBulkPermissionsRequestItem{
Resource: item.ToGID().ToObjectReference(),
Permission: "read",
Subject: r.subjectFrom(ctx),
}
}),
})
if err != nil {
pls.LogError(ctx, err)
return x.Default[[]T]()
}
filteredItems := make([]T, 0)
for i, pair := range response.Pairs {
if item := pair.GetItem(); item != nil {
if item.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION {
filteredItems = append(filteredItems, allItems[i])
}
}
}
return filteredItems
}
func (r *authorization[T]) Find(ctx context.Context, id domain.ID) T {
item := r.repository.Find(ctx, id)
response, err := r.client.CheckPermission(ctx, &v1.CheckPermissionRequest{
Resource: item.ToGID().ToObjectReference(),
Permission: "read",
Subject: r.subjectFrom(ctx),
})
if err != nil {
pls.LogError(ctx, err)
return x.Default[T]()
}
if response.Permissionship != v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION {
return x.Default[T]()
}
return item
}
func (r *authorization[T]) Save(ctx context.Context, item T) error {
currentUser := cfg.CurrentUser.From(ctx)
if currentUser == nil {
return errors.New("authentication required for creating or updating entities")
}
if item.GetID() != "" {
response, err := r.client.CheckPermission(ctx, &v1.CheckPermissionRequest{
Resource: item.ToGID().ToObjectReference(),
Permission: "update",
Subject: currentUser.ToSubjectReference(),
})
if err != nil {
return err
}
if response.Permissionship != v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION {
return errors.New("user does not have permission to update this entity")
}
}
if sparkle, ok := any(item).(*domain.Sparkle); ok && item.GetID() == "" {
sparkle.Author = currentUser
}
return r.repository.Save(ctx, item)
}
func (r *authorization[T]) subjectFrom(ctx context.Context) *v1.SubjectReference {
currentUser := cfg.CurrentUser.From(ctx)
return currentUser.ToSubjectReference()
}
|