From bbd200101fd33fdaa8b5c44da37c72cb52eee063 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 7 Aug 2020 17:56:55 -0400 Subject: [PATCH] Move update versioning to query parameter, and fix up scope API tests (#244) * Move update versioning to query parameter, and fix up scope API tests * Add version checks for update requests in other services --- api/authmethods/account.gen.go | 5 + api/authmethods/authmethods.gen.go | 9 +- api/authtokens/authtokens.gen.go | 2 +- api/groups/group.gen.go | 25 ++- api/hosts/host.gen.go | 5 + api/hosts/host_catalog.gen.go | 9 +- api/internal/genapi/templates.go | 37 ++++- api/roles/role.gen.go | 40 ++++- api/scopes/project_test.go | 157 ++++++++++-------- api/scopes/scope.gen.go | 30 +++- api/users/user.gen.go | 10 +- internal/cmd/commands/scopes/create.go | 1 + .../handlers/groups/group_service.go | 3 + .../controller/handlers/roles/role_service.go | 3 + .../handlers/scopes/scope_service.go | 3 + .../controller/handlers/users/user_service.go | 3 + 16 files changed, 240 insertions(+), 102 deletions(-) diff --git a/api/authmethods/account.gen.go b/api/authmethods/account.gen.go index c9fb7fcce..2649cc4a5 100644 --- a/api/authmethods/account.gen.go +++ b/api/authmethods/account.gen.go @@ -4,6 +4,7 @@ package authmethods import ( "context" "fmt" + "net/url" "time" "github.com/hashicorp/watchtower/api" @@ -113,6 +114,10 @@ func (c *accountsClient) Update(ctx context.Context, authMethodId string, accoun return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) diff --git a/api/authmethods/authmethods.gen.go b/api/authmethods/authmethods.gen.go index fc67ee037..8d9775ee3 100644 --- a/api/authmethods/authmethods.gen.go +++ b/api/authmethods/authmethods.gen.go @@ -4,6 +4,7 @@ package authmethods import ( "context" "fmt" + "net/url" "time" "github.com/hashicorp/watchtower/api" @@ -36,7 +37,7 @@ func (c *authmethodsClient) Create(ctx context.Context, opt ...Option) (*AuthMet opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "auth-methods", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } @@ -100,6 +101,10 @@ func (c *authmethodsClient) Update(ctx context.Context, authMethodId string, ver return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -154,7 +159,7 @@ func (c *authmethodsClient) List(ctx context.Context, opt ...Option) ([]*AuthMet _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-methods"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "auth-methods", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } diff --git a/api/authtokens/authtokens.gen.go b/api/authtokens/authtokens.gen.go index eff7dd3b3..27a7e092d 100644 --- a/api/authtokens/authtokens.gen.go +++ b/api/authtokens/authtokens.gen.go @@ -100,7 +100,7 @@ func (c *authtokensClient) List(ctx context.Context, opt ...Option) ([]*AuthToke _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-tokens"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "auth-tokens", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } diff --git a/api/groups/group.gen.go b/api/groups/group.gen.go index d32a8e437..bb86e5128 100644 --- a/api/groups/group.gen.go +++ b/api/groups/group.gen.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "net/url" "time" "github.com/kr/pretty" @@ -41,7 +42,7 @@ func (c *groupsClient) Create(ctx context.Context, opt ...Option) (*Group, *api. opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("groups"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "groups", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } @@ -116,13 +117,16 @@ func (c *groupsClient) Update(ctx context.Context, groupId string, version uint3 } version = existingTarget.Version } - opts.valueMap["version"] = version req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("groups/%s", groupId), opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -177,7 +181,7 @@ func (c *groupsClient) List(ctx context.Context, opt ...Option) ([]*Group, *api. _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("groups"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "groups", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } @@ -225,7 +229,6 @@ func (c *groupsClient) AddMembers(ctx context.Context, groupId string, version u } version = existingTarget.Version } - opts.valueMap["version"] = version if len(memberIds) > 0 { opts.valueMap["member_ids"] = memberIds @@ -236,6 +239,10 @@ func (c *groupsClient) AddMembers(ctx context.Context, groupId string, version u return nil, nil, fmt.Errorf("error creating AddMembers request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during AddMembers call: %w", err) @@ -276,7 +283,6 @@ func (c *groupsClient) SetMembers(ctx context.Context, groupId string, version u } version = existingTarget.Version } - opts.valueMap["version"] = version if len(memberIds) > 0 { opts.valueMap["member_ids"] = memberIds @@ -290,6 +296,10 @@ func (c *groupsClient) SetMembers(ctx context.Context, groupId string, version u return nil, nil, fmt.Errorf("error creating SetMembers request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during SetMembers call: %w", err) @@ -330,7 +340,6 @@ func (c *groupsClient) RemoveMembers(ctx context.Context, groupId string, versio } version = existingTarget.Version } - opts.valueMap["version"] = version if len(memberIds) > 0 { opts.valueMap["member_ids"] = memberIds @@ -341,6 +350,10 @@ func (c *groupsClient) RemoveMembers(ctx context.Context, groupId string, versio return nil, nil, fmt.Errorf("error creating RemoveMembers request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during RemoveMembers call: %w", err) diff --git a/api/hosts/host.gen.go b/api/hosts/host.gen.go index 7f4190130..0eff2d0c8 100644 --- a/api/hosts/host.gen.go +++ b/api/hosts/host.gen.go @@ -4,6 +4,7 @@ package hosts import ( "context" "fmt" + "net/url" "time" "github.com/hashicorp/watchtower/api" @@ -112,6 +113,10 @@ func (c *hostsClient) Update(ctx context.Context, hostCatalogId string, hostId s return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) diff --git a/api/hosts/host_catalog.gen.go b/api/hosts/host_catalog.gen.go index c1f40ffad..0cce885f6 100644 --- a/api/hosts/host_catalog.gen.go +++ b/api/hosts/host_catalog.gen.go @@ -4,6 +4,7 @@ package hosts import ( "context" "fmt" + "net/url" "time" "github.com/hashicorp/watchtower/api" @@ -37,7 +38,7 @@ func (c *hostcatalogsClient) Create(ctx context.Context, opt ...Option) (*HostCa opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "host-catalogs", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } @@ -101,6 +102,10 @@ func (c *hostcatalogsClient) Update(ctx context.Context, hostCatalogId string, v return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -155,7 +160,7 @@ func (c *hostcatalogsClient) List(ctx context.Context, opt ...Option) ([]*HostCa _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "host-catalogs", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } diff --git a/api/internal/genapi/templates.go b/api/internal/genapi/templates.go index 42fafc987..f5e8dcf46 100644 --- a/api/internal/genapi/templates.go +++ b/api/internal/genapi/templates.go @@ -14,6 +14,15 @@ import ( ) func toPath(segments []string, action string) string { + // If it's just a collection name, don't do a fmt.Sprintf + if len(segments) == 1 { + ret := segments[0] + if action != "" { + ret = fmt.Sprintf("%s:%s", ret, action) + } + return fmt.Sprintf(`"%s"`, ret) + } + var printfString, printfArg []string for i, s := range segments { if i%2 == 0 { @@ -40,7 +49,13 @@ func getArgsAndPaths(in []string, action string) (colArgs, resArgs []string, col pathSegment = append(pathSegment, collectionName, varName) } - return argNames[:len(argNames)-1], argNames, toPath(pathSegment[:len(pathSegment)-1], action), toPath(pathSegment, action) + colArgs, resArgs, colPath, resPath = argNames[:len(argNames)-1], argNames, toPath(pathSegment[:len(pathSegment)-1], action), toPath(pathSegment, action) + + // Scopes create and list operations always need scope ID + if colPath == `"scopes"` { + colArgs = append(colArgs, "scopeId") + } + return } type templateInput struct { @@ -185,6 +200,11 @@ func (c *{{ .ClientName }}Client) List(ctx context.Context, {{ range .Collection if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } + {{ if ( eq .CollectionPath "\"scopes\"" ) }} + q := url.Values{} + q.Add("scope_id", scopeId) + req.URL.RawQuery = q.Encode() + {{ end }} resp, err := c.client.Do(req) if err != nil { @@ -287,6 +307,11 @@ func (c *{{ .ClientName }}Client) Create(ctx context.Context, {{ range .Collecti if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } + {{ if ( eq .CollectionPath "\"scopes\"" ) }} + q := url.Values{} + q.Add("scope_id", scopeId) + req.URL.RawQuery = q.Encode() + {{ end }} resp, err := c.client.Do(req) if err != nil { @@ -331,7 +356,6 @@ func (c *{{ .ClientName }}Client) Update(ctx context.Context, {{ range .Resource } version = existingTarget.Version } - opts.valueMap["version"] = version {{ end }} req, err := c.client.NewRequest(ctx, "PATCH", {{ .ResourcePath }}, opts.valueMap, apiOpts...) @@ -339,6 +363,10 @@ func (c *{{ .ClientName }}Client) Update(ctx context.Context, {{ range .Resource return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -395,7 +423,6 @@ func (c *{{ $input.ClientName }}Client) {{ $fullName }}(ctx context.Context, {{ } version = existingTarget.Version } - opts.valueMap["version"] = version {{ end }} if len({{ $value }}) > 0 { @@ -411,6 +438,10 @@ func (c *{{ $input.ClientName }}Client) {{ $fullName }}(ctx context.Context, {{ return nil, nil, fmt.Errorf("error creating {{ $fullName }} request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during {{ $fullName }} call: %w", err) diff --git a/api/roles/role.gen.go b/api/roles/role.gen.go index 5321b1d52..5ce35190e 100644 --- a/api/roles/role.gen.go +++ b/api/roles/role.gen.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "net/url" "time" "github.com/kr/pretty" @@ -44,7 +45,7 @@ func (c *rolesClient) Create(ctx context.Context, opt ...Option) (*Role, *api.Er opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("roles"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "roles", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } @@ -119,13 +120,16 @@ func (c *rolesClient) Update(ctx context.Context, roleId string, version uint32, } version = existingTarget.Version } - opts.valueMap["version"] = version req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("roles/%s", roleId), opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -180,7 +184,7 @@ func (c *rolesClient) List(ctx context.Context, opt ...Option) ([]*Role, *api.Er _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("roles"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "roles", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } @@ -228,7 +232,6 @@ func (c *rolesClient) AddGrants(ctx context.Context, roleId string, version uint } version = existingTarget.Version } - opts.valueMap["version"] = version if len(grantStrings) > 0 { opts.valueMap["grant_strings"] = grantStrings @@ -239,6 +242,10 @@ func (c *rolesClient) AddGrants(ctx context.Context, roleId string, version uint return nil, nil, fmt.Errorf("error creating AddGrants request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during AddGrants call: %w", err) @@ -279,7 +286,6 @@ func (c *rolesClient) AddPrincipals(ctx context.Context, roleId string, version } version = existingTarget.Version } - opts.valueMap["version"] = version if len(principalIds) > 0 { opts.valueMap["principal_ids"] = principalIds @@ -290,6 +296,10 @@ func (c *rolesClient) AddPrincipals(ctx context.Context, roleId string, version return nil, nil, fmt.Errorf("error creating AddPrincipals request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during AddPrincipals call: %w", err) @@ -330,7 +340,6 @@ func (c *rolesClient) SetGrants(ctx context.Context, roleId string, version uint } version = existingTarget.Version } - opts.valueMap["version"] = version if len(grantStrings) > 0 { opts.valueMap["grant_strings"] = grantStrings @@ -344,6 +353,10 @@ func (c *rolesClient) SetGrants(ctx context.Context, roleId string, version uint return nil, nil, fmt.Errorf("error creating SetGrants request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during SetGrants call: %w", err) @@ -384,7 +397,6 @@ func (c *rolesClient) SetPrincipals(ctx context.Context, roleId string, version } version = existingTarget.Version } - opts.valueMap["version"] = version if len(principalIds) > 0 { opts.valueMap["principal_ids"] = principalIds @@ -398,6 +410,10 @@ func (c *rolesClient) SetPrincipals(ctx context.Context, roleId string, version return nil, nil, fmt.Errorf("error creating SetPrincipals request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during SetPrincipals call: %w", err) @@ -438,7 +454,6 @@ func (c *rolesClient) RemoveGrants(ctx context.Context, roleId string, version u } version = existingTarget.Version } - opts.valueMap["version"] = version if len(grantStrings) > 0 { opts.valueMap["grant_strings"] = grantStrings @@ -449,6 +464,10 @@ func (c *rolesClient) RemoveGrants(ctx context.Context, roleId string, version u return nil, nil, fmt.Errorf("error creating RemoveGrants request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during RemoveGrants call: %w", err) @@ -489,7 +508,6 @@ func (c *rolesClient) RemovePrincipals(ctx context.Context, roleId string, versi } version = existingTarget.Version } - opts.valueMap["version"] = version if len(principalIds) > 0 { opts.valueMap["principal_ids"] = principalIds @@ -500,6 +518,10 @@ func (c *rolesClient) RemovePrincipals(ctx context.Context, roleId string, versi return nil, nil, fmt.Errorf("error creating RemovePrincipals request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during RemovePrincipals call: %w", err) diff --git a/api/scopes/project_test.go b/api/scopes/project_test.go index 59d8b9652..cb1965645 100644 --- a/api/scopes/project_test.go +++ b/api/scopes/project_test.go @@ -1,49 +1,54 @@ package scopes_test -/* +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/scopes" + "github.com/hashicorp/watchtower/internal/servers/controller" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + func TestProjects_List(t *testing.T) { - assert := assert.New(t) - tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true}) + assert, require := assert.New(t), require.New(t) + orgId := "o_1234567890" + amId := "paum_1234567890" + tc := controller.NewTestController(t, &controller.TestControllerOpts{ + DisableAuthorizationFailures: true, + DefaultOrgId: orgId, + DefaultAuthMethodId: amId, + DefaultUsername: "user", + DefaultPassword: "passpass", + }) defer tc.Shutdown() client := tc.Client() - org := &scopes.Org{ - Client: client, - } - ctx := context.Background() + scps := scopes.NewScopesClient(client) - pl, apiErr, err := org.ListProjects(ctx) - assert.NoError(err) + pl, apiErr, err := scps.List(tc.Context(), orgId) + require.NoError(err) assert.Nil(apiErr) assert.Empty(pl) - var expected []*scopes.Project + expected := make([]*scopes.Scope, 10) for i := 0; i < 10; i++ { - expected = append(expected, &scopes.Project{Name: api.String(fmt.Sprint(i))}) - } - - expected[0], apiErr, err = org.CreateProject(ctx, expected[0]) - assert.NoError(err) - assert.Nil(apiErr) - - pl, apiErr, err = org.ListProjects(ctx) - assert.NoError(err) - assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(pl)) - - for i := 1; i < 10; i++ { - expected[i], apiErr, err = org.CreateProject(ctx, expected[i]) - assert.NoError(err) + expected[i], apiErr, err = scps.Create(tc.Context(), orgId, scopes.WithName(fmt.Sprintf("%d", i))) + require.NoError(err) assert.Nil(apiErr) } - pl, apiErr, err = org.ListProjects(ctx) + pl, apiErr, err = scps.List(tc.Context(), orgId) + require.NoError(err) + assert.Nil(apiErr) assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl)) } -func comparableSlice(in []*scopes.Project) []scopes.Project { - var filtered []scopes.Project +func comparableSlice(in []*scopes.Scope) []scopes.Scope { + var filtered []scopes.Scope for _, i := range in { - p := scopes.Project{ + p := scopes.Scope{ Id: i.Id, Name: i.Name, Description: i.Description, @@ -57,76 +62,86 @@ func comparableSlice(in []*scopes.Project) []scopes.Project { } func TestProjects_Crud(t *testing.T) { - tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true}) + assert, require := assert.New(t), require.New(t) + orgId := "o_1234567890" + amId := "paum_1234567890" + tc := controller.NewTestController(t, &controller.TestControllerOpts{ + DisableAuthorizationFailures: true, + DefaultOrgId: orgId, + DefaultAuthMethodId: amId, + DefaultUsername: "user", + DefaultPassword: "passpass", + }) defer tc.Shutdown() client := tc.Client() - org := &scopes.Org{ - Client: client, - } + scps := scopes.NewScopesClient(client) - checkProject := func(step string, p *scopes.Project, apiErr *api.Error, err error, wantedName string) { - assert := assert.New(t) - assert.NoError(err, step) + checkProject := func(step string, s *scopes.Scope, apiErr *api.Error, err error, wantedName string, wantedVersion uint32) { + require.NoError(err, step) assert.Nil(apiErr, step) - assert.NotNil(p, "returned project", step) + assert.NotNil(s, "returned project", step) gotName := "" - if p.Name != nil { - gotName = *p.Name + if s.Name != "" { + gotName = s.Name } assert.Equal(wantedName, gotName, step) + assert.Equal(wantedVersion, s.Version) } - p, apiErr, err := org.CreateProject(tc.Context(), &scopes.Project{Name: api.String("foo")}) - checkProject("create", p, apiErr, err, "foo") + s, apiErr, err := scps.Create(tc.Context(), orgId, scopes.WithName("foo")) + checkProject("create", s, apiErr, err, "foo", 1) - p, apiErr, err = org.ReadProject(tc.Context(), &scopes.Project{Id: p.Id}) - checkProject("read", p, apiErr, err, "foo") + s, apiErr, err = scps.Read(tc.Context(), s.Id) + checkProject("read", s, apiErr, err, "foo", 1) - p = &scopes.Project{Id: p.Id} - p.Name = api.String("bar") - p, apiErr, err = org.UpdateProject(tc.Context(), p) - checkProject("update", p, apiErr, err, "bar") + s, apiErr, err = scps.Update(tc.Context(), s.Id, s.Version, scopes.WithName("bar")) + checkProject("update", s, apiErr, err, "bar", 2) - p = &scopes.Project{Id: p.Id} - p.SetDefault("name") - p, apiErr, err = org.UpdateProject(tc.Context(), p) - checkProject("update, unset name", p, apiErr, err, "") + s, apiErr, err = scps.Update(tc.Context(), s.Id, s.Version, scopes.DefaultName()) + checkProject("update, unset name", s, apiErr, err, "", 3) - existed, apiErr, err := org.DeleteProject(tc.Context(), p) - assert.NoError(t, err) - assert.True(t, existed, "Expected existing project when deleted, but it wasn't.") + existed, apiErr, err := scps.Delete(tc.Context(), s.Id) + require.NoError(err) + assert.Nil(apiErr) + assert.True(existed, "Expected existing project when deleted, but it wasn't.") - existed, apiErr, err = org.DeleteProject(tc.Context(), p) - assert.NoError(t, err) - assert.False(t, existed, "Expected project to not exist when deleted, but it did.") + _, apiErr, err = scps.Delete(tc.Context(), s.Id) + require.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusForbidden, apiErr.Status, "Expected project to not exist when deleted, but it did.") } // TODO: Get better coverage for expected errors and error formats. func TestProject_Errors(t *testing.T) { - assert := assert.New(t) - tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true}) + assert, require := assert.New(t), require.New(t) + orgId := "o_1234567890" + amId := "paum_1234567890" + tc := controller.NewTestController(t, &controller.TestControllerOpts{ + DisableAuthorizationFailures: true, + DefaultOrgId: orgId, + DefaultAuthMethodId: amId, + DefaultUsername: "user", + DefaultPassword: "passpass", + }) defer tc.Shutdown() - ctx := tc.Context() client := tc.Client() - org := &scopes.Org{ - Client: client, - } - createdProj, apiErr, err := org.CreateProject(ctx, &scopes.Project{}) - assert.NoError(err) + scps := scopes.NewScopesClient(client) + + createdProj, apiErr, err := scps.Create(tc.Context(), orgId) + require.NoError(err) assert.NotNil(createdProj) assert.Nil(apiErr) - _, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "p_doesntexis"}) - assert.NoError(err) + _, apiErr, err = scps.Read(tc.Context(), "p_doesntexis") + require.NoError(err) // TODO: Should this be nil instead of just a Project that has no values set assert.NotNil(apiErr) - assert.EqualValues(apiErr.Status, http.StatusNotFound) + assert.EqualValues(http.StatusForbidden, apiErr.Status) - _, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "invalid id"}) + _, apiErr, err = scps.Read(tc.Context(), "invalid id") assert.NoError(err) assert.NotNil(apiErr) - assert.EqualValues(apiErr.Status, http.StatusBadRequest) + assert.EqualValues(http.StatusForbidden, apiErr.Status) } -*/ diff --git a/api/scopes/scope.gen.go b/api/scopes/scope.gen.go index 17046ff72..03a36c375 100644 --- a/api/scopes/scope.gen.go +++ b/api/scopes/scope.gen.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "net/url" "time" "github.com/kr/pretty" @@ -31,18 +32,26 @@ func NewScopesClient(c *api.Client) *scopesClient { return &scopesClient{client: c} } -func (c *scopesClient) Create(ctx context.Context, opt ...Option) (*Scope, *api.Error, error) { +func (c *scopesClient) Create(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) { + if scopeId == "" { + return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") + } + if c.client == nil { return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("scopes"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "scopes", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } + q := url.Values{} + q.Add("scope_id", scopeId) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) @@ -113,13 +122,16 @@ func (c *scopesClient) Update(ctx context.Context, scopeId string, version uint3 } version = existingTarget.Version } - opts.valueMap["version"] = version req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("scopes/%s", scopeId), opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -167,18 +179,26 @@ func (c *scopesClient) Delete(ctx context.Context, scopeId string, opt ...Option return target.Existed, apiErr, nil } -func (c *scopesClient) List(ctx context.Context, opt ...Option) ([]*Scope, *api.Error, error) { +func (c *scopesClient) List(ctx context.Context, scopeId string, opt ...Option) ([]*Scope, *api.Error, error) { + if scopeId == "" { + return nil, nil, fmt.Errorf("empty scopeId value passed into List request") + } + if c.client == nil { return nil, nil, fmt.Errorf("nil client") } _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("scopes"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "scopes", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } + q := url.Values{} + q.Add("scope_id", scopeId) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) diff --git a/api/users/user.gen.go b/api/users/user.gen.go index cd2a1fe31..5994eef65 100644 --- a/api/users/user.gen.go +++ b/api/users/user.gen.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "net/url" "time" "github.com/kr/pretty" @@ -39,7 +40,7 @@ func (c *usersClient) Create(ctx context.Context, opt ...Option) (*User, *api.Er opts, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("users"), opts.valueMap, apiOpts...) + req, err := c.client.NewRequest(ctx, "POST", "users", opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Create request: %w", err) } @@ -114,13 +115,16 @@ func (c *usersClient) Update(ctx context.Context, userId string, version uint32, } version = existingTarget.Version } - opts.valueMap["version"] = version req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("users/%s", userId), opts.valueMap, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating Update request: %w", err) } + q := url.Values{} + q.Add("version", fmt.Sprintf("%d", version)) + req.URL.RawQuery = q.Encode() + resp, err := c.client.Do(req) if err != nil { return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) @@ -175,7 +179,7 @@ func (c *usersClient) List(ctx context.Context, opt ...Option) ([]*User, *api.Er _, apiOpts := getOpts(opt...) - req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("users"), nil, apiOpts...) + req, err := c.client.NewRequest(ctx, "GET", "users", nil, apiOpts...) if err != nil { return nil, nil, fmt.Errorf("error creating List request: %w", err) } diff --git a/internal/cmd/commands/scopes/create.go b/internal/cmd/commands/scopes/create.go index c053f644e..040138d94 100644 --- a/internal/cmd/commands/scopes/create.go +++ b/internal/cmd/commands/scopes/create.go @@ -86,6 +86,7 @@ func (c *CreateScopeCommand) Run(args []string) int { } scp, apiErr, err := scopes.NewScopesClient(client).Create(c.Context, + client.ScopeId(), scopes.WithName(c.flagName), scopes.WithDescription(c.flagDescription)) diff --git a/internal/servers/controller/handlers/groups/group_service.go b/internal/servers/controller/handlers/groups/group_service.go index ec8fd34d9..f6a3df1af 100644 --- a/internal/servers/controller/handlers/groups/group_service.go +++ b/internal/servers/controller/handlers/groups/group_service.go @@ -409,6 +409,9 @@ func validateUpdateRequest(req *pbs.UpdateGroupRequest) error { if req.GetUpdateMask() == nil { badFields["update_mask"] = "UpdateMask not provided but is required to update a group." } + if req.GetVersion() == 0 { + badFields["version"] = "Existing resource version is required for an update." + } item := req.GetItem() if item == nil { diff --git a/internal/servers/controller/handlers/roles/role_service.go b/internal/servers/controller/handlers/roles/role_service.go index 359a38c64..55677c5c0 100644 --- a/internal/servers/controller/handlers/roles/role_service.go +++ b/internal/servers/controller/handlers/roles/role_service.go @@ -574,6 +574,9 @@ func validateUpdateRequest(req *pbs.UpdateRoleRequest, scope *scopes.ScopeInfo) if req.GetUpdateMask() == nil { badFields["update_mask"] = "UpdateMask not provided but is required to update a role." } + if req.GetVersion() == 0 { + badFields["version"] = "Existing resource version is required for an update." + } item := req.GetItem() if item == nil { diff --git a/internal/servers/controller/handlers/scopes/scope_service.go b/internal/servers/controller/handlers/scopes/scope_service.go index 403168aa6..3848ce08a 100644 --- a/internal/servers/controller/handlers/scopes/scope_service.go +++ b/internal/servers/controller/handlers/scopes/scope_service.go @@ -364,6 +364,9 @@ func validateUpdateRequest(req *pbs.UpdateScopeRequest) error { if req.GetUpdateMask() == nil { badFields["update_mask"] = "UpdateMask not provided but is required to update a project." } + if req.GetVersion() == 0 { + badFields["version"] = "Existing resource version is required for an update." + } item := req.GetItem() if item == nil { diff --git a/internal/servers/controller/handlers/users/user_service.go b/internal/servers/controller/handlers/users/user_service.go index 99fd8c4f1..98768ff17 100644 --- a/internal/servers/controller/handlers/users/user_service.go +++ b/internal/servers/controller/handlers/users/user_service.go @@ -296,6 +296,9 @@ func validateUpdateRequest(req *pbs.UpdateUserRequest) error { if req.GetUpdateMask() == nil { badFields["update_mask"] = "UpdateMask not provided but is required to update a user." } + if req.GetVersion() == 0 { + badFields["version"] = "Existing resource version is required for an update." + } item := req.GetItem() if item == nil {