@@ -21,9 +21,11 @@ import (
21
21
"encoding/json"
22
22
"errors"
23
23
"fmt"
24
+ apiBean "github.com/devtron-labs/devtron/api/restHandler/app/pipeline/configure/bean"
24
25
"github.com/devtron-labs/devtron/internal/sql/constants"
25
26
"github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging"
26
27
bean2 "github.com/devtron-labs/devtron/pkg/build/pipeline/bean"
28
+ "github.com/devtron-labs/devtron/util/stringsUtil"
27
29
"golang.org/x/exp/maps"
28
30
"io"
29
31
"net/http"
@@ -47,21 +49,12 @@ import (
47
49
bean1 "github.com/devtron-labs/devtron/pkg/pipeline/bean"
48
50
"github.com/devtron-labs/devtron/pkg/pipeline/types"
49
51
resourceGroup "github.com/devtron-labs/devtron/pkg/resourceGroup"
50
- util2 "github.com/devtron-labs/devtron/util"
51
52
"github.com/devtron-labs/devtron/util/response"
52
53
"github.com/go-pg/pg"
53
54
"github.com/gorilla/mux"
54
55
"go.opentelemetry.io/otel"
55
56
)
56
57
57
- const GIT_MATERIAL_DELETE_SUCCESS_RESP = "Git material deleted successfully."
58
-
59
- type BuildHistoryResponse struct {
60
- HideImageTaggingHardDelete bool `json:"hideImageTaggingHardDelete"`
61
- TagsEditable bool `json:"tagsEditable"`
62
- AppReleaseTagNames []string `json:"appReleaseTagNames"` //unique list of tags exists in the app
63
- CiWorkflows []types.WorkflowResponse `json:"ciWorkflows"`
64
- }
65
58
type DevtronAppBuildRestHandler interface {
66
59
CreateCiConfig (w http.ResponseWriter , r * http.Request )
67
60
UpdateCiTemplate (w http.ResponseWriter , r * http.Request )
@@ -648,72 +641,48 @@ func (handler *PipelineConfigRestHandlerImpl) GetExternalCiById(w http.ResponseW
648
641
common .WriteJsonResp (w , err , ciConf , http .StatusOK )
649
642
}
650
643
651
- func (handler * PipelineConfigRestHandlerImpl ) TriggerCiPipeline (w http.ResponseWriter , r * http.Request ) {
652
- userId , err := handler .userAuthService .GetLoggedInUser (r )
653
- if userId == 0 || err != nil {
654
- common .WriteJsonResp (w , err , "Unauthorized User" , http .StatusUnauthorized )
655
- return
656
- }
657
- decoder := json .NewDecoder (r .Body )
658
- var ciTriggerRequest bean.CiTriggerRequest
659
- err = decoder .Decode (& ciTriggerRequest )
644
+ func (handler * PipelineConfigRestHandlerImpl ) validateCiTriggerRBAC (token string , ciPipelineId , triggerEnvironmentId int ) error {
645
+ // RBAC STARTS
646
+ // checking if user has trigger access on app, if not will be forbidden to trigger independent of number of cd cdPipelines
647
+ ciPipeline , err := handler .ciPipelineRepository .FindById (ciPipelineId )
660
648
if err != nil {
661
- handler .Logger .Errorw ("request err, TriggerCiPipeline" , "err" , err , "payload " , ciTriggerRequest )
662
- common . WriteJsonResp ( w , err , nil , http . StatusBadRequest )
663
- return
649
+ handler .Logger .Errorw ("err in finding ci pipeline , TriggerCiPipeline" , "err" , err , "ciPipelineId " , ciPipelineId )
650
+ errMsg := fmt . Sprintf ( "error in finding ci pipeline for id '%d'" , ciPipelineId )
651
+ return util . NewApiError ( http . StatusBadRequest , errMsg , errMsg )
664
652
}
665
- if ! handler .validForMultiMaterial (ciTriggerRequest ) {
666
- handler .Logger .Errorw ("invalid req, commit hash not present for multi-git" , "payload" , ciTriggerRequest )
667
- common .WriteJsonResp (w , errors .New ("invalid req, commit hash not present for multi-git" ),
668
- nil , http .StatusBadRequest )
669
- }
670
- ciTriggerRequest .TriggeredBy = userId
671
- token := r .Header .Get ("token" )
672
-
673
- handler .Logger .Infow ("request payload, TriggerCiPipeline" , "payload" , ciTriggerRequest )
674
-
675
- //RBAC STARTS
676
- //checking if user has trigger access on app, if not will be forbidden to trigger independent of number of cd cdPipelines
677
- ciPipeline , err := handler .ciPipelineRepository .FindById (ciTriggerRequest .PipelineId )
678
- if err != nil {
679
- handler .Logger .Errorw ("err in finding ci pipeline, TriggerCiPipeline" , "err" , err , "ciPipelineId" , ciTriggerRequest .PipelineId )
680
- common .WriteJsonResp (w , err , nil , http .StatusInternalServerError )
681
- return
682
- }
683
- appWorkflowMapping , err := handler .appWorkflowService .FindAppWorkflowByCiPipelineId (ciTriggerRequest .PipelineId )
653
+ appWorkflowMapping , err := handler .appWorkflowService .FindAppWorkflowByCiPipelineId (ciPipelineId )
684
654
if err != nil {
685
- handler .Logger .Errorw ("err in finding appWorkflowMapping, TriggerCiPipeline" , "err" , err , "ciPipelineId" , ciTriggerRequest . PipelineId )
686
- common . WriteJsonResp ( w , err , nil , http . StatusInternalServerError )
687
- return
655
+ handler .Logger .Errorw ("err in finding appWorkflowMapping, TriggerCiPipeline" , "err" , err , "ciPipelineId" , ciPipelineId )
656
+ errMsg := fmt . Sprintf ( "error in finding appWorkflowMapping for ciPipelineId '%d'" , ciPipelineId )
657
+ return util . NewApiError ( http . StatusBadRequest , errMsg , errMsg )
688
658
}
689
659
workflowName := ""
690
660
if len (appWorkflowMapping ) > 0 {
691
661
workflowName = appWorkflowMapping [0 ].AppWorkflow .Name
692
662
}
693
663
// This is being done for jobs, jobs execute in default-env (devtron-ci) namespace by default. so considering DefaultCiNamespace as env for rbac enforcement
694
664
envName := ""
695
- if ciTriggerRequest . EnvironmentId == 0 {
665
+ if triggerEnvironmentId == 0 {
696
666
envName = pipeline .DefaultCiWorkflowNamespace
697
667
}
698
668
appObject := handler .enforcerUtil .GetAppRBACNameByAppId (ciPipeline .AppId )
699
- workflowObject := handler .enforcerUtil .GetWorkflowRBACByCiPipelineId (ciTriggerRequest . PipelineId , workflowName )
700
- triggerObject := handler .enforcerUtil .GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName (ciTriggerRequest . PipelineId , ciTriggerRequest . EnvironmentId , envName )
669
+ workflowObject := handler .enforcerUtil .GetWorkflowRBACByCiPipelineId (ciPipelineId , workflowName )
670
+ triggerObject := handler .enforcerUtil .GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName (ciPipelineId , triggerEnvironmentId , envName )
701
671
appRbacOk := handler .enforcer .Enforce (token , casbin .ResourceApplications , casbin .ActionTrigger , appObject )
702
672
if ! appRbacOk {
703
673
appRbacOk = handler .enforcer .Enforce (token , casbin .ResourceJobs , casbin .ActionTrigger , appObject ) && handler .enforcer .Enforce (token , casbin .ResourceWorkflow , casbin .ActionTrigger , workflowObject ) && handler .enforcer .Enforce (token , casbin .ResourceJobsEnv , casbin .ActionTrigger , triggerObject )
704
674
}
705
675
706
676
if ! appRbacOk {
707
677
handler .Logger .Debug (fmt .Errorf ("unauthorized user" ), "Unauthorized User" , http .StatusForbidden )
708
- common .WriteJsonResp (w , err , "Unauthorized User" , http .StatusForbidden )
709
- return
678
+ return util .NewApiError (http .StatusForbidden , common .UnAuthorisedUser , common .UnAuthorisedUser )
710
679
}
711
- //checking rbac for cd cdPipelines
712
- cdPipelines , err := handler .pipelineRepository .FindByCiPipelineId (ciTriggerRequest . PipelineId )
680
+ // checking rbac for cd cdPipelines
681
+ cdPipelines , err := handler .pipelineRepository .FindByCiPipelineId (ciPipelineId )
713
682
if err != nil {
714
- handler .Logger .Errorw ("error in finding ccd cdPipelines by ciPipelineId" , "err" , err , "ciPipelineId" , ciTriggerRequest . PipelineId )
715
- common . WriteJsonResp ( w , err , nil , http . StatusInternalServerError )
716
- return
683
+ handler .Logger .Errorw ("error in finding ccd cdPipelines by ciPipelineId" , "err" , err , "ciPipelineId" , ciPipelineId )
684
+ errMsg := fmt . Sprintf ( "error in finding cd cdPipelines for ciPipelineId '%d'" , ciPipelineId )
685
+ return util . NewApiError ( http . StatusBadRequest , errMsg , errMsg )
717
686
}
718
687
cdPipelineRbacObjects := make ([]string , len (cdPipelines ))
719
688
rbacObjectCdTriggerTypeMap := make (map [string ]pipelineConfig.TriggerType , len (cdPipelines ))
@@ -729,21 +698,50 @@ func (handler *PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseW
729
698
envRbacResultMap := handler .enforcer .EnforceInBatch (token , casbin .ResourceEnvironment , casbin .ActionTrigger , cdPipelineRbacObjects )
730
699
for rbacObject , rbacResultOk := range envRbacResultMap {
731
700
if rbacObjectCdTriggerTypeMap [rbacObject ] == pipelineConfig .TRIGGER_TYPE_AUTOMATIC && ! rbacResultOk {
732
- common .WriteJsonResp (w , err , "Unauthorized User" , http .StatusForbidden )
733
- return
701
+ return util .NewApiError (http .StatusForbidden , common .UnAuthorisedUser , common .UnAuthorisedUser )
734
702
}
735
703
if rbacResultOk { //this flow will come if pipeline is automatic and has access or if pipeline is manual,
736
704
// by which we can ensure if there are no automatic pipelines then atleast access on one manual is present
737
705
hasAnyEnvTriggerAccess = true
738
706
}
739
707
}
740
708
if ! hasAnyEnvTriggerAccess {
741
- common .WriteJsonResp (w , err , "Unauthorized User" , http .StatusForbidden )
742
- return
709
+ return util .NewApiError (http .StatusForbidden , common .UnAuthorisedUser , common .UnAuthorisedUser )
743
710
}
744
711
}
712
+ // RBAC ENDS
713
+ return nil
714
+ }
745
715
746
- //RBAC ENDS
716
+ func (handler * PipelineConfigRestHandlerImpl ) TriggerCiPipeline (w http.ResponseWriter , r * http.Request ) {
717
+ userId , err := handler .userAuthService .GetLoggedInUser (r )
718
+ if userId == 0 || err != nil {
719
+ common .WriteJsonResp (w , err , "Unauthorized User" , http .StatusUnauthorized )
720
+ return
721
+ }
722
+ decoder := json .NewDecoder (r .Body )
723
+ var ciTriggerRequest bean.CiTriggerRequest
724
+ err = decoder .Decode (& ciTriggerRequest )
725
+ if err != nil {
726
+ handler .Logger .Errorw ("request err, TriggerCiPipeline" , "err" , err , "payload" , ciTriggerRequest )
727
+ common .WriteJsonResp (w , err , nil , http .StatusBadRequest )
728
+ return
729
+ }
730
+ token := r .Header .Get ("token" )
731
+ // RBAC block starts
732
+ err = handler .validateCiTriggerRBAC (token , ciTriggerRequest .PipelineId , ciTriggerRequest .EnvironmentId )
733
+ if err != nil {
734
+ common .WriteJsonResp (w , err , nil , http .StatusInternalServerError )
735
+ return
736
+ }
737
+ // RBAC block ends
738
+ if ! handler .validForMultiMaterial (ciTriggerRequest ) {
739
+ handler .Logger .Errorw ("invalid req, commit hash not present for multi-git" , "payload" , ciTriggerRequest )
740
+ common .WriteJsonResp (w , errors .New ("invalid req, commit hash not present for multi-git" ),
741
+ nil , http .StatusBadRequest )
742
+ }
743
+ ciTriggerRequest .TriggeredBy = userId
744
+ handler .Logger .Infow ("request payload, TriggerCiPipeline" , "payload" , ciTriggerRequest )
747
745
response := make (map [string ]string )
748
746
resp , err := handler .ciHandler .HandleCIManual (ciTriggerRequest )
749
747
if errors .Is (err , bean1 .ErrImagePathInUse ) {
@@ -916,7 +914,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCiPipelineMin(w http.ResponseWr
916
914
envIdsString := v .Get ("envIds" )
917
915
envIds := make ([]int , 0 )
918
916
if len (envIdsString ) > 0 {
919
- envIds , err = util2 .SplitCommaSeparatedIntValues (envIdsString )
917
+ envIds , err = stringsUtil .SplitCommaSeparatedIntValues (envIdsString )
920
918
if err != nil {
921
919
common .WriteJsonResp (w , err , "please provide valid envIds" , http .StatusBadRequest )
922
920
return
@@ -1103,7 +1101,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildHistory(w http.ResponseWri
1103
1101
//RBAC for edit tag access , user should have build permission in current ci-pipeline
1104
1102
triggerAccess := handler .enforcer .Enforce (token , casbin .ResourceApplications , casbin .ActionTrigger , object ) || handler .enforcer .Enforce (token , casbin .ResourceJobs , casbin .ActionTrigger , object )
1105
1103
//RBAC
1106
- resp := BuildHistoryResponse {}
1104
+ resp := apiBean. BuildHistoryResponse {}
1107
1105
workflowsResp , err := handler .ciHandler .GetBuildHistory (pipelineId , ciPipeline .AppId , offset , limit )
1108
1106
resp .CiWorkflows = workflowsResp
1109
1107
if err != nil {
@@ -1501,7 +1499,7 @@ func (handler *PipelineConfigRestHandlerImpl) DeleteMaterial(w http.ResponseWrit
1501
1499
common .WriteJsonResp (w , err , nil , http .StatusInternalServerError )
1502
1500
return
1503
1501
}
1504
- common .WriteJsonResp (w , err , GIT_MATERIAL_DELETE_SUCCESS_RESP , http .StatusOK )
1502
+ common .WriteJsonResp (w , err , apiBean . GIT_MATERIAL_DELETE_SUCCESS_RESP , http .StatusOK )
1505
1503
}
1506
1504
1507
1505
func (handler * PipelineConfigRestHandlerImpl ) HandleWorkflowWebhook (w http.ResponseWriter , r * http.Request ) {
0 commit comments