diff --git a/cmd/root.go b/cmd/root.go index 67c3ed41e..79bc453cd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -29,7 +29,6 @@ import ( "opendev.org/airship/airshipctl/cmd/document" "opendev.org/airship/airshipctl/cmd/phase" "opendev.org/airship/airshipctl/cmd/plan" - "opendev.org/airship/airshipctl/cmd/secret" cfg "opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipctl/pkg/log" ) @@ -82,7 +81,6 @@ func AddDefaultAirshipCTLCommands(cmd *cobra.Command, factory cfg.Factory) *cobr cmd.AddCommand(completion.NewCompletionCommand()) cmd.AddCommand(document.NewDocumentCommand(factory)) cmd.AddCommand(config.NewConfigCommand(factory)) - cmd.AddCommand(secret.NewSecretCommand()) cmd.AddCommand(phase.NewPhaseCommand(factory)) cmd.AddCommand(plan.NewPlanCommand(factory)) cmd.AddCommand(NewVersionCommand()) diff --git a/cmd/secret/generate/encryptionkey/encryptionkey.go b/cmd/secret/generate/encryptionkey/encryptionkey.go deleted file mode 100644 index 7bafa001b..000000000 --- a/cmd/secret/generate/encryptionkey/encryptionkey.go +++ /dev/null @@ -1,69 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package encryptionkey - -import ( - "fmt" - - "github.com/spf13/cobra" - - "opendev.org/airship/airshipctl/pkg/errors" - "opendev.org/airship/airshipctl/pkg/secret/generate" -) - -const ( - cmdLong = ` -Generates a secure encryption key or passphrase. - -If regex arguments are passed the encryption key created would match the regular expression passed. -` - - cmdExample = ` -Generates a secure encryption key or passphrase. -# airshipctl secret generate encryptionkey - -Generates a secure encryption key or passphrase matching the regular expression -# airshipctl secret generate encryptionkey --regex Xy[a-c][0-9]!a* -` -) - -// NewGenerateEncryptionKeyCommand creates a new command for generating secret information -func NewGenerateEncryptionKeyCommand() *cobra.Command { - var regex string - var limit int - - encryptionKeyCmd := &cobra.Command{ - Use: "encryptionkey", - Short: "Airshipctl command to generate a secure encryption key or passphrase", - Long: cmdLong[1:], - Example: cmdExample, - RunE: func(cmd *cobra.Command, args []string) error { - if cmd.Flags().Changed("limit") && !cmd.Flags().Changed("regex") { - return fmt.Errorf("required Regex flag with limit option") - } - if cmd.Flags().Changed("regex") && cmd.Flags().Changed("limit") { - return errors.ErrNotImplemented{What: "Regex support not implemented yet!"} - } - engine := generate.NewEncryptionKeyEngine(nil) - encryptionKey := engine.GenerateEncryptionKey() - fmt.Fprintln(cmd.OutOrStdout(), encryptionKey) - return nil - }, - } - - encryptionKeyCmd.Flags().StringVar(®ex, "regex", "", "regular expression string") - encryptionKeyCmd.Flags().IntVar(&limit, "limit", 5, "limit number of characters for + or * regex") - return encryptionKeyCmd -} diff --git a/cmd/secret/generate/encryptionkey/encryptionkey_test.go b/cmd/secret/generate/encryptionkey/encryptionkey_test.go deleted file mode 100644 index 090a278b4..000000000 --- a/cmd/secret/generate/encryptionkey/encryptionkey_test.go +++ /dev/null @@ -1,43 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package encryptionkey_test - -import ( - "fmt" - "testing" - - "opendev.org/airship/airshipctl/cmd/secret/generate/encryptionkey" - "opendev.org/airship/airshipctl/testutil" -) - -func TestGenerateEncryptionKey(t *testing.T) { - cmdTests := []*testutil.CmdTest{ - { - Name: "generate-encryptionkey-cmd-with-help", - CmdLine: "--help", - Cmd: encryptionkey.NewGenerateEncryptionKeyCommand(), - }, - { - Name: "generate-encryptionkey-cmd-error", - CmdLine: "--limit 10", - Error: fmt.Errorf("required Regex flag with limit option"), - Cmd: encryptionkey.NewGenerateEncryptionKeyCommand(), - }, - } - - for _, tt := range cmdTests { - testutil.RunTest(t, tt) - } -} diff --git a/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-error.golden b/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-error.golden deleted file mode 100644 index 1c20da5df..000000000 --- a/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-error.golden +++ /dev/null @@ -1,18 +0,0 @@ -Error: required Regex flag with limit option -Usage: - encryptionkey [flags] - -Examples: - -Generates a secure encryption key or passphrase. -# airshipctl secret generate encryptionkey - -Generates a secure encryption key or passphrase matching the regular expression -# airshipctl secret generate encryptionkey --regex Xy[a-c][0-9]!a* - - -Flags: - -h, --help help for encryptionkey - --limit int limit number of characters for + or * regex (default 5) - --regex string regular expression string - diff --git a/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden b/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden deleted file mode 100644 index b71ffc566..000000000 --- a/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden +++ /dev/null @@ -1,20 +0,0 @@ -Generates a secure encryption key or passphrase. - -If regex arguments are passed the encryption key created would match the regular expression passed. - -Usage: - encryptionkey [flags] - -Examples: - -Generates a secure encryption key or passphrase. -# airshipctl secret generate encryptionkey - -Generates a secure encryption key or passphrase matching the regular expression -# airshipctl secret generate encryptionkey --regex Xy[a-c][0-9]!a* - - -Flags: - -h, --help help for encryptionkey - --limit int limit number of characters for + or * regex (default 5) - --regex string regular expression string diff --git a/cmd/secret/generate/generate.go b/cmd/secret/generate/generate.go deleted file mode 100644 index 2395a9fe5..000000000 --- a/cmd/secret/generate/generate.go +++ /dev/null @@ -1,34 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package generate - -import ( - "github.com/spf13/cobra" - - "opendev.org/airship/airshipctl/cmd/secret/generate/encryptionkey" -) - -// NewGenerateCommand creates a new command for generating secret information -func NewGenerateCommand() *cobra.Command { - generateRootCmd := &cobra.Command{ - Use: "generate", - // TODO(howell): Make this more expressive - Short: "Airshipctl command to generate secrets", - } - - generateRootCmd.AddCommand(encryptionkey.NewGenerateEncryptionKeyCommand()) - - return generateRootCmd -} diff --git a/cmd/secret/secret.go b/cmd/secret/secret.go deleted file mode 100644 index f8b89989a..000000000 --- a/cmd/secret/secret.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package secret - -import ( - "github.com/spf13/cobra" - - "opendev.org/airship/airshipctl/cmd/secret/generate" -) - -// NewSecretCommand creates a new command for managing airshipctl secrets -func NewSecretCommand() *cobra.Command { - secretRootCmd := &cobra.Command{ - Use: "secret", - // TODO(howell): Make this more expressive - Short: "Airshipctl command to manage secrets", - Long: "Commands and sub-commnads defined can be used to manage secrets.", - } - - secretRootCmd.AddCommand(generate.NewGenerateCommand()) - - return secretRootCmd -} diff --git a/cmd/testdata/TestRootGoldenOutput/rootCmd-with-default-subcommands.golden b/cmd/testdata/TestRootGoldenOutput/rootCmd-with-default-subcommands.golden index 0370e08c5..a950bdebc 100644 --- a/cmd/testdata/TestRootGoldenOutput/rootCmd-with-default-subcommands.golden +++ b/cmd/testdata/TestRootGoldenOutput/rootCmd-with-default-subcommands.golden @@ -14,7 +14,6 @@ Available Commands: help Help about any command phase Airshipctl command to manage phases plan Airshipctl command to manage plans - secret Airshipctl command to manage secrets version Airshipctl command to display the current version number Flags: diff --git a/docs/source/cli/airshipctl.rst b/docs/source/cli/airshipctl.rst index a2a365d2f..6ec398c86 100644 --- a/docs/source/cli/airshipctl.rst +++ b/docs/source/cli/airshipctl.rst @@ -33,6 +33,5 @@ SEE ALSO * :ref:`airshipctl document ` - Airshipctl command to manage site manifest documents * :ref:`airshipctl phase ` - Airshipctl command to manage phases * :ref:`airshipctl plan ` - Airshipctl command to manage plans -* :ref:`airshipctl secret ` - Airshipctl command to manage secrets * :ref:`airshipctl version ` - Airshipctl command to display the current version number diff --git a/docs/source/cli/index.rst b/docs/source/cli/index.rst index fef72a2bf..4abb27dde 100644 --- a/docs/source/cli/index.rst +++ b/docs/source/cli/index.rst @@ -14,5 +14,4 @@ Commands help/index phase/index plan/index - secret/index version/index diff --git a/pkg/secret/generate/encryptionkey.go b/pkg/secret/generate/encryptionkey.go deleted file mode 100644 index 574d0d86f..000000000 --- a/pkg/secret/generate/encryptionkey.go +++ /dev/null @@ -1,112 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package generate - -import ( - "math/rand" - "strings" -) - -const ( - defaultLength = 24 - - asciiLowers = "abcdefghijklmnopqrstuvwxyz" - asciiUppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - asciiNumbers = "0123456789" - asciiSymbols = "@#&-+=?" -) - -var ( - // pool is the complete collection of characters that can be used for a - // passphrase - pool []byte -) - -func init() { - pool = append(pool, []byte(asciiLowers)...) - pool = append(pool, []byte(asciiUppers)...) - pool = append(pool, []byte(asciiNumbers)...) - pool = append(pool, []byte(asciiSymbols)...) -} - -// EncryptionKeyEngine is used to generate secure random passphrases -type EncryptionKeyEngine struct { - rng *rand.Rand - pool []byte -} - -// NewEncryptionKeyEngine creates an PassphraseEngine using src. If src is nil, -// the returned PassphraseEngine will use the default Source -func NewEncryptionKeyEngine(src rand.Source) *EncryptionKeyEngine { - if src == nil { - src = &Source{} - } - return &EncryptionKeyEngine{ - rng: rand.New(src), //nolint:gosec - pool: pool, - } -} - -// GenerateEncryptionKey returns a secure random string of length 24, -// containing at least one of each from the following sets: -// [0-9] -// [a-z] -// [A-Z] -// [@#&-+=?] -func (e *EncryptionKeyEngine) GenerateEncryptionKey() string { - return e.GenerateEncryptionKeyN(defaultLength) -} - -// GenerateEncryptionKeyN returns a secure random string containing at least -// one of each from the following sets. Its length will be max(length, 24) -// [0-9] -// [a-z] -// [A-Z] -// [@#&-+=?] -func (e *EncryptionKeyEngine) GenerateEncryptionKeyN(length int) string { - if length < defaultLength { - length = defaultLength - } - var encryptionkey string - for !e.isValidEncryptionKey(encryptionkey) { - var sb strings.Builder - for i := 0; i < length; i++ { - randIndex := e.rng.Intn(len(e.pool)) - randChar := e.pool[randIndex] - sb.WriteString(string(randChar)) - } - encryptionkey = sb.String() - } - return encryptionkey -} - -func (e *EncryptionKeyEngine) isValidEncryptionKey(encryptionkey string) bool { - if len(encryptionkey) < defaultLength { - return false - } - - charSets := []string{ - asciiLowers, - asciiUppers, - asciiNumbers, - asciiSymbols, - } - for _, charSet := range charSets { - if !strings.ContainsAny(encryptionkey, charSet) { - return false - } - } - return true -} diff --git a/pkg/secret/generate/encryptionkey_test.go b/pkg/secret/generate/encryptionkey_test.go deleted file mode 100644 index 1ab66de2b..000000000 --- a/pkg/secret/generate/encryptionkey_test.go +++ /dev/null @@ -1,115 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package generate_test - -import ( - "math/rand" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "opendev.org/airship/airshipctl/pkg/secret/generate" -) - -const ( - asciiLowers = "abcdefghijklmnopqrstuvwxyz" - asciiUppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - asciiNumbers = "0123456789" - asciiSymbols = "@#&-+=?" - - defaultLength = 24 -) - -func TestDeterministicGenerateValidEncryptionKey(t *testing.T) { - assert := assert.New(t) - testSource := rand.NewSource(42) - engine := generate.NewEncryptionKeyEngine(testSource) - - // pre-calculated for rand.NewSource(42) - expectedEncryptionKey := []string{ - "erx&97vfqd7LN3HJ?t@oPhds", - "##Xeuvf5Njy@hNWSaRoleFkf", - "jB=kirg7acIt-=fx1Fb-tZ+7", - "eOS#W8yoAljSThPL2oT&aUZu", - "vlaQqKr-jXSCJfXYnvGik3b1", - "rBKtHZkOmFUM75?c2UWiZjdh", - "9g?QV?w6BCWN2EKAc+dZ-Jun", - "X@IIyqAg7Mz@Wm8eRE6KMEf3", - "7JpQkLd3ufhj4bLB8S=ipjNP", - "XC?bDaHTa3mrBYLMG@#B=Q0B", - } - - for i, expected := range expectedEncryptionKey { - actual := engine.GenerateEncryptionKey() - assert.Equal(expected, actual, "Test #%d failed", i) - } -} - -func TestNondeterministicGenerateValidEncryptionKey(t *testing.T) { - assert := assert.New(t) - // Due to the nondeterminism of random number generators, this - // functionality is impossible to fully test. Let's just generate - // enough passphrases that we can be confident in the randomness. - // Fortunately, Go is pretty fast, so we can do upward of 10,000 of - // these without slowing down the test too much - charSets := []string{ - asciiLowers, - asciiUppers, - asciiNumbers, - asciiSymbols, - } - - engine := generate.NewEncryptionKeyEngine(nil) - for i := 0; i < 10000; i++ { - passphrase := engine.GenerateEncryptionKey() - assert.Truef(len(passphrase) >= defaultLength, - "%s does not meet the length requirement", passphrase) - - for _, charSet := range charSets { - assert.Truef(strings.ContainsAny(passphrase, charSet), - "%s does not contain any characters from [%s]", - passphrase, charSet) - } - } -} - -func TestGenerateValidEncryptionKeyN(t *testing.T) { - assert := assert.New(t) - testSource := rand.NewSource(42) - engine := generate.NewEncryptionKeyEngine(testSource) - tests := []struct { - inputLegth int - expectedLength int - }{ - { - inputLegth: 10, - expectedLength: defaultLength, - }, - { - inputLegth: -5, - expectedLength: defaultLength, - }, - { - inputLegth: 30, - expectedLength: 30, - }, - } - - for _, tt := range tests { - passphrase := engine.GenerateEncryptionKeyN(tt.inputLegth) - assert.Len(passphrase, tt.expectedLength) - } -} diff --git a/pkg/secret/generate/rngsource.go b/pkg/secret/generate/rngsource.go deleted file mode 100644 index b2fecaf6b..000000000 --- a/pkg/secret/generate/rngsource.go +++ /dev/null @@ -1,47 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package generate - -import ( - crypto "crypto/rand" - "encoding/binary" - "math/rand" - - "opendev.org/airship/airshipctl/pkg/log" -) - -// Source implements rand.Source -type Source struct{} - -var _ rand.Source = &Source{} - -// Uint64 returns a secure random uint64 in the range [0, 1<<64]. It will fail -// if an error is returned from the system's secure random number generator -func (s *Source) Uint64() uint64 { - var value uint64 - err := binary.Read(crypto.Reader, binary.BigEndian, &value) - if err != nil { - log.Fatalf("could not generate a random number: %s", err.Error()) - } - return value -} - -// Int63 returns a secure random int64 in the range [0, 1<<63] -func (s *Source) Int63() int64 { - return int64(s.Uint64() & ^(uint64(1 << 63))) -} - -// Seed does nothing, since Source will use the crypto library -func (s *Source) Seed(_ int64) {}