All checks were successful
check / check (push) Successful in 1m8s
- Replace .golangci.yml with the canonical strict config (all linters enabled except the standard disable list; lll 88, funlen 80/50, cyclop 15, dupl 100; test files now linted) - Pin the Dockerfile lint stage to golangci/golangci-lint:v2.12.2 by tag and digest (Debian-based) - Fix all ~1550 findings surfaced by the new config: line wrapping, wsl_v5/nlreturn blank lines, noinlineerr splits, err113 sentinel errors, perfsprint/modernize rewrites, goconst constants, thelper, testifylint, noctx CommandContext, testpackage conversions, t.Parallel() where safe, and complexity/dupl helper extraction - Record the change and follow-up items in TODO.md
96 lines
2.8 KiB
Go
96 lines
2.8 KiB
Go
package vault_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.eeqj.de/sneak/secret/internal/secret"
|
|
"git.eeqj.de/sneak/secret/internal/vault"
|
|
"github.com/awnumar/memguard"
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestGetSecretVersionRejectsPathTraversal verifies that GetSecretVersion
|
|
// validates the secret name and rejects path traversal attempts.
|
|
// This is a regression test for https://git.eeqj.de/sneak/secret/issues/13
|
|
//
|
|
//nolint:paralleltest // t.Setenv in parent forbids parallel subtests
|
|
func TestGetSecretVersionRejectsPathTraversal(t *testing.T) {
|
|
t.Setenv(secret.EnvMnemonic, testMnemonic)
|
|
t.Setenv(secret.EnvUnlockPassphrase, testPassphrase)
|
|
|
|
fs := afero.NewMemMapFs()
|
|
|
|
vlt, err := vault.CreateVault(fs, testStateDir, testVaultName)
|
|
require.NoError(t, err)
|
|
|
|
// Add a legitimate secret so the vault is set up
|
|
value := memguard.NewBufferFromBytes([]byte("legitimate-secret"))
|
|
err = vlt.AddSecret("legit", value, false)
|
|
require.NoError(t, err)
|
|
|
|
// These names contain path traversal and should be rejected
|
|
maliciousNames := []string{
|
|
"../../../etc/passwd",
|
|
"..%2f..%2fetc/passwd",
|
|
".secret",
|
|
"../sibling-vault/secrets.d/target",
|
|
"foo/../bar",
|
|
"a/../../etc/passwd",
|
|
}
|
|
|
|
for _, name := range maliciousNames {
|
|
t.Run(name, func(t *testing.T) {
|
|
_, err := vlt.GetSecretVersion(name, "")
|
|
require.Error(t, err,
|
|
"GetSecretVersion should reject malicious name: %s", name)
|
|
require.Contains(t, err.Error(), "invalid secret name",
|
|
"error should indicate invalid name for: %s", name)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGetSecretRejectsPathTraversal verifies GetSecret (which calls
|
|
// GetSecretVersion) also rejects path traversal names.
|
|
func TestGetSecretRejectsPathTraversal(t *testing.T) {
|
|
t.Setenv(secret.EnvMnemonic, testMnemonic)
|
|
t.Setenv(secret.EnvUnlockPassphrase, testPassphrase)
|
|
|
|
fs := afero.NewMemMapFs()
|
|
|
|
vlt, err := vault.CreateVault(fs, testStateDir, testVaultName)
|
|
require.NoError(t, err)
|
|
|
|
_, err = vlt.GetSecret("../../../etc/passwd")
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid secret name")
|
|
}
|
|
|
|
// TestGetSecretObjectRejectsPathTraversal verifies GetSecretObject
|
|
// also validates names and rejects path traversal attempts.
|
|
//
|
|
//nolint:paralleltest // t.Setenv in parent forbids parallel subtests
|
|
func TestGetSecretObjectRejectsPathTraversal(t *testing.T) {
|
|
t.Setenv(secret.EnvMnemonic, testMnemonic)
|
|
t.Setenv(secret.EnvUnlockPassphrase, testPassphrase)
|
|
|
|
fs := afero.NewMemMapFs()
|
|
|
|
vlt, err := vault.CreateVault(fs, testStateDir, testVaultName)
|
|
require.NoError(t, err)
|
|
|
|
maliciousNames := []string{
|
|
"../../../etc/passwd",
|
|
"foo/../bar",
|
|
"a/../../etc/passwd",
|
|
}
|
|
|
|
for _, name := range maliciousNames {
|
|
t.Run(name, func(t *testing.T) {
|
|
_, err := vlt.GetSecretObject(name)
|
|
require.Error(t, err, "GetSecretObject should reject: %s", name)
|
|
require.Contains(t, err.Error(), "invalid secret name")
|
|
})
|
|
}
|
|
}
|