From 98a2fe265f0e3c5ff066f0a6a134f72a64f035b5 Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Wed, 15 Jun 2022 15:07:19 +0200 Subject: [PATCH 1/9] Support for Service Authorizations When a user has the "engineer" level, specific access to specific services can be granted using service authorizations. This change adds support for creating, retrieving, updating and deleting service authorizations using the Go client. --- fastly/errors.go | 8 + .../service_authorizations/cleanup.yaml | 41 ++++ .../service_authorizations/create.yaml | 49 +++++ .../service_authorizations/delete.yaml | 45 ++++ .../fixtures/service_authorizations/get.yaml | 41 ++++ .../service_authorizations/update.yaml | 49 +++++ fastly/service_authorization.go | 192 ++++++++++++++++++ fastly/service_authorization_test.go | 149 ++++++++++++++ 8 files changed, 574 insertions(+) create mode 100644 fastly/fixtures/service_authorizations/cleanup.yaml create mode 100644 fastly/fixtures/service_authorizations/create.yaml create mode 100644 fastly/fixtures/service_authorizations/delete.yaml create mode 100644 fastly/fixtures/service_authorizations/get.yaml create mode 100644 fastly/fixtures/service_authorizations/update.yaml create mode 100644 fastly/service_authorization.go create mode 100644 fastly/service_authorization_test.go diff --git a/fastly/errors.go b/fastly/errors.go index a759ffdcf..84c48044a 100644 --- a/fastly/errors.go +++ b/fastly/errors.go @@ -171,6 +171,14 @@ var ErrMissingServerSideEncryptionKMSKeyID = NewFieldError("ServerSideEncryption // requires a "ServiceID" key, but one was not set. var ErrMissingServiceID = NewFieldError("ServiceID") +// ErrMissingUserID is an error that is returned when an input struct +// requires a "UserID" key, but one was not set +var ErrMissingUserID = NewFieldError("UserID") + +// ErrMissingPermissions is an error that is returned when an input struct +// requires a "Permissions" key, but one was not set +var ErrMissingPermissions = NewFieldError("Permissions") + // ErrMissingServiceVersion is an error that is returned when an input struct // requires a "ServiceVersion" key, but one was not set. var ErrMissingServiceVersion = NewFieldError("ServiceVersion") diff --git a/fastly/fixtures/service_authorizations/cleanup.yaml b/fastly/fixtures/service_authorizations/cleanup.yaml new file mode 100644 index 000000000..0be10a4be --- /dev/null +++ b/fastly/fixtures/service_authorizations/cleanup.yaml @@ -0,0 +1,41 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + User-Agent: + - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) + url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + method: DELETE + response: + body: "" + headers: + Accept-Ranges: + - bytes + Cache-Control: + - no-store + Date: + - Wed, 15 Jun 2022 12:43:18 GMT + Fastly-Ratelimit-Remaining: + - "974" + Fastly-Ratelimit-Reset: + - "1655298000" + Status: + - 204 No Content + Strict-Transport-Security: + - max-age=31536000 + Via: + - 1.1 varnish, 1.1 varnish + X-Cache: + - MISS, MISS + X-Cache-Hits: + - 0, 0 + X-Served-By: + - cache-control-slwdc9037-CONTROL-SLWDC, cache-bma1665-BMA + X-Timer: + - S1655296998.615067,VS0,VE438 + status: 204 No Content + code: 204 + duration: "" diff --git a/fastly/fixtures/service_authorizations/create.yaml b/fastly/fixtures/service_authorizations/create.yaml new file mode 100644 index 000000000..51bbb9253 --- /dev/null +++ b/fastly/fixtures/service_authorizations/create.yaml @@ -0,0 +1,49 @@ +--- +version: 1 +interactions: +- request: + body: '{"data":{"attributes":{"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}},"type":"service_authorization"}}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) + url: https://api.fastly.com/service-authorizations + method: POST + response: + body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:16Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + headers: + Accept-Ranges: + - bytes + Cache-Control: + - no-store + Content-Type: + - application/vnd.api+json + Date: + - Wed, 15 Jun 2022 12:43:16 GMT + Fastly-Ratelimit-Remaining: + - "976" + Fastly-Ratelimit-Reset: + - "1655298000" + Status: + - 200 OK + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Accept-Encoding + Via: + - 1.1 varnish, 1.1 varnish + X-Cache: + - MISS, MISS + X-Cache-Hits: + - 0, 0 + X-Served-By: + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1665-BMA + X-Timer: + - S1655296997.569927,VS0,VE263 + status: 200 OK + code: 200 + duration: "" diff --git a/fastly/fixtures/service_authorizations/delete.yaml b/fastly/fixtures/service_authorizations/delete.yaml new file mode 100644 index 000000000..2d03f3875 --- /dev/null +++ b/fastly/fixtures/service_authorizations/delete.yaml @@ -0,0 +1,45 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + User-Agent: + - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) + url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + method: DELETE + response: + body: '{"msg":"Record not found","detail":"Cannot find serviceauthorization ''RpPAg3cWoOTz6WbzXkA2a''"}' + headers: + Accept-Ranges: + - bytes + Cache-Control: + - no-store + Content-Type: + - application/json + Date: + - Wed, 15 Jun 2022 13:15:35 GMT + Fastly-Ratelimit-Remaining: + - "995" + Fastly-Ratelimit-Reset: + - "1655301600" + Status: + - 404 Not Found + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Accept-Encoding + Via: + - 1.1 varnish, 1.1 varnish + X-Cache: + - MISS, MISS + X-Cache-Hits: + - 0, 0 + X-Served-By: + - cache-control-slwdc9037-CONTROL-SLWDC, cache-bma1653-BMA + X-Timer: + - S1655298935.038067,VS0,VE340 + status: 404 Not Found + code: 404 + duration: "" diff --git a/fastly/fixtures/service_authorizations/get.yaml b/fastly/fixtures/service_authorizations/get.yaml new file mode 100644 index 000000000..e5f550715 --- /dev/null +++ b/fastly/fixtures/service_authorizations/get.yaml @@ -0,0 +1,41 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + User-Agent: + - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) + url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + method: GET + response: + body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:16Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + headers: + Accept-Ranges: + - bytes + Cache-Control: + - no-store + Content-Type: + - application/vnd.api+json + Date: + - Wed, 15 Jun 2022 12:43:17 GMT + Status: + - 200 OK + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Accept-Encoding + Via: + - 1.1 varnish, 1.1 varnish + X-Cache: + - MISS, MISS + X-Cache-Hits: + - 0, 0 + X-Served-By: + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1665-BMA + X-Timer: + - S1655296997.874631,VS0,VE326 + status: 200 OK + code: 200 + duration: "" diff --git a/fastly/fixtures/service_authorizations/update.yaml b/fastly/fixtures/service_authorizations/update.yaml new file mode 100644 index 000000000..33bb01772 --- /dev/null +++ b/fastly/fixtures/service_authorizations/update.yaml @@ -0,0 +1,49 @@ +--- +version: 1 +interactions: +- request: + body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","attributes":{"permission":"purge_select"},"type":"service_authorization"}}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) + url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + method: PATCH + response: + body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:17Z","deleted_at":null,"permission":"purge_select"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + headers: + Accept-Ranges: + - bytes + Cache-Control: + - no-store + Content-Type: + - application/vnd.api+json + Date: + - Wed, 15 Jun 2022 12:43:17 GMT + Fastly-Ratelimit-Remaining: + - "975" + Fastly-Ratelimit-Reset: + - "1655298000" + Status: + - 200 OK + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Accept-Encoding + Via: + - 1.1 varnish, 1.1 varnish + X-Cache: + - MISS, MISS + X-Cache-Hits: + - 0, 0 + X-Served-By: + - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1665-BMA + X-Timer: + - S1655296997.218665,VS0,VE383 + status: 200 OK + code: 200 + duration: "" diff --git a/fastly/service_authorization.go b/fastly/service_authorization.go new file mode 100644 index 000000000..4be61a235 --- /dev/null +++ b/fastly/service_authorization.go @@ -0,0 +1,192 @@ +package fastly + +import ( + "fmt" +) + +type ServiceAuthorizationPermission string +type ServiceAuthorizationType string + +const ( + PermissionFull = "full" + PermissionReadOnly = "read_only" + PermissionPurgeSelect = "purge_select" + PermissionPurgeAll = "purge_all" +) + +const ( + ServiceAuthorizationTypeServiceAuthorization = "service_authorization" +) + +type ServiceAuthorization struct { + ID string `mapstructure:"id"` + Permission ServiceAuthorizationPermission `mapstructure:"permission"` + UserID string `mapstructure:"relationships.user.data.id"` + ServiceID string `mapstructure:"relationships.service.data.id"` + Type ServiceAuthorizationType `mapstructure:"type"` +} + +type serviceAuthorizationAttributesModel struct { + Permission ServiceAuthorizationPermission `mapstructure:"permission,omitempty" json:"permission,omitempty"` +} + +type serviceAuthorizationRelationshipDataModel struct { + ID string `mapstructure:"id" json:"id,omitempty"` + Type string `mapstructure:"type" json:"type,omitempty"` +} + +type serviceAuthorizationRelationshipsAPIModel struct { + Data serviceAuthorizationRelationshipDataModel `mapstructure:"data" json:"data,omitempty"` +} + +type serviceAuthorizationRelationshipsModel struct { + Service serviceAuthorizationRelationshipsAPIModel `mapstructure:"service" json:"service,omitempty"` + User serviceAuthorizationRelationshipsAPIModel `mapstructure:"user" json:"user,omitempty"` +} + +type serviceAuthorizationDataModel struct { + ID string `mapstructure:"id,omitempty" json:"id,omitempty"` + Attributes serviceAuthorizationAttributesModel `mapstructure:"attributes" json:"attributes,omitempty"` + Relationships *serviceAuthorizationRelationshipsModel `mapstructure:"relationships" json:"relationships,omitempty"` + Type ServiceAuthorizationType `mapstructure:"type" json:"type,omitempty"` +} + +type serviceAuthorizationAPIModel struct { + Data serviceAuthorizationDataModel `mapstructure:"data" json:"data"` +} + +func (a serviceAuthorizationAPIModel) ToServiceAuthorization() *ServiceAuthorization { + return &ServiceAuthorization{ + ID: a.Data.ID, + Permission: a.Data.Attributes.Permission, + UserID: a.Data.Relationships.User.Data.ID, + ServiceID: a.Data.Relationships.Service.Data.ID, + Type: a.Data.Type, + } +} + +type GetServiceAuthorizationInput struct { + ID string +} + +func (c *Client) GetServiceAuthorization(i *GetServiceAuthorizationInput) (*ServiceAuthorization, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + path := fmt.Sprintf("/service-authorizations/%s", i.ID) + resp, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var a *serviceAuthorizationAPIModel + if err := decodeBodyMap(resp.Body, &a); err != nil { + return nil, err + } + + return a.ToServiceAuthorization(), nil +} + +type CreateServiceAuthorizationInput struct { + ServiceID string + UserID string + Permission ServiceAuthorizationPermission +} + +func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) (*ServiceAuthorization, error) { + if i.ServiceID == "" { + return nil, ErrMissingServiceID + } + if i.UserID == "" { + return nil, ErrMissingUserID + } + + out := serviceAuthorizationAPIModel{ + Data: serviceAuthorizationDataModel{ + Attributes: serviceAuthorizationAttributesModel{ + Permission: i.Permission, + }, + Relationships: &serviceAuthorizationRelationshipsModel{ + Service: serviceAuthorizationRelationshipsAPIModel{ + Data: serviceAuthorizationRelationshipDataModel{ + ID: i.ServiceID, + Type: "service", + }, + }, + User: serviceAuthorizationRelationshipsAPIModel{ + Data: serviceAuthorizationRelationshipDataModel{ + ID: i.UserID, + Type: "user", + }, + }, + }, + Type: ServiceAuthorizationTypeServiceAuthorization, + }, + } + + resp, err := c.PostJSON("/service-authorizations", &out, nil) + if err != nil { + return nil, err + } + + var a *serviceAuthorizationAPIModel + if err := decodeBodyMap(resp.Body, &a); err != nil { + return nil, err + } + + return a.ToServiceAuthorization(), nil +} + +type UpdateServiceAuthorizationInput struct { + ID string + Permissions ServiceAuthorizationPermission +} + +func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) (*ServiceAuthorization, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + if i.Permissions == "" { + return nil, ErrMissingPermissions + } + + out := &serviceAuthorizationAPIModel{ + Data: serviceAuthorizationDataModel{ + ID: i.ID, + Type: "service_authorization", + Attributes: serviceAuthorizationAttributesModel{ + Permission: i.Permissions, + }, + }, + } + + path := fmt.Sprintf("/service-authorizations/%s", i.ID) + resp, err := c.PatchJSON(path, out, nil) + if err != nil { + return nil, err + } + + var a *serviceAuthorizationAPIModel + if err := decodeBodyMap(resp.Body, &a); err != nil { + return nil, err + } + + return a.ToServiceAuthorization(), nil +} + +type DeleteServiceAuthorizationInput struct { + ID string +} + +func (c *Client) DeleteServiceAuthorization(i *DeleteServiceAuthorizationInput) error { + if i.ID == "" { + return ErrMissingID + } + + path := fmt.Sprintf("/service-authorizations/%s", i.ID) + _, err := c.Delete(path, nil) + + return err +} diff --git a/fastly/service_authorization_test.go b/fastly/service_authorization_test.go new file mode 100644 index 000000000..f5ca61915 --- /dev/null +++ b/fastly/service_authorization_test.go @@ -0,0 +1,149 @@ +package fastly + +import ( + "testing" +) + +func TestClient_ServiceAuthorizations(t *testing.T) { + t.Parallel() + + fixtureBase := "service_authorizations/" + + // Create + var err error + var sa *ServiceAuthorization + record(t, fixtureBase+"create", func(c *Client) { + sa, err = c.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ + ServiceID: "7ZVxm5pPWdzKdl3P5UW7jR", + UserID: "4tKBSuFhNEiIpNDxmmVydt", + Permission: PermissionFull, + }) + }) + if err != nil { + t.Fatal(err) + } + + // Ensure deleted + defer func() { + record(t, fixtureBase+"cleanup", func(c *Client) { + c.DeleteServiceAuthorization(&DeleteServiceAuthorizationInput{ + ID: sa.ID, + }) + + }) + }() + + if sa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { + t.Errorf("bad service id: %v", sa.ServiceID) + } + + if sa.UserID != "4tKBSuFhNEiIpNDxmmVydt" { + t.Errorf("bad user id: %v", sa.UserID) + } + + if sa.Permission != PermissionFull { + t.Errorf("bad permission: %v", sa.Permission) + } + + // Get + var nsa *ServiceAuthorization + record(t, fixtureBase+"get", func(c *Client) { + nsa, err = c.GetServiceAuthorization(&GetServiceAuthorizationInput{ + ID: sa.ID, + }) + }) + if err != nil { + t.Fatal(err) + } + + if nsa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { + t.Errorf("bad service id: %v", nsa.ServiceID) + } + + // Update + var usa *ServiceAuthorization + record(t, fixtureBase+"update", func(c *Client) { + usa, err = c.UpdateServiceAuthorization(&UpdateServiceAuthorizationInput{ + ID: sa.ID, + Permissions: PermissionPurgeSelect, + }) + }) + if err != nil { + t.Fatal(err) + } + + if usa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { + t.Errorf("bad service id: %v", usa.ServiceID) + } + if usa.Permission != PermissionPurgeSelect { + t.Errorf("bad permission: %v", usa.Permission) + } + + // Delete + record(t, fixtureBase+"delete", func(c *Client) { + err = c.DeleteServiceAuthorization(&DeleteServiceAuthorizationInput{ + ID: sa.ID, + }) + }) + if err != nil { + t.Fatal(err) + } +} + +func TestClient_GetServiceAuthorization_validation(t *testing.T) { + var err error + _, err = testClient.GetServiceAuthorization(&GetServiceAuthorizationInput{ + ID: "", + }) + if err != ErrMissingID { + t.Errorf("bad error: %s", err) + } +} + +func TestClient_CreateServiceAuthorization_validation(t *testing.T) { + var err error + _, err = testClient.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ + ServiceID: "", + UserID: "", + }) + if err != ErrMissingServiceID { + t.Errorf("bad error: %s", err) + } + + _, err = testClient.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ + ServiceID: "my-service-id", + UserID: "", + }) + if err != ErrMissingUserID { + t.Errorf("bad error: %s", err) + } +} + +func TestClient_UpdateServiceAuthorization_validation(t *testing.T) { + var err error + _, err = testClient.UpdateServiceAuthorization(&UpdateServiceAuthorizationInput{ + ID: "", + Permissions: "", + }) + if err != ErrMissingID { + t.Errorf("bad error: %s", err) + } + + _, err = testClient.UpdateServiceAuthorization(&UpdateServiceAuthorizationInput{ + ID: "my-service-authorization-id", + Permissions: "", + }) + if err != ErrMissingPermissions { + t.Errorf("bad error: %s", err) + } +} + +func TestClient_DeleteServiceAuthorization_validation(t *testing.T) { + err := testClient.DeleteServiceAuthorization(&DeleteServiceAuthorizationInput{ + ID: "", + }) + if err != ErrMissingID { + t.Errorf("bad error: %s", err) + } + +} From 03301f6a479a07ea0345112c0abca2948f9c6ff7 Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Thu, 16 Jun 2022 14:41:40 +0200 Subject: [PATCH 2/9] service_authorization: Remove superfluous types We can use the string directly instead of creating new types for permissions and data types as we do not require any extra functionality on these types. --- fastly/service_authorization.go | 34 ++++++++-------------------- fastly/service_authorization_test.go | 8 +++---- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/fastly/service_authorization.go b/fastly/service_authorization.go index 4be61a235..4b478bf0e 100644 --- a/fastly/service_authorization.go +++ b/fastly/service_authorization.go @@ -4,30 +4,16 @@ import ( "fmt" ) -type ServiceAuthorizationPermission string -type ServiceAuthorizationType string - -const ( - PermissionFull = "full" - PermissionReadOnly = "read_only" - PermissionPurgeSelect = "purge_select" - PermissionPurgeAll = "purge_all" -) - -const ( - ServiceAuthorizationTypeServiceAuthorization = "service_authorization" -) - type ServiceAuthorization struct { - ID string `mapstructure:"id"` - Permission ServiceAuthorizationPermission `mapstructure:"permission"` - UserID string `mapstructure:"relationships.user.data.id"` - ServiceID string `mapstructure:"relationships.service.data.id"` - Type ServiceAuthorizationType `mapstructure:"type"` + ID string `mapstructure:"id"` + Permission string `mapstructure:"permission"` + UserID string `mapstructure:"relationships.user.data.id"` + ServiceID string `mapstructure:"relationships.service.data.id"` + Type string `mapstructure:"type"` } type serviceAuthorizationAttributesModel struct { - Permission ServiceAuthorizationPermission `mapstructure:"permission,omitempty" json:"permission,omitempty"` + Permission string `mapstructure:"permission,omitempty" json:"permission,omitempty"` } type serviceAuthorizationRelationshipDataModel struct { @@ -48,7 +34,7 @@ type serviceAuthorizationDataModel struct { ID string `mapstructure:"id,omitempty" json:"id,omitempty"` Attributes serviceAuthorizationAttributesModel `mapstructure:"attributes" json:"attributes,omitempty"` Relationships *serviceAuthorizationRelationshipsModel `mapstructure:"relationships" json:"relationships,omitempty"` - Type ServiceAuthorizationType `mapstructure:"type" json:"type,omitempty"` + Type string `mapstructure:"type" json:"type,omitempty"` } type serviceAuthorizationAPIModel struct { @@ -91,7 +77,7 @@ func (c *Client) GetServiceAuthorization(i *GetServiceAuthorizationInput) (*Serv type CreateServiceAuthorizationInput struct { ServiceID string UserID string - Permission ServiceAuthorizationPermission + Permission string } func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) (*ServiceAuthorization, error) { @@ -121,7 +107,7 @@ func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) }, }, }, - Type: ServiceAuthorizationTypeServiceAuthorization, + Type: "service_authorization", }, } @@ -140,7 +126,7 @@ func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) type UpdateServiceAuthorizationInput struct { ID string - Permissions ServiceAuthorizationPermission + Permissions string } func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) (*ServiceAuthorization, error) { diff --git a/fastly/service_authorization_test.go b/fastly/service_authorization_test.go index f5ca61915..6a8f4e020 100644 --- a/fastly/service_authorization_test.go +++ b/fastly/service_authorization_test.go @@ -16,7 +16,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { sa, err = c.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ ServiceID: "7ZVxm5pPWdzKdl3P5UW7jR", UserID: "4tKBSuFhNEiIpNDxmmVydt", - Permission: PermissionFull, + Permission: "full", }) }) if err != nil { @@ -41,7 +41,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { t.Errorf("bad user id: %v", sa.UserID) } - if sa.Permission != PermissionFull { + if sa.Permission != "full" { t.Errorf("bad permission: %v", sa.Permission) } @@ -65,7 +65,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { record(t, fixtureBase+"update", func(c *Client) { usa, err = c.UpdateServiceAuthorization(&UpdateServiceAuthorizationInput{ ID: sa.ID, - Permissions: PermissionPurgeSelect, + Permissions: "purge_select", }) }) if err != nil { @@ -75,7 +75,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { if usa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { t.Errorf("bad service id: %v", usa.ServiceID) } - if usa.Permission != PermissionPurgeSelect { + if usa.Permission != "purge_select" { t.Errorf("bad permission: %v", usa.Permission) } From 54870e0847a072848d44e49ccae4b9574db4a797 Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Thu, 16 Jun 2022 16:46:57 +0200 Subject: [PATCH 3/9] service_authorization: Use jsonapi Using `jsonapi` saves us from constructing a lot of extra models because the API provided by fastly already follows the conventions outlined by `jsonapi`. --- fastly/service_authorization.go | 133 ++++++++++---------------------- 1 file changed, 41 insertions(+), 92 deletions(-) diff --git a/fastly/service_authorization.go b/fastly/service_authorization.go index 4b478bf0e..9ec5646f6 100644 --- a/fastly/service_authorization.go +++ b/fastly/service_authorization.go @@ -2,53 +2,27 @@ package fastly import ( "fmt" -) - -type ServiceAuthorization struct { - ID string `mapstructure:"id"` - Permission string `mapstructure:"permission"` - UserID string `mapstructure:"relationships.user.data.id"` - ServiceID string `mapstructure:"relationships.service.data.id"` - Type string `mapstructure:"type"` -} - -type serviceAuthorizationAttributesModel struct { - Permission string `mapstructure:"permission,omitempty" json:"permission,omitempty"` -} + "time" -type serviceAuthorizationRelationshipDataModel struct { - ID string `mapstructure:"id" json:"id,omitempty"` - Type string `mapstructure:"type" json:"type,omitempty"` -} - -type serviceAuthorizationRelationshipsAPIModel struct { - Data serviceAuthorizationRelationshipDataModel `mapstructure:"data" json:"data,omitempty"` -} - -type serviceAuthorizationRelationshipsModel struct { - Service serviceAuthorizationRelationshipsAPIModel `mapstructure:"service" json:"service,omitempty"` - User serviceAuthorizationRelationshipsAPIModel `mapstructure:"user" json:"user,omitempty"` -} + "github.com/google/jsonapi" +) -type serviceAuthorizationDataModel struct { - ID string `mapstructure:"id,omitempty" json:"id,omitempty"` - Attributes serviceAuthorizationAttributesModel `mapstructure:"attributes" json:"attributes,omitempty"` - Relationships *serviceAuthorizationRelationshipsModel `mapstructure:"relationships" json:"relationships,omitempty"` - Type string `mapstructure:"type" json:"type,omitempty"` +type SAUser struct { + ID string `jsonapi:"primary,user"` } -type serviceAuthorizationAPIModel struct { - Data serviceAuthorizationDataModel `mapstructure:"data" json:"data"` +type SAService struct { + ID string `jsonapi:"primary,service"` } -func (a serviceAuthorizationAPIModel) ToServiceAuthorization() *ServiceAuthorization { - return &ServiceAuthorization{ - ID: a.Data.ID, - Permission: a.Data.Attributes.Permission, - UserID: a.Data.Relationships.User.Data.ID, - ServiceID: a.Data.Relationships.Service.Data.ID, - Type: a.Data.Type, - } +type ServiceAuthorization struct { + ID string `jsonapi:"primary,service_authorization"` + Permission string `jsonapi:"attr,permission,omitempty"` + CreatedAt *time.Time `jsonapi:"attr,created_at,iso8601"` + UpdatedAt *time.Time `jsonapi:"attr,updated_at,iso8601"` + DeltedAt *time.Time `jsonapi:"attr,deleted_at,iso8601"` + User *SAUser `jsonapi:"relation,user,omitempty"` + Service *SAService `jsonapi:"relation,service,omitempty"` } type GetServiceAuthorizationInput struct { @@ -66,67 +40,52 @@ func (c *Client) GetServiceAuthorization(i *GetServiceAuthorizationInput) (*Serv return nil, err } - var a *serviceAuthorizationAPIModel - if err := decodeBodyMap(resp.Body, &a); err != nil { + var sa ServiceAuthorization + if err := jsonapi.UnmarshalPayload(resp.Body, &sa); err != nil { return nil, err } - return a.ToServiceAuthorization(), nil + return &sa, nil } type CreateServiceAuthorizationInput struct { - ServiceID string - UserID string - Permission string + // ID value is ignored and should not be set, needed to make JSONAPI work correctly. + ID string `jsonapi:"primary,service_authorization"` + + // Permission is the level of permissions to grant the user to the service. Valid values are "full", "read_only", "purge_select" or "purge_all". + Permission string `jsonapi:"attr,permission,omitempty"` + + // ServiceID is the ID of the service to grant permissions for. + Service *SAService `jsonapi:"relation,service,omitempty"` + + // UserID is the ID of the user which should have its permissions set. + User *SAUser `jsonapi:"relation,user,omitempty"` } func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) (*ServiceAuthorization, error) { - if i.ServiceID == "" { + if i.Service == nil || i.Service.ID == "" { return nil, ErrMissingServiceID } - if i.UserID == "" { + if i.User == nil || i.User.ID == "" { return nil, ErrMissingUserID } - out := serviceAuthorizationAPIModel{ - Data: serviceAuthorizationDataModel{ - Attributes: serviceAuthorizationAttributesModel{ - Permission: i.Permission, - }, - Relationships: &serviceAuthorizationRelationshipsModel{ - Service: serviceAuthorizationRelationshipsAPIModel{ - Data: serviceAuthorizationRelationshipDataModel{ - ID: i.ServiceID, - Type: "service", - }, - }, - User: serviceAuthorizationRelationshipsAPIModel{ - Data: serviceAuthorizationRelationshipDataModel{ - ID: i.UserID, - Type: "user", - }, - }, - }, - Type: "service_authorization", - }, - } - - resp, err := c.PostJSON("/service-authorizations", &out, nil) + resp, err := c.PostJSONAPI("/service-authorizations", i, nil) if err != nil { return nil, err } - var a *serviceAuthorizationAPIModel - if err := decodeBodyMap(resp.Body, &a); err != nil { + var sa ServiceAuthorization + if err := jsonapi.UnmarshalPayload(resp.Body, &sa); err != nil { return nil, err } - return a.ToServiceAuthorization(), nil + return &sa, nil } type UpdateServiceAuthorizationInput struct { - ID string - Permissions string + ID string `jsonapi:"primary,service_authorization"` + Permissions string `jsonapi:"attr,permission,omitempty"` } func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) (*ServiceAuthorization, error) { @@ -138,28 +97,18 @@ func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) return nil, ErrMissingPermissions } - out := &serviceAuthorizationAPIModel{ - Data: serviceAuthorizationDataModel{ - ID: i.ID, - Type: "service_authorization", - Attributes: serviceAuthorizationAttributesModel{ - Permission: i.Permissions, - }, - }, - } - path := fmt.Sprintf("/service-authorizations/%s", i.ID) - resp, err := c.PatchJSON(path, out, nil) + resp, err := c.PatchJSONAPI(path, i, nil) if err != nil { return nil, err } - var a *serviceAuthorizationAPIModel - if err := decodeBodyMap(resp.Body, &a); err != nil { + var sa ServiceAuthorization + if err := jsonapi.UnmarshalPayload(resp.Body, &sa); err != nil { return nil, err } - return a.ToServiceAuthorization(), nil + return &sa, nil } type DeleteServiceAuthorizationInput struct { From c5081169e243ed4dc477c8fc4ed0a34b2f8ea17e Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Thu, 16 Jun 2022 16:48:52 +0200 Subject: [PATCH 4/9] test: anonymize the IDs used Anonymizes the IDs used for service authorizations as well as adds a new "default" id for user, which can be anonymized to a default User ID in the `fix-fixtures` target of the makefile. --- fastly/fastly_test.go | 16 +++++++++++ .../service_authorizations/cleanup.yaml | 24 +++++++++------- .../service_authorizations/create.yaml | 19 +++++++------ .../service_authorizations/delete.yaml | 24 +++++++--------- .../fixtures/service_authorizations/get.yaml | 10 +++---- .../service_authorizations/update.yaml | 21 +++++++------- fastly/service_authorization_test.go | 28 +++++++++---------- scripts/fixFixtures.sh | 11 ++++++++ 8 files changed, 91 insertions(+), 62 deletions(-) diff --git a/fastly/fastly_test.go b/fastly/fastly_test.go index 9634922a0..1878eea2a 100644 --- a/fastly/fastly_test.go +++ b/fastly/fastly_test.go @@ -19,9 +19,15 @@ var testStatsClient = NewRealtimeStatsClient() // testServiceID is the ID of the testing service. var testServiceID = serviceIDForTest() +// testUserID is the ID of the testing user. +var testUserID = userIDForTest() + // Default ID of the testing service. var defaultTestServiceID = "7i6HN3TK9wS159v2gPAZ8A" +// Default ID of the testing user. +var defaultTestUserID = "4tKBSuFhNEiIpNDxmmVydt" + const ( // ServiceTypeVCL is the type for VCL services. ServiceTypeVCL = "vcl" @@ -43,6 +49,16 @@ func serviceIDForTest() string { return defaultTestServiceID } +func userIDForTest() string { + uid := os.Getenv("FASTLY_TEST_USER_ID") + + if uid != "" { + return uid + } + + return defaultTestUserID +} + func vcrDisabled() bool { vcrDisable := os.Getenv("VCR_DISABLE") diff --git a/fastly/fixtures/service_authorizations/cleanup.yaml b/fastly/fixtures/service_authorizations/cleanup.yaml index 0be10a4be..d90a57911 100644 --- a/fastly/fixtures/service_authorizations/cleanup.yaml +++ b/fastly/fixtures/service_authorizations/cleanup.yaml @@ -7,25 +7,29 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff method: DELETE response: - body: "" + body: '{"msg":"Record not found","detail":"Cannot find serviceauthorization ''dTYPkfosjJ6dMSBZNAPff''"}' headers: Accept-Ranges: - bytes Cache-Control: - no-store + Content-Type: + - application/json Date: - - Wed, 15 Jun 2022 12:43:18 GMT + - Thu, 16 Jun 2022 14:54:33 GMT Fastly-Ratelimit-Remaining: - - "974" + - "956" Fastly-Ratelimit-Reset: - - "1655298000" + - "1655391600" Status: - - 204 No Content + - 404 Not Found Strict-Transport-Security: - max-age=31536000 + Vary: + - Accept-Encoding Via: - 1.1 varnish, 1.1 varnish X-Cache: @@ -33,9 +37,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9037-CONTROL-SLWDC, cache-bma1665-BMA + - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1646-BMA X-Timer: - - S1655296998.615067,VS0,VE438 - status: 204 No Content - code: 204 + - S1655391273.306991,VS0,VE433 + status: 404 Not Found + code: 404 duration: "" diff --git a/fastly/fixtures/service_authorizations/create.yaml b/fastly/fixtures/service_authorizations/create.yaml index 51bbb9253..9dd8b186d 100644 --- a/fastly/fixtures/service_authorizations/create.yaml +++ b/fastly/fixtures/service_authorizations/create.yaml @@ -2,19 +2,20 @@ version: 1 interactions: - request: - body: '{"data":{"attributes":{"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}},"type":"service_authorization"}}' + body: | + {"data":{"type":"service_authorization","attributes":{"permission":"full"},"relationships":{"service":{"data":{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"}},"user":{"data":{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"}}}},"included":[{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"},{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"}]} form: {} headers: Accept: - - application/json + - application/vnd.api+json Content-Type: - - application/json + - application/vnd.api+json User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) url: https://api.fastly.com/service-authorizations method: POST response: - body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:16Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -23,11 +24,11 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Wed, 15 Jun 2022 12:43:16 GMT + - Thu, 16 Jun 2022 14:54:32 GMT Fastly-Ratelimit-Remaining: - - "976" + - "959" Fastly-Ratelimit-Reset: - - "1655298000" + - "1655391600" Status: - 200 OK Strict-Transport-Security: @@ -41,9 +42,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1665-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA X-Timer: - - S1655296997.569927,VS0,VE263 + - S1655391272.193824,VS0,VE172 status: 200 OK code: 200 duration: "" diff --git a/fastly/fixtures/service_authorizations/delete.yaml b/fastly/fixtures/service_authorizations/delete.yaml index 2d03f3875..ca868650b 100644 --- a/fastly/fixtures/service_authorizations/delete.yaml +++ b/fastly/fixtures/service_authorizations/delete.yaml @@ -7,29 +7,25 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff method: DELETE response: - body: '{"msg":"Record not found","detail":"Cannot find serviceauthorization ''RpPAg3cWoOTz6WbzXkA2a''"}' + body: "" headers: Accept-Ranges: - bytes Cache-Control: - no-store - Content-Type: - - application/json Date: - - Wed, 15 Jun 2022 13:15:35 GMT + - Thu, 16 Jun 2022 14:54:33 GMT Fastly-Ratelimit-Remaining: - - "995" + - "957" Fastly-Ratelimit-Reset: - - "1655301600" + - "1655391600" Status: - - 404 Not Found + - 204 No Content Strict-Transport-Security: - max-age=31536000 - Vary: - - Accept-Encoding Via: - 1.1 varnish, 1.1 varnish X-Cache: @@ -37,9 +33,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9037-CONTROL-SLWDC, cache-bma1653-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA X-Timer: - - S1655298935.038067,VS0,VE340 - status: 404 Not Found - code: 404 + - S1655391273.032612,VS0,VE260 + status: 204 No Content + code: 204 duration: "" diff --git a/fastly/fixtures/service_authorizations/get.yaml b/fastly/fixtures/service_authorizations/get.yaml index e5f550715..1723ef51a 100644 --- a/fastly/fixtures/service_authorizations/get.yaml +++ b/fastly/fixtures/service_authorizations/get.yaml @@ -7,10 +7,10 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff method: GET response: - body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:16Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -19,7 +19,7 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Wed, 15 Jun 2022 12:43:17 GMT + - Thu, 16 Jun 2022 14:54:32 GMT Status: - 200 OK Strict-Transport-Security: @@ -33,9 +33,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1665-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA X-Timer: - - S1655296997.874631,VS0,VE326 + - S1655391272.387855,VS0,VE432 status: 200 OK code: 200 duration: "" diff --git a/fastly/fixtures/service_authorizations/update.yaml b/fastly/fixtures/service_authorizations/update.yaml index 33bb01772..a63f9cd3e 100644 --- a/fastly/fixtures/service_authorizations/update.yaml +++ b/fastly/fixtures/service_authorizations/update.yaml @@ -2,19 +2,20 @@ version: 1 interactions: - request: - body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","attributes":{"permission":"purge_select"},"type":"service_authorization"}}' + body: | + {"data":{"type":"service_authorization","id":"dTYPkfosjJ6dMSBZNAPff","attributes":{"permission":"purge_select"}}} form: {} headers: Accept: - - application/json + - application/vnd.api+json Content-Type: - - application/json + - application/vnd.api+json User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/RpPAg3cWoOTz6WbzXkA2a + url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff method: PATCH response: - body: '{"data":{"id":"RpPAg3cWoOTz6WbzXkA2a","type":"service_authorization","attributes":{"created_at":"2022-06-15T12:43:16Z","updated_at":"2022-06-15T12:43:17Z","deleted_at":null,"permission":"purge_select"},"relationships":{"service":{"data":{"id":"7ZVxm5pPWdzKdl3P5UW7jR","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"purge_select"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -23,11 +24,11 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Wed, 15 Jun 2022 12:43:17 GMT + - Thu, 16 Jun 2022 14:54:33 GMT Fastly-Ratelimit-Remaining: - - "975" + - "958" Fastly-Ratelimit-Reset: - - "1655298000" + - "1655391600" Status: - 200 OK Strict-Transport-Security: @@ -41,9 +42,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1665-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA X-Timer: - - S1655296997.218665,VS0,VE383 + - S1655391273.836430,VS0,VE181 status: 200 OK code: 200 duration: "" diff --git a/fastly/service_authorization_test.go b/fastly/service_authorization_test.go index 6a8f4e020..18f0140e7 100644 --- a/fastly/service_authorization_test.go +++ b/fastly/service_authorization_test.go @@ -14,8 +14,8 @@ func TestClient_ServiceAuthorizations(t *testing.T) { var sa *ServiceAuthorization record(t, fixtureBase+"create", func(c *Client) { sa, err = c.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ - ServiceID: "7ZVxm5pPWdzKdl3P5UW7jR", - UserID: "4tKBSuFhNEiIpNDxmmVydt", + Service: &SAService{ID: testServiceID}, + User: &SAUser{ID: testUserID}, Permission: "full", }) }) @@ -33,12 +33,12 @@ func TestClient_ServiceAuthorizations(t *testing.T) { }) }() - if sa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { - t.Errorf("bad service id: %v", sa.ServiceID) + if sa.Service.ID != testServiceID { + t.Errorf("bad service id: %v", sa.Service.ID) } - if sa.UserID != "4tKBSuFhNEiIpNDxmmVydt" { - t.Errorf("bad user id: %v", sa.UserID) + if sa.User.ID != testUserID { + t.Errorf("bad user id: %v", sa.User.ID) } if sa.Permission != "full" { @@ -56,8 +56,8 @@ func TestClient_ServiceAuthorizations(t *testing.T) { t.Fatal(err) } - if nsa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { - t.Errorf("bad service id: %v", nsa.ServiceID) + if nsa.Service.ID != testServiceID { + t.Errorf("bad service id: %v", nsa.Service) } // Update @@ -72,8 +72,8 @@ func TestClient_ServiceAuthorizations(t *testing.T) { t.Fatal(err) } - if usa.ServiceID != "7ZVxm5pPWdzKdl3P5UW7jR" { - t.Errorf("bad service id: %v", usa.ServiceID) + if usa.Service.ID != testServiceID { + t.Errorf("bad service id: %v", usa.Service) } if usa.Permission != "purge_select" { t.Errorf("bad permission: %v", usa.Permission) @@ -103,16 +103,16 @@ func TestClient_GetServiceAuthorization_validation(t *testing.T) { func TestClient_CreateServiceAuthorization_validation(t *testing.T) { var err error _, err = testClient.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ - ServiceID: "", - UserID: "", + Service: &SAService{ID: ""}, + User: &SAUser{ID: ""}, }) if err != ErrMissingServiceID { t.Errorf("bad error: %s", err) } _, err = testClient.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ - ServiceID: "my-service-id", - UserID: "", + Service: &SAService{ID: "my-service-id"}, + User: &SAUser{ID: ""}, }) if err != ErrMissingUserID { t.Errorf("bad error: %s", err) diff --git a/scripts/fixFixtures.sh b/scripts/fixFixtures.sh index 90c06e708..f14e2379f 100755 --- a/scripts/fixFixtures.sh +++ b/scripts/fixFixtures.sh @@ -3,6 +3,7 @@ set -e FASTLY_TEST_SERVICE_ID=$1 DEFAULT_TEST_SERVICE_ID="7i6HN3TK9wS159v2gPAZ8A" +DEFAULT_TEST_USER_ID="4tKBSuFhNEiIpNDxmmVydt" FIXTURESDIR="$(pwd)/fastly/fixtures/" if [[ -z ${FASTLY_TEST_SERVICE_ID} && -z $1 ]]; then @@ -10,7 +11,17 @@ if [[ -z ${FASTLY_TEST_SERVICE_ID} && -z $1 ]]; then exit fi +if [[ -z ${FASTLY_TEST_USER_ID} && -z $2 ]]; then + echo "You must supply a user ID as the second argument" + exit +fi + for file in $(grep --recursive --files-with-matches "${FASTLY_TEST_SERVICE_ID}" "${FIXTURESDIR}") do sed -i.bak "s/${FASTLY_TEST_SERVICE_ID}/${DEFAULT_TEST_SERVICE_ID}/g" "$file" && rm "${file}.bak" done + +for file in $(grep --recursive --files-with-matches "${FASTLY_TEST_USER_ID}" "${FIXTURESDIR}") +do + sed -i.bak "s/${FASTLY_TEST_USER_ID}/${DEFAULT_TEST_USER_ID}/g" "$file" && rm "${file}.bak" +done From 4a299a27ec6bec0920d94a803e3932abc9d54d7e Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Thu, 16 Jun 2022 17:08:32 +0200 Subject: [PATCH 5/9] service_authorization: Expand with Go docs Add Godocs to the exposed functions and structs used as inputs. --- fastly/service_authorization.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fastly/service_authorization.go b/fastly/service_authorization.go index 9ec5646f6..823a27bf1 100644 --- a/fastly/service_authorization.go +++ b/fastly/service_authorization.go @@ -25,10 +25,13 @@ type ServiceAuthorization struct { Service *SAService `jsonapi:"relation,service,omitempty"` } +// GetServiceAuthorizationInput is used as input to the GetServiceAuthorization function. type GetServiceAuthorizationInput struct { + // ID of the service authorization to retrieve. ID string } +// GetServiceAuthorization retrieves an existing service authorization using its ID. func (c *Client) GetServiceAuthorization(i *GetServiceAuthorizationInput) (*ServiceAuthorization, error) { if i.ID == "" { return nil, ErrMissingID @@ -48,6 +51,7 @@ func (c *Client) GetServiceAuthorization(i *GetServiceAuthorizationInput) (*Serv return &sa, nil } +// CreateServiceAuthorizationInput is used as input to the CreateServiceAuthorization function. type CreateServiceAuthorizationInput struct { // ID value is ignored and should not be set, needed to make JSONAPI work correctly. ID string `jsonapi:"primary,service_authorization"` @@ -62,6 +66,7 @@ type CreateServiceAuthorizationInput struct { User *SAUser `jsonapi:"relation,user,omitempty"` } +// CreateServiceAuthorization creates a new service authorization granting granular service and user permissions. func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) (*ServiceAuthorization, error) { if i.Service == nil || i.Service.ID == "" { return nil, ErrMissingServiceID @@ -83,11 +88,16 @@ func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) return &sa, nil } +// UpdateServiceAuthorizationInput is used as input to the UpdateServiceAuthorization function. type UpdateServiceAuthorizationInput struct { - ID string `jsonapi:"primary,service_authorization"` + // ID uniquely identifies the service authorization (service and user pair) to be updated. + ID string `jsonapi:"primary,service_authorization"` + + // The permission to grant the user to the service referenced by this service authorization. Permissions string `jsonapi:"attr,permission,omitempty"` } +// UpdateServiceAuthorization updates an exisitng service authorization. The ID must be known. func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) (*ServiceAuthorization, error) { if i.ID == "" { return nil, ErrMissingID @@ -111,10 +121,13 @@ func (c *Client) UpdateServiceAuthorization(i *UpdateServiceAuthorizationInput) return &sa, nil } +// DeleteServiceAuthorizationInput is used as input to the DeleteServiceAuthorization function. type DeleteServiceAuthorizationInput struct { + // ID of the service authorization to delete. ID string } +// DeleteServiceAuthorization deletes an existing service authorization using the ID. func (c *Client) DeleteServiceAuthorization(i *DeleteServiceAuthorizationInput) error { if i.ID == "" { return ErrMissingID From a386cf6a6146194fa3143c17dd3516c485c9bb13 Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Mon, 20 Jun 2022 11:08:09 +0200 Subject: [PATCH 6/9] service_authorization: Remove default user id Only the serviceid needs to be default and normalized. --- fastly/fastly_test.go | 16 ---------------- .../fixtures/service_authorizations/cleanup.yaml | 14 +++++++------- .../fixtures/service_authorizations/create.yaml | 14 +++++++------- .../fixtures/service_authorizations/delete.yaml | 12 ++++++------ fastly/fixtures/service_authorizations/get.yaml | 10 +++++----- .../fixtures/service_authorizations/update.yaml | 16 ++++++++-------- fastly/service_authorization_test.go | 4 ++-- scripts/fixFixtures.sh | 11 ----------- 8 files changed, 35 insertions(+), 62 deletions(-) diff --git a/fastly/fastly_test.go b/fastly/fastly_test.go index 1878eea2a..9634922a0 100644 --- a/fastly/fastly_test.go +++ b/fastly/fastly_test.go @@ -19,15 +19,9 @@ var testStatsClient = NewRealtimeStatsClient() // testServiceID is the ID of the testing service. var testServiceID = serviceIDForTest() -// testUserID is the ID of the testing user. -var testUserID = userIDForTest() - // Default ID of the testing service. var defaultTestServiceID = "7i6HN3TK9wS159v2gPAZ8A" -// Default ID of the testing user. -var defaultTestUserID = "4tKBSuFhNEiIpNDxmmVydt" - const ( // ServiceTypeVCL is the type for VCL services. ServiceTypeVCL = "vcl" @@ -49,16 +43,6 @@ func serviceIDForTest() string { return defaultTestServiceID } -func userIDForTest() string { - uid := os.Getenv("FASTLY_TEST_USER_ID") - - if uid != "" { - return uid - } - - return defaultTestUserID -} - func vcrDisabled() bool { vcrDisable := os.Getenv("VCR_DISABLE") diff --git a/fastly/fixtures/service_authorizations/cleanup.yaml b/fastly/fixtures/service_authorizations/cleanup.yaml index d90a57911..7a2fcffcd 100644 --- a/fastly/fixtures/service_authorizations/cleanup.yaml +++ b/fastly/fixtures/service_authorizations/cleanup.yaml @@ -7,10 +7,10 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff + url: https://api.fastly.com/service-authorizations/3LA2qxhWzpRitVKTq9SsEU method: DELETE response: - body: '{"msg":"Record not found","detail":"Cannot find serviceauthorization ''dTYPkfosjJ6dMSBZNAPff''"}' + body: '{"msg":"Record not found","detail":"Cannot find serviceauthorization ''3LA2qxhWzpRitVKTq9SsEU''"}' headers: Accept-Ranges: - bytes @@ -19,11 +19,11 @@ interactions: Content-Type: - application/json Date: - - Thu, 16 Jun 2022 14:54:33 GMT + - Mon, 20 Jun 2022 09:05:33 GMT Fastly-Ratelimit-Remaining: - - "956" + - "966" Fastly-Ratelimit-Reset: - - "1655391600" + - "1655719200" Status: - 404 Not Found Strict-Transport-Security: @@ -37,9 +37,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1646-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1641-BMA X-Timer: - - S1655391273.306991,VS0,VE433 + - S1655715933.446686,VS0,VE438 status: 404 Not Found code: 404 duration: "" diff --git a/fastly/fixtures/service_authorizations/create.yaml b/fastly/fixtures/service_authorizations/create.yaml index 9dd8b186d..b4838c938 100644 --- a/fastly/fixtures/service_authorizations/create.yaml +++ b/fastly/fixtures/service_authorizations/create.yaml @@ -3,7 +3,7 @@ version: 1 interactions: - request: body: | - {"data":{"type":"service_authorization","attributes":{"permission":"full"},"relationships":{"service":{"data":{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"}},"user":{"data":{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"}}}},"included":[{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"},{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"}]} + {"data":{"type":"service_authorization","attributes":{"permission":"full"},"relationships":{"service":{"data":{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"}},"user":{"data":{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"}}}},"included":[{"type":"service","id":"7i6HN3TK9wS159v2gPAZ8A"},{"type":"user","id":"4tKBSuFhNEiIpNDxmmVydt"}]} form: {} headers: Accept: @@ -15,7 +15,7 @@ interactions: url: https://api.fastly.com/service-authorizations method: POST response: - body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"3LA2qxhWzpRitVKTq9SsEU","type":"service_authorization","attributes":{"created_at":"2022-06-20T09:05:32Z","updated_at":"2022-06-20T09:05:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -24,11 +24,11 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Thu, 16 Jun 2022 14:54:32 GMT + - Mon, 20 Jun 2022 09:05:32 GMT Fastly-Ratelimit-Remaining: - - "959" + - "969" Fastly-Ratelimit-Reset: - - "1655391600" + - "1655719200" Status: - 200 OK Strict-Transport-Security: @@ -42,9 +42,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA + - cache-control-slwdc9037-CONTROL-SLWDC, cache-bma1641-BMA X-Timer: - - S1655391272.193824,VS0,VE172 + - S1655715932.138355,VS0,VE362 status: 200 OK code: 200 duration: "" diff --git a/fastly/fixtures/service_authorizations/delete.yaml b/fastly/fixtures/service_authorizations/delete.yaml index ca868650b..f9dd60cfb 100644 --- a/fastly/fixtures/service_authorizations/delete.yaml +++ b/fastly/fixtures/service_authorizations/delete.yaml @@ -7,7 +7,7 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff + url: https://api.fastly.com/service-authorizations/3LA2qxhWzpRitVKTq9SsEU method: DELETE response: body: "" @@ -17,11 +17,11 @@ interactions: Cache-Control: - no-store Date: - - Thu, 16 Jun 2022 14:54:33 GMT + - Mon, 20 Jun 2022 09:05:33 GMT Fastly-Ratelimit-Remaining: - - "957" + - "967" Fastly-Ratelimit-Reset: - - "1655391600" + - "1655719200" Status: - 204 No Content Strict-Transport-Security: @@ -33,9 +33,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA + - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1641-BMA X-Timer: - - S1655391273.032612,VS0,VE260 + - S1655715933.228193,VS0,VE203 status: 204 No Content code: 204 duration: "" diff --git a/fastly/fixtures/service_authorizations/get.yaml b/fastly/fixtures/service_authorizations/get.yaml index 1723ef51a..e45efd9c0 100644 --- a/fastly/fixtures/service_authorizations/get.yaml +++ b/fastly/fixtures/service_authorizations/get.yaml @@ -7,10 +7,10 @@ interactions: headers: User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff + url: https://api.fastly.com/service-authorizations/3LA2qxhWzpRitVKTq9SsEU method: GET response: - body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"3LA2qxhWzpRitVKTq9SsEU","type":"service_authorization","attributes":{"created_at":"2022-06-20T09:05:32Z","updated_at":"2022-06-20T09:05:32Z","deleted_at":null,"permission":"full"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -19,7 +19,7 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Thu, 16 Jun 2022 14:54:32 GMT + - Mon, 20 Jun 2022 09:05:32 GMT Status: - 200 OK Strict-Transport-Security: @@ -33,9 +33,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA + - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1641-BMA X-Timer: - - S1655391272.387855,VS0,VE432 + - S1655715933.614930,VS0,VE139 status: 200 OK code: 200 duration: "" diff --git a/fastly/fixtures/service_authorizations/update.yaml b/fastly/fixtures/service_authorizations/update.yaml index a63f9cd3e..72896287d 100644 --- a/fastly/fixtures/service_authorizations/update.yaml +++ b/fastly/fixtures/service_authorizations/update.yaml @@ -3,7 +3,7 @@ version: 1 interactions: - request: body: | - {"data":{"type":"service_authorization","id":"dTYPkfosjJ6dMSBZNAPff","attributes":{"permission":"purge_select"}}} + {"data":{"type":"service_authorization","id":"3LA2qxhWzpRitVKTq9SsEU","attributes":{"permission":"purge_select"}}} form: {} headers: Accept: @@ -12,10 +12,10 @@ interactions: - application/vnd.api+json User-Agent: - FastlyGo/6.3.2 (+github.com/fastly/go-fastly; go1.18) - url: https://api.fastly.com/service-authorizations/dTYPkfosjJ6dMSBZNAPff + url: https://api.fastly.com/service-authorizations/3LA2qxhWzpRitVKTq9SsEU method: PATCH response: - body: '{"data":{"id":"dTYPkfosjJ6dMSBZNAPff","type":"service_authorization","attributes":{"created_at":"2022-06-16T14:54:32Z","updated_at":"2022-06-16T14:54:32Z","deleted_at":null,"permission":"purge_select"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' + body: '{"data":{"id":"3LA2qxhWzpRitVKTq9SsEU","type":"service_authorization","attributes":{"created_at":"2022-06-20T09:05:32Z","updated_at":"2022-06-20T09:05:33Z","deleted_at":null,"permission":"purge_select"},"relationships":{"service":{"data":{"id":"7i6HN3TK9wS159v2gPAZ8A","type":"service"}},"user":{"data":{"id":"4tKBSuFhNEiIpNDxmmVydt","type":"user"}}}}}' headers: Accept-Ranges: - bytes @@ -24,11 +24,11 @@ interactions: Content-Type: - application/vnd.api+json Date: - - Thu, 16 Jun 2022 14:54:33 GMT + - Mon, 20 Jun 2022 09:05:33 GMT Fastly-Ratelimit-Remaining: - - "958" + - "968" Fastly-Ratelimit-Reset: - - "1655391600" + - "1655719200" Status: - 200 OK Strict-Transport-Security: @@ -42,9 +42,9 @@ interactions: X-Cache-Hits: - 0, 0 X-Served-By: - - cache-control-slwdc9036-CONTROL-SLWDC, cache-bma1646-BMA + - cache-control-slwdc9035-CONTROL-SLWDC, cache-bma1641-BMA X-Timer: - - S1655391273.836430,VS0,VE181 + - S1655715933.770167,VS0,VE391 status: 200 OK code: 200 duration: "" diff --git a/fastly/service_authorization_test.go b/fastly/service_authorization_test.go index 18f0140e7..90365dce8 100644 --- a/fastly/service_authorization_test.go +++ b/fastly/service_authorization_test.go @@ -15,7 +15,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { record(t, fixtureBase+"create", func(c *Client) { sa, err = c.CreateServiceAuthorization(&CreateServiceAuthorizationInput{ Service: &SAService{ID: testServiceID}, - User: &SAUser{ID: testUserID}, + User: &SAUser{ID: "4tKBSuFhNEiIpNDxmmVydt"}, Permission: "full", }) }) @@ -37,7 +37,7 @@ func TestClient_ServiceAuthorizations(t *testing.T) { t.Errorf("bad service id: %v", sa.Service.ID) } - if sa.User.ID != testUserID { + if sa.User.ID != "4tKBSuFhNEiIpNDxmmVydt" { t.Errorf("bad user id: %v", sa.User.ID) } diff --git a/scripts/fixFixtures.sh b/scripts/fixFixtures.sh index f14e2379f..90c06e708 100755 --- a/scripts/fixFixtures.sh +++ b/scripts/fixFixtures.sh @@ -3,7 +3,6 @@ set -e FASTLY_TEST_SERVICE_ID=$1 DEFAULT_TEST_SERVICE_ID="7i6HN3TK9wS159v2gPAZ8A" -DEFAULT_TEST_USER_ID="4tKBSuFhNEiIpNDxmmVydt" FIXTURESDIR="$(pwd)/fastly/fixtures/" if [[ -z ${FASTLY_TEST_SERVICE_ID} && -z $1 ]]; then @@ -11,17 +10,7 @@ if [[ -z ${FASTLY_TEST_SERVICE_ID} && -z $1 ]]; then exit fi -if [[ -z ${FASTLY_TEST_USER_ID} && -z $2 ]]; then - echo "You must supply a user ID as the second argument" - exit -fi - for file in $(grep --recursive --files-with-matches "${FASTLY_TEST_SERVICE_ID}" "${FIXTURESDIR}") do sed -i.bak "s/${FASTLY_TEST_SERVICE_ID}/${DEFAULT_TEST_SERVICE_ID}/g" "$file" && rm "${file}.bak" done - -for file in $(grep --recursive --files-with-matches "${FASTLY_TEST_USER_ID}" "${FIXTURESDIR}") -do - sed -i.bak "s/${FASTLY_TEST_USER_ID}/${DEFAULT_TEST_USER_ID}/g" "$file" && rm "${file}.bak" -done From 3b516a2ffb43de2bbc38bb7354c857813ecfd783 Mon Sep 17 00:00:00 2001 From: Alexander Pochill Date: Mon, 20 Jun 2022 11:11:47 +0200 Subject: [PATCH 7/9] service_authorization: Use dedicated errors Instead of re-using amibuous error messages, create and use a dedicated error when CreateServiceAuthorization is used incorrectly. --- fastly/errors.go | 8 ++++++++ fastly/service_authorization.go | 4 ++-- fastly/service_authorization_test.go | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fastly/errors.go b/fastly/errors.go index 84c48044a..46c4efefe 100644 --- a/fastly/errors.go +++ b/fastly/errors.go @@ -171,6 +171,14 @@ var ErrMissingServerSideEncryptionKMSKeyID = NewFieldError("ServerSideEncryption // requires a "ServiceID" key, but one was not set. var ErrMissingServiceID = NewFieldError("ServiceID") +// ErrMissingServiceAuthorizationsService is an error that is returned when an input struct +// requires a "ServiceAuthorizationService" key, but one was not set. +var ErrMissingServiceAuthorizationsService = NewFieldError("Service").Message("SAService requires an ID") + +// ErrMissingServiceAuthorizationsUser is an error that is returned when an input struct +// requires a "ServiceAuthorizationUser" key, but one was not set. +var ErrMissingServiceAuthorizationsUser = NewFieldError("User").Message("SAUser requires an ID") + // ErrMissingUserID is an error that is returned when an input struct // requires a "UserID" key, but one was not set var ErrMissingUserID = NewFieldError("UserID") diff --git a/fastly/service_authorization.go b/fastly/service_authorization.go index 823a27bf1..38880526f 100644 --- a/fastly/service_authorization.go +++ b/fastly/service_authorization.go @@ -69,10 +69,10 @@ type CreateServiceAuthorizationInput struct { // CreateServiceAuthorization creates a new service authorization granting granular service and user permissions. func (c *Client) CreateServiceAuthorization(i *CreateServiceAuthorizationInput) (*ServiceAuthorization, error) { if i.Service == nil || i.Service.ID == "" { - return nil, ErrMissingServiceID + return nil, ErrMissingServiceAuthorizationsService } if i.User == nil || i.User.ID == "" { - return nil, ErrMissingUserID + return nil, ErrMissingServiceAuthorizationsUser } resp, err := c.PostJSONAPI("/service-authorizations", i, nil) diff --git a/fastly/service_authorization_test.go b/fastly/service_authorization_test.go index 90365dce8..9e0a2905d 100644 --- a/fastly/service_authorization_test.go +++ b/fastly/service_authorization_test.go @@ -106,7 +106,7 @@ func TestClient_CreateServiceAuthorization_validation(t *testing.T) { Service: &SAService{ID: ""}, User: &SAUser{ID: ""}, }) - if err != ErrMissingServiceID { + if err != ErrMissingServiceAuthorizationsService { t.Errorf("bad error: %s", err) } @@ -114,7 +114,7 @@ func TestClient_CreateServiceAuthorization_validation(t *testing.T) { Service: &SAService{ID: "my-service-id"}, User: &SAUser{ID: ""}, }) - if err != ErrMissingUserID { + if err != ErrMissingServiceAuthorizationsUser { t.Errorf("bad error: %s", err) } } From 0d6d16b52504b7df4525fcfb49362cce77e490bb Mon Sep 17 00:00:00 2001 From: Mark McDonnell Date: Mon, 20 Jun 2022 13:19:09 +0100 Subject: [PATCH 8/9] Update fastly/errors.go --- fastly/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/errors.go b/fastly/errors.go index 46c4efefe..fe052976e 100644 --- a/fastly/errors.go +++ b/fastly/errors.go @@ -172,7 +172,7 @@ var ErrMissingServerSideEncryptionKMSKeyID = NewFieldError("ServerSideEncryption var ErrMissingServiceID = NewFieldError("ServiceID") // ErrMissingServiceAuthorizationsService is an error that is returned when an input struct -// requires a "ServiceAuthorizationService" key, but one was not set. +// requires a "Service" key of type SAService, but one was not set or was misconfigured. var ErrMissingServiceAuthorizationsService = NewFieldError("Service").Message("SAService requires an ID") // ErrMissingServiceAuthorizationsUser is an error that is returned when an input struct From 83f8dfe8fa2274a561d3dc680d646891f82d995c Mon Sep 17 00:00:00 2001 From: Mark McDonnell Date: Mon, 20 Jun 2022 13:19:16 +0100 Subject: [PATCH 9/9] Update fastly/errors.go --- fastly/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/errors.go b/fastly/errors.go index fe052976e..3b2849c88 100644 --- a/fastly/errors.go +++ b/fastly/errors.go @@ -176,7 +176,7 @@ var ErrMissingServiceID = NewFieldError("ServiceID") var ErrMissingServiceAuthorizationsService = NewFieldError("Service").Message("SAService requires an ID") // ErrMissingServiceAuthorizationsUser is an error that is returned when an input struct -// requires a "ServiceAuthorizationUser" key, but one was not set. +// requires a "User" key of type SAUser, but one was not set or was misconfigured. var ErrMissingServiceAuthorizationsUser = NewFieldError("User").Message("SAUser requires an ID") // ErrMissingUserID is an error that is returned when an input struct