Example #1
0
        public async Task Options()
        {
            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            //-------------------------------------------------
                            // Verify that the [run] command handles command line options correctly.

                            File.WriteAllText("test.cmd", "echo %* > output.txt");

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "test.cmd", "-foo", "--bar=foobar", "--hello", "world");

                            Assert.Equal(0, result.ExitCode);

                            Assert.Contains("-foo --bar=foobar --hello world", File.ReadAllText("output.txt"));
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #2
0
        public async Task VariableInjectEncrypted()
        {
            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            var vault = new NeonVault(Program.LookupPassword);

                            // Create a test password and a [.password-name] file in the
                            // temp test folder.

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test");

                            Assert.Equal(0, result.ExitCode);

                            //-------------------------------------------------
                            // Verify that we can inject variables into an
                            // ENCRYPTED file.

                            File.WriteAllText("test.cmd", "type %1 > output.txt");

                            File.WriteAllText("file.txt",
                                              @"
$<<TEST_A>>
$<<TEST_B>>
$<<TEST_C>>
$<<TEST_D>>
");
                            File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test"));
                            Assert.True(NeonVault.IsEncrypted("file.txt"));

                            result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--TEST_A=A-VALUE", "--TEST_B=B-VALUE", "--TEST_C=C-VALUE", "--TEST_D=D-VALUE", "--", "test.cmd", "_..file.txt");

                            Assert.Equal(0, result.ExitCode);

                            var output = File.ReadAllText("output.txt");

                            Assert.Contains("A-VALUE", output);
                            Assert.Contains("B-VALUE", output);
                            Assert.Contains("C-VALUE", output);
                            Assert.Contains("D-VALUE", output);
                            File.Delete("output.txt");
                            File.Delete("file.txt");
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #3
0
        public async Task PasswordList()
        {
            ExecuteResponse result;

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    // Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "list");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Lists passwords.", result.OutputText);

                    // Add a few passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "one", "tool", "password", "set", "pwd-1", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "two", "tool", "password", "set", "pwd-2", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "three", "tool", "password", "set", "pwd-3", "-");

                    Assert.Equal(0, result.ExitCode);

                    // Verify that we can list via: list

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "list");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-2
pwd-3
",
                        result.OutputText);

                    // Verify that we can list via: ls

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-2
pwd-3
",
                        result.OutputText);
                }
            }
        }
Example #4
0
        public void LoadEnvironmentEncrypted()
        {
            // Verify that we can load an encryoted settings file into the
            // environment variables.

            using (var testManager = new KubeTestManager())
            {
                try
                {
                    using (var tempFile = new TempFile())
                    {
                        // Initialze the file.

                        using (var writer = new StreamWriter(tempFile.Path))
                        {
                            foreach (var item in testSettings)
                            {
                                writer.WriteLine($"{item.Key}={item.Value}");
                            }
                        }

                        var passwordPath = Path.Combine(KubeHelper.PasswordsFolder, "test");

                        File.WriteAllText(passwordPath, password);

                        var vault = new NeonVault(KubeHelper.LookupPassword);

                        File.WriteAllBytes(tempFile.Path, vault.Encrypt(tempFile.Path, "test"));
                        Assert.True(NeonVault.IsEncrypted(tempFile.Path));

                        // Perform the test.

                        Assert.Null(TestContext.Current);

                        using (var testContext = new TestContext())
                        {
                            Assert.Same(testContext, TestContext.Current);

                            testContext.LoadEnvironment(tempFile.Path, KubeHelper.LookupPassword);

                            foreach (var item in testSettings)
                            {
                                Assert.Equal(item.Value, Environment.GetEnvironmentVariable(item.Key));
                            }
                        }
                    }
                }
                finally
                {
                    // Be sure to remove the test enmvironment variables.

                    foreach (var item in testSettings)
                    {
                        Environment.SetEnvironmentVariable(item.Key, null);
                    }
                }
            }
        }
Example #5
0
        public void LoadEnvironmentDecrypted()
        {
            // Verify that we can load a decrypted settings file into the
            // environment variables.

            using (var testManager = new KubeTestManager())
            {
                try
                {
                    using (var tempFile = new TempFile())
                    {
                        // Initialze the file.

                        using (var writer = new StreamWriter(tempFile.Path))
                        {
                            foreach (var item in testSettings)
                            {
                                writer.WriteLine($"{item.Key}={item.Value}");
                            }
                        }

                        // Perform the test.

                        Assert.Null(TestContext.Current);

                        using (var testContext = new TestContext())
                        {
                            Assert.Same(testContext, TestContext.Current);

                            testContext.LoadEnvironment(tempFile.Path);

                            foreach (var item in testSettings)
                            {
                                Assert.Equal(item.Value, Environment.GetEnvironmentVariable(item.Key));
                            }
                        }
                    }
                }
                finally
                {
                    // Be sure to remove the test enmvironment variables.

                    foreach (var item in testSettings)
                    {
                        Environment.SetEnvironmentVariable(item.Key, null);
                    }
                }
            }
        }
Example #6
0
        public void LoadSettingsEncrypted()
        {
            // Verify that we can load an encrypted settings file into the
            // [TestContext.Settings] dictionary.

            using (var testManager = new KubeTestManager())
            {
                using (var tempFile = new TempFile())
                {
                    // Initialze the file.

                    using (var writer = new StreamWriter(tempFile.Path))
                    {
                        foreach (var item in testSettings)
                        {
                            writer.WriteLine($"{item.Key}={item.Value}");
                        }
                    }

                    var passwordPath = Path.Combine(KubeHelper.PasswordsFolder, "test");

                    File.WriteAllText(passwordPath, password);

                    var vault = new NeonVault(KubeHelper.LookupPassword);

                    File.WriteAllBytes(tempFile.Path, vault.Encrypt(tempFile.Path, "test"));
                    Assert.True(NeonVault.IsEncrypted(tempFile.Path));

                    // Perform the test.

                    Assert.Null(TestContext.Current);

                    using (var testContext = new TestContext())
                    {
                        Assert.Same(testContext, TestContext.Current);

                        testContext.LoadSettings(tempFile.Path, KubeHelper.LookupPassword);

                        foreach (var item in testSettings)
                        {
                            Assert.Equal(item.Value, testContext.Settings[item.Key]);
                        }
                    }
                }
            }
        }
Example #7
0
        public async Task VariableOptions()
        {
            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            var vault = new NeonVault(Program.LookupPassword);

                            //-------------------------------------------------
                            // Verify that we can process [--name=value] run command options.

                            File.WriteAllText("test.cmd", "echo %* > output.txt");

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--TEST_A=A-VALUE", "--TEST_B=B-VALUE", "--TEST_C=C-VALUE", "--TEST_D=D-VALUE", "--", "test.cmd", "_.TEST_A", "_.TEST_B", "_.TEST_C", "_.TEST_D");

                            Assert.Equal(0, result.ExitCode);

                            var output = File.ReadAllText("output.txt");

                            Assert.Contains("A-VALUE", output);
                            Assert.Contains("B-VALUE", output);
                            Assert.Contains("C-VALUE", output);
                            Assert.Contains("D-VALUE", output);
                            File.Delete("output.txt");
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #8
0
        public void LoadSettingsDecrypted()
        {
            // Verify that we can load a decrypted settings file into the
            // [TestContext.Settings] dictionary.

            using (var testManager = new KubeTestManager())
            {
                using (var tempFile = new TempFile())
                {
                    // Initialze the file.

                    using (var writer = new StreamWriter(tempFile.Path))
                    {
                        foreach (var item in testSettings)
                        {
                            writer.WriteLine($"{item.Key}={item.Value}");
                        }
                    }

                    // Perform the test.

                    Assert.Null(TestContext.Current);

                    using (var testContext = new TestContext())
                    {
                        Assert.Same(testContext, TestContext.Current);

                        testContext.LoadSettings(tempFile.Path);

                        foreach (var item in testSettings)
                        {
                            Assert.Equal(item.Value, testContext.Settings[item.Key]);
                        }
                    }
                }
            }
        }
Example #9
0
        public async Task StandardFiles()
        {
            // We had a problem with [NeonHelper_Execute] where standard output
            // and standard error streams weren't being relayed back to the
            // corresponding [neon-cli] streams when the sub-process was an
            // actual executable rather than a batch script.  So the unit tests
            // above that ran a script passed.
            //
            // This test verifies that we get output from an actual executable.

            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            File.WriteAllText("test.txt", "Hello World!");

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "cat", "test.txt");

                            Assert.Equal(0, result.ExitCode);
                            Assert.Contains("Hello World!", result.AllText);
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #10
0
        public async Task ReadVariables_Decrypted()
        {
            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            var vault = new NeonVault(Program.LookupPassword);

                            // Create a test password and a [.password-name] file in the
                            // temp test folder.

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test");

                            Assert.Equal(0, result.ExitCode);

                            File.WriteAllText(".password-name", "test");

                            //-------------------------------------------------
                            // Verify that we can read variables from a couple of
                            // unencrypted variable files.

                            File.WriteAllText("test.cmd", "echo %* > output.txt");

                            File.WriteAllText("var1.txt",
                                              @"# This is a comment.

TEST_A=A-VALUE
TEST_B=B-VALUE
");

                            File.WriteAllText("var2.txt",
                                              @"# This is a comment.

TEST_C=C-VALUE
TEST_D=D-VALUE
");
                            result = await runner.ExecuteAsync(Program.Main, "tool", "run", "var1.txt", "var2.txt", "--", "test.cmd", "_.TEST_A", "_.TEST_B", "_.TEST_C", "_.TEST_D");

                            Assert.Equal(0, result.ExitCode);

                            var output = File.ReadAllText("output.txt");

                            Assert.Contains("A-VALUE", output);
                            Assert.Contains("B-VALUE", output);
                            Assert.Contains("C-VALUE", output);
                            Assert.Contains("D-VALUE", output);
                            File.Delete("output.txt");
                            File.Delete("var1.txt");
                            File.Delete("var2.txt");
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #11
0
        public async Task PasswordRemove()
        {
            ExecuteResponse result;

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    // Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "remove");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Removes a specific named password or all passwords.", result.OutputText);

                    // Add a few passwords:

                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-1"), "one");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-2"), "two");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-3"), "three");

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-1", Path.Combine(testManager.TestFolder, "pwd-1"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-2", Path.Combine(testManager.TestFolder, "pwd-2"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-3", Path.Combine(testManager.TestFolder, "pwd-3"));

                    Assert.Equal(0, result.ExitCode);

                    // Verify that we can list the passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-2
pwd-3
",
                        result.OutputText);

                    // Verify that we can remove a specific password.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "pwd-2");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-3
",
                        result.OutputText);

                    // Verify that we can remove all passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "remove", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "list");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Empty(result.OutputText);

                    // Verify that we see errors for missing arguments:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("NAME argument is required.", result.ErrorText);

                    // Verify what we see an error when trying to remove a password
                    // that doesn't exist:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "BAD");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("does not exist", result.ErrorText);
                }
            }
        }
Example #12
0
        public async Task PasswordGenerate()
        {
            ExecuteResponse result;

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    //// Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "generate");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Generates a cryptographically secure password.", result.OutputText);

                    // Verify that we can generate a password with the default length.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal(20, result.OutputText.Trim().Length);

                    // Verify that we can generate a password with a specific length.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "30");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal(30, result.OutputText.Trim().Length);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "8");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal(8, result.OutputText.Trim().Length);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "100");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal(100, result.OutputText.Trim().Length);

                    // Verify that invalid password lengths are detected.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "BAD");

                    Assert.NotEqual(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "0");

                    Assert.NotEqual(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "7");

                    Assert.NotEqual(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "101");

                    Assert.NotEqual(0, result.ExitCode);

                    // Verify that we get different passwords when we run this
                    // multiple times.

                    var previousPasswords = new HashSet <string>();

                    for (int i = 0; i < 50; i++)
                    {
                        result = await runner.ExecuteAsync(Program.Main, "tool", "password", "generate", "100");

                        Assert.Equal(0, result.ExitCode);

                        var password = result.OutputText.Trim();

                        Assert.DoesNotContain(previousPasswords, p => p == password);
                        previousPasswords.Add(password);
                    }
                }
            }
        }
Example #13
0
        public async Task PasswordSet()
        {
            ExecuteResponse result;

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    // Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "set");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Creates or modifies a named password.", result.OutputText);

                    // Add a few passwords via files and verify:

                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-1"), "one");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-2"), "two");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-3"), "three");

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-1", Path.Combine(testManager.TestFolder, "pwd-1"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-2", Path.Combine(testManager.TestFolder, "pwd-2"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-3", Path.Combine(testManager.TestFolder, "pwd-3"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("two", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-3");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("three", result.OutputText.Trim());

                    // Verify that we can set a password from STDIN:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "one", "tool", "password", "set", "pwd-1", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "two", "tool", "password", "set", "pwd-2", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "three", "tool", "password", "set", "pwd-3", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("two", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-3");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("three", result.OutputText.Trim());

                    // Verify that we can update a password.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "one", "tool", "password", "set", "pwd-1", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteWithInputAsync(Program.Main, "1", "tool", "password", "set", "pwd-1", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("1", result.OutputText.Trim());

                    // Verify that password names with all possible character classes works:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "password", "tool", "password", "set", "a.1_2-3", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "a.1_2-3");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("password", result.OutputText.Trim());

                    // Verify that a 20 character password is generated when no PATH argument is passed:

                    result = await runner.ExecuteWithInputAsync(Program.Main, "password", "tool", "password", "set", "abc");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "abc");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal(20, result.OutputText.Trim().Length);

                    // Verify that we see errors for missing arguments:

                    result = await runner.ExecuteWithInputAsync(Program.Main, "password", "tool", "password", "set");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("NAME argument is required.", result.ErrorText);

                    // Verify that password name error checking works:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "", "tool", "password", "set", "pwd@1", "-");

                    Assert.NotEqual(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "", "tool", "password", "set", $"{new string('a', 101)}", "-");

                    Assert.NotEqual(0, result.ExitCode);

                    // Verify that password length error checking works:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "", "tool", "password", "set", "pwd-1", "-");

                    Assert.NotEqual(0, result.ExitCode);
                }
            }
        }
Example #14
0
        public async Task VaultPasswordName()
        {
            using (var testManager = new KubeTestManager())
            {
                using (var tempFolder = new TempFolder())
                {
                    var orgDir = Environment.CurrentDirectory;

                    Environment.CurrentDirectory = tempFolder.Path;
                    NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText);

                    try
                    {
                        using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder))
                        {
                            File.WriteAllText(passwordFile.Path, testPassword);

                            var vault = new NeonVault(passwordName => testPassword);

                            using (var runner = new ProgramRunner())
                            {
                                // Verify that the PATH argument is required.

                                var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText);

                                // Verify that we can create an encrypted file with an explicitly
                                // named password.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test1.txt", passwordFile.Name);

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt")));

                                // Verify that we can get the password with a line ending.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name", "test1.txt", passwordFile.Name);

                                Assert.Equal(0, result.ExitCode);
                                Assert.Contains(passwordFile.Name, result.OutputText);
                                Assert.Contains('\n', result.OutputText);

                                // Verify that we can get the password without a line ending.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "password-name", "-n", "test1.txt", passwordFile.Name);

                                Assert.Equal(0, result.ExitCode);
                                Assert.Equal(passwordFile.Name, result.OutputText);
                            }
                        }
                    }
                    finally
                    {
                        Environment.CurrentDirectory = orgDir;
                        NeonHelper.OpenEditorHandler = null;
                    }
                }
            }
        }
Example #15
0
        public async Task VaultEncrypt()
        {
            using (var testManager = new KubeTestManager())
            {
                using (var tempFolder = new TempFolder())
                {
                    var orgDir = Environment.CurrentDirectory;

                    Environment.CurrentDirectory = tempFolder.Path;
                    NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText);

                    try
                    {
                        using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder))
                        {
                            File.WriteAllText(passwordFile.Path, testPassword);

                            var vault = new NeonVault(passwordName => testPassword);

                            using (var runner = new ProgramRunner())
                            {
                                // Verify that the PATH argument is required.

                                var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText);

                                // Verify that the TARGET argument is required when [--password-name]
                                // or [--p] is not present.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "decrypt", "source.txt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The TARGET argument is required.", result.ErrorText);

                                // Verify that we can encrypt a file in-place, specifying an
                                // explicit password name (using --password-name=NAME).

                                File.WriteAllText("test1.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test1.txt", $"--password-name={passwordFile.Name}");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt")));

                                // Verify that we can encrypt a file in-place, specifying an
                                // explicit password name (using --p=NAME).

                                File.WriteAllText("test2.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test2.txt", $"-p={passwordFile.Name}");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test2.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test2.txt")));

                                // Verify that we get an error trying to encrypt in-place without a
                                // password name being explicitly specified and also without a
                                // [.password-name] file present.

                                File.WriteAllText("test3.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test3.txt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText);

                                // Verify that we get an error trying to encrypt (not in-place) without a
                                // password name being explicitly specified and also without a
                                // [.password-name] file present.

                                File.WriteAllText("test4.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test4.txt", "test4.encypted.txt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText);

                                // Verify that we can encrypt a file to another with
                                // and explicit password argument.

                                File.WriteAllText("test5.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test5.txt", "test5.encypted.txt", passwordName);

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test5.encypted.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test5.encypted.txt")));

                                // Verify that we can encrypt a file to another with
                                // and explicit [--password-name] option.

                                File.WriteAllText("test6.txt", plainText);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test6.txt", "test6.encypted.txt", $"--password-name={passwordName}");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test6.encypted.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test6.encypted.txt")));

                                // Verify that we can encrypt a file in-place using a [.password-name] file.

                                File.WriteAllText("test7.txt", plainText);
                                File.WriteAllText(".password-name", passwordName);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", "test7.txt");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test7.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test7.txt")));

                                // Verify that we can encrypt a file (not in-place) to another where
                                // the source file is located in a different directory from the target
                                // to ensure that we look for the [.password-name] file starting at
                                // the target directory.

                                using (var tempFile = new TempFile())
                                {
                                    File.WriteAllText(tempFile.Path, plainText);

                                    result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "encrypt", tempFile.Path, "test8.encrypted.txt");

                                    Assert.Equal(0, result.ExitCode);
                                    Assert.True(NeonVault.IsEncrypted("test8.encrypted.txt", out passwordName));
                                    Assert.Equal(passwordFile.Name, passwordName);
                                    Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test8.encrypted.txt")));
                                }
                            }
                        }
                    }
                    finally
                    {
                        Environment.CurrentDirectory = orgDir;
                        NeonHelper.OpenEditorHandler = null;
                    }
                }
            }
        }
Example #16
0
        public async Task PasswordImportExport()
        {
            const string zipPassword = "******";

            ExecuteResponse result;

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    // Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "import");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Imports passwords from an encrypted ZIP file.", result.OutputText);

                    // Verify that [import] checks the PATH argument.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "import");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("PATH argument is required.", result.ErrorText);

                    // Verify that [help] works:

                    result = await runner.ExecuteAsync(Program.Main, "help", "tool", "password", "export");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Contains("Exports selected passwords to an encrypted ZIP file.", result.OutputText);

                    // Verify that [export] checks the PATH argument.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "export");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("PATH argument is required.", result.ErrorText);

                    // Verify that [export] checks the NAME argument.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "export", "test.zip");

                    Assert.NotEqual(0, result.ExitCode);
                    Assert.Contains("At least one NAME argument is required.", result.ErrorText);

                    // Add a few passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "one", "tool", "password", "set", "pwd-1", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "two", "tool", "password", "set", "pwd-2", "-");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, "three", "tool", "password", "set", "pwd-3", "-");

                    Assert.Equal(0, result.ExitCode);

                    // Export all passwords to a ZIP file:

                    var zipPath = Path.Combine(testManager.TestFolder, "passwords.zip");

                    result = await runner.ExecuteWithInputAsync(Program.Main, zipPassword, "tool", "password", "export", "--stdin", zipPath, "*");

                    Assert.Equal(0, result.ExitCode);
                    Assert.True(File.Exists(zipPath));

                    // Remove all passwords, import the passwords using a zip password file, and verify.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, zipPassword, "tool", "password", "import", "--stdin", zipPath);

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("two", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-3");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("three", result.OutputText.Trim());

                    // Export two of the three passwords to a ZIP file:

                    result = await runner.ExecuteWithInputAsync(Program.Main, zipPassword, "tool", "password", "export", "--stdin", zipPath, "pwd-1", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.True(File.Exists(zipPath));

                    // Remove all passwords, import the passwords using a zip password file, and verify.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteWithInputAsync(Program.Main, zipPassword, "tool", "password", "import", "--stdin", zipPath);

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("two", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-3");

                    Assert.NotEqual(0, result.ExitCode);    // This one wasn't exported.
                }
            }
        }
Example #17
0
        public async Task VaultCreate()
        {
            using (var testManager = new KubeTestManager())
            {
                using (var tempFolder = new TempFolder())
                {
                    var orgDir = Environment.CurrentDirectory;

                    Environment.CurrentDirectory = tempFolder.Path;
                    NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText);

                    try
                    {
                        using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder))
                        {
                            File.WriteAllText(passwordFile.Path, testPassword);

                            var vault = new NeonVault(passwordName => testPassword);

                            using (var runner = new ProgramRunner())
                            {
                                // Verify that the PATH argument is required.

                                var result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The PATH argument is required.", result.ErrorText);

                                // Verify that the PASSWORD-NAME argument is required when there's
                                // no default [.password-name] file.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test1.txt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: A PASSWORD-NAME argument or [.password-name] file is required.", result.ErrorText);

                                // Verify that we can create an encrypted file with an explicitly
                                // named password.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test2.txt", passwordFile.Name);

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test2.txt", out var passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test2.txt")));

                                // Verify that we see an error for a missing password.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test3.txt", missingPasswordName);

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains($"*** ERROR: [System.Security.Cryptography.CryptographicException]: Password named [{missingPasswordName}] not found or is blank or whitespace.", result.ErrorText);

                                // Verify that we see an error for an invalid password.

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test4.txt", badPasswordName);

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains($"*** ERROR: [System.Security.Cryptography.CryptographicException]: Password name [bad/password] contains invalid characters.  Only ASCII letters, digits, underscores, dashs and dots are allowed.", result.ErrorText);

                                // Verify that a local [.password-name] file is used successfully when we don't
                                // explicitly pass a password name.

                                File.WriteAllText(".password-name", passwordFile.Name);

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test5.txt");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test5.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test5.txt")));

                                // Verify that a [.password-name] file in the parent directory is used successfully
                                // when we don't explicitly pass a password name.

                                Directory.CreateDirectory("subfolder");
                                Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, "subfolder");

                                result = await runner.ExecuteAsync(Program.Main, "tool", "vault", "create", "test6.txt");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test6.txt", out passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test6.txt")));
                            }
                        }
                    }
                    finally
                    {
                        Environment.CurrentDirectory = orgDir;
                        NeonHelper.OpenEditorHandler = null;
                    }
                }
            }
        }
Example #18
0
        public async Task DecryptFile()
        {
            var orgDirectory = Environment.CurrentDirectory;

            try
            {
                using (var testManager = new KubeTestManager())
                {
                    using (var runner = new ProgramRunner())
                    {
                        using (var tempFolder = new TempFolder())
                        {
                            Environment.CurrentDirectory = tempFolder.Path;

                            var vault = new NeonVault(Program.LookupPassword);

                            // Create a test password and a [.password-name] file in the
                            // temp test folder.

                            var result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "test");

                            Assert.Equal(0, result.ExitCode);

                            //-------------------------------------------------
                            // Verify that we can decrypt a file.

                            File.WriteAllText("test.cmd", "type %1 > output.txt");

                            const string plainText = "The quick brown fox jumped over the lazy dog.";

                            File.WriteAllText("file.txt", plainText);
                            File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test"));
                            Assert.True(NeonVault.IsEncrypted("file.txt"));

                            result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "test.cmd", "_...file.txt");

                            Assert.Equal(0, result.ExitCode);

                            var output = File.ReadAllText("output.txt");

                            Assert.Contains(plainText, output);
                            File.Delete("output.txt");
                            File.Delete("file.txt");

                            //-------------------------------------------------
                            // Try this again calling a command directly (batch files seem to have different behavior).

                            File.WriteAllText("type", "%1");

                            File.WriteAllText("file.txt", plainText);
                            File.WriteAllBytes("file.txt", vault.Encrypt("file.txt", "test"));
                            Assert.True(NeonVault.IsEncrypted("file.txt"));

                            result = await runner.ExecuteAsync(Program.Main, "tool", "run", "--", "cat", "_...file.txt");

                            Assert.Equal(0, result.ExitCode);

                            Assert.Contains(plainText, result.OutputText);
                            File.Delete("output.txt");
                            File.Delete("file.txt");
                        }
                    }
                }
            }
            finally
            {
                Environment.CurrentDirectory = orgDirectory;
            }
        }
Example #19
0
        public async Task PasswordBasics()
        {
            ExecuteResponse result;

            // Verify basic password operations: get, set, list|ls, and remove|rm:

            using (var testManager = new KubeTestManager())
            {
                using (var runner = new ProgramRunner())
                {
                    // We should start out with no passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "list");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Empty(result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Empty(result.OutputText.Trim());

                    // Add a few passwords via files and verify:

                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-1"), "one");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-2"), "two");
                    File.WriteAllText(Path.Combine(testManager.TestFolder, "pwd-3"), "three");

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-1", Path.Combine(testManager.TestFolder, "pwd-1"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-2", Path.Combine(testManager.TestFolder, "pwd-2"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "set", "pwd-3", Path.Combine(testManager.TestFolder, "pwd-3"));

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-1");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("one", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-2");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("two", result.OutputText.Trim());

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "get", "pwd-3");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Equal("three", result.OutputText.Trim());

                    // Verify that we can list the passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-2
pwd-3
",
                        result.OutputText);

                    // Verify that we can remove a specific password.

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "pwd-2");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    TestHelper.AssertEqualLines(
                        @"pwd-1
pwd-3
",
                        result.OutputText);

                    // Verify that we can remove all passwords:

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "rm", "--force", "*");

                    Assert.Equal(0, result.ExitCode);

                    result = await runner.ExecuteAsync(Program.Main, "tool", "password", "ls");

                    Assert.Equal(0, result.ExitCode);
                    Assert.Empty(result.OutputText);
                }
            }
        }
Example #20
0
        public void VaultDecrypt()
        {
            using (var manager = new KubeTestManager())
            {
                using (var tempFolder = new TempFolder())
                {
                    var orgDir = Environment.CurrentDirectory;

                    Environment.CurrentDirectory = tempFolder.Path;
                    NeonHelper.OpenEditorHandler = path => File.WriteAllText(path, plainText);

                    try
                    {
                        using (var passwordFile = new TempFile(folder: KubeHelper.PasswordsFolder))
                        {
                            File.WriteAllText(passwordFile.Path, testPassword);

                            var vault = new NeonVault(passwordName => testPassword);

                            using (var runner = new ProgramRunner())
                            {
                                // Verify that the SOURCE argument is required.

                                var result = runner.Execute(Program.Main, "vault", "decrypt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The SOURCE argument is required.", result.ErrorText);

                                // Verify that the TARGET argument is required.

                                result = runner.Execute(Program.Main, "vault", "decrypt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The SOURCE argument is required.", result.ErrorText);

                                // Verify that the SOURCE-PATH argument is required.

                                result = runner.Execute(Program.Main, "vault", "decrypt", "test.txt");

                                Assert.NotEqual(0, result.ExitCode);
                                Assert.Contains("*** ERROR: The TARGET argument is required.", result.ErrorText);

                                // Verify that we can create an encrypted file with an explicitly
                                // named password.

                                result = runner.Execute(Program.Main, "vault", "create", "test1.txt", passwordFile.Name);

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test1.txt", out var passwordName));
                                Assert.Equal(passwordFile.Name, passwordName);
                                Assert.Equal(plainText, Encoding.UTF8.GetString(vault.Decrypt("test1.txt")));

                                // Verify that we can decrypt the file.

                                result = runner.Execute(Program.Main, "vault", "decrypt", "test1.txt", "decrypted.txt");

                                Assert.Equal(0, result.ExitCode);
                                Assert.True(NeonVault.IsEncrypted("test1.txt", out passwordName));
                                Assert.True(!NeonVault.IsEncrypted("decrypted.txt", out passwordName));
                                Assert.Equal(plainText, File.ReadAllText("decrypted.txt"));
                            }
                        }
                    }
                    finally
                    {
                        Environment.CurrentDirectory = orgDir;
                        NeonHelper.OpenEditorHandler = null;
                    }
                }
            }
        }