@@ -4,6 +4,7 @@ package e2e
44
55import (
66 "context"
7+ "encoding/json"
78 "fmt"
89 "sync"
910 "time"
@@ -15,10 +16,12 @@ import (
1516 corev1 "k8s.io/api/core/v1"
1617 k8serrors "k8s.io/apimachinery/pkg/api/errors"
1718 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+ "k8s.io/apimachinery/pkg/types"
1820 "k8s.io/apiserver/pkg/endpoints/request"
1921 "k8s.io/apiserver/pkg/storage/names"
2022 "k8s.io/client-go/kubernetes"
2123 "k8s.io/client-go/tools/clientcmd"
24+ "k8s.io/utils/pointer"
2225
2326 "github.com/authzed/spicedb-kubeapi-proxy/pkg/authz/distributedtx"
2427 "github.com/authzed/spicedb-kubeapi-proxy/pkg/config/proxyrule"
@@ -136,6 +139,41 @@ var _ = Describe("Proxy", func() {
136139 _ , err := client .CoreV1 ().Pods (namespace ).Get (ctx , name , metav1.GetOptions {})
137140 return err
138141 }
142+ GetAndUpdatePodLabels := func (ctx context.Context , client kubernetes.Interface , namespace , name string , labels map [string ]string ) error {
143+ pod , err := client .CoreV1 ().Pods (namespace ).Get (ctx , name , metav1.GetOptions {})
144+ if err != nil {
145+ return err
146+ }
147+ pod .Labels = labels
148+ _ , err = client .CoreV1 ().Pods (namespace ).Update (ctx , pod , metav1.UpdateOptions {})
149+ return err
150+ }
151+ PatchPodLabels := func (ctx context.Context , client kubernetes.Interface , namespace , name string , labels map [string ]string ) error {
152+ patch := & corev1.Pod {
153+ TypeMeta : metav1.TypeMeta {
154+ Kind : "Pod" ,
155+ APIVersion : "v1" ,
156+ },
157+ ObjectMeta : metav1.ObjectMeta {
158+ Name : name ,
159+ Namespace : namespace ,
160+ Labels : labels ,
161+ },
162+ }
163+ data , err := json .Marshal (patch )
164+ if err != nil {
165+ return err
166+ }
167+ _ , err = client .CoreV1 ().Pods (namespace ).Patch (ctx , name , types .ApplyPatchType , data , metav1.PatchOptions {FieldManager : "Test" , Force : pointer .Bool (true )})
168+ return err
169+ }
170+ ListPods := func (ctx context.Context , client kubernetes.Interface , namespace string ) []string {
171+ visibleNamespaces , err := client .CoreV1 ().Pods (namespace ).List (ctx , metav1.ListOptions {})
172+ Expect (err ).To (Succeed ())
173+ return lo .Map (visibleNamespaces .Items , func (item corev1.Pod , index int ) string {
174+ return item .Name
175+ })
176+ }
139177 WatchPods := func (ctx context.Context , client kubernetes.Interface , namespace string , expected int , timeout time.Duration ) []string {
140178 ctx , cancel := context .WithTimeout (ctx , timeout )
141179 defer cancel ()
@@ -167,6 +205,43 @@ var _ = Describe("Proxy", func() {
167205 })
168206
169207 AssertDualWriteBehavior := func () {
208+
209+ It ("supports rules for every verb" , func (ctx context.Context ) {
210+ // watch
211+ var wg sync.WaitGroup
212+ defer wg .Wait ()
213+ wg .Add (1 )
214+ go func () {
215+ defer GinkgoRecover ()
216+ Expect (WatchPods (ctx , paulClient , paulNamespace , 1 , 10 * time .Second )).To (ContainElement (paulPod ))
217+ wg .Done ()
218+ }()
219+
220+ // create
221+ Expect (CreateNamespace (ctx , paulClient , paulNamespace )).To (Succeed ())
222+ Expect (CreatePod (ctx , paulClient , paulNamespace , paulPod )).To (Succeed ())
223+
224+ // get
225+ Expect (GetPod (ctx , paulClient , paulNamespace , paulPod )).To (Succeed ())
226+ Expect (GetPod (ctx , chaniClient , paulNamespace , paulPod )).To (Not (Succeed ()))
227+
228+ // update
229+ Expect (GetAndUpdatePodLabels (ctx , paulClient , paulNamespace , paulPod , map [string ]string {"a" : "label" })).To (Succeed ())
230+ Expect (GetAndUpdatePodLabels (ctx , chaniClient , paulNamespace , paulPod , map [string ]string {"a" : "label" })).To (Not (Succeed ()))
231+
232+ // patch
233+ Expect (PatchPodLabels (ctx , paulClient , paulNamespace , paulPod , map [string ]string {"b" : "label" })).To (Succeed ())
234+ Expect (PatchPodLabels (ctx , chaniClient , paulNamespace , paulPod , map [string ]string {"b" : "label" })).To (Not (Succeed ()))
235+
236+ // list
237+ Expect (ListPods (ctx , paulClient , paulNamespace )).To (Equal ([]string {paulPod }))
238+ Expect (ListPods (ctx , chaniClient , paulNamespace )).To (Equal ([]string {}))
239+
240+ // delete
241+ Expect (DeletePod (ctx , chaniClient , paulNamespace , paulPod )).To (Not (Succeed ()))
242+ Expect (DeletePod (ctx , paulClient , paulNamespace , paulPod )).To (Succeed ())
243+ })
244+
170245 It ("doesn't show users namespaces the other has created" , func (ctx context.Context ) {
171246 var wg sync.WaitGroup
172247 defer wg .Wait ()
@@ -623,6 +698,9 @@ var (
623698 Resource : "pods" ,
624699 Verbs : []string {"delete" },
625700 }},
701+ Checks : []proxyrule.StringOrTemplate {{
702+ Template : "pod:{{namespacedName}}#edit@user:{{user.Name}}" ,
703+ }},
626704 Writes : []proxyrule.StringOrTemplate {{
627705 Template : "pod:{{namespacedName}}#creator@user:{{user.Name}}" ,
628706 }, {
@@ -644,6 +722,19 @@ var (
644722 },
645723 }
646724
725+ updatePod = proxyrule.Config {
726+ Spec : proxyrule.Spec {
727+ Matches : []proxyrule.Match {{
728+ GroupVersion : "v1" ,
729+ Resource : "pods" ,
730+ Verbs : []string {"update" , "patch" },
731+ }},
732+ Checks : []proxyrule.StringOrTemplate {{
733+ Template : "pod:{{namespacedName}}#edit@user:{{user.Name}}" ,
734+ }},
735+ },
736+ }
737+
647738 listWatchPod = proxyrule.Config {
648739 Spec : proxyrule.Spec {
649740 Matches : []proxyrule.Match {{
@@ -669,6 +760,7 @@ func testOptimisticMatcher() rules.MapMatcher {
669760 createPod (),
670761 deletePod (),
671762 getPod ,
763+ updatePod ,
672764 listWatchPod ,
673765 })
674766 Expect (err ).To (Succeed ())
@@ -701,6 +793,7 @@ func testPessimisticMatcher() rules.MapMatcher {
701793 pessimisticCreatePod ,
702794 pessimisticDeletePod ,
703795 getPod ,
796+ updatePod ,
704797 listWatchPod ,
705798 })
706799 Expect (err ).To (Succeed ())
0 commit comments