Files
act_runner/internal/app/run/runner_env_test.go
Lunny Xiao 763b38ece3 fix: isolate per-task runner envs (#959)
## Summary
- clone the runner environment map for each task before injecting runtime and OIDC tokens
- keep the shared base environment immutable so concurrent jobs cannot hit `concurrent map writes`
- add a unit test covering task-local env cloning

Fixes #958

---------

Co-authored-by: Nicolas <bircni@icloud.com>
Reviewed-on: https://gitea.com/gitea/runner/pulls/959
Reviewed-by: Nicolas <bircni@icloud.com>
2026-05-12 18:50:25 +00:00

62 lines
1.7 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package run
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRunnerCloneEnvsReturnsTaskLocalCopy(t *testing.T) {
r := &Runner{
envs: map[string]string{
"ACTIONS_CACHE_URL": "http://cache.example",
"ACTIONS_RUNTIME_URL": "http://runner.example",
},
}
cloned := r.cloneEnvs()
require.Equal(t, r.envs, cloned)
cloned["ACTIONS_RUNTIME_TOKEN"] = "task-token"
cloned["ACTIONS_ID_TOKEN_REQUEST_URL"] = "http://oidc.example"
assert.NotContains(t, r.envs, "ACTIONS_RUNTIME_TOKEN")
assert.NotContains(t, r.envs, "ACTIONS_ID_TOKEN_REQUEST_URL")
assert.Equal(t, "http://cache.example", r.envs["ACTIONS_CACHE_URL"])
}
// Regression test for #958: concurrent tasks writing task-specific env keys
// used to race on the shared r.envs map and crash the runner with
// "fatal error: concurrent map writes". Each task must mutate its own clone.
func TestRunnerCloneEnvsConcurrentMutation(t *testing.T) {
r := &Runner{
envs: map[string]string{
"ACTIONS_CACHE_URL": "http://cache.example",
"ACTIONS_RUNTIME_URL": "http://runner.example",
},
}
const goroutines = 16
var wg sync.WaitGroup
wg.Add(goroutines)
for range goroutines {
go func() {
defer wg.Done()
envs := r.cloneEnvs()
envs["ACTIONS_RUNTIME_TOKEN"] = "task-token"
envs["ACTIONS_ID_TOKEN_REQUEST_URL"] = "http://oidc.example"
envs["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = "oidc-token"
}()
}
wg.Wait()
assert.NotContains(t, r.envs, "ACTIONS_RUNTIME_TOKEN")
assert.NotContains(t, r.envs, "ACTIONS_ID_TOKEN_REQUEST_URL")
assert.NotContains(t, r.envs, "ACTIONS_ID_TOKEN_REQUEST_TOKEN")
}