Merge "Remove secret generate cmd and its implementation"

This commit is contained in:
Zuul 2021-07-10 07:43:58 +00:00 committed by Gerrit Code Review
commit 3544c96249
13 changed files with 0 additions and 498 deletions

View File

@ -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())

View File

@ -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(&regex, "regex", "", "regular expression string")
encryptionKeyCmd.Flags().IntVar(&limit, "limit", 5, "limit number of characters for + or * regex")
return encryptionKeyCmd
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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:

View File

@ -33,6 +33,5 @@ SEE ALSO
* :ref:`airshipctl document <airshipctl_document>` - Airshipctl command to manage site manifest documents
* :ref:`airshipctl phase <airshipctl_phase>` - Airshipctl command to manage phases
* :ref:`airshipctl plan <airshipctl_plan>` - Airshipctl command to manage plans
* :ref:`airshipctl secret <airshipctl_secret>` - Airshipctl command to manage secrets
* :ref:`airshipctl version <airshipctl_version>` - Airshipctl command to display the current version number

View File

@ -14,5 +14,4 @@ Commands
help/index
phase/index
plan/index
secret/index
version/index

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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) {}