diff --git a/internal/randutil/randutil.go b/internal/randutil/randutil.go new file mode 100644 index 0000000000..5c642b8b13 --- /dev/null +++ b/internal/randutil/randutil.go @@ -0,0 +1,39 @@ +package randutil + +import ( + "math/rand" +) + +const ( + AsciiLower = "abcdefghijklmnopqrstuvwxyz" + AsciiUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + AsciiDigit = "0123456789" + AsciiSymbol = "!@#$%^&*()-_=+[]{}|;:',.<>/?`~" +) + +// String returns a (weak) random string of the length "n". When not +// passing a seqs it will generate the string based on ascii +// lower,upper,digits and a bunch of (ascii) symbols. +// +// With seqs passed it will select based on the provided +// sequences, i.e. String(10, AsciiDigits) will produce 10 +// random digits. +// +// Do not use to generate secrets. +func String(n int, seqs ...string) string { + if len(seqs) == 0 { + seqs = []string{AsciiLower, AsciiUpper, AsciiDigit, AsciiSymbol} + } + + var inp []byte + for _, s := range seqs { + inp = append(inp, []byte(s)...) + } + + b := make([]byte, n) + for i := range b { + // nolint:gosec + b[i] = inp[rand.Intn(len(inp))] + } + return string(b) +} diff --git a/internal/randutil/randutil_test.go b/internal/randutil/randutil_test.go new file mode 100644 index 0000000000..182706b62c --- /dev/null +++ b/internal/randutil/randutil_test.go @@ -0,0 +1,33 @@ +package randutil_test + +import ( + "testing" + "unicode" + + "github.com/stretchr/testify/assert" + + "github.com/osbuild/images/internal/randutil" +) + +func TestChoiceSimple(t *testing.T) { + n := 128 + + r1 := randutil.String(n) + r2 := randutil.String(n) + assert.NotEqual(t, r1, r2) + assert.Len(t, r1, n) + assert.Len(t, r2, n) + // by default we pick lower,upper,digit,symbols, ensure + // we do not stray from this range + defaultChars := randutil.AsciiLower + randutil.AsciiUpper + randutil.AsciiDigit + randutil.AsciiSymbol + for _, char := range r1 { + assert.Contains(t, []rune(defaultChars), char) + } +} + +func TestChoiceHonorsSeq(t *testing.T) { + result := randutil.String(128, randutil.AsciiDigit) + for _, char := range result { + assert.True(t, unicode.IsDigit(char)) + } +} diff --git a/pkg/distro/bootc/bootc_test.go b/pkg/distro/bootc/bootc_test.go index 275e18c39d..5870a9c72f 100644 --- a/pkg/distro/bootc/bootc_test.go +++ b/pkg/distro/bootc/bootc_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -12,6 +11,7 @@ import ( "github.com/osbuild/blueprint/pkg/blueprint" "github.com/osbuild/images/internal/common" + "github.com/osbuild/images/internal/randutil" "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/dnfjson" @@ -54,19 +54,9 @@ func TestManifestGenerationEmptyConfig(t *testing.T) { } } -func randomLetters(n int) string { - const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - - b := make([]byte, n) - for i := range b { - b[i] = letters[rand.Intn(len(letters))] - } - return string(b) -} - func getUserConfig() *blueprint.Blueprint { // add a user - pass := randomLetters(20) + pass := randutil.String(20) key := "ssh-ed25519 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" return &blueprint.Blueprint{ Customizations: &blueprint.Customizations{