feat(deployment): add secure Linux runtime (#17)
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
using FinalFactory.Rendezvous.Server.Abuse;
|
||||
using FinalFactory.Rendezvous.Server.Deployment;
|
||||
|
||||
namespace FinalFactory.Rendezvous.Tests.Deployment;
|
||||
|
||||
public sealed class DeploymentOptionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ProductionConfigurationAcceptsExplicitPublicEndpointsAndTrustBoundary()
|
||||
{
|
||||
DeploymentOptions options = ValidOptions();
|
||||
AbuseProtectionOptions abuse = new()
|
||||
{
|
||||
TrustedProxyAddresses = ["192.0.2.10"],
|
||||
};
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
abuse,
|
||||
"rendezvous.finalfactory.at");
|
||||
|
||||
Assert.Empty(errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProductionConfigurationRejectsUnsafeAndAmbiguousDefaults()
|
||||
{
|
||||
DeploymentOptions options = new()
|
||||
{
|
||||
SingleActiveInstance = false,
|
||||
};
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
new AbuseProtectionOptions(),
|
||||
"*");
|
||||
|
||||
Assert.Contains(errors, error => error.Contains("SingleActiveInstance", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("PublicHttpBaseUrl", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("PublicUdpHost", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("TrustedProxyAddresses", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("AllowedHosts", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://rendezvous.example.com/")]
|
||||
[InlineData("https://user@example.com/")]
|
||||
[InlineData("https://rendezvous.example.com/path")]
|
||||
[InlineData("https://localhost/")]
|
||||
[InlineData("https://10.0.0.1/")]
|
||||
[InlineData("https://192.0.2.10/")]
|
||||
[InlineData("https://[::ffff:10.0.0.1]/")]
|
||||
[InlineData("https://[ff02::1]/")]
|
||||
[InlineData("https://rendezvous.invalid/")]
|
||||
public void ProductionConfigurationRejectsUnsafeHttpEndpoint(string endpoint)
|
||||
{
|
||||
DeploymentOptions options = ValidOptions() with { PublicHttpBaseUrl = endpoint };
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
new AbuseProtectionOptions { TrustedProxyAddresses = ["192.0.2.10"] },
|
||||
"rendezvous.finalfactory.at");
|
||||
|
||||
Assert.Contains(errors, error => error.Contains("PublicHttpBaseUrl", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0.1.2.3")]
|
||||
[InlineData("100.64.0.1")]
|
||||
[InlineData("192.0.2.1")]
|
||||
[InlineData("198.18.0.1")]
|
||||
[InlineData("198.51.100.1")]
|
||||
[InlineData("203.0.113.1")]
|
||||
[InlineData("224.0.0.1")]
|
||||
[InlineData("255.255.255.255")]
|
||||
[InlineData("::ffff:192.168.1.1")]
|
||||
[InlineData("2001:db8::1")]
|
||||
[InlineData("ff02::1")]
|
||||
[InlineData("rendezvous.example.com")]
|
||||
[InlineData("rendezvous.home.arpa")]
|
||||
[InlineData("rendezvous.alt")]
|
||||
[InlineData("service.test")]
|
||||
public void ProductionConfigurationRejectsNonPublicUdpEndpoint(string endpoint)
|
||||
{
|
||||
DeploymentOptions options = ValidOptions() with { PublicUdpHost = endpoint };
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
new AbuseProtectionOptions { TrustedProxyAddresses = ["192.0.2.10"] },
|
||||
"rendezvous.finalfactory.at");
|
||||
|
||||
Assert.Contains(errors, error => error.Contains("PublicUdpHost", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsolatedSmokeTestRequiresExplicitPrivateEndpointOverride()
|
||||
{
|
||||
DeploymentOptions options = ValidOptions() with
|
||||
{
|
||||
PublicHttpBaseUrl = "https://localhost/",
|
||||
PublicUdpHost = "127.0.0.1",
|
||||
AllowPrivatePublicEndpoints = true,
|
||||
};
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
new AbuseProtectionOptions { TrustedProxyAddresses = ["127.0.0.1"] },
|
||||
"localhost");
|
||||
|
||||
Assert.Empty(errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProductionConfigurationRejectsInvalidPortsDeadlinesAndMismatchedHostFilter()
|
||||
{
|
||||
DeploymentOptions options = ValidOptions() with
|
||||
{
|
||||
PublicUdpPort = 0,
|
||||
DrainDeadlineSeconds = 31,
|
||||
MinimumDrainSeconds = 6,
|
||||
};
|
||||
|
||||
IReadOnlyList<string> errors = options.ValidateProduction(
|
||||
new AbuseProtectionOptions { TrustedProxyAddresses = ["192.0.2.10"] },
|
||||
"different.finalfactory.at");
|
||||
|
||||
Assert.Contains(errors, error => error.Contains("PublicUdpPort", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("DrainDeadlineSeconds", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("MinimumDrainSeconds", StringComparison.Ordinal));
|
||||
Assert.Contains(errors, error => error.Contains("exact host", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static DeploymentOptions ValidOptions() => new()
|
||||
{
|
||||
PublicHttpBaseUrl = "https://rendezvous.finalfactory.at/",
|
||||
PublicUdpHost = "rendezvous-udp.finalfactory.at",
|
||||
PublicUdpPort = 9050,
|
||||
DrainDeadlineSeconds = 10,
|
||||
MinimumDrainSeconds = 1,
|
||||
SingleActiveInstance = true,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user