Skip to content

Commit f31bcb8

Browse files
authored
Merge pull request #413 from nblumhardt/encryptor-test
Basic tests for `SeqCliEncryptionProviderConfig` and `ExternalDataProtector`
2 parents 736238e + 36313d7 commit f31bcb8

File tree

8 files changed

+165
-19
lines changed

8 files changed

+165
-19
lines changed

src/SeqCli/Config/SeqCliEncryptionProviderConfig.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System;
1516
using SeqCli.Encryptor;
1617

1718
namespace SeqCli.Config;
@@ -26,14 +27,20 @@ class SeqCliEncryptionProviderConfig
2627

2728
public IDataProtector DataProtector()
2829
{
29-
#if WINDOWS
30-
return new WindowsNativeDataProtector();
31-
#else
32-
if (!string.IsNullOrWhiteSpace(Encryptor) && !string.IsNullOrWhiteSpace(Decryptor))
30+
if (!string.IsNullOrWhiteSpace(Encryptor) || !string.IsNullOrWhiteSpace(Decryptor))
3331
{
34-
return new ExternalDataProtector(this);
32+
if (string.IsNullOrWhiteSpace(Encryptor) || string.IsNullOrWhiteSpace(Decryptor))
33+
{
34+
throw new ArgumentException(
35+
"If either of `encryption.encryptor` or `encryption.decryptor` is specified, both must be specified.");
36+
}
37+
38+
return new ExternalDataProtector(Encryptor, EncryptorArgs, Decryptor, DecryptorArgs);
3539
}
3640

41+
#if WINDOWS
42+
return new WindowsNativeDataProtector();
43+
#else
3744
return new PlaintextDataProtector();
3845
#endif
3946
}

src/SeqCli/Encryptor/ExternalDataProtector.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ namespace SeqCli.Encryptor;
99

1010
class ExternalDataProtector : IDataProtector
1111
{
12-
public ExternalDataProtector(SeqCliEncryptionProviderConfig providerConfig)
12+
public ExternalDataProtector(string encryptor, string? encryptorArgs, string decryptor, string? decryptorArgs)
1313
{
14-
_encryptor = providerConfig.Encryptor!;
15-
_encryptorArgs = providerConfig.EncryptorArgs;
16-
17-
_decryptor = providerConfig.Decryptor!;
18-
_decryptorArgs = providerConfig.DecryptorArgs;
14+
_encryptor = encryptor ?? throw new ArgumentNullException(nameof(encryptor));
15+
_encryptorArgs = encryptorArgs;
16+
_decryptor = decryptor ?? throw new ArgumentNullException(nameof(decryptor));
17+
_decryptorArgs = decryptorArgs;
1918
}
2019

2120
readonly string _encryptor;
@@ -28,7 +27,7 @@ public byte[] Encrypt(byte[] unencrypted)
2827
var exit = Invoke(_encryptor, _encryptorArgs, unencrypted, out var encrypted, out var err);
2928
if (exit != 0)
3029
{
31-
throw new Exception($"Encryptor failed with exit code {exit} and produced: {err}");
30+
throw new Exception($"Encryptor failed with exit code {exit} and produced: {err}.");
3231
}
3332

3433
return encrypted;
@@ -39,7 +38,7 @@ public byte[] Decrypt(byte[] encrypted)
3938
var exit = Invoke(_decryptor, _decryptorArgs, encrypted, out var decrypted, out var err);
4039
if (exit != 0)
4140
{
42-
throw new Exception($"Decryptor failed with exit code {exit} and produced: {err}");
41+
throw new Exception($"Decryptor failed with exit code {exit} and produced: {err}.");
4342
}
4443

4544
return decrypted;
@@ -50,6 +49,7 @@ static int Invoke(string fullExePath, string? args, byte[] stdin, out byte[] std
5049
var startInfo = new ProcessStartInfo
5150
{
5251
UseShellExecute = false,
52+
RedirectStandardInput = true,
5353
RedirectStandardError = true,
5454
RedirectStandardOutput = true,
5555
WindowStyle = ProcessWindowStyle.Hidden,

src/SeqCli/SeqCli.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@
2222
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
2323
</PropertyGroup>
2424
<PropertyGroup Condition="'$(IsWindows)'=='true'">
25-
<DefineConstants>WINDOWS</DefineConstants>
25+
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
2626
</PropertyGroup>
2727
<PropertyGroup Condition="'$(IsOSX)'=='true'">
28-
<DefineConstants>OSX</DefineConstants>
28+
<DefineConstants>$(DefineConstants);OSX</DefineConstants>
2929
</PropertyGroup>
3030
<PropertyGroup Condition="'$(IsLinux)'=='true'">
31-
<DefineConstants>LINUX</DefineConstants>
31+
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
3232
</PropertyGroup>
3333
<PropertyGroup Condition="'$(IsWindows)'!='true'">
34-
<DefineConstants>UNIX</DefineConstants>
34+
<DefineConstants>$(DefineConstants);UNIX</DefineConstants>
3535
</PropertyGroup>
3636
<ItemGroup>
3737
<Content Include="..\..\asset\SeqCli.ico" Link="SeqCli.ico" />

test/SeqCli.EndToEnd/Support/TestDataFolder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public TestDataFolder()
1111
{
1212
_basePath = System.IO.Path.Combine(
1313
System.IO.Path.GetTempPath(),
14-
"SeqCli Test",
14+
"SeqCli.Tests.EndToEnd",
1515
Guid.NewGuid().ToString("n"));
1616

1717
Directory.CreateDirectory(_basePath);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.IO;
4+
using System.Text;
5+
using SeqCli.Encryptor;
6+
using SeqCli.Tests.Support;
7+
using Xunit;
8+
9+
namespace SeqCli.Tests.Config;
10+
11+
public class ExternalDataProtectorTests
12+
{
13+
[Fact]
14+
public void IfEncryptorDoesNotExistEncryptThrows()
15+
{
16+
var protector = new ExternalDataProtector(Some.String(), null, Some.String(), null);
17+
Assert.Throws<Win32Exception>(() => protector.Encrypt(Some.Bytes(200)));
18+
}
19+
20+
#if UNIX
21+
[Fact]
22+
public void IfEncryptorFailsEncryptThrows()
23+
{
24+
var protector = new ExternalDataProtector("bash", "-c \"exit 1\"", Some.String(), null);
25+
// May be `Exception` or `IOException`.
26+
Assert.ThrowsAny<Exception>(() => protector.Encrypt(Some.Bytes(200)));
27+
}
28+
29+
[Fact]
30+
public void EncryptCallsEncryptor()
31+
{
32+
const string prefix = "123";
33+
34+
var encoding = new UTF8Encoding(false);
35+
using var temp = TempFolder.ForCaller();
36+
var filename = temp.AllocateFilename();
37+
File.WriteAllBytes(filename, encoding.GetBytes(prefix));
38+
39+
const string input = "Hello, world!";
40+
41+
var protector = new ExternalDataProtector("bash", $"-c \"cat '{filename}' -\"", Some.String(), null);
42+
var actual = encoding.GetString(protector.Encrypt(encoding.GetBytes(input)));
43+
44+
Assert.Equal($"{prefix}{input}", actual);
45+
}
46+
47+
[Fact]
48+
public void EncryptionRoundTrips()
49+
{
50+
const string echo = "bash";
51+
const string echoArgs = "-c \"cat -\"";
52+
var protector = new ExternalDataProtector(echo, echoArgs, echo, echoArgs);
53+
var expected = Some.Bytes(200);
54+
var actual = protector.Decrypt(protector.Encrypt(expected));
55+
Assert.Equal(expected, actual);
56+
}
57+
#endif
58+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using SeqCli.Config;
4+
using SeqCli.Encryptor;
5+
using Xunit;
6+
7+
namespace SeqCli.Tests.Config;
8+
9+
public class SeqCliEncryptionProviderConfigTests
10+
{
11+
#if WINDOWS
12+
[Fact]
13+
public void DefaultDataProtectorOnWindowsIsDpapi()
14+
{
15+
Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
16+
17+
var config = new SeqCliEncryptionProviderConfig();
18+
var provider = config.DataProtector();
19+
Assert.IsType<WindowsNativeDataProtector>(provider);
20+
}
21+
#else
22+
[Fact]
23+
public void DefaultDataProtectorOnUnixIsPlaintext()
24+
{
25+
Assert.False(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
26+
27+
var config = new SeqCliEncryptionProviderConfig();
28+
var provider = config.DataProtector();
29+
Assert.IsType<PlaintextDataProtector>(provider);
30+
}
31+
#endif
32+
33+
[Fact]
34+
public void SpecifyingEncryptorRequiresDecryptor()
35+
{
36+
var config = new SeqCliEncryptionProviderConfig
37+
{
38+
Encryptor = "test"
39+
};
40+
41+
Assert.Throws<ArgumentException>(() => config.DataProtector());
42+
}
43+
44+
[Fact]
45+
public void SpecifyingDecryptorRequiresEncryptor()
46+
{
47+
var config = new SeqCliEncryptionProviderConfig
48+
{
49+
Decryptor = "test"
50+
};
51+
52+
Assert.Throws<ArgumentException>(() => config.DataProtector());
53+
}
54+
55+
[Fact]
56+
public void SpecifyingEncryptorAndDecryptorActivatesExternalDataProtector()
57+
{
58+
var config = new SeqCliEncryptionProviderConfig
59+
{
60+
Encryptor = "test",
61+
Decryptor = "test"
62+
};
63+
64+
Assert.IsType<ExternalDataProtector>(config.DataProtector());
65+
}
66+
}

test/SeqCli.Tests/SeqCli.Tests.csproj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22
<PropertyGroup>
33
<TargetFrameworks>net9.0</TargetFrameworks>
44
<TargetFrameworks Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">$(TargetFrameworks);net9.0-windows</TargetFrameworks>
5+
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
6+
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
7+
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
8+
</PropertyGroup>
9+
<PropertyGroup Condition="'$(IsWindows)'=='true'">
10+
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
11+
</PropertyGroup>
12+
<PropertyGroup Condition="'$(IsOSX)'=='true'">
13+
<DefineConstants>$(DefineConstants);OSX</DefineConstants>
14+
</PropertyGroup>
15+
<PropertyGroup Condition="'$(IsLinux)'=='true'">
16+
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
17+
</PropertyGroup>
18+
<PropertyGroup Condition="'$(IsWindows)'!='true'">
19+
<DefineConstants>$(DefineConstants);UNIX</DefineConstants>
520
</PropertyGroup>
621
<ItemGroup>
722
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />

test/SeqCli.Tests/Support/TempFolder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public TempFolder(string name)
1515
{
1616
Path = System.IO.Path.Combine(
1717
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
18-
"SeqCli.Forwarder.Tests",
18+
"SeqCli.Tests",
1919
Session.ToString("n"),
2020
name);
2121

0 commit comments

Comments
 (0)