fix: fix panics, enable the forcetypeassert lint (#1123)

An unchecked type assertion panics on input it did not expect, as a missing `tool_cache` key did in https://gitea.com/gitea/runner/pulls/1122.

Every flagged site is now handled where it can fail, or typed so it cannot: a `lock.Keyed` replaces the two `sync.Map` mutex registries, and the reporter's outputs carry an explicit sent flag. Mocks keep their assertions, a mismatch there is a setup error the panic names.

Bugs it turned up (only the first is reachable from workflows):

1. A scalar `matrix.include` or `matrix.exclude`, e.g. `include: foo` or `include: [1, 2]`, panicked the runner with `interface conversion: interface {} is string, not map[string]interface {}`. Verified against `main`, it is now a workflow error. `OnSchedule` panicked the same way on a malformed `on.schedule` entry.
1. `ExternalURL()` panicked on the nil listener after `Close()`, the port is now resolved once at startup.
1. `errors.Is(err, git.ErrShortRef)` followed by `err.(*git.Error)` panics as soon as anything wraps that error, so it is `errors.As` now.
1. An output name the server acknowledged without ever being sent one was recorded as sent forever, which silently dropped a later value for that name.

48576ab3e5 fixes one discovered issue: a matrix key holding a nested object was logged and then run as if the job had no matrix, so it now fails like an unknown `exclude` key.
Reviewed-on: https://gitea.com/gitea/runner/pulls/1123
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind
2026-07-30 07:09:53 +00:00
committed by silverwind
parent 0192861155
commit 3f7fd16ea1
15 changed files with 210 additions and 109 deletions

View File

@@ -667,7 +667,9 @@ func TestReadWorkflow_Strategy(t *testing.T) {
matrixes, err := job.GetMatrixes()
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, matrixes, []map[string]any{{}}) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Matrix(), map[string][]any(nil))
matrix, err := job.Matrix()
require.NoError(t, err)
assert.Empty(t, matrix)
assert.Equal(t, job.Strategy.MaxParallel, 2) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Strategy.FailFast, true) //nolint:testifylint // pre-existing issue from nektos/act
@@ -675,7 +677,9 @@ func TestReadWorkflow_Strategy(t *testing.T) {
matrixes, err = job.GetMatrixes()
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, matrixes, []map[string]any{{}}) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Matrix(), map[string][]any(nil))
matrix, err = job.Matrix()
require.NoError(t, err)
assert.Empty(t, matrix)
assert.Equal(t, job.Strategy.MaxParallel, 4) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Strategy.FailFast, false) //nolint:testifylint // pre-existing issue from nektos/act
@@ -683,7 +687,9 @@ func TestReadWorkflow_Strategy(t *testing.T) {
matrixes, err = job.GetMatrixes()
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, matrixes, []map[string]any{{}}) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Matrix(), map[string][]any(nil))
matrix, err = job.Matrix()
require.NoError(t, err)
assert.Empty(t, matrix)
assert.Equal(t, job.Strategy.MaxParallel, 2) //nolint:testifylint // pre-existing issue from nektos/act
assert.Equal(t, job.Strategy.FailFast, false) //nolint:testifylint // pre-existing issue from nektos/act
@@ -700,7 +706,9 @@ func TestReadWorkflow_Strategy(t *testing.T) {
{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
},
)
assert.Equal(t, job.Matrix(), //nolint:testifylint // pre-existing issue from nektos/act
matrix, err = job.Matrix()
require.NoError(t, err)
assert.Equal(t, matrix, //nolint:testifylint // pre-existing issue from nektos/act
map[string][]any{
"datacenter": {"site-c", "site-d"},
"exclude": {
@@ -1092,13 +1100,15 @@ jobs:
t.Fatal("job not found")
}
matrix := job.Matrix()
matrix, err := job.Matrix()
if tt.wantErr {
require.Error(t, err)
assert.Nil(t, matrix, "matrix should be nil on error")
} else {
require.NoError(t, err)
if tt.wantLen == 0 {
assert.Nil(t, matrix, "matrix should be nil for jobs without strategy")
assert.Empty(t, matrix, "no matrix for jobs without strategy")
} else {
assert.NotNil(t, matrix, "matrix should not be nil")
assert.Len(t, matrix, tt.wantLen, "matrix should have expected number of keys")
@@ -1130,11 +1140,9 @@ func TestJobMatrixValidation(t *testing.T) {
},
}
// Attempt to get matrix
matrix := job.Matrix()
// Should return nil due to validation error
assert.Nil(t, matrix, "matrix with nested map should return nil")
matrix, err := job.Matrix()
require.ErrorContains(t, err, `matrix key "config" has invalid nested object value`)
assert.Nil(t, matrix)
})
}