4
0

GitConfigurationTests.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using LibGit2Sharp;
  2. using Microsoft.Extensions.Configuration;
  3. using Microsoft.Extensions.DependencyInjection;
  4. using RackPeek.Domain;
  5. using RackPeek.Domain.Git;
  6. namespace Tests.Git;
  7. [Collection("Git static state")]
  8. public sealed class GitConfigurationTests : IDisposable {
  9. private readonly string _tempDir;
  10. public GitConfigurationTests() {
  11. _tempDir = Path.Combine(
  12. Path.GetTempPath(),
  13. "rackpeek-git-cfg-tests",
  14. Guid.NewGuid().ToString());
  15. Directory.CreateDirectory(_tempDir);
  16. }
  17. public void Dispose() {
  18. try {
  19. if (Directory.Exists(_tempDir))
  20. Directory.Delete(_tempDir, true);
  21. }
  22. catch {
  23. // ignore cleanup issues
  24. }
  25. }
  26. private static IConfiguration BuildConfig(Dictionary<string, string?> values) =>
  27. new ConfigurationBuilder()
  28. .AddInMemoryCollection(values)
  29. .Build();
  30. [Fact]
  31. public void Missing_Git_Token_Registers_NullGitRepository() {
  32. // Doc: GIT_TOKEN is required to enable the integration. Without it the
  33. // indicator never appears (RpkConstants.HasGitServices stays false) and
  34. // every git call is a no-op via NullGitRepository.
  35. var services = new ServiceCollection();
  36. services.AddGitServices(BuildConfig(new Dictionary<string, string?>()), _tempDir);
  37. ServiceProvider provider = services.BuildServiceProvider();
  38. IGitRepository repo = provider.GetRequiredService<IGitRepository>();
  39. Assert.IsType<NullGitRepository>(repo);
  40. Assert.False(RpkConstants.HasGitServices);
  41. }
  42. [Fact]
  43. public void Empty_Git_Token_Registers_NullGitRepository() {
  44. // An empty/whitespace GIT_TOKEN must be treated the same as unset.
  45. var services = new ServiceCollection();
  46. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  47. ["GIT_TOKEN"] = " "
  48. }), _tempDir);
  49. ServiceProvider provider = services.BuildServiceProvider();
  50. IGitRepository repo = provider.GetRequiredService<IGitRepository>();
  51. Assert.IsType<NullGitRepository>(repo);
  52. Assert.False(RpkConstants.HasGitServices);
  53. }
  54. [Fact]
  55. public void Git_Token_Set_Registers_LibGit2GitRepository_And_Flips_HasGitServices() {
  56. // Doc: with GIT_TOKEN set, a Git status indicator appears in the
  57. // header. The header gates the indicator on RpkConstants.HasGitServices.
  58. var services = new ServiceCollection();
  59. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  60. ["GIT_TOKEN"] = "ghp_test_token",
  61. ["GIT_USERNAME"] = "octocat"
  62. }), _tempDir);
  63. ServiceProvider provider = services.BuildServiceProvider();
  64. IGitRepository repo = provider.GetRequiredService<IGitRepository>();
  65. Assert.IsType<LibGit2GitRepository>(repo);
  66. Assert.True(RpkConstants.HasGitServices);
  67. }
  68. [Fact]
  69. public void Git_Username_Defaults_To_git_When_Only_Token_Provided() {
  70. // Doc table says GIT_USERNAME is "required", but in practice the code
  71. // defaults it to the conventional "git" so users with personal access
  72. // tokens that don't care about the username (e.g. GitHub fine-grained
  73. // tokens) still authenticate correctly.
  74. var services = new ServiceCollection();
  75. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  76. ["GIT_TOKEN"] = "ghp_test_token"
  77. }), _tempDir);
  78. IGitCredentialsProvider creds = services.BuildServiceProvider()
  79. .GetRequiredService<IGitCredentialsProvider>();
  80. LibGit2Sharp.Handlers.CredentialsHandler handler = creds.GetHandler();
  81. var credentials = (UsernamePasswordCredentials)handler("https://example.com", null!,
  82. SupportedCredentialTypes.UsernamePassword);
  83. Assert.Equal("git", credentials.Username);
  84. Assert.Equal("ghp_test_token", credentials.Password);
  85. }
  86. [Fact]
  87. public void Insecure_Tls_Flag_Defaults_To_False() {
  88. // Doc: GIT_INSECURE_TLS is optional. Default behaviour must validate
  89. // certificates so we don't silently accept MITM on public hosts.
  90. var services = new ServiceCollection();
  91. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  92. ["GIT_TOKEN"] = "ghp_test_token"
  93. }), _tempDir);
  94. var repo = (LibGit2GitRepository)services.BuildServiceProvider()
  95. .GetRequiredService<IGitRepository>();
  96. Assert.False(repo.InsecureTls);
  97. }
  98. [Fact]
  99. public void Insecure_Tls_True_Is_Plumbed_Through_To_Repository() {
  100. // Doc: GIT_INSECURE_TLS=true skips TLS validation. The flag must
  101. // reach the repository instance that runs push/pull/fetch.
  102. var services = new ServiceCollection();
  103. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  104. ["GIT_TOKEN"] = "ghp_test_token",
  105. ["GIT_INSECURE_TLS"] = "true"
  106. }), _tempDir);
  107. var repo = (LibGit2GitRepository)services.BuildServiceProvider()
  108. .GetRequiredService<IGitRepository>();
  109. Assert.True(repo.InsecureTls);
  110. }
  111. [Fact]
  112. public void Insecure_Tls_String_Comparison_Is_Case_Insensitive() {
  113. // Common YAML/.env idiom is "True" or "TRUE"; the doc shows lowercase
  114. // but users will type whatever feels natural.
  115. var services = new ServiceCollection();
  116. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  117. ["GIT_TOKEN"] = "ghp_test_token",
  118. ["GIT_INSECURE_TLS"] = "TRUE"
  119. }), _tempDir);
  120. var repo = (LibGit2GitRepository)services.BuildServiceProvider()
  121. .GetRequiredService<IGitRepository>();
  122. Assert.True(repo.InsecureTls);
  123. }
  124. [Fact]
  125. public void Insecure_Tls_Any_Other_Value_Means_False() {
  126. // Only "true" enables the bypass — strings like "yes", "1", etc.
  127. // must NOT silently disable TLS.
  128. var services = new ServiceCollection();
  129. services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
  130. ["GIT_TOKEN"] = "ghp_test_token",
  131. ["GIT_INSECURE_TLS"] = "yes"
  132. }), _tempDir);
  133. var repo = (LibGit2GitRepository)services.BuildServiceProvider()
  134. .GetRequiredService<IGitRepository>();
  135. Assert.False(repo.InsecureTls);
  136. }
  137. }