mirror of
https://gitea.com/gitea/runner.git
synced 2026-08-26 13:57:46 +00:00
0712b2a7a1
A secret in a matrix value reached the log in the clear:
```yaml
strategy:
matrix:
include: "${{ github.token }}"
```
Chasing that one route is pointless, so this masks every sink a secret leaves a job by: the uploaded log rows and the on-disk `job.log`, both through one choke point in `appendLogRow`; the runner's own log, which is where planning errors like that one land with no job logger in reach; the job logger's stdout under debug logging; job summaries; job outputs; and the job name that becomes a container name.
Values the runner knows but the job never declared, the proxy password and the task token, are hidden the same way. Masks apply longest first, since `strings.Replacer` matches in argument order and one secret prefixing another would otherwise mask the prefix and print the rest.
### What changes for users
An output whose value carries a secret is skipped with a warning instead of sent, matching GitHub. Output that showed a secret now shows `***`. `ACTIONS_STEP_DEBUG` and `ACTIONS_RUNNER_DEBUG` are never masked, also matching GitHub, so an output of `true` still reaches the jobs that need it.
Each fix has a test that fails without it.
Reviewed-on: https://gitea.com/gitea/runner/pulls/1188
Reviewed-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
73 lines
2.0 KiB
Go
73 lines
2.0 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"gitea.com/gitea/runner/internal/pkg/config"
|
|
"gitea.com/gitea/runner/internal/pkg/report"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestResolveLabels(t *testing.T) {
|
|
var (
|
|
cfgLabels = []string{"cfg:host"}
|
|
regLabels = []string{"reg:host"}
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
arg string
|
|
cfg []string
|
|
reg []string
|
|
want []string
|
|
}{
|
|
{"flag wins", "flag:host,other", cfgLabels, regLabels, []string{"flag:host", "other"}},
|
|
{"config wins over registration", "", cfgLabels, regLabels, cfgLabels},
|
|
{"registration is the fallback", "", nil, regLabels, regLabels},
|
|
{"blank flag is ignored", " , ", cfgLabels, regLabels, cfgLabels},
|
|
{"nothing configured", "", nil, nil, nil},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
require.Equal(t, tt.want, resolveLabels(tt.arg, tt.cfg, tt.reg))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetDockerSocketPathUsesConfigAndEnvironment(t *testing.T) {
|
|
got, err := getDockerSocketPath("tcp://docker.example:2376")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "tcp://docker.example:2376", got)
|
|
|
|
t.Setenv("DOCKER_HOST", "unix:///tmp/docker.sock")
|
|
got, err = getDockerSocketPath("-")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "unix:///tmp/docker.sock", got)
|
|
}
|
|
|
|
func TestInitLoggingSetsLevelAndCaller(t *testing.T) {
|
|
oldLevel := log.GetLevel()
|
|
oldReportCaller := log.StandardLogger().ReportCaller
|
|
t.Cleanup(func() {
|
|
log.SetLevel(oldLevel)
|
|
log.SetReportCaller(oldReportCaller)
|
|
})
|
|
|
|
oldFormatter := log.StandardLogger().Formatter
|
|
t.Cleanup(func() { log.SetFormatter(oldFormatter) })
|
|
|
|
cfg := &config.Config{}
|
|
cfg.Log.Level = "debug"
|
|
initLogging(cfg)
|
|
|
|
require.Equal(t, log.DebugLevel, log.GetLevel())
|
|
require.True(t, log.StandardLogger().ReportCaller)
|
|
// act plans a job on this logger, so a live task's secrets have to be masked out of it
|
|
require.IsType(t, report.MaskingFormatter(nil), log.StandardLogger().Formatter)
|
|
}
|