Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7b951a42b | ||
|
|
acb4b9cb6a |
@@ -214,23 +214,25 @@ func TestImportSecretVariousSizes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAddSecretBufferGrowth tests that our buffer growth strategy works correctly
|
// TestAddSecretAroundPageSize tests that secret add, which reads its input
|
||||||
|
// one memory page (usually 4 KiB) at a time, stores values just under, at and
|
||||||
|
// just over one and two pages unchanged.
|
||||||
//
|
//
|
||||||
//nolint:paralleltest // in parallel, size tests could exceed the memlock limit
|
//nolint:paralleltest // in parallel, size tests could exceed the memlock limit
|
||||||
func TestAddSecretBufferGrowth(t *testing.T) {
|
func TestAddSecretAroundPageSize(t *testing.T) {
|
||||||
// Test various sizes that should trigger buffer growth
|
// Sizes around one and two pages of 4 KiB, then larger ones up to 1 MiB
|
||||||
sizes := []int{
|
sizes := []int{
|
||||||
1, // Single byte
|
1, // Single byte
|
||||||
100, // Small
|
100, // Small
|
||||||
4095, // Just under initial 4KB
|
4095, // Just under 4KB
|
||||||
4096, // Exactly 4KB
|
4096, // Exactly 4KB
|
||||||
4097, // Just over 4KB
|
4097, // Just over 4KB
|
||||||
8191, // Just under 8KB (first double)
|
8191, // Just under 8KB
|
||||||
8192, // Exactly 8KB
|
8192, // Exactly 8KB
|
||||||
8193, // Just over 8KB
|
8193, // Just over 8KB
|
||||||
12288, // 12KB (should trigger second double)
|
12288, // 12KB
|
||||||
16384, // 16KB
|
16384, // 16KB
|
||||||
32768, // 32KB (after more doublings)
|
32768, // 32KB
|
||||||
65536, // 64KB
|
65536, // 64KB
|
||||||
131072, // 128KB
|
131072, // 128KB
|
||||||
524288, // 512KB
|
524288, // 512KB
|
||||||
@@ -391,8 +393,8 @@ func requireRefusedAtLockedMemoryLimit(
|
|||||||
// locked-memory limit (ulimit -l) lowered to 1 MiB, where memguard would crash
|
// locked-memory limit (ulimit -l) lowered to 1 MiB, where memguard would crash
|
||||||
// the process with a panic instead of returning an error. add must store the
|
// the process with a panic instead of returning an error. add must store the
|
||||||
// largest value that fits, which takes holding it in locked memory only once.
|
// largest value that fits, which takes holding it in locked memory only once.
|
||||||
// add, import and generate secret must refuse a value one byte larger, and one
|
// add, import and generate secret must refuse a value one byte larger with
|
||||||
// over 100 MB, with exit status 1 and an error saying why.
|
// exit status 1 and an error saying why.
|
||||||
func TestSecretsAtLockedMemoryLimit(t *testing.T) {
|
func TestSecretsAtLockedMemoryLimit(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -405,12 +407,6 @@ func TestSecretsAtLockedMemoryLimit(t *testing.T) {
|
|||||||
tooBigFile := filepath.Join(t.TempDir(), "too-big")
|
tooBigFile := filepath.Join(t.TempDir(), "too-big")
|
||||||
require.NoError(t, os.WriteFile(tooBigFile, make([]byte, fits+1), 0o600))
|
require.NoError(t, os.WriteFile(tooBigFile, make([]byte, fits+1), 0o600))
|
||||||
|
|
||||||
// Sparse, so that it takes no room on disk
|
|
||||||
overMaxSize, err := os.Create(filepath.Join(t.TempDir(), "over-max-size"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
t.Cleanup(func() { _ = overMaxSize.Close() })
|
|
||||||
require.NoError(t, overMaxSize.Truncate(maxSecretSize+1))
|
|
||||||
|
|
||||||
output, err := runAtLockedMemoryLimit(t, stateDir, limitKiB,
|
output, err := runAtLockedMemoryLimit(t, stateDir, limitKiB,
|
||||||
bytes.NewReader(make([]byte, fits)), "add", "fits")
|
bytes.NewReader(make([]byte, fits)), "add", "fits")
|
||||||
require.NoError(t, err, "the largest value that fits: %s", output)
|
require.NoError(t, err, "the largest value that fits: %s", output)
|
||||||
@@ -421,15 +417,6 @@ func TestSecretsAtLockedMemoryLimit(t *testing.T) {
|
|||||||
nil, "import", "too-big", "--source", tooBigFile)
|
nil, "import", "too-big", "--source", tooBigFile)
|
||||||
requireRefusedAtLockedMemoryLimit(t, stateDir, limitKiB, limitError,
|
requireRefusedAtLockedMemoryLimit(t, stateDir, limitKiB, limitError,
|
||||||
nil, "generate", "secret", "too-big", "--length", strconv.Itoa(fits+1))
|
nil, "generate", "secret", "too-big", "--length", strconv.Itoa(fits+1))
|
||||||
|
|
||||||
requireRefusedAtLockedMemoryLimit(t, stateDir, limitKiB,
|
|
||||||
errSecretTooLarge.Error(), overMaxSize, "add", "too-big")
|
|
||||||
requireRefusedAtLockedMemoryLimit(t, stateDir, limitKiB,
|
|
||||||
errSecretTooLarge.Error(), nil,
|
|
||||||
"import", "too-big", "--source", overMaxSize.Name())
|
|
||||||
requireRefusedAtLockedMemoryLimit(t, stateDir, limitKiB,
|
|
||||||
errSecretTooLarge.Error(), nil,
|
|
||||||
"generate", "secret", "too-big", "--length", strconv.Itoa(maxSecretSize+1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSecretsUnderSmallLockedMemoryLimits runs add, import and generate
|
// TestSecretsUnderSmallLockedMemoryLimits runs add, import and generate
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func VersionCommands(cli *Instance) *cobra.Command {
|
|||||||
promoteCmd := &cobra.Command{
|
promoteCmd := &cobra.Command{
|
||||||
Use: "promote <secret-name> <version>",
|
Use: "promote <secret-name> <version>",
|
||||||
Short: "Promote a specific version to current",
|
Short: "Promote a specific version to current",
|
||||||
Long: "Updates the current symlink to point to the specified " +
|
Long: "Rewrites the secret's current file to name the specified " +
|
||||||
"version. The versions' own times are left unchanged; secret " +
|
"version. The versions' own times are left unchanged; secret " +
|
||||||
"list then gives the time of the promote as the secret's last " +
|
"list then gives the time of the promote as the secret's last " +
|
||||||
"update.",
|
"update.",
|
||||||
@@ -293,7 +293,7 @@ func (cli *Instance) PromoteVersion(
|
|||||||
version, vault.ErrVersionNotFound, secretName)
|
version, vault.ErrVersionNotFound, secretName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the current symlink using the proper function
|
// Rewrite the secret's current file to name the version
|
||||||
err = secret.SetCurrentVersion(cli.fs, secretDir, version)
|
err = secret.SetCurrentVersion(cli.fs, secretDir, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update current version: %w", err)
|
return fmt.Errorf("failed to update current version: %w", err)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
// - TestListVersionsNonExistentSecret: Tests error handling for missing secrets
|
// - TestListVersionsNonExistentSecret: Tests error handling for missing secrets
|
||||||
// - TestPromoteVersionCommand: Tests `secret version promote` command
|
// - TestPromoteVersionCommand: Tests `secret version promote` command
|
||||||
// - TestPromoteNonExistentVersion: Tests error handling for invalid promotion
|
// - TestPromoteNonExistentVersion: Tests error handling for invalid promotion
|
||||||
|
// - TestPromoteHelpSaysCurrentFileIsRewritten: Tests `secret version promote
|
||||||
|
// --help` text
|
||||||
// - TestGetSecretWithVersion: Tests `secret get --version` flag functionality
|
// - TestGetSecretWithVersion: Tests `secret get --version` flag functionality
|
||||||
// - TestGetSecretWritesBinaryValue: Tests `secret get` output of binary values
|
// - TestGetSecretWritesBinaryValue: Tests `secret get` output of binary values
|
||||||
// - TestGetSecretReturnsWriteError: Tests `secret get` when stdout fails
|
// - TestGetSecretReturnsWriteError: Tests `secret get` when stdout fails
|
||||||
@@ -270,6 +272,23 @@ func TestPromoteNonExistentVersion(t *testing.T) {
|
|||||||
require.ErrorIs(t, err, vault.ErrVersionNotFound)
|
require.ErrorIs(t, err, vault.ErrVersionNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPromoteHelpSaysCurrentFileIsRewritten is a regression test for
|
||||||
|
// https://git.eeqj.de/sneak/secret/issues/153: `secret version promote
|
||||||
|
// --help` said it updates a symlink, but promote rewrites the secret's
|
||||||
|
// `current` file, which is a plain file.
|
||||||
|
//
|
||||||
|
//nolint:paralleltest // executes the CLI in-process and sets the environment
|
||||||
|
func TestPromoteHelpSaysCurrentFileIsRewritten(t *testing.T) {
|
||||||
|
env := map[string]string{secret.EnvStateDir: t.TempDir()}
|
||||||
|
|
||||||
|
output, err := ExecuteCommandInProcess(
|
||||||
|
[]string{"version", "promote", "--help"}, "", env)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NotContains(t, output, "symlink")
|
||||||
|
assert.Contains(t, output, "current file")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetSecretWithVersion(t *testing.T) {
|
func TestGetSecretWithVersion(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user