From 4d7605a86bd141ef85d1813949444dcdf9eb47c9 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Thu, 23 May 2019 12:59:11 +0200 Subject: [PATCH] gateway: improve ErrFromRemote handling Don't create an ErrFromRemote wrapping the returned error but wrap the ErrFromRemote Also use xerrors Is/As to get the underlying error to return to api clients while maintaining context for logging --- internal/services/configstore/api/api.go | 36 ++++++++++++--- internal/services/gateway/action/auth.go | 10 ++--- internal/services/gateway/action/org.go | 8 ++-- internal/services/gateway/action/project.go | 30 ++++++------- .../services/gateway/action/projectgroup.go | 12 ++--- .../services/gateway/action/remotesource.go | 6 +-- internal/services/gateway/action/secret.go | 4 +- internal/services/gateway/action/user.go | 44 +++++++++---------- internal/services/gateway/action/variable.go | 10 ++--- internal/services/gateway/api/api.go | 38 +++++++++++----- internal/services/runservice/api/api.go | 36 ++++++++++++--- internal/util/errors.go | 8 ++-- 12 files changed, 152 insertions(+), 90 deletions(-) diff --git a/internal/services/configstore/api/api.go b/internal/services/configstore/api/api.go index 78a3646..e8ff513 100644 --- a/internal/services/configstore/api/api.go +++ b/internal/services/configstore/api/api.go @@ -30,11 +30,29 @@ type ErrorResponse struct { } func ErrorResponseFromError(err error) *ErrorResponse { + var aerr error + // use inner errors if of these types switch { - case util.IsErrBadRequest(err): - fallthrough - case util.IsErrNotFound(err): - return &ErrorResponse{Message: err.Error()} + case errors.Is(err, &util.ErrBadRequest{}): + var cerr *util.ErrBadRequest + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrNotFound{}): + var cerr *util.ErrNotFound + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrForbidden{}): + var cerr *util.ErrForbidden + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrUnauthorized{}): + var cerr *util.ErrUnauthorized + errors.As(err, &cerr) + aerr = cerr + } + + if aerr != nil { + return &ErrorResponse{Message: aerr.Error()} } // on generic error return an generic message to not leak the real error @@ -53,12 +71,18 @@ func httpError(w http.ResponseWriter, err error) bool { return true } switch { - case util.IsErrBadRequest(err): + case errors.Is(err, &util.ErrBadRequest{}): w.WriteHeader(http.StatusBadRequest) w.Write(resj) - case util.IsErrNotFound(err): + case errors.Is(err, &util.ErrNotFound{}): w.WriteHeader(http.StatusNotFound) w.Write(resj) + case errors.Is(err, &util.ErrForbidden{}): + w.WriteHeader(http.StatusForbidden) + w.Write(resj) + case errors.Is(err, &util.ErrUnauthorized{}): + w.WriteHeader(http.StatusUnauthorized) + w.Write(resj) default: w.WriteHeader(http.StatusInternalServerError) w.Write(resj) diff --git a/internal/services/gateway/action/auth.go b/internal/services/gateway/action/auth.go index dcb4b73..39f38cb 100644 --- a/internal/services/gateway/action/auth.go +++ b/internal/services/gateway/action/auth.go @@ -61,7 +61,7 @@ func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, err userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, ErrFromRemote(resp, errors.Errorf("failed to get user orgs: %w", err)) + return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) } for _, userOrg := range userOrgs { @@ -96,7 +96,7 @@ func (h *ActionHandler) IsProjectOwner(ctx context.Context, ownerType types.Conf if ownerType == types.ConfigTypeOrg { userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, ErrFromRemote(resp, errors.Errorf("failed to get user orgs: %w", err)) + return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) } for _, userOrg := range userOrgs { @@ -132,7 +132,7 @@ func (h *ActionHandler) IsProjectMember(ctx context.Context, ownerType types.Con if ownerType == types.ConfigTypeOrg { userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, ErrFromRemote(resp, errors.Errorf("failed to get user orgs: %w", err)) + return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) } for _, userOrg := range userOrgs { @@ -153,14 +153,14 @@ func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType types.Co case types.ConfigTypeProjectGroup: pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return false, ErrFromRemote(resp, errors.Errorf("failed to get project group %q: %w", parentRef, err)) + return false, errors.Errorf("failed to get project group %q: %w", parentRef, ErrFromRemote(resp, err)) } ownerType = pg.OwnerType ownerID = pg.OwnerID case types.ConfigTypeProject: p, resp, err := h.configstoreClient.GetProject(ctx, parentRef) if err != nil { - return false, ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", parentRef, err)) + return false, errors.Errorf("failed to get project %q: %w", parentRef, ErrFromRemote(resp, err)) } ownerType = p.OwnerType ownerID = p.OwnerID diff --git a/internal/services/gateway/action/org.go b/internal/services/gateway/action/org.go index ae95ca2..0e4d095 100644 --- a/internal/services/gateway/action/org.go +++ b/internal/services/gateway/action/org.go @@ -109,7 +109,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* h.log.Infof("creating organization") org, resp, err := h.configstoreClient.CreateOrg(ctx, org) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create organization: %w", err)) + return nil, errors.Errorf("failed to create organization: %w", ErrFromRemote(resp, err)) } h.log.Infof("organization %s created, ID: %s", org.Name, org.ID) @@ -132,7 +132,7 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { resp, err = h.configstoreClient.DeleteOrg(ctx, orgRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete org: %w", err)) + return errors.Errorf("failed to delete org: %w", ErrFromRemote(resp, err)) } return nil } @@ -163,7 +163,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string orgmember, resp, err := h.configstoreClient.AddOrgMember(ctx, orgRef, userRef, role) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to add/update organization member: %w", err)) + return nil, errors.Errorf("failed to add/update organization member: %w", ErrFromRemote(resp, err)) } return &AddOrgMemberResponse{ @@ -189,7 +189,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str resp, err = h.configstoreClient.RemoveOrgMember(ctx, orgRef, userRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to remove organization member: %w", err)) + return errors.Errorf("failed to remove organization member: %w", ErrFromRemote(resp, err)) } return nil diff --git a/internal/services/gateway/action/project.go b/internal/services/gateway/action/project.go index 5ca3c4a..5143e83 100644 --- a/internal/services/gateway/action/project.go +++ b/internal/services/gateway/action/project.go @@ -62,7 +62,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", curUserID, err)) + return nil, errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) } parentRef := req.ParentRef if parentRef == "" { @@ -72,7 +72,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project group %q: %w", parentRef, err)) + return nil, errors.Errorf("failed to get project group %q: %w", parentRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -97,7 +97,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq _, resp, err = h.configstoreClient.GetProject(ctx, projectPath) if err != nil { if resp != nil && resp.StatusCode != http.StatusNotFound { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", req.Name, err)) + return nil, errors.Errorf("failed to get project %q: %w", req.Name, ErrFromRemote(resp, err)) } } else { return nil, util.NewErrBadRequest(errors.Errorf("project %q already exists", projectPath)) @@ -105,7 +105,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) var la *types.LinkedAccount @@ -155,7 +155,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq h.log.Infof("creating project") rp, resp, err := h.configstoreClient.CreateProject(ctx, p) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create project: %w", err)) + return nil, errors.Errorf("failed to create project: %w", ErrFromRemote(resp, err)) } h.log.Infof("project %s created, ID: %s", p.Name, p.ID) @@ -170,7 +170,7 @@ type UpdateProjectRequest struct { func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, req *UpdateProjectRequest) (*csapi.Project, error) { p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", projectRef, err)) + return nil, errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -187,7 +187,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, re h.log.Infof("updating project") rp, resp, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to update project: %w", err)) + return nil, errors.Errorf("failed to update project: %w", ErrFromRemote(resp, err)) } h.log.Infof("project %s updated, ID: %s", p.Name, p.ID) @@ -199,12 +199,12 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", curUserID, err)) + return nil, errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) } p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", projectRef, err)) + return nil, errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -217,7 +217,7 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) var la *types.LinkedAccount @@ -248,7 +248,7 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj h.log.Infof("updating project") rp, resp, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to update project: %w", err)) + return nil, errors.Errorf("failed to update project: %w", ErrFromRemote(resp, err)) } h.log.Infof("project %s updated, ID: %s", p.Name, p.ID) @@ -298,7 +298,7 @@ func (h *ActionHandler) SetupProject(ctx context.Context, rs *types.RemoteSource func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) error { p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", projectRef, err)) + return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -311,7 +311,7 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) user, resp, err := h.configstoreClient.GetUserByLinkedAccount(ctx, p.LinkedAccountID) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get user with linked account id %q: %w", p.LinkedAccountID, err)) + return errors.Errorf("failed to get user with linked account id %q: %w", p.LinkedAccountID, ErrFromRemote(resp, err)) } la := user.LinkedAccounts[p.LinkedAccountID] @@ -322,7 +322,7 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) + return errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, ErrFromRemote(resp, err)) } // TODO(sgotti) update project repo path if the remote let us query by repository id @@ -333,7 +333,7 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error { p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", projectRef, err)) + return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) diff --git a/internal/services/gateway/action/projectgroup.go b/internal/services/gateway/action/projectgroup.go index 013dbaf..4b14524 100644 --- a/internal/services/gateway/action/projectgroup.go +++ b/internal/services/gateway/action/projectgroup.go @@ -63,7 +63,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project group %q: %w", req.ParentRef, err)) + return nil, errors.Errorf("failed to get project group %q: %w", req.ParentRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -76,7 +76,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", req.CurrentUserID, err)) + return nil, errors.Errorf("failed to get user %q: %w", req.CurrentUserID, ErrFromRemote(resp, err)) } parentRef := req.ParentRef @@ -97,7 +97,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje h.log.Infof("creating projectGroup") rp, resp, err := h.configstoreClient.CreateProjectGroup(ctx, p) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create projectGroup: %w", err)) + return nil, errors.Errorf("failed to create projectGroup: %w", ErrFromRemote(resp, err)) } h.log.Infof("projectGroup %s created, ID: %s", rp.Name, rp.ID) @@ -112,7 +112,7 @@ type UpdateProjectGroupRequest struct { func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef string, req *UpdateProjectGroupRequest) (*csapi.ProjectGroup, error) { pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get project group %q: %w", projectGroupRef, err)) + return nil, errors.Errorf("failed to get project group %q: %w", projectGroupRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -129,7 +129,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef h.log.Infof("updating project group") rp, resp, err := h.configstoreClient.UpdateProjectGroup(ctx, pg.ID, pg.ProjectGroup) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to update project group: %w", err)) + return nil, errors.Errorf("failed to update project group: %w", ErrFromRemote(resp, err)) } h.log.Infof("project group %q updated, ID: %s", pg.Name, pg.ID) @@ -139,7 +139,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectRef string) error { p, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get project %q: %w", projectRef, err)) + return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) diff --git a/internal/services/gateway/action/remotesource.go b/internal/services/gateway/action/remotesource.go index 9226cfd..5c363c6 100644 --- a/internal/services/gateway/action/remotesource.go +++ b/internal/services/gateway/action/remotesource.go @@ -108,7 +108,7 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemot h.log.Infof("creating remotesource") rs, resp, err := h.configstoreClient.CreateRemoteSource(ctx, rs) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create remotesource: %w", err)) + return nil, errors.Errorf("failed to create remotesource: %w", ErrFromRemote(resp, err)) } h.log.Infof("remotesource %s created, ID: %s", rs.Name, rs.ID) @@ -162,7 +162,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot h.log.Infof("updating remotesource") rs, resp, err = h.configstoreClient.UpdateRemoteSource(ctx, req.RemoteSourceRef, rs) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to update remotesource: %w", err)) + return nil, errors.Errorf("failed to update remotesource: %w", ErrFromRemote(resp, err)) } h.log.Infof("remotesource %s updated", rs.Name) @@ -176,7 +176,7 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, rsRef string) er resp, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete remote source: %w", err)) + return errors.Errorf("failed to delete remote source: %w", ErrFromRemote(resp, err)) } return nil } diff --git a/internal/services/gateway/action/secret.go b/internal/services/gateway/action/secret.go index 403ad87..2d50eb5 100644 --- a/internal/services/gateway/action/secret.go +++ b/internal/services/gateway/action/secret.go @@ -101,7 +101,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque rs, resp, err = h.configstoreClient.CreateProjectSecret(ctx, req.ParentRef, s) } if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create secret: %w", err)) + return nil, errors.Errorf("failed to create secret: %w", ErrFromRemote(resp, err)) } h.log.Infof("secret %s created, ID: %s", rs.Name, rs.ID) @@ -127,7 +127,7 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi resp, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, name) } if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete secret: %w", err)) + return errors.Errorf("failed to delete secret: %w", ErrFromRemote(resp, err)) } return nil } diff --git a/internal/services/gateway/action/user.go b/internal/services/gateway/action/user.go index 96ab8a7..95fedcf 100644 --- a/internal/services/gateway/action/user.go +++ b/internal/services/gateway/action/user.go @@ -93,7 +93,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) h.log.Infof("creating user") u, resp, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create user: %w", err)) + return nil, errors.Errorf("failed to create user: %w", ErrFromRemote(resp, err)) } h.log.Infof("user %s created, ID: %s", u.Name, u.ID) @@ -121,7 +121,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, req *CreateUserToke userRef := req.UserRef user, resp, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return "", ErrFromRemote(resp, errors.Errorf("failed to get user: %w", err)) + return "", errors.Errorf("failed to get user: %w", ErrFromRemote(resp, err)) } // only admin or the same logged user can create a token @@ -138,7 +138,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, req *CreateUserToke } res, resp, err := h.configstoreClient.CreateUserToken(ctx, userRef, creq) if err != nil { - return "", ErrFromRemote(resp, errors.Errorf("failed to create user token: %w", err)) + return "", errors.Errorf("failed to create user token: %w", ErrFromRemote(resp, err)) } h.log.Infof("token %q for user %q created", req.TokenName, userRef) @@ -159,11 +159,11 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque userRef := req.UserRef user, resp, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", userRef, err)) + return nil, errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) } rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) var la *types.LinkedAccount @@ -208,7 +208,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque h.log.Infof("creating linked account") la, resp, err = h.configstoreClient.CreateUserLA(ctx, userRef, creq) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create linked account: %w", err)) + return nil, errors.Errorf("failed to create linked account: %w", ErrFromRemote(resp, err)) } h.log.Infof("linked account %q for user %q created", la.ID, userRef) @@ -218,7 +218,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *types.LinkedAccount) error { user, resp, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", userRef, err)) + return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) } laFound := false for _, ula := range user.LinkedAccounts { @@ -244,7 +244,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *ty h.log.Infof("updating user %q linked account", userRef) la, resp, err = h.configstoreClient.UpdateUserLA(ctx, userRef, la.ID, creq) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to update user: %w", err)) + return errors.Errorf("failed to update user: %w", ErrFromRemote(resp, err)) } h.log.Infof("linked account %q for user %q updated", la.ID, userRef) @@ -309,7 +309,7 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) @@ -346,7 +346,7 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque h.log.Infof("creating user account") u, resp, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to create linked account: %w", err)) + return nil, errors.Errorf("failed to create linked account: %w", ErrFromRemote(resp, err)) } h.log.Infof("user %q created", req.UserName) @@ -369,7 +369,7 @@ type LoginUserResponse struct { func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (*LoginUserResponse, error) { rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) @@ -392,7 +392,7 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* user, resp, err := h.configstoreClient.GetUserByLinkedAccountRemoteUserAndSource(ctx, remoteUserInfo.ID, rs.ID) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", remoteUserInfo.ID, rs.ID, err)) + return nil, errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", remoteUserInfo.ID, rs.ID, ErrFromRemote(resp, err)) } var la *types.LinkedAccount @@ -428,7 +428,7 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* h.log.Infof("updating user %q linked account", user.Name) la, resp, err = h.configstoreClient.UpdateUserLA(ctx, user.Name, la.ID, creq) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to update user: %w", err)) + return nil, errors.Errorf("failed to update user: %w", ErrFromRemote(resp, err)) } h.log.Infof("linked account %q for user %q updated", la.ID, user.Name) } @@ -460,7 +460,7 @@ type AuthorizeResponse struct { func (h *ActionHandler) Authorize(ctx context.Context, req *AuthorizeRequest) (*AuthorizeResponse, error) { rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) @@ -495,7 +495,7 @@ type RemoteSourceAuthResponse struct { func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSourceName, loginName, loginPassword string, requestType RemoteSourceRequestType, req interface{}) (*RemoteSourceAuthResponse, error) { rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) @@ -505,7 +505,7 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource user, resp, err := h.configstoreClient.GetUser(ctx, req.UserRef) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", req.UserRef, err)) + return nil, errors.Errorf("failed to get user %q: %w", req.UserRef, ErrFromRemote(resp, err)) } curUserID := h.CurrentUserID(ctx) @@ -736,7 +736,7 @@ func (h *ActionHandler) HandleOauth2Callback(ctx context.Context, code, state st rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, ErrFromRemote(resp, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) + return nil, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, ErrFromRemote(resp, err)) } h.log.Infof("rs: %s", util.Dump(rs)) @@ -760,7 +760,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { resp, err := h.configstoreClient.DeleteUser(ctx, userRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete user: %w", err)) + return errors.Errorf("failed to delete user: %w", ErrFromRemote(resp, err)) } return nil } @@ -775,7 +775,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) user, resp, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", userRef, err)) + return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) } // only admin or the same logged user can create a token @@ -785,7 +785,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) resp, err = h.configstoreClient.DeleteUserLA(ctx, userRef, laID) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete user linked account: %w", err)) + return errors.Errorf("failed to delete user linked account: %w", ErrFromRemote(resp, err)) } return nil } @@ -800,7 +800,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName user, resp, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to get user %q: %w", userRef, err)) + return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) } // only admin or the same logged user can create a token @@ -810,7 +810,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName resp, err = h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName) if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete user token: %w", err)) + return errors.Errorf("failed to delete user token: %w", ErrFromRemote(resp, err)) } return nil } diff --git a/internal/services/gateway/action/variable.go b/internal/services/gateway/action/variable.go index 25eadcb..f1337c7 100644 --- a/internal/services/gateway/action/variable.go +++ b/internal/services/gateway/action/variable.go @@ -114,26 +114,26 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableR var resp *http.Response cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, ErrFromRemote(resp, errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, err)) + return nil, nil, errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) } h.log.Infof("creating project group variable") rv, resp, err = h.configstoreClient.CreateProjectGroupVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, ErrFromRemote(resp, errors.Errorf("failed to create variable: %w", err)) + return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) } case types.ConfigTypeProject: var err error var resp *http.Response cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, ErrFromRemote(resp, errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, err)) + return nil, nil, errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) } h.log.Infof("creating project variable") rv, resp, err = h.configstoreClient.CreateProjectVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, ErrFromRemote(resp, errors.Errorf("failed to create variable: %w", err)) + return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) } } h.log.Infof("variable %s created, ID: %s", rv.Name, rv.ID) @@ -160,7 +160,7 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con resp, err = h.configstoreClient.DeleteProjectVariable(ctx, parentRef, name) } if err != nil { - return ErrFromRemote(resp, errors.Errorf("failed to delete variable: %w", err)) + return errors.Errorf("failed to delete variable: %w", ErrFromRemote(resp, err)) } return nil } diff --git a/internal/services/gateway/api/api.go b/internal/services/gateway/api/api.go index f13d6a6..a0d88b9 100644 --- a/internal/services/gateway/api/api.go +++ b/internal/services/gateway/api/api.go @@ -31,15 +31,29 @@ type ErrorResponse struct { } func ErrorResponseFromError(err error) *ErrorResponse { + var aerr error + // use inner errors if of these types switch { - case util.IsErrBadRequest(err): - fallthrough - case util.IsErrNotFound(err): - fallthrough - case util.IsErrForbidden(err): - fallthrough - case util.IsErrUnauthorized(err): - return &ErrorResponse{Message: err.Error()} + case errors.Is(err, &util.ErrBadRequest{}): + var cerr *util.ErrBadRequest + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrNotFound{}): + var cerr *util.ErrNotFound + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrForbidden{}): + var cerr *util.ErrForbidden + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrUnauthorized{}): + var cerr *util.ErrUnauthorized + errors.As(err, &cerr) + aerr = cerr + } + + if aerr != nil { + return &ErrorResponse{Message: aerr.Error()} } // on generic error return an generic message to not leak the real error @@ -58,16 +72,16 @@ func httpError(w http.ResponseWriter, err error) bool { return true } switch { - case util.IsErrBadRequest(err): + case errors.Is(err, &util.ErrBadRequest{}): w.WriteHeader(http.StatusBadRequest) w.Write(resj) - case util.IsErrNotFound(err): + case errors.Is(err, &util.ErrNotFound{}): w.WriteHeader(http.StatusNotFound) w.Write(resj) - case util.IsErrForbidden(err): + case errors.Is(err, &util.ErrForbidden{}): w.WriteHeader(http.StatusForbidden) w.Write(resj) - case util.IsErrUnauthorized(err): + case errors.Is(err, &util.ErrUnauthorized{}): w.WriteHeader(http.StatusUnauthorized) w.Write(resj) default: diff --git a/internal/services/runservice/api/api.go b/internal/services/runservice/api/api.go index 737740b..d39af4d 100644 --- a/internal/services/runservice/api/api.go +++ b/internal/services/runservice/api/api.go @@ -47,11 +47,29 @@ type ErrorResponse struct { } func ErrorResponseFromError(err error) *ErrorResponse { + var aerr error + // use inner errors if of these types switch { - case util.IsErrBadRequest(err): - fallthrough - case util.IsErrNotFound(err): - return &ErrorResponse{Message: err.Error()} + case errors.Is(err, &util.ErrBadRequest{}): + var cerr *util.ErrBadRequest + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrNotFound{}): + var cerr *util.ErrNotFound + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrForbidden{}): + var cerr *util.ErrForbidden + errors.As(err, &cerr) + aerr = cerr + case errors.Is(err, &util.ErrUnauthorized{}): + var cerr *util.ErrUnauthorized + errors.As(err, &cerr) + aerr = cerr + } + + if aerr != nil { + return &ErrorResponse{Message: aerr.Error()} } // on generic error return an generic message to not leak the real error @@ -70,12 +88,18 @@ func httpError(w http.ResponseWriter, err error) bool { return true } switch { - case util.IsErrBadRequest(err): + case errors.Is(err, &util.ErrBadRequest{}): w.WriteHeader(http.StatusBadRequest) w.Write(resj) - case util.IsErrNotFound(err): + case errors.Is(err, &util.ErrNotFound{}): w.WriteHeader(http.StatusNotFound) w.Write(resj) + case errors.Is(err, &util.ErrForbidden{}): + w.WriteHeader(http.StatusForbidden) + w.Write(resj) + case errors.Is(err, &util.ErrUnauthorized{}): + w.WriteHeader(http.StatusUnauthorized) + w.Write(resj) default: w.WriteHeader(http.StatusInternalServerError) w.Write(resj) diff --git a/internal/util/errors.go b/internal/util/errors.go index 945e342..5cdf7bc 100644 --- a/internal/util/errors.go +++ b/internal/util/errors.go @@ -70,7 +70,7 @@ func NewErrBadRequest(err error) *ErrBadRequest { return &ErrBadRequest{Err: err} } -func IsErrBadRequest(err error) bool { +func (*ErrBadRequest) Is(err error) bool { _, ok := err.(*ErrBadRequest) return ok } @@ -89,7 +89,7 @@ func NewErrNotFound(err error) *ErrNotFound { return &ErrNotFound{Err: err} } -func IsErrNotFound(err error) bool { +func (*ErrNotFound) Is(err error) bool { _, ok := err.(*ErrNotFound) return ok } @@ -108,7 +108,7 @@ func NewErrForbidden(err error) *ErrForbidden { return &ErrForbidden{Err: err} } -func IsErrForbidden(err error) bool { +func (*ErrForbidden) Is(err error) bool { _, ok := err.(*ErrForbidden) return ok } @@ -127,7 +127,7 @@ func NewErrUnauthorized(err error) *ErrUnauthorized { return &ErrUnauthorized{Err: err} } -func IsErrUnauthorized(err error) bool { +func (*ErrUnauthorized) Is(err error) bool { _, ok := err.(*ErrUnauthorized) return ok }