From 5ac0da65ee1991783219818ca46734f8a804e20d Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 5 Oct 2026 23:06:06 +0000 Subject: [PATCH] Test only small secrets in the size tests (closes #52) The size tests for secret add, secret import and the stdin buffer no longer store 2 MB to 101 MB secrets; the largest is 1 MiB. The cases checking that a secret over the 100 MB limit is rejected are deleted and not replaced. The limit itself is unchanged. With nothing large left, the helper that skipped a case for want of locked memory is gone. Model: opus-5-5 --- TODO.md | 6 ++ internal/cli/secrets_size_test.go | 121 ++++-------------------------- 2 files changed, 19 insertions(+), 108 deletions(-) diff --git a/TODO.md b/TODO.md index ee18d34..02f2cf9 100644 --- a/TODO.md +++ b/TODO.md @@ -18,6 +18,12 @@ https://git.eeqj.de/sneak/secret/milestone/12 # Completed Steps +- 2026-10-05: No test stores a secret larger than 1 MiB + (https://git.eeqj.de/sneak/secret/issues/52). The size tests for `secret add`, + `secret import` and the stdin buffer no longer try 2 MB, 10 MB, 99 MB, 100 MB + or 101 MB secrets, and nothing tests that a secret over the 100 MB limit is + rejected; the limit itself is unchanged. With nothing large left, the size + tests no longer skip a case for want of locked memory. - 2026-10-05: The Go module path is `sneak.berlin/go/secret`, as `REPO_POLICIES.md` requires, not `git.eeqj.de/sneak/secret` (https://git.eeqj.de/sneak/secret/issues/43). Every import uses it, as do the diff --git a/internal/cli/secrets_size_test.go b/internal/cli/secrets_size_test.go index b2ad35a..ae707c4 100644 --- a/internal/cli/secrets_size_test.go +++ b/internal/cli/secrets_size_test.go @@ -14,7 +14,6 @@ import ( "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/sys/unix" "sneak.berlin/go/secret/internal/vault" "sneak.berlin/go/secret/pkg/agehd" ) @@ -22,45 +21,6 @@ import ( // testVaultName is the vault name used by the size tests. const testVaultName = "test-vault" -// lockedBytesPerSecretByte bounds the locked memory that storing a secret -// holds at once: the buffers it is read into reach up to 1.5 times its -// size, and they are then copied into one more buffer of its size. -const lockedBytesPerSecretByte = 3 - -// skipIfLockedMemoryTooLow skips the test when this process cannot lock -// the memory a secret of size bytes needs, found by locking a buffer of -// that size and releasing it. memguard panics, ending the whole test run, -// when it cannot lock a buffer, and a plain `docker build .` runs the -// tests under an 8 MiB locked-memory limit (RLIMIT_MEMLOCK). A process -// allowed to lock past that limit runs every case. -func skipIfLockedMemoryTooLow(t *testing.T, size int) { - t.Helper() - - need := lockedBytesPerSecretByte * size - - buf, err := unix.Mmap(-1, 0, need, - unix.PROT_READ|unix.PROT_WRITE, unix.MAP_PRIVATE|unix.MAP_ANON) - require.NoError(t, err) - - lockErr := unix.Mlock(buf) - - // Unmapping the buffer also unlocks it. - err = unix.Munmap(buf) - require.NoError(t, err) - - if lockErr != nil { - var limit unix.Rlimit - - err = unix.Getrlimit(unix.RLIMIT_MEMLOCK, &limit) - require.NoError(t, err) - - t.Skipf("a %d-byte secret needs up to %d bytes of locked memory, "+ - "which could not be locked under the locked-memory limit "+ - "(RLIMIT_MEMLOCK) of %d bytes: %v", - size, need, limit.Cur, lockErr) - } -} - // newSizeTestVault creates an in-memory vault unlocked with the test // mnemonic and returns the filesystem and vault. // @@ -93,10 +53,9 @@ func newSizeTestVault(t *testing.T) (afero.Fs, *vault.Vault) { } // runAddSecretSizeCase adds a secret of the given size through stdin and -// verifies the outcome: wantErr, or the secret stored when wantErr is nil. -func runAddSecretSizeCase(t *testing.T, size int, wantErr error) { +// verifies that it is stored. +func runAddSecretSizeCase(t *testing.T, size int) { t.Helper() - skipIfLockedMemoryTooLow(t, size) fs, vlt := newSizeTestVault(t) @@ -127,13 +86,6 @@ func runAddSecretSizeCase(t *testing.T, size int, wantErr error) { // Test adding the secret secretName := fmt.Sprintf("test-secret-%d", size) err = cli.AddSecret(secretName, false) - - if wantErr != nil { - require.ErrorIs(t, err, wantErr) - - return - } - require.NoError(t, err) // Verify the secret was stored correctly @@ -147,10 +99,9 @@ func runAddSecretSizeCase(t *testing.T, size int, wantErr error) { } // runImportSecretSizeCase imports a secret file of the given size and -// verifies the outcome: wantErr, or the secret stored when wantErr is nil. -func runImportSecretSizeCase(t *testing.T, size int, wantErr error) { +// verifies that it is stored. +func runImportSecretSizeCase(t *testing.T, size int) { t.Helper() - skipIfLockedMemoryTooLow(t, size) fs, vlt := newSizeTestVault(t) @@ -179,13 +130,6 @@ func runImportSecretSizeCase(t *testing.T, size int, wantErr error) { // Test importing the secret secretName := fmt.Sprintf("imported-secret-%d", size) err = cli.ImportSecret(cmd, secretName, testFile, false) - - if wantErr != nil { - require.ErrorIs(t, err, wantErr) - - return - } - require.NoError(t, err) // Verify the secret was stored correctly @@ -200,12 +144,11 @@ func runImportSecretSizeCase(t *testing.T, size int, wantErr error) { // TestAddSecretVariousSizes tests adding secrets of various sizes through stdin // -//nolint:paralleltest // together the subtests lock more than the memlock limit +//nolint:paralleltest // in parallel, size tests could exceed the memlock limit func TestAddSecretVariousSizes(t *testing.T) { tests := []struct { - name string - size int - wantErr error + name string + size int }{ { name: "1KB secret", @@ -223,40 +166,22 @@ func TestAddSecretVariousSizes(t *testing.T) { name: "1MB secret", size: 1024 * 1024, }, - { - name: "10MB secret", - size: 10 * 1024 * 1024, - }, - { - name: "99MB secret", - size: 99 * 1024 * 1024, - }, - { - name: "100MB secret minus 1 byte", - size: 100*1024*1024 - 1, - }, - { - name: "101MB secret - should fail", - size: 101 * 1024 * 1024, - wantErr: errSecretTooLarge, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - runAddSecretSizeCase(t, tt.size, tt.wantErr) + runAddSecretSizeCase(t, tt.size) }) } } // TestImportSecretVariousSizes tests importing secrets of various sizes from files // -//nolint:paralleltest // together the subtests lock more than the memlock limit +//nolint:paralleltest // in parallel, size tests could exceed the memlock limit func TestImportSecretVariousSizes(t *testing.T) { tests := []struct { - name string - size int - wantErr error + name string + size int }{ { name: "1KB file", @@ -274,35 +199,18 @@ func TestImportSecretVariousSizes(t *testing.T) { name: "1MB file", size: 1024 * 1024, }, - { - name: "10MB file", - size: 10 * 1024 * 1024, - }, - { - name: "99MB file", - size: 99 * 1024 * 1024, - }, - { - name: "100MB file", - size: 100 * 1024 * 1024, - }, - { - name: "101MB file - should fail", - size: 101 * 1024 * 1024, - wantErr: errSecretTooLarge, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - runImportSecretSizeCase(t, tt.size, tt.wantErr) + runImportSecretSizeCase(t, tt.size) }) } } // TestAddSecretBufferGrowth tests that our buffer growth strategy works correctly // -//nolint:paralleltest // together the subtests lock more than the memlock limit +//nolint:paralleltest // in parallel, size tests could exceed the memlock limit func TestAddSecretBufferGrowth(t *testing.T) { // Test various sizes that should trigger buffer growth sizes := []int{ @@ -321,13 +229,10 @@ func TestAddSecretBufferGrowth(t *testing.T) { 131072, // 128KB 524288, // 512KB 1048576, // 1MB - 2097152, // 2MB } for _, size := range sizes { t.Run(fmt.Sprintf("size_%d", size), func(t *testing.T) { - skipIfLockedMemoryTooLow(t, size) - fs, vlt := newSizeTestVault(t) // Create test data of exactly the specified size -- 2.54.0