Avoid panic caused by broken payload when creating commit status (#23216)
When creating commit status for Actons jobs, a payload with nil `HeadCommit` will cause panic. Reported at: https://gitea.com/gitea/act_runner/issues/28#issuecomment-732166 Although the `HeadCommit` probably can not be nil after #23215, `CreateCommitStatus` should protect itself, to avoid being broken in the future. In addition, it's enough to print error log instead of returning err when `CreateCommitStatus` failed. --------- Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
		
							parent
							
								
									ca84a61761
								
							
						
					
					
						commit
						47b912cd52
					
				|  | @ -150,7 +150,7 @@ func (s *Service) UpdateTask( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := actions_service.CreateCommitStatus(ctx, task.Job); err != nil { | 	if err := actions_service.CreateCommitStatus(ctx, task.Job); err != nil { | ||||||
| 		log.Error("Update commit status failed: %v", err) | 		log.Error("Update commit status for job %v failed: %v", task.Job.ID, err) | ||||||
| 		// go on
 | 		// go on
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/models/unit" | 	"code.gitea.io/gitea/models/unit" | ||||||
| 	"code.gitea.io/gitea/modules/actions" | 	"code.gitea.io/gitea/modules/actions" | ||||||
| 	context_module "code.gitea.io/gitea/modules/context" | 	context_module "code.gitea.io/gitea/modules/context" | ||||||
|  | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
| 	"code.gitea.io/gitea/modules/web" | 	"code.gitea.io/gitea/modules/web" | ||||||
|  | @ -214,15 +215,18 @@ func Rerun(ctx *context_module.Context) { | ||||||
| 	job.Stopped = 0 | 	job.Stopped = 0 | ||||||
| 
 | 
 | ||||||
| 	if err := db.WithTx(ctx, func(ctx context.Context) error { | 	if err := db.WithTx(ctx, func(ctx context.Context) error { | ||||||
| 		if _, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped"); err != nil { | 		_, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped") | ||||||
| 			return err | 		return err | ||||||
| 		} |  | ||||||
| 		return actions_service.CreateCommitStatus(ctx, job) |  | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, err.Error()) | 		ctx.Error(http.StatusInternalServerError, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if err := actions_service.CreateCommitStatus(ctx, job); err != nil { | ||||||
|  | 		log.Error("Update commit status for job %v failed: %v", job.ID, err) | ||||||
|  | 		// go on
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ctx.JSON(http.StatusOK, struct{}{}) | 	ctx.JSON(http.StatusOK, struct{}{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -255,9 +259,6 @@ func Cancel(ctx *context_module.Context) { | ||||||
| 			if err := actions_model.StopTask(ctx, job.TaskID, actions_model.StatusCancelled); err != nil { | 			if err := actions_model.StopTask(ctx, job.TaskID, actions_model.StatusCancelled); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			if err := actions_service.CreateCommitStatus(ctx, job); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		return nil | 		return nil | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
|  | @ -265,6 +266,13 @@ func Cancel(ctx *context_module.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	for _, job := range jobs { | ||||||
|  | 		if err := actions_service.CreateCommitStatus(ctx, job); err != nil { | ||||||
|  | 			log.Error("Update commit status for job %v failed: %v", job.ID, err) | ||||||
|  | 			// go on
 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ctx.JSON(http.StatusOK, struct{}{}) | 	ctx.JSON(http.StatusOK, struct{}{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error { | ||||||
| 		return fmt.Errorf("find tasks: %w", err) | 		return fmt.Errorf("find tasks: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	jobs := make([]*actions_model.ActionRunJob, 0, len(tasks)) | ||||||
| 	for _, task := range tasks { | 	for _, task := range tasks { | ||||||
| 		if err := db.WithTx(ctx, func(ctx context.Context) error { | 		if err := db.WithTx(ctx, func(ctx context.Context) error { | ||||||
| 			if err := actions_model.StopTask(ctx, task.ID, actions_model.StatusFailure); err != nil { | 			if err := actions_model.StopTask(ctx, task.ID, actions_model.StatusFailure); err != nil { | ||||||
|  | @ -51,7 +52,8 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error { | ||||||
| 			if err := task.LoadJob(ctx); err != nil { | 			if err := task.LoadJob(ctx); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			return CreateCommitStatus(ctx, task.Job) | 			jobs = append(jobs, task.Job) | ||||||
|  | 			return nil | ||||||
| 		}); err != nil { | 		}); err != nil { | ||||||
| 			log.Warn("Cannot stop task %v: %v", task.ID, err) | 			log.Warn("Cannot stop task %v: %v", task.ID, err) | ||||||
| 			// go on
 | 			// go on
 | ||||||
|  | @ -61,6 +63,14 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error { | ||||||
| 			remove() | 			remove() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, job := range jobs { | ||||||
|  | 		if err := CreateCommitStatus(ctx, job); err != nil { | ||||||
|  | 			log.Error("Update commit status for job %v failed: %v", job.ID, err) | ||||||
|  | 			// go on
 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -80,14 +90,16 @@ func CancelAbandonedJobs(ctx context.Context) error { | ||||||
| 		job.Status = actions_model.StatusCancelled | 		job.Status = actions_model.StatusCancelled | ||||||
| 		job.Stopped = now | 		job.Stopped = now | ||||||
| 		if err := db.WithTx(ctx, func(ctx context.Context) error { | 		if err := db.WithTx(ctx, func(ctx context.Context) error { | ||||||
| 			if _, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped"); err != nil { | 			_, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped") | ||||||
| 				return err | 			return err | ||||||
| 			} |  | ||||||
| 			return CreateCommitStatus(ctx, job) |  | ||||||
| 		}); err != nil { | 		}); err != nil { | ||||||
| 			log.Warn("cancel abandoned job %v: %v", job.ID, err) | 			log.Warn("cancel abandoned job %v: %v", job.ID, err) | ||||||
| 			// go on
 | 			// go on
 | ||||||
| 		} | 		} | ||||||
|  | 		if err := CreateCommitStatus(ctx, job); err != nil { | ||||||
|  | 			log.Error("Update commit status for job %v failed: %v", job.ID, err) | ||||||
|  | 			// go on
 | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
|  | @ -30,6 +30,16 @@ func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er | ||||||
| 		return fmt.Errorf("GetPushEventPayload: %w", err) | 		return fmt.Errorf("GetPushEventPayload: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// Since the payload comes from json data, we should check if it's broken, or it will cause panic
 | ||||||
|  | 	switch { | ||||||
|  | 	case payload.Repo == nil: | ||||||
|  | 		return fmt.Errorf("repo is missing in event payload") | ||||||
|  | 	case payload.Pusher == nil: | ||||||
|  | 		return fmt.Errorf("pusher is missing in event payload") | ||||||
|  | 	case payload.HeadCommit == nil: | ||||||
|  | 		return fmt.Errorf("head commit is missing in event payload") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	creator, err := user_model.GetUserByID(ctx, payload.Pusher.ID) | 	creator, err := user_model.GetUserByID(ctx, payload.Pusher.ID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("GetUserByID: %w", err) | 		return fmt.Errorf("GetUserByID: %w", err) | ||||||
|  |  | ||||||
|  | @ -187,7 +187,8 @@ func notify(ctx context.Context, input *notifyInput) error { | ||||||
| 		} else { | 		} else { | ||||||
| 			for _, job := range jobs { | 			for _, job := range jobs { | ||||||
| 				if err := CreateCommitStatus(ctx, job); err != nil { | 				if err := CreateCommitStatus(ctx, job); err != nil { | ||||||
| 					log.Error("CreateCommitStatus: %v", err) | 					log.Error("Update commit status for job %v failed: %v", job.ID, err) | ||||||
|  | 					// go on
 | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue