Fix scheduled action panic with null event payload (#37459)

This fixes the scheduled action panic when an event payload is JSON
`null` by initializing the payload map before adding `schedule`. It also
adds regression coverage for the null-payload case.

Fixes #37447.

Testing:
- `go test -tags 'sqlite sqlite_unlock_notify' ./services/actions -run
'^TestWithScheduleInEventPayload$' -count=1`
- Local note: this agent ran the command as root with a temporary
`GITEA_TEST_CONF=custom/conf/app-test-root.ini` file that only set
`I_AM_BEING_UNSAFE_RUNNING_AS_ROOT = true`.

Authorship: cyphercodes; AI assistance disclosed: Hermes Agent
(GPT-5.5).

---------

Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: Hermes Agent (GPT-5.5) <hermes-agent@users.noreply.github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
Rayan Salhab
2026-04-28 04:58:04 +03:00
committed by GitHub
parent 15b23f037d
commit c8e67799b2
2 changed files with 26 additions and 7 deletions

View File

@@ -132,14 +132,22 @@ func CreateScheduleTask(ctx context.Context, spec *actions_model.ActionScheduleS
}
func withScheduleInEventPayload(eventPayload, schedule string) string {
if schedule == "" || eventPayload == "" {
if schedule == "" {
return eventPayload
}
event := map[string]any{}
if err := json.Unmarshal([]byte(eventPayload), &event); err != nil {
log.Error("withScheduleInEventPayload: unmarshal: %v", err)
return eventPayload
// eventPayload originates from json.Marshal(input.Payload) in handleSchedules,
// so a nil payload is stored as the literal "null" and pre-existing rows may be
// empty. Both cases start from a fresh map so the schedule field can still be set.
var event map[string]any
if eventPayload != "" {
if err := json.Unmarshal([]byte(eventPayload), &event); err != nil {
log.Error("withScheduleInEventPayload: unmarshal: %v", err)
return eventPayload
}
}
if event == nil {
event = map[string]any{}
}
event["schedule"] = schedule

View File

@@ -22,9 +22,20 @@ func TestWithScheduleInEventPayload(t *testing.T) {
assert.Equal(t, "refs/heads/main", event["ref"])
})
t.Run("keeps empty payload", func(t *testing.T) {
t.Run("adds schedule to null payload", func(t *testing.T) {
updated := withScheduleInEventPayload("null", "37 12 5 1 2")
event := map[string]any{}
assert.NoError(t, json.Unmarshal([]byte(updated), &event))
assert.Equal(t, "37 12 5 1 2", event["schedule"])
})
t.Run("adds schedule to empty payload", func(t *testing.T) {
updated := withScheduleInEventPayload("", "37 12 5 1 2")
assert.Empty(t, updated)
event := map[string]any{}
assert.NoError(t, json.Unmarshal([]byte(updated), &event))
assert.Equal(t, "37 12 5 1 2", event["schedule"])
})
t.Run("keeps payload when schedule empty", func(t *testing.T) {