mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
* Trim pwsh special chars when masking secrets * Add pwsh valueEncoder * Explain regex * Update ValueEncoders.cs * Add tests for pwsh color codes in secrets * Formatting * Group tests into theories * Split secret on PS chars and mask for them * Clean up comments * Remove unused unittest * Rename escape methods
189 lines
7.3 KiB
C#
189 lines
7.3 KiB
C#
using GitHub.Runner.Common.Util;
|
|
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Xunit;
|
|
|
|
namespace GitHub.Runner.Common.Tests
|
|
{
|
|
public sealed class HostContextL0
|
|
{
|
|
private HostContext _hc;
|
|
private CancellationTokenSource _tokenSource;
|
|
|
|
[Fact]
|
|
[Trait("Level", "L0")]
|
|
[Trait("Category", "Common")]
|
|
public void CreateServiceReturnsNewInstance()
|
|
{
|
|
try
|
|
{
|
|
// Arrange.
|
|
Setup();
|
|
|
|
// Act.
|
|
var reference1 = _hc.CreateService<IRunnerServer>();
|
|
var reference2 = _hc.CreateService<IRunnerServer>();
|
|
|
|
// Assert.
|
|
Assert.NotNull(reference1);
|
|
Assert.IsType<RunnerServer>(reference1);
|
|
Assert.NotNull(reference2);
|
|
Assert.IsType<RunnerServer>(reference2);
|
|
Assert.False(object.ReferenceEquals(reference1, reference2));
|
|
}
|
|
finally
|
|
{
|
|
// Cleanup.
|
|
Teardown();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
[Trait("Level", "L0")]
|
|
[Trait("Category", "Common")]
|
|
public void GetServiceReturnsSingleton()
|
|
{
|
|
try
|
|
{
|
|
// Arrange.
|
|
Setup();
|
|
|
|
// Act.
|
|
var reference1 = _hc.GetService<IRunnerServer>();
|
|
var reference2 = _hc.GetService<IRunnerServer>();
|
|
|
|
// Assert.
|
|
Assert.NotNull(reference1);
|
|
Assert.IsType<RunnerServer>(reference1);
|
|
Assert.NotNull(reference2);
|
|
Assert.True(object.ReferenceEquals(reference1, reference2));
|
|
}
|
|
finally
|
|
{
|
|
// Cleanup.
|
|
Teardown();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
[Trait("Level", "L0")]
|
|
[Trait("Category", "Common")]
|
|
public void DefaultSecretMaskers()
|
|
{
|
|
try
|
|
{
|
|
// Arrange.
|
|
Setup();
|
|
|
|
// Act.
|
|
_hc.SecretMasker.AddValue("Password123!");
|
|
_hc.SecretMasker.AddValue("Pass\"word\"123!");
|
|
_hc.SecretMasker.AddValue("Pass word 123!");
|
|
_hc.SecretMasker.AddValue("Pass<word>123!");
|
|
_hc.SecretMasker.AddValue("Pass'word'123!");
|
|
_hc.SecretMasker.AddValue("\"Password123!!\"");
|
|
_hc.SecretMasker.AddValue("\"short\"");
|
|
|
|
// Assert.
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Password123!123"));
|
|
Assert.Equal("password123", _hc.SecretMasker.MaskSecrets("password123"));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Pass\\\"word\\\"123!123"));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Pass%20word%20123%21123"));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Pass<word>123!123"));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Pass''word''123!123"));
|
|
Assert.Equal("OlBh***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($":Password123!"))));
|
|
Assert.Equal("YTpQ***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($"a:Password123!"))));
|
|
Assert.Equal("YWI6***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($"ab:Password123!"))));
|
|
Assert.Equal("YWJjOlBh***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($"abc:Password123!"))));
|
|
Assert.Equal("YWJjZDpQ***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($"abcd:Password123!"))));
|
|
Assert.Equal("YWJjZGU6***", _hc.SecretMasker.MaskSecrets(Convert.ToBase64String(Encoding.UTF8.GetBytes($"abcde:Password123!"))));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123Password123!!123"));
|
|
Assert.Equal("123short123", _hc.SecretMasker.MaskSecrets("123short123"));
|
|
Assert.Equal("123***123", _hc.SecretMasker.MaskSecrets("123\"short\"123"));
|
|
}
|
|
finally
|
|
{
|
|
// Cleanup.
|
|
Teardown();
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("secret&secret&secret", "secret&secret&\x0033[96msecret\x0033[0m", "***\x0033[96m***\x0033[0m")]
|
|
[InlineData("secret&secret+secret", "secret&\x0033[96msecret+secret\x0033[0m", "***\x0033[96m***\x0033[0m")]
|
|
[InlineData("secret+secret&secret", "secret+secret&\x0033[96msecret\x0033[0m", "***\x0033[96m***\x0033[0m")]
|
|
[InlineData("secret&secret&+secretsecret", "secret&secret&+\x0033[96ms\x0033[0mecretsecret", "***\x0033[96ms\x0033[0m***")]
|
|
[InlineData("secret&+secret&secret", "secret&+\x0033[96ms\x0033[0mecret&secret", "***\x0033[96ms\x0033[0m***")]
|
|
[InlineData("secret&+secret&+secret", "secret&+\x0033[96ms\x0033[0mecret&+secret", "***\x0033[96ms\x0033[0m***")]
|
|
[InlineData("secret&+secret&secret&+secret", "secret&+\x0033[96ms\x0033[0mecret&secret&+secret", "***\x0033[96ms\x0033[0m***")]
|
|
[Trait("Level", "L0")]
|
|
[Trait("Category", "Common")]
|
|
public void SecretSectionMasking(string secret, string rawOutput, string maskedOutput)
|
|
{
|
|
try
|
|
{
|
|
// Arrange.
|
|
Setup();
|
|
|
|
// Act.
|
|
_hc.SecretMasker.AddValue(secret);
|
|
|
|
// Assert.
|
|
Assert.Equal(maskedOutput, _hc.SecretMasker.MaskSecrets(rawOutput));
|
|
}
|
|
finally
|
|
{
|
|
// Cleanup.
|
|
Teardown();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
[Trait("Level", "L0")]
|
|
[Trait("Category", "Common")]
|
|
public void SecretMaskerForProxy()
|
|
{
|
|
try
|
|
{
|
|
Environment.SetEnvironmentVariable("http_proxy", "http://user:password123@127.0.0.1:8888");
|
|
|
|
// Arrange.
|
|
Setup();
|
|
|
|
// Assert.
|
|
var logFile = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), $"trace_{nameof(HostContextL0)}_{nameof(SecretMaskerForProxy)}.log");
|
|
var tempFile = Path.GetTempFileName();
|
|
File.Delete(tempFile);
|
|
File.Copy(logFile, tempFile);
|
|
var content = File.ReadAllText(tempFile);
|
|
Assert.DoesNotContain("password123", content);
|
|
Assert.Contains("http://user:***@127.0.0.1:8888", content);
|
|
}
|
|
finally
|
|
{
|
|
Environment.SetEnvironmentVariable("http_proxy", null);
|
|
// Cleanup.
|
|
Teardown();
|
|
}
|
|
}
|
|
|
|
private void Setup([CallerMemberName] string testName = "")
|
|
{
|
|
_tokenSource = new CancellationTokenSource();
|
|
_hc = new HostContext(
|
|
hostType: "L0Test",
|
|
logFile: Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), $"trace_{nameof(HostContextL0)}_{testName}.log"));
|
|
}
|
|
|
|
private void Teardown()
|
|
{
|
|
_hc?.Dispose();
|
|
_tokenSource?.Dispose();
|
|
}
|
|
}
|
|
}
|