Skip to content

Commit 62be0ef

Browse files
committed
feat(e2etest): add e2e test for hook overwrite case
1 parent 72ae6dc commit 62be0ef

File tree

5 files changed

+219
-31
lines changed

5 files changed

+219
-31
lines changed

test/e2e_test/smoke/proxy_test.go

Lines changed: 107 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/stretchr/testify/suite"
1212

1313
"github.com/goto/shield/config"
14+
"github.com/goto/shield/internal/store/postgres"
1415
"github.com/goto/shield/pkg/db"
1516
shieldv1beta1 "github.com/goto/shield/proto/v1beta1"
1617
"github.com/goto/shield/test/e2e_test/testbench"
@@ -96,12 +97,16 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
9697
defer res.Body.Close()
9798
s.Assert().Equal(200, res.StatusCode)
9899
})
99-
s.Run("resource created on echo server should persist in shieldDB", func() {
100-
url := fmt.Sprintf("http://localhost:%d/api/resource", s.appConfig.Proxy.Services[0].Port)
100+
101+
s.Run("user not part of group will not be authenticated by middleware auth", func() {
102+
groupDetail, err := s.client.GetGroup(context.Background(), &shieldv1beta1.GetGroupRequest{Id: s.groupID})
103+
s.Require().NoError(err)
104+
105+
url := fmt.Sprintf("http://localhost:%d/api/resource_slug", s.appConfig.Proxy.Services[0].Port)
101106
reqBodyMap := map[string]string{
102-
"project": s.projID,
103-
"name": "test-resource",
104-
"group": s.groupID,
107+
"project": s.projID,
108+
"name": "test-resource-group-slug",
109+
"group_slug": groupDetail.GetGroup().GetSlug(),
105110
}
106111
reqBodyBytes, err := json.Marshal(reqBodyMap)
107112
s.Require().NoError(err)
@@ -117,30 +122,17 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
117122

118123
defer res.Body.Close()
119124

120-
resourceSelectQuery := "SELECT name FROM resources"
121-
resources, err := s.dbClient.DB.Query(resourceSelectQuery)
122-
s.Require().NoError(err)
123-
defer resources.Close()
124-
125-
var resourceName = ""
126-
for resources.Next() {
127-
if err := resources.Scan(&resourceName); err != nil {
128-
s.Require().NoError(err)
129-
}
130-
}
131-
s.Assert().Equal(200, res.StatusCode)
132-
s.Assert().Equal("test-resource", resourceName)
125+
s.Assert().Equal(401, res.StatusCode)
133126
})
127+
}
134128

135-
s.Run("user not part of group will not be authenticated by middleware auth", func() {
136-
groupDetail, err := s.client.GetGroup(context.Background(), &shieldv1beta1.GetGroupRequest{Id: s.groupID})
137-
s.Require().NoError(err)
138-
139-
url := fmt.Sprintf("http://localhost:%d/api/resource_slug", s.appConfig.Proxy.Services[0].Port)
129+
func (s *EndToEndProxySmokeTestSuite) TestResourceRelation() {
130+
s.Run("resource created on echo server should persist in shieldDB", func() {
131+
url := fmt.Sprintf("http://localhost:%d/api/resource", s.appConfig.Proxy.Services[0].Port)
140132
reqBodyMap := map[string]string{
141-
"project": s.projID,
142-
"name": "test-resource-group-slug",
143-
"group_slug": groupDetail.GetGroup().GetSlug(),
133+
"project": s.projID,
134+
"name": "test-resource",
135+
"group": s.groupID,
144136
}
145137
reqBodyBytes, err := json.Marshal(reqBodyMap)
146138
s.Require().NoError(err)
@@ -156,7 +148,19 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
156148

157149
defer res.Body.Close()
158150

159-
s.Assert().Equal(401, res.StatusCode)
151+
resourceSelectQuery := "SELECT name FROM resources"
152+
resources, err := s.dbClient.DB.Query(resourceSelectQuery)
153+
s.Require().NoError(err)
154+
defer resources.Close()
155+
156+
var resourceName = ""
157+
for resources.Next() {
158+
if err := resources.Scan(&resourceName); err != nil {
159+
s.Require().NoError(err)
160+
}
161+
}
162+
s.Assert().Equal(200, res.StatusCode)
163+
s.Assert().Equal("test-resource", resourceName)
160164
})
161165

162166
s.Run("permission expression: user not having permission at org level will not be authenticated by middleware auth", func() {
@@ -285,6 +289,7 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
285289
}
286290
s.Assert().Equal(s.userID, subjectID)
287291
})
292+
288293
s.Run("resource created on echo server should persist in shieldDB when using user e-mail", func() {
289294
userDetail, err := s.client.GetUser(context.Background(), &shieldv1beta1.GetUserRequest{Id: s.userID})
290295
s.Require().NoError(err)
@@ -339,6 +344,81 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
339344
})
340345
}
341346

347+
func (s *EndToEndProxySmokeTestSuite) TestEdgeCases() {
348+
s.Run("Two relations created in POST hook won't be overwritten when 1 relation in PUT hook is created", func() {
349+
var (
350+
resourceName = "test-resource-overwrite"
351+
staticGroupUUID = "6b591fe0-fc94-4fd2-82bc-45f8a5d12a88"
352+
)
353+
354+
userDetail, err := s.client.GetUser(context.Background(), &shieldv1beta1.GetUserRequest{Id: s.userID})
355+
s.Require().NoError(err)
356+
sqlRes, err := s.dbClient.DB.Exec(fmt.Sprintf("UPDATE groups SET id = '%s' WHERE slug = 'org1-group3'", staticGroupUUID))
357+
s.Require().NoError(err)
358+
rowsAffected, err := sqlRes.RowsAffected()
359+
s.Require().NoError(err)
360+
s.Require().Equal(int64(1), rowsAffected)
361+
362+
// POST
363+
url := fmt.Sprintf("http://localhost:%d/api/resource", s.appConfig.Proxy.Services[0].Port)
364+
reqBodyMap := map[string]string{
365+
"project": s.projID,
366+
"group": s.groupID,
367+
"name": resourceName,
368+
"user_email": userDetail.GetUser().GetEmail(),
369+
}
370+
reqBodyBytes, err := json.Marshal(reqBodyMap)
371+
s.Require().NoError(err)
372+
373+
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBodyBytes))
374+
s.Require().NoError(err)
375+
376+
req.Header.Set(testbench.IdentityHeader, "[email protected]")
377+
req.Header.Set("X-Shield-Org", s.orgID)
378+
379+
res, err := http.DefaultClient.Do(req)
380+
s.Require().NoError(err)
381+
defer res.Body.Close()
382+
383+
s.Require().Equal(200, res.StatusCode)
384+
385+
// Validate resource & relation
386+
var resourceShield = struct {
387+
ID string `db:"id"`
388+
Name string `db:"name"`
389+
}{}
390+
391+
s.Require().NoError(s.dbClient.DB.Get(&resourceShield, fmt.Sprintf("SELECT id, name FROM resources WHERE name = '%s'", resourceName)))
392+
s.Assert().Equal(resourceShield.Name, resourceName)
393+
394+
var relationsShield []postgres.Relation
395+
s.Require().NoError(s.dbClient.DB.Select(&relationsShield, "SELECT * FROM relations WHERE role_id = 'entropy/firehose:owner'"))
396+
s.Assert().Len(relationsShield, 2)
397+
398+
// PUT
399+
req, err = http.NewRequest(http.MethodPut, url, bytes.NewBuffer(reqBodyBytes))
400+
s.Require().NoError(err)
401+
402+
req.Header.Set(testbench.IdentityHeader, "[email protected]")
403+
req.Header.Set("X-Shield-Org", s.orgID)
404+
405+
res, err = http.DefaultClient.Do(req)
406+
s.Require().NoError(err)
407+
defer res.Body.Close()
408+
409+
s.Require().Equal(200, res.StatusCode)
410+
411+
// Validate resource & relation
412+
s.Require().NoError(s.dbClient.DB.Get(&resourceShield, fmt.Sprintf("SELECT id, name FROM resources WHERE name = '%s'", resourceName)))
413+
s.Assert().Equal(resourceShield.Name, resourceName)
414+
415+
var updatedRelations []postgres.Relation
416+
s.Require().NoError(s.dbClient.DB.Select(&updatedRelations, "SELECT * FROM relations WHERE role_id = 'entropy/firehose:owner'"))
417+
fmt.Println(updatedRelations)
418+
s.Assert().Len(updatedRelations, 2)
419+
})
420+
}
421+
342422
func TestEndToEndProxySmokeTestSuite(t *testing.T) {
343423
suite.Run(t, new(EndToEndProxySmokeTestSuite))
344424
}

test/e2e_test/testbench/mockserver.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ func startMockServer(ctx context.Context, logger *log.Zap, port int) {
3939

4040
reqBody["org"] = orgName
4141
reqBody["urn"] = reqBody["name"]
42+
reqBody["api"] = "POST"
43+
44+
respBytes, err := json.Marshal(reqBody)
45+
if err != nil {
46+
internalServerErrorWriter(w)
47+
return
48+
}
49+
50+
w.Write(respBytes)
51+
}
52+
updateResourceFn = func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
53+
b, err := io.ReadAll(r.Body)
54+
defer r.Body.Close()
55+
if err != nil {
56+
internalServerErrorWriter(w)
57+
return
58+
}
59+
60+
var reqBody map[string]string
61+
if err := json.Unmarshal(b, &reqBody); err != nil {
62+
internalServerErrorWriter(w)
63+
return
64+
}
65+
66+
var orgName = ""
67+
if hOrg, ok := r.Header["X-Shield-Org"]; ok {
68+
orgName = hOrg[0]
69+
}
70+
71+
reqBody["org"] = orgName
72+
reqBody["urn"] = reqBody["name"]
73+
reqBody["api"] = "PUT"
4274

4375
respBytes, err := json.Marshal(reqBody)
4476
if err != nil {
@@ -54,6 +86,8 @@ func startMockServer(ctx context.Context, logger *log.Zap, port int) {
5486
w.Write([]byte("pong"))
5587
})
5688
router.POST("/api/resource", createResourceFn)
89+
router.PUT("/api/resource", updateResourceFn)
90+
5791
router.POST("/api/resource_slug", createResourceFn)
5892
router.POST("/api/resource_user_id", createResourceFn)
5993
router.POST("/api/resource_user_email", createResourceFn)

test/e2e_test/testbench/testbench.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ func initTestBench(ctx context.Context, appConfig *config.Shield, mockServerPort
104104
URL: connMainPGExternal,
105105
MaxIdleConns: 10,
106106
MaxOpenConns: 10,
107-
ConnMaxLifeTime: time.Millisecond * 100,
108-
MaxQueryTimeoutInMS: time.Millisecond * 100,
107+
ConnMaxLifeTime: time.Millisecond * 1000,
108+
MaxQueryTimeoutInMS: time.Millisecond * 1000,
109109
}
110110

111111
te.SpiceDBConfig = spicedb.Config{
@@ -243,7 +243,7 @@ func SetupTests(t *testing.T) (shieldv1beta1.ShieldServiceClient, *config.Shield
243243
if err := BootstrapGroup(ctx, client, OrgAdminEmail, testDataPath); err != nil {
244244
t.Fatal(err)
245245
}
246-
time.Sleep(10 * time.Second)
246+
time.Sleep(5 * time.Second)
247247
if err := AssignGroupManager(ctx, client, OrgAdminEmail); err != nil {
248248
t.Fatal(err)
249249
}

test/e2e_test/testbench/testdata/configs/rules/rule.yaml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,51 @@
11
rules:
22
- backends:
33
- name: entropy
4-
target: "http://localhost:63758"
4+
target: "http://localhost:54217"
55
frontends:
66
- name: ping
77
path: "/api/ping"
88
method: "GET"
99
- name: create_resource
1010
path: "/api/resource"
1111
method: "POST"
12+
hooks:
13+
- name: authz
14+
config:
15+
action: authz_action
16+
attributes:
17+
resource:
18+
key: urn
19+
type: json_payload
20+
source: response
21+
project:
22+
key: project
23+
type: json_payload
24+
source: request
25+
group:
26+
key: group
27+
type: json_payload
28+
source: request
29+
organization:
30+
key: X-Shield-Org
31+
type: header
32+
source: request
33+
resource_type:
34+
value: "firehose"
35+
type: constant
36+
additional_group:
37+
value: 6b591fe0-fc94-4fd2-82bc-45f8a5d12a88
38+
type: constant
39+
relations:
40+
- role: owner
41+
subject_principal: shield/group
42+
subject_id_attribute: group
43+
- role: owner
44+
subject_principal: shield/group
45+
subject_id_attribute: additional_group
46+
- name: update_resource
47+
path: "/api/resource"
48+
method: "PUT"
1249
hooks:
1350
- name: authz
1451
config:

test/e2e_test/testbench/testdata/configs/rules/rule.yamltpl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,43 @@ rules:
99
- name: create_resource
1010
path: "/api/resource"
1111
method: "POST"
12+
hooks:
13+
- name: authz
14+
config:
15+
action: authz_action
16+
attributes:
17+
resource:
18+
key: urn
19+
type: json_payload
20+
source: response
21+
project:
22+
key: project
23+
type: json_payload
24+
source: request
25+
group:
26+
key: group
27+
type: json_payload
28+
source: request
29+
organization:
30+
key: X-Shield-Org
31+
type: header
32+
source: request
33+
resource_type:
34+
value: "firehose"
35+
type: constant
36+
additional_group:
37+
value: 6b591fe0-fc94-4fd2-82bc-45f8a5d12a88
38+
type: constant
39+
relations:
40+
- role: owner
41+
subject_principal: shield/group
42+
subject_id_attribute: group
43+
- role: owner
44+
subject_principal: shield/group
45+
subject_id_attribute: additional_group
46+
- name: update_resource
47+
path: "/api/resource"
48+
method: "PUT"
1249
hooks:
1350
- name: authz
1451
config:

0 commit comments

Comments
 (0)