@@ -23,9 +23,10 @@ import (
23
23
"github.com/emicklei/go-restful"
24
24
"k8s.io/apiserver/pkg/authentication/user"
25
25
log "k8s.io/klog"
26
+ "k8s.io/klog/v2"
26
27
"kubesphere.io/kubesphere/pkg/api"
27
28
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
28
- iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2 "
29
+ "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer "
29
30
"kubesphere.io/kubesphere/pkg/apiserver/request"
30
31
"kubesphere.io/kubesphere/pkg/constants"
31
32
"kubesphere.io/kubesphere/pkg/models/devops"
@@ -279,11 +280,53 @@ func (h *ProjectPipelineHandler) GetPipelineRunNodes(req *restful.Request, resp
279
280
resp .WriteAsJson (res )
280
281
}
281
282
282
- func (h * ProjectPipelineHandler ) approvableCheck (nodes []clientDevOps.NodesDetail , req * restful.Request ) {
283
- currentUserName , roleName := h .getCurrentUser (req )
283
+ // there're two situation here:
284
+ // 1. the particular submitters exist
285
+ // the users who are the owner of this Pipeline or the submitter of this Pipeline, or has the auth to create a DevOps project
286
+ // 2. no particular submitters
287
+ // only the owner of this Pipeline can approve or reject it
288
+ func (h * ProjectPipelineHandler ) approvableCheck (nodes []clientDevOps.NodesDetail , pipe pipelineParam ) {
289
+ var userInfo user.Info
290
+ var ok bool
291
+ var isAdmin bool
284
292
// check if current user belong to the admin group, grant it if it's true
285
- isAdmin := roleName == iamv1alpha2 .PlatformAdmin
293
+ if userInfo , ok = request .UserFrom (pipe .Context ); ok {
294
+ createAuth := authorizer.AttributesRecord {
295
+ User : userInfo ,
296
+ Verb : authorizer .VerbCreate ,
297
+ Workspace : pipe .Workspace ,
298
+ Resource : "devopsprojects" ,
299
+ ResourceRequest : true ,
300
+ ResourceScope : request .DevOpsScope ,
301
+ }
302
+
303
+ if decision , _ , err := h .authorizer .Authorize (createAuth ); err == nil {
304
+ isAdmin = decision == authorizer .DecisionAllow
305
+ } else {
306
+ // this is an expected case, printing the debug info for troubleshooting
307
+ klog .V (8 ).Infof ("authorize failed with '%v', error is '%v'" ,
308
+ createAuth , err )
309
+ }
310
+ } else {
311
+ klog .V (6 ).Infof ("cannot get the current user when checking the approvable with pipeline '%s/%s'" ,
312
+ pipe .ProjectName , pipe .Name )
313
+ return
314
+ }
286
315
316
+ var createdByCurrentUser bool // indicate if the current user is the owner
317
+ if pipeline , err := h .devopsOperator .GetPipelineObj (pipe .ProjectName , pipe .Name ); err == nil {
318
+ if creator , ok := pipeline .GetAnnotations ()[constants .CreatorAnnotationKey ]; ok {
319
+ createdByCurrentUser = userInfo .GetName () == creator
320
+ } else {
321
+ klog .V (6 ).Infof ("annotation '%s' is necessary but it is missing from '%s/%s'" ,
322
+ constants .CreatorAnnotationKey , pipe .ProjectName , pipe .Name )
323
+ }
324
+ } else {
325
+ klog .V (6 ).Infof ("cannot find pipeline '%s/%s', error is '%v'" , pipe .ProjectName , pipe .Name , err )
326
+ return
327
+ }
328
+
329
+ // check every input steps if it's approvable
287
330
for i , node := range nodes {
288
331
if node .State != clientDevOps .StatePaused {
289
332
continue
@@ -294,7 +337,7 @@ func (h *ProjectPipelineHandler) approvableCheck(nodes []clientDevOps.NodesDetai
294
337
continue
295
338
}
296
339
297
- nodes [i ].Steps [j ].Approvable = isAdmin || step .Input .Approvable (currentUserName )
340
+ nodes [i ].Steps [j ].Approvable = isAdmin || createdByCurrentUser || step .Input .Approvable (userInfo . GetName () )
298
341
}
299
342
}
300
343
}
@@ -310,33 +353,8 @@ func (h *ProjectPipelineHandler) createdBy(projectName string, pipelineName stri
310
353
return false
311
354
}
312
355
313
- func (h * ProjectPipelineHandler ) getCurrentUser (req * restful.Request ) (username , roleName string ) {
314
- var userInfo user.Info
315
- var ok bool
316
- var err error
317
-
318
- ctx := req .Request .Context ()
319
- if userInfo , ok = request .UserFrom (ctx ); ok {
320
- var role * iamv1alpha2.GlobalRole
321
- username = userInfo .GetName ()
322
- if role , err = h .amInterface .GetGlobalRoleOfUser (username ); err == nil {
323
- roleName = role .Name
324
- }
325
- }
326
- return
327
- }
328
-
329
356
func (h * ProjectPipelineHandler ) hasSubmitPermission (req * restful.Request ) (hasPermit bool , err error ) {
330
- currentUserName , roleName := h .getCurrentUser (req )
331
- projectName := req .PathParameter ("devops" )
332
- pipelineName := req .PathParameter ("pipeline" )
333
- // check if current user belong to the admin group or he's the owner, grant it if it's true
334
- if roleName == iamv1alpha2 .PlatformAdmin || h .createdBy (projectName , pipelineName , currentUserName ) {
335
- hasPermit = true
336
- return
337
- }
338
-
339
- // step 2, check if current user if was addressed
357
+ pipeParam := parsePipelineParam (req )
340
358
httpReq := & http.Request {
341
359
URL : req .Request .URL ,
342
360
Header : req .Request .Header ,
@@ -350,7 +368,9 @@ func (h *ProjectPipelineHandler) hasSubmitPermission(req *restful.Request) (hasP
350
368
351
369
// check if current user can approve this input
352
370
var res []clientDevOps.NodesDetail
353
- if res , err = h .devopsOperator .GetNodesDetail (projectName , pipelineName , runId , httpReq ); err == nil {
371
+ if res , err = h .devopsOperator .GetNodesDetail (pipeParam .ProjectName , pipeParam .Name , runId , httpReq ); err == nil {
372
+ h .approvableCheck (res , parsePipelineParam (req ))
373
+
354
374
for _ , node := range res {
355
375
if node .ID != nodeId {
356
376
continue
@@ -361,7 +381,7 @@ func (h *ProjectPipelineHandler) hasSubmitPermission(req *restful.Request) (hasP
361
381
continue
362
382
}
363
383
364
- hasPermit = step .Input . Approvable ( currentUserName )
384
+ hasPermit = step .Approvable
365
385
break
366
386
}
367
387
break
@@ -412,7 +432,7 @@ func (h *ProjectPipelineHandler) GetNodesDetail(req *restful.Request, resp *rest
412
432
parseErr (err , resp )
413
433
return
414
434
}
415
- h .approvableCheck (res , req )
435
+ h .approvableCheck (res , parsePipelineParam ( req ) )
416
436
417
437
resp .WriteAsJson (res )
418
438
}
@@ -620,10 +640,19 @@ func (h *ProjectPipelineHandler) GetBranchNodesDetail(req *restful.Request, resp
620
640
parseErr (err , resp )
621
641
return
622
642
}
623
- h .approvableCheck (res , req )
643
+ h .approvableCheck (res , parsePipelineParam ( req ) )
624
644
resp .WriteAsJson (res )
625
645
}
626
646
647
+ func parsePipelineParam (req * restful.Request ) pipelineParam {
648
+ return pipelineParam {
649
+ Workspace : req .PathParameter ("workspace" ),
650
+ ProjectName : req .PathParameter ("devops" ),
651
+ Name : req .PathParameter ("pipeline" ),
652
+ Context : req .Request .Context (),
653
+ }
654
+ }
655
+
627
656
func (h * ProjectPipelineHandler ) GetPipelineBranch (req * restful.Request , resp * restful.Response ) {
628
657
projectName := req .PathParameter ("devops" )
629
658
pipelineName := req .PathParameter ("pipeline" )
0 commit comments