mirror of
https://github.com/coder/coder.git
synced 2026-06-03 04:58:23 +00:00
c650aabbef
My agent added `//nolint:testpackage` to a test file on one of my PRs. Again. This PR cleans it up across the entire repo and updates the in-repo conventions so future agents stop doing it. The repo already has a precedent for white-box tests that need to touch unexported symbols: `*_internal_test.go` (145+ existing files). The `testpackage` linter's default `skip-regexp` exempts that filename suffix, so the `//nolint:testpackage` directive is unnecessary in every case where someone reached for it. This PR renames 51 such files to `*_internal_test.go` via `git mv` so blame and history follow, and strips the dead directive from 2 files that were already correctly named (`coderd/oauth2provider/authorize_internal_test.go`, `coderd/x/chatd/advisor_internal_test.go`). `.claude/docs/TESTING.md` now documents the rule explicitly under *Test Package Naming*, which is imported into the root `AGENTS.md` via `@.claude/docs/TESTING.md`. The rule: prefer `package foo_test`; if you need internal access, rename the file to `*_internal_test.go` rather than adding a nolint directive.
186 lines
5.3 KiB
Go
186 lines
5.3 KiB
Go
package agent
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"cdr.dev/slog/v3/sloggers/slogtest"
|
|
"github.com/coder/coder/v2/codersdk/agentsdk"
|
|
"github.com/coder/coder/v2/testutil"
|
|
)
|
|
|
|
func TestWriteSecretFiles(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("AbsolutePath", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "/etc/myapp/config.json", Value: []byte(`{"key":"val"}`)},
|
|
})
|
|
|
|
content, err := afero.ReadFile(fs, "/etc/myapp/config.json")
|
|
require.NoError(t, err)
|
|
require.Equal(t, `{"key":"val"}`, string(content))
|
|
|
|
fi, err := fs.Stat("/etc/myapp/config.json")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0o600, int(fi.Mode().Perm()))
|
|
|
|
di, err := fs.Stat("/etc/myapp")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0o700, int(di.Mode().Perm()))
|
|
})
|
|
|
|
t.Run("TildePath", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "~/.ssh/id_rsa", Value: []byte("private-key")},
|
|
})
|
|
|
|
content, err := afero.ReadFile(fs, "/home/coder/.ssh/id_rsa")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "private-key", string(content))
|
|
|
|
fi, err := fs.Stat("/home/coder/.ssh/id_rsa")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0o600, int(fi.Mode().Perm()))
|
|
|
|
di, err := fs.Stat("/home/coder/.ssh")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0o700, int(di.Mode().Perm()))
|
|
})
|
|
|
|
t.Run("TildePathNoHomeDir", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "~/.config/token", Value: []byte("token")},
|
|
})
|
|
|
|
empty, err := afero.IsEmpty(fs, "/")
|
|
require.NoError(t, err)
|
|
require.True(t, empty, "no file should be written when home dir is unknown")
|
|
})
|
|
|
|
t.Run("EmptyFilePathSkipped", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", []agentsdk.WorkspaceSecret{
|
|
{EnvName: "MY_TOKEN", Value: []byte("token")},
|
|
})
|
|
|
|
// Nothing should be written.
|
|
empty, err := afero.IsEmpty(fs, "/")
|
|
require.NoError(t, err)
|
|
require.True(t, empty)
|
|
})
|
|
|
|
t.Run("MultipleSecrets", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "/etc/secret-a", Value: []byte("aaa")},
|
|
{FilePath: "~/.secret-b", Value: []byte("bbb")},
|
|
{EnvName: "SKIP_ME", Value: []byte("env-only")},
|
|
})
|
|
|
|
a, err := afero.ReadFile(fs, "/etc/secret-a")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "aaa", string(a))
|
|
|
|
b, err := afero.ReadFile(fs, "/home/coder/.secret-b")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "bbb", string(b))
|
|
})
|
|
|
|
t.Run("OverwritesExisting", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
require.NoError(t, afero.WriteFile(fs, "/secret", []byte("old"), 0o644))
|
|
|
|
writeSecretFiles(ctx, logger, fs, "", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "/secret", Value: []byte("new")},
|
|
})
|
|
|
|
content, err := afero.ReadFile(fs, "/secret")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "new", string(content))
|
|
|
|
// Pre-existing file permissions are intentionally preserved.
|
|
// The file may not have been created by us (e.g. a template
|
|
// provisioned it), so we should not alter its permissions.
|
|
fi, err := fs.Stat("/secret")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0o644, int(fi.Mode().Perm()))
|
|
})
|
|
|
|
t.Run("PathCollisionAfterTildeResolution", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
// "~/collide" and "/home/coder/collide" resolve to the same
|
|
// absolute path. The later secret should win.
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "~/collide", Value: []byte("first")},
|
|
{FilePath: "/home/coder/collide", Value: []byte("second")},
|
|
})
|
|
|
|
content, err := afero.ReadFile(fs, "/home/coder/collide")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "second", string(content))
|
|
})
|
|
|
|
t.Run("EmptySlice", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
writeSecretFiles(ctx, logger, fs, "/home/coder", nil)
|
|
|
|
empty, err := afero.IsEmpty(fs, "/")
|
|
require.NoError(t, err)
|
|
require.True(t, empty)
|
|
})
|
|
|
|
t.Run("BinaryContent", func(t *testing.T) {
|
|
t.Parallel()
|
|
fs := afero.NewMemMapFs()
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
logger := slogtest.Make(t, nil)
|
|
|
|
binaryData := []byte{0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD}
|
|
writeSecretFiles(ctx, logger, fs, "", []agentsdk.WorkspaceSecret{
|
|
{FilePath: "/cert.der", Value: binaryData},
|
|
})
|
|
|
|
content, err := afero.ReadFile(fs, "/cert.der")
|
|
require.NoError(t, err)
|
|
require.Equal(t, binaryData, content)
|
|
})
|
|
}
|