From f9b42fd16c98c2d130c7851c149d42fe1c16650b Mon Sep 17 00:00:00 2001 From: Salim Afiune Maya Date: Fri, 31 Jul 2020 08:12:12 -0600 Subject: [PATCH] feat(cli): --remove_tenant from config file A user will be able to configure a persistent tenant with the command: ``` $ lacework configure --tenant sub-account ``` To remove the configured tenant use the `--remove_tenant` flag: ``` $ lacework configure --remove_tenant ``` Signed-off-by: Salim Afiune Maya --- cli/cmd/configure.go | 26 +++++++- integration/configure_test.go | 108 ++++++++++++++++++++++++++++++++++ integration/help_test.go | 4 ++ 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/cli/cmd/configure.go b/cli/cmd/configure.go index 0acb2dc72..db5d854d4 100644 --- a/cli/cmd/configure.go +++ b/cli/cmd/configure.go @@ -79,6 +79,10 @@ var ( // configureJsonFile is the API key file downloaded form the Lacework WebUI configureJsonFile string + // removeTenant tells the configure command to remove the configured tenant + // from the profile that is being configured + removeTenant bool + // configureCmd represents the configure command configureCmd = &cobra.Command{ Use: "configure", @@ -102,7 +106,10 @@ specify a profile to use. You can configure multiple profiles by using the --profile argument. If a config file does not exist (the default location is ~/.lacework.toml), the -Lacework CLI will create it for you.`, +Lacework CLI will create it for you. + +For organization administrators, use the argument --tenant to configure a +sub-account. To remove this configuration pass the --remove_tenant flag.`, RunE: func(_ *cobra.Command, _ []string) error { return promptConfigureSetup() }, @@ -115,6 +122,10 @@ func init() { configureCmd.Flags().StringVarP(&configureJsonFile, "json_file", "j", "", "loads the generated API key JSON file from the WebUI", ) + + configureCmd.Flags().BoolVar(&removeTenant, + "remove_tenant", false, "removes the configured tenant of the profile being modified", + ) } func promptConfigureSetup() error { @@ -202,6 +213,17 @@ func promptConfigureSetup() error { newCreds.ApiSecret = cli.Secret } + tenantMsg := "" + if len(cli.Tenant) != 0 { + newCreds.Tenant = cli.Tenant + tenantMsg = fmt.Sprintf("Tenant '%s' configured. ", cli.Tenant) + } + + if removeTenant && newCreds.Tenant != "" { + tenantMsg = fmt.Sprintf("Tenant '%s' removed. ", newCreds.Tenant) + newCreds.Tenant = "" + } + if err := newCreds.Verify(); err != nil { return errors.Wrap(err, "unable to configure the command-line") } @@ -240,7 +262,7 @@ func promptConfigureSetup() error { return err } - cli.OutputHuman("You are all set!\n") + cli.OutputHuman("%sYou are all set!\n", tenantMsg) return nil } diff --git a/integration/configure_test.go b/integration/configure_test.go index 1947f7a24..1b3f7e18d 100644 --- a/integration/configure_test.go +++ b/integration/configure_test.go @@ -240,6 +240,114 @@ func TestConfigureCommandWithExistingConfigAndMultiProfile(t *testing.T) { `, laceworkTOML, "there is a problem with the generated config") } +func TestConfigureCommandWithTenant(t *testing.T) { + _, laceworkTOML := runConfigureTest(t, + func(c *expect.Console) { + c.ExpectString("Account:") + c.SendLine("test-account") + c.ExpectString("Access Key ID:") + c.SendLine("INTTEST_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890AAABBBCCC00") + c.ExpectString("Secret Access Key:") + c.SendLine("_00000000000000000000000000000000") + c.ExpectString("You are all set!") + }, + "configure", "--tenant", "sub-account", + ) + + assert.Equal(t, `[default] + account = "test-account" + api_key = "INTTEST_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890AAABBBCCC00" + api_secret = "_00000000000000000000000000000000" + tenant = "sub-account" +`, laceworkTOML, "there is a problem with the generated config") +} + +func TestConfigureCommandWithExistingConfigAndMultiProfileWithRemoveTenantFlag(t *testing.T) { + dir := createTOMLConfig() + defer os.RemoveAll(dir) + + _, laceworkTOML := runConfigureTestFromDir(t, dir, + func(c *expect.Console) { + c.ExpectString("Account:") + c.SendLine("") // using the default, which should be auto-populated from the provided --profile flag + c.ExpectString("Access Key ID:") + c.SendLine("") // using the default, which should be auto-populated from the provided --profile flag + c.ExpectString("Secret Access Key:") + c.SendLine("") // using the default, which should be auto-populated from the provided --profile flag + c.ExpectString("Tenant 'sub-acc' removed. You are all set!") + }, + "configure", "--profile", "integration", "--remove_tenant", + ) + + assert.Equal(t, `[default] + account = "test.account" + api_key = "INTTEST_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890AAABBBCCC00" + api_secret = "_00000000000000000000000000000000" + +[dev] + account = "dev.example" + api_key = "DEVDEV_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890AAABBBCCC000" + api_secret = "_11111111111111111111111111111111" + +[integration] + account = "integration" + api_key = "INTEGRATION_3DF1234AABBCCDD5678XXYYZZ1234ABC8BEC6500DC70001" + api_secret = "_1234abdc00ff11vv22zz33xyz1234abc" +`, laceworkTOML, "there is a problem with the generated config") // NOTE: there is no tenant +} + +func TestConfigureCommandNonInteractiveWithTenantPlusRemoval(t *testing.T) { + home, err := ioutil.TempDir("", "lacework-cli") + if err != nil { + panic(err) + } + + defer os.RemoveAll(home) + out, errB, exitcode := LaceworkCLIWithHome(home, "configure", + "--noninteractive", + "-a", "my-account", + "-k", "my-key", + "-s", "my-secret", + "-t", "sub-account", + ) + + assert.Empty(t, errB.String()) + assert.Equal(t, 0, exitcode) + assert.Equal(t, "Tenant 'sub-account' configured. You are all set!\n", out.String(), + "you are not all set, check configure cmd") + + configPath := path.Join(home, ".lacework.toml") + assert.FileExists(t, configPath, "the configuration file is missing") + laceworkTOML, err := ioutil.ReadFile(configPath) + if err != nil { + panic(err) + } + + assert.Equal(t, `[default] + account = "my-account" + api_key = "my-key" + api_secret = "my-secret" + tenant = "sub-account" +`, string(laceworkTOML), "there is a problem with the generated config") + + // removing the tenant configuration + out, errB, exitcode = LaceworkCLIWithHome(home, "configure", "--noninteractive", "--remove_tenant") + assert.Empty(t, errB.String()) + assert.Equal(t, 0, exitcode) + assert.Equal(t, "Tenant 'sub-account' removed. You are all set!\n", out.String(), + "you are not all set, check configure cmd") + laceworkTOML, err = ioutil.ReadFile(configPath) + if err != nil { + panic(err) + } + + assert.Equal(t, `[default] + account = "my-account" + api_key = "my-key" + api_secret = "my-secret" +`, string(laceworkTOML), "there is a problem with the generated config") // NOTE: no tenant anymore +} + func TestConfigureCommandErrors(t *testing.T) { _, laceworkTOML := runConfigureTest(t, func(c *expect.Console) { diff --git a/integration/help_test.go b/integration/help_test.go index 82ea77615..25ad9e165 100644 --- a/integration/help_test.go +++ b/integration/help_test.go @@ -60,12 +60,16 @@ You can configure multiple profiles by using the --profile argument. If a config file does not exist (the default location is ~/.lacework.toml), the Lacework CLI will create it for you. +For organization administrators, use the argument --tenant to configure a +sub-account. To remove this configuration pass the --remove_tenant flag. + Usage: lacework configure [flags] Flags: -h, --help help for configure -j, --json_file string loads the generated API key JSON file from the WebUI + --remove_tenant removes the configured tenant of the profile being modified Global Flags: -a, --account string account subdomain of URL (i.e. .lacework.net)