gateway: initial authorization
This commit is contained in:
parent
081ac8a44f
commit
a04dd62e91
|
@ -0,0 +1,242 @@
|
||||||
|
// Copyright 2019 Sorint.lab
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package action
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sorintlab/agola/internal/services/gateway/common"
|
||||||
|
"github.com/sorintlab/agola/internal/services/types"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *ActionHandler) CurrentUserID(ctx context.Context) string {
|
||||||
|
userIDVal := ctx.Value("userid")
|
||||||
|
if userIDVal == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return userIDVal.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsUserLogged(ctx context.Context) bool {
|
||||||
|
return ctx.Value("userid") != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsUserAdmin(ctx context.Context) bool {
|
||||||
|
isAdmin := false
|
||||||
|
isAdminVal := ctx.Value("admin")
|
||||||
|
if isAdminVal != nil {
|
||||||
|
isAdmin = isAdminVal.(bool)
|
||||||
|
}
|
||||||
|
return isAdmin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsUserLoggedOrAdmin(ctx context.Context) bool {
|
||||||
|
return h.IsUserLogged(ctx) || h.IsUserAdmin(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, error) {
|
||||||
|
isAdmin := h.IsUserAdmin(ctx)
|
||||||
|
if isAdmin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := h.CurrentUserID(ctx)
|
||||||
|
if userID == "" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user orgs"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userOrg := range userOrgs {
|
||||||
|
if userOrg.Organization.ID != orgID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if userOrg.Role == types.MemberRoleOwner {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsProjectOwner(ctx context.Context, ownerType types.ConfigType, ownerID string) (bool, error) {
|
||||||
|
isAdmin := h.IsUserAdmin(ctx)
|
||||||
|
if isAdmin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := h.CurrentUserID(ctx)
|
||||||
|
if userID == "" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ownerType == types.ConfigTypeUser {
|
||||||
|
if userID == ownerID {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ownerType == types.ConfigTypeOrg {
|
||||||
|
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user orgs"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userOrg := range userOrgs {
|
||||||
|
if userOrg.Organization.ID != ownerID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if userOrg.Role == types.MemberRoleOwner {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsProjectMember(ctx context.Context, ownerType types.ConfigType, ownerID string) (bool, error) {
|
||||||
|
isAdmin := h.IsUserAdmin(ctx)
|
||||||
|
if isAdmin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := h.CurrentUserID(ctx)
|
||||||
|
if userID == "" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ownerType == types.ConfigTypeUser {
|
||||||
|
if userID == ownerID {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ownerType == types.ConfigTypeOrg {
|
||||||
|
userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user orgs"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userOrg := range userOrgs {
|
||||||
|
if userOrg.Organization.ID != ownerID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if userOrg.Role == types.MemberRoleMember {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType types.ConfigType, parentRef string) (bool, error) {
|
||||||
|
var ownerType types.ConfigType
|
||||||
|
var ownerID string
|
||||||
|
switch parentType {
|
||||||
|
case types.ConfigTypeProjectGroup:
|
||||||
|
pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, errors.Wrapf(err, "failed to get project group %q", parentRef))
|
||||||
|
}
|
||||||
|
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.Wrapf(err, "failed to get project %q", parentRef))
|
||||||
|
}
|
||||||
|
ownerType = p.OwnerType
|
||||||
|
ownerID = p.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.IsProjectOwner(ctx, ownerType, ownerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, error) {
|
||||||
|
groupType, groupID, err := common.GroupTypeIDFromRunGroup(runGroup)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var visibility types.Visibility
|
||||||
|
var ownerType types.ConfigType
|
||||||
|
var ownerID string
|
||||||
|
switch groupType {
|
||||||
|
case common.GroupTypeProject:
|
||||||
|
p, resp, err := h.configstoreClient.GetProject(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
ownerType = p.OwnerType
|
||||||
|
ownerID = p.OwnerID
|
||||||
|
visibility = p.GlobalVisibility
|
||||||
|
case common.GroupTypeUser:
|
||||||
|
// user local runs
|
||||||
|
ownerType = types.ConfigTypeUser
|
||||||
|
ownerID = groupID
|
||||||
|
visibility = types.VisibilityPrivate
|
||||||
|
}
|
||||||
|
|
||||||
|
isProjectMember, err := h.IsProjectMember(ctx, ownerType, ownerID)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if visibility == types.VisibilityPublic {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if !isProjectMember {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) CanDoRunActions(ctx context.Context, runGroup string) (bool, error) {
|
||||||
|
groupType, groupID, err := common.GroupTypeIDFromRunGroup(runGroup)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ownerType types.ConfigType
|
||||||
|
var ownerID string
|
||||||
|
switch groupType {
|
||||||
|
case common.GroupTypeProject:
|
||||||
|
p, resp, err := h.configstoreClient.GetProject(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return false, ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
ownerType = p.OwnerType
|
||||||
|
ownerID = p.OwnerID
|
||||||
|
case common.GroupTypeUser:
|
||||||
|
// user local runs
|
||||||
|
ownerType = types.ConfigTypeUser
|
||||||
|
ownerID = groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
isProjectOwner, err := h.IsProjectOwner(ctx, ownerType, ownerID)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isProjectOwner {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
|
@ -52,6 +52,10 @@ type CreateOrgRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (*types.Organization, error) {
|
func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (*types.Organization, error) {
|
||||||
|
if !h.IsUserLoggedOrAdmin(ctx) {
|
||||||
|
return nil, errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
if req.Name == "" {
|
if req.Name == "" {
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("organization name required"))
|
return nil, util.NewErrBadRequest(errors.Errorf("organization name required"))
|
||||||
}
|
}
|
||||||
|
@ -77,7 +81,20 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error {
|
func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error {
|
||||||
resp, err := h.configstoreClient.DeleteOrg(ctx, orgRef)
|
org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isOrgOwner, err := h.IsOrgOwner(ctx, org.ID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isOrgOwner {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = h.configstoreClient.DeleteOrg(ctx, orgRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete org"))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete org"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,18 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*csa
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isProjectMember, err := h.IsProjectMember(ctx, project.OwnerType, project.OwnerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if project.GlobalVisibility == types.VisibilityPublic {
|
||||||
|
return project, nil
|
||||||
|
}
|
||||||
|
if !isProjectMember {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
return project, nil
|
return project, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +59,29 @@ type CreateProjectRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectRequest) (*csapi.Project, error) {
|
func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectRequest) (*csapi.Project, error) {
|
||||||
|
user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID))
|
||||||
|
}
|
||||||
|
parentRef := req.ParentRef
|
||||||
|
if parentRef == "" {
|
||||||
|
// create project in current user namespace
|
||||||
|
parentRef = path.Join("user", user.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get project group %q", parentRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isProjectOwner {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
if !util.ValidateName(req.Name) {
|
if !util.ValidateName(req.Name) {
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("invalid project name %q", req.Name))
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid project name %q", req.Name))
|
||||||
}
|
}
|
||||||
|
@ -57,11 +92,6 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("empty remote repo path"))
|
return nil, util.NewErrBadRequest(errors.Errorf("empty remote repo path"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef)
|
|
||||||
if err != nil {
|
|
||||||
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get project group %q", req.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
projectPath := path.Join(pg.Path, req.Name)
|
projectPath := path.Join(pg.Path, req.Name)
|
||||||
_, resp, err = h.configstoreClient.GetProject(ctx, projectPath)
|
_, resp, err = h.configstoreClient.GetProject(ctx, projectPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -72,11 +102,6 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("project %q already exists", projectPath))
|
return nil, util.NewErrBadRequest(errors.Errorf("project %q already exists", projectPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID))
|
|
||||||
}
|
|
||||||
|
|
||||||
rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName)
|
rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
||||||
|
@ -110,12 +135,6 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq
|
||||||
return nil, errors.Wrapf(err, "failed to generate ssh key pair")
|
return nil, errors.Wrapf(err, "failed to generate ssh key pair")
|
||||||
}
|
}
|
||||||
|
|
||||||
parentRef := req.ParentRef
|
|
||||||
if parentRef == "" {
|
|
||||||
// create project in current user namespace
|
|
||||||
parentRef = path.Join("user", user.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &types.Project{
|
p := &types.Project{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Parent: types.Parent{
|
Parent: types.Parent{
|
||||||
|
@ -188,6 +207,14 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string)
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get project %q", projectRef))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get project %q", projectRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isProjectOwner {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
user, resp, err := h.configstoreClient.GetUserByLinkedAccount(ctx, p.LinkedAccountID)
|
user, resp, err := h.configstoreClient.GetUserByLinkedAccount(ctx, p.LinkedAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get user with linked account id %q", p.LinkedAccountID))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get user with linked account id %q", p.LinkedAccountID))
|
||||||
|
@ -210,7 +237,20 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error {
|
func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error {
|
||||||
resp, err := h.configstoreClient.DeleteProject(ctx, projectRef)
|
p, resp, err := h.configstoreClient.GetProject(ctx, projectRef)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get project %q", projectRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isProjectOwner {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = h.configstoreClient.DeleteProject(ctx, projectRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, err)
|
return ErrFromRemote(resp, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,19 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("invalid projectGroup name %q", req.Name))
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid projectGroup name %q", req.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get project group %q", req.ParentRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isProjectOwner {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID)
|
user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID))
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.CurrentUserID))
|
||||||
|
|
|
@ -55,6 +55,10 @@ type CreateRemoteSourceRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemoteSourceRequest) (*types.RemoteSource, error) {
|
func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemoteSourceRequest) (*types.RemoteSource, error) {
|
||||||
|
if !h.IsUserAdmin(ctx) {
|
||||||
|
return nil, errors.Errorf("user not admin")
|
||||||
|
}
|
||||||
|
|
||||||
if !util.ValidateName(req.Name) {
|
if !util.ValidateName(req.Name) {
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("invalid remotesource name %q", req.Name))
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid remotesource name %q", req.Name))
|
||||||
}
|
}
|
||||||
|
@ -106,6 +110,10 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, rsRef string) error {
|
func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, rsRef string) error {
|
||||||
|
if !h.IsUserAdmin(ctx) {
|
||||||
|
return errors.Errorf("user not admin")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef)
|
resp, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete remote source"))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete remote source"))
|
||||||
|
|
|
@ -30,12 +30,20 @@ func (h *ActionHandler) GetRun(ctx context.Context, runID string) (*rsapi.RunRes
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine permissions")
|
||||||
|
}
|
||||||
|
if !canGetRun {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
return runResp, nil
|
return runResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetRunsRequest struct {
|
type GetRunsRequest struct {
|
||||||
PhaseFilter []string
|
PhaseFilter []string
|
||||||
Groups []string
|
Group string
|
||||||
LastRun bool
|
LastRun bool
|
||||||
ChangeGroups []string
|
ChangeGroups []string
|
||||||
StartRunID string
|
StartRunID string
|
||||||
|
@ -44,7 +52,16 @@ type GetRunsRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) GetRuns(ctx context.Context, req *GetRunsRequest) (*rsapi.GetRunsResponse, error) {
|
func (h *ActionHandler) GetRuns(ctx context.Context, req *GetRunsRequest) (*rsapi.GetRunsResponse, error) {
|
||||||
runsResp, resp, err := h.runserviceClient.GetRuns(ctx, req.PhaseFilter, req.Groups, req.LastRun, req.ChangeGroups, req.StartRunID, req.Limit, req.Asc)
|
canGetRun, err := h.CanGetRun(ctx, req.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine permissions")
|
||||||
|
}
|
||||||
|
if !canGetRun {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := []string{req.Group}
|
||||||
|
runsResp, resp, err := h.runserviceClient.GetRuns(ctx, req.PhaseFilter, groups, req.LastRun, req.ChangeGroups, req.StartRunID, req.Limit, req.Asc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +79,19 @@ type GetLogsRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) GetLogs(ctx context.Context, req *GetLogsRequest) (*http.Response, error) {
|
func (h *ActionHandler) GetLogs(ctx context.Context, req *GetLogsRequest) (*http.Response, error) {
|
||||||
resp, err := h.runserviceClient.GetLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step, req.Follow, req.Stream)
|
runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine permissions")
|
||||||
|
}
|
||||||
|
if !canGetRun {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = h.runserviceClient.GetLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step, req.Follow, req.Stream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
}
|
}
|
||||||
|
@ -86,6 +115,18 @@ type RunActionsRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) error {
|
func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) error {
|
||||||
|
runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
canGetRun, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine permissions")
|
||||||
|
}
|
||||||
|
if !canGetRun {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
switch req.ActionType {
|
switch req.ActionType {
|
||||||
case RunActionTypeRestart:
|
case RunActionTypeRestart:
|
||||||
rsreq := &rsapi.RunCreateRequest{
|
rsreq := &rsapi.RunCreateRequest{
|
||||||
|
@ -130,6 +171,18 @@ type RunTaskActionsRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRequest) error {
|
func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRequest) error {
|
||||||
|
runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, err)
|
||||||
|
}
|
||||||
|
canGetRun, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine permissions")
|
||||||
|
}
|
||||||
|
if !canGetRun {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
switch req.ActionType {
|
switch req.ActionType {
|
||||||
case RunTaskActionTypeApprove:
|
case RunTaskActionTypeApprove:
|
||||||
rsreq := &rsapi.RunTaskActionsRequest{
|
rsreq := &rsapi.RunTaskActionsRequest{
|
||||||
|
|
|
@ -72,6 +72,14 @@ type CreateSecretHandler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretRequest) (*csapi.Secret, error) {
|
func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretRequest) (*csapi.Secret, error) {
|
||||||
|
isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isVariableOwner {
|
||||||
|
return nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
if !util.ValidateName(req.Name) {
|
if !util.ValidateName(req.Name) {
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name))
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name))
|
||||||
}
|
}
|
||||||
|
@ -84,7 +92,6 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
var rs *csapi.Secret
|
var rs *csapi.Secret
|
||||||
var err error
|
|
||||||
switch req.ParentType {
|
switch req.ParentType {
|
||||||
case types.ConfigTypeProjectGroup:
|
case types.ConfigTypeProjectGroup:
|
||||||
h.log.Infof("creating project group secret")
|
h.log.Infof("creating project group secret")
|
||||||
|
@ -102,8 +109,15 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.ConfigType, parentRef, name string) error {
|
func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.ConfigType, parentRef, name string) error {
|
||||||
|
isVariableOwner, err := h.IsVariableOwner(ctx, parentType, parentRef)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isVariableOwner {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
var err error
|
|
||||||
switch parentType {
|
switch parentType {
|
||||||
case types.ConfigTypeProjectGroup:
|
case types.ConfigTypeProjectGroup:
|
||||||
h.log.Infof("deleting project group secret")
|
h.log.Infof("deleting project group secret")
|
||||||
|
|
|
@ -41,6 +41,10 @@ func isAccessTokenExpired(expiresAt time.Time) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) GetUser(ctx context.Context, userRef string) (*types.User, error) {
|
func (h *ActionHandler) GetUser(ctx context.Context, userRef string) (*types.User, error) {
|
||||||
|
if !h.IsUserLoggedOrAdmin(ctx) {
|
||||||
|
return nil, errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
user, resp, err := h.configstoreClient.GetUser(ctx, userRef)
|
user, resp, err := h.configstoreClient.GetUser(ctx, userRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
|
@ -55,6 +59,10 @@ type GetUsersRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) GetUsers(ctx context.Context, req *GetUsersRequest) ([]*types.User, error) {
|
func (h *ActionHandler) GetUsers(ctx context.Context, req *GetUsersRequest) ([]*types.User, error) {
|
||||||
|
if !h.IsUserAdmin(ctx) {
|
||||||
|
return nil, errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
users, resp, err := h.configstoreClient.GetUsers(ctx, req.Start, req.Limit, req.Asc)
|
users, resp, err := h.configstoreClient.GetUsers(ctx, req.Start, req.Limit, req.Asc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, err)
|
return nil, ErrFromRemote(resp, err)
|
||||||
|
@ -67,6 +75,10 @@ type CreateUserRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) (*types.User, error) {
|
func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) (*types.User, error) {
|
||||||
|
if !h.IsUserAdmin(ctx) {
|
||||||
|
return nil, errors.Errorf("user not admin")
|
||||||
|
}
|
||||||
|
|
||||||
if req.UserName == "" {
|
if req.UserName == "" {
|
||||||
return nil, util.NewErrBadRequest(errors.Errorf("user name required"))
|
return nil, util.NewErrBadRequest(errors.Errorf("user name required"))
|
||||||
}
|
}
|
||||||
|
@ -490,10 +502,20 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource
|
||||||
switch requestType {
|
switch requestType {
|
||||||
case RemoteSourceRequestTypeCreateUserLA:
|
case RemoteSourceRequestTypeCreateUserLA:
|
||||||
req := req.(*CreateUserLARequest)
|
req := req.(*CreateUserLARequest)
|
||||||
|
|
||||||
user, resp, err := h.configstoreClient.GetUser(ctx, req.UserRef)
|
user, resp, err := h.configstoreClient.GetUser(ctx, req.UserRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.UserRef))
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.UserRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curUserID := h.CurrentUserID(ctx)
|
||||||
|
|
||||||
|
// user must be already logged in the create a linked account and can create a
|
||||||
|
// linked account only on itself.
|
||||||
|
if user.ID != curUserID {
|
||||||
|
return nil, util.NewErrBadRequest(errors.Errorf("logged in user cannot create linked account for another user"))
|
||||||
|
}
|
||||||
|
|
||||||
var la *types.LinkedAccount
|
var la *types.LinkedAccount
|
||||||
for _, v := range user.LinkedAccounts {
|
for _, v := range user.LinkedAccounts {
|
||||||
if v.RemoteSourceID == rs.ID {
|
if v.RemoteSourceID == rs.ID {
|
||||||
|
@ -729,6 +751,10 @@ func (h *ActionHandler) HandleOauth2Callback(ctx context.Context, code, state st
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error {
|
func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error {
|
||||||
|
if !h.IsUserAdmin(ctx) {
|
||||||
|
return errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := h.configstoreClient.DeleteUser(ctx, userRef)
|
resp, err := h.configstoreClient.DeleteUser(ctx, userRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user"))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user"))
|
||||||
|
@ -737,7 +763,24 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) error {
|
func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) error {
|
||||||
resp, err := h.configstoreClient.DeleteUserLA(ctx, userRef, laID)
|
if !h.IsUserLoggedOrAdmin(ctx) {
|
||||||
|
return errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin := !h.IsUserAdmin(ctx)
|
||||||
|
curUserID := h.CurrentUserID(ctx)
|
||||||
|
|
||||||
|
user, resp, err := h.configstoreClient.GetUser(ctx, userRef)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", userRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
// only admin or the same logged user can create a token
|
||||||
|
if !isAdmin && user.ID != curUserID {
|
||||||
|
return util.NewErrBadRequest(errors.Errorf("logged in user cannot create token for another user"))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = h.configstoreClient.DeleteUserLA(ctx, userRef, laID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user linked account"))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user linked account"))
|
||||||
}
|
}
|
||||||
|
@ -745,7 +788,24 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName string) error {
|
func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName string) error {
|
||||||
resp, err := h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName)
|
if !h.IsUserLoggedOrAdmin(ctx) {
|
||||||
|
return errors.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin := !h.IsUserAdmin(ctx)
|
||||||
|
curUserID := h.CurrentUserID(ctx)
|
||||||
|
|
||||||
|
user, resp, err := h.configstoreClient.GetUser(ctx, userRef)
|
||||||
|
if err != nil {
|
||||||
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", userRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
// only admin or the same logged user can create a token
|
||||||
|
if !isAdmin && user.ID != curUserID {
|
||||||
|
return util.NewErrBadRequest(errors.Errorf("logged in user cannot delete token for another user"))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user token"))
|
return ErrFromRemote(resp, errors.Wrapf(err, "failed to delete user token"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,14 @@ type CreateVariableRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableRequest) (*csapi.Variable, []*csapi.Secret, error) {
|
func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableRequest) (*csapi.Variable, []*csapi.Secret, error) {
|
||||||
|
isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isVariableOwner {
|
||||||
|
return nil, nil, util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
if !util.ValidateName(req.Name) {
|
if !util.ValidateName(req.Name) {
|
||||||
return nil, nil, util.NewErrBadRequest(errors.Errorf("invalid variable name %q", req.Name))
|
return nil, nil, util.NewErrBadRequest(errors.Errorf("invalid variable name %q", req.Name))
|
||||||
}
|
}
|
||||||
|
@ -134,7 +142,14 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.ConfigType, parentRef, name string) error {
|
func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.ConfigType, parentRef, name string) error {
|
||||||
var err error
|
isVariableOwner, err := h.IsVariableOwner(ctx, parentType, parentRef)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to determine ownership")
|
||||||
|
}
|
||||||
|
if !isVariableOwner {
|
||||||
|
return util.NewErrForbidden(errors.Errorf("user not authorized"))
|
||||||
|
}
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
switch parentType {
|
switch parentType {
|
||||||
case types.ConfigTypeProjectGroup:
|
case types.ConfigTypeProjectGroup:
|
||||||
|
|
|
@ -313,9 +313,10 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
q := r.URL.Query()
|
q := r.URL.Query()
|
||||||
|
|
||||||
groups := q["group"]
|
// we currently accept only one group
|
||||||
|
group := q.Get("group")
|
||||||
// we require that groups are specified to not return all runs
|
// we require that groups are specified to not return all runs
|
||||||
if len(groups) == 0 {
|
if group == "" {
|
||||||
httpError(w, util.NewErrBadRequest(errors.Errorf("no groups specified")))
|
httpError(w, util.NewErrBadRequest(errors.Errorf("no groups specified")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -350,7 +351,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
areq := &action.GetRunsRequest{
|
areq := &action.GetRunsRequest{
|
||||||
PhaseFilter: phaseFilter,
|
PhaseFilter: phaseFilter,
|
||||||
Groups: groups,
|
Group: group,
|
||||||
LastRun: lastRun,
|
LastRun: lastRun,
|
||||||
ChangeGroups: changeGroups,
|
ChangeGroups: changeGroups,
|
||||||
StartRunID: start,
|
StartRunID: start,
|
||||||
|
|
|
@ -27,8 +27,11 @@ import (
|
||||||
type GroupType string
|
type GroupType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GroupTypeProject GroupType = "project"
|
// base groups
|
||||||
GroupTypeUser GroupType = "user"
|
GroupTypeProject GroupType = "project"
|
||||||
|
GroupTypeUser GroupType = "user"
|
||||||
|
|
||||||
|
// sub groups
|
||||||
GroupTypeBranch GroupType = "branch"
|
GroupTypeBranch GroupType = "branch"
|
||||||
GroupTypeTag GroupType = "tag"
|
GroupTypeTag GroupType = "tag"
|
||||||
GroupTypePullRequest GroupType = "pr"
|
GroupTypePullRequest GroupType = "pr"
|
||||||
|
@ -49,10 +52,10 @@ func GenRunGroup(baseGroupType GroupType, baseGroupID string, webhookData *types
|
||||||
panic(fmt.Errorf("invalid webhook event type: %q", webhookData.Event))
|
panic(fmt.Errorf("invalid webhook event type: %q", webhookData.Event))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectIDFromRunGroup(group string) (string, error) {
|
func GroupTypeIDFromRunGroup(group string) (GroupType, string, error) {
|
||||||
pl := util.PathList(group)
|
pl := util.PathList(group)
|
||||||
if len(pl) < 2 {
|
if len(pl) < 2 {
|
||||||
return "", errors.Errorf("cannot determine group project id, wrong group path %q", group)
|
return "", "", errors.Errorf("cannot determine group project id, wrong group path %q", group)
|
||||||
}
|
}
|
||||||
return pl[1], nil
|
return GroupType(pl[0]), pl[1], nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue