| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- using LibGit2Sharp;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using RackPeek.Domain;
- using RackPeek.Domain.Git;
- namespace Tests.Git;
- [Collection("Git static state")]
- public sealed class GitConfigurationTests : IDisposable {
- private readonly string _tempDir;
- public GitConfigurationTests() {
- _tempDir = Path.Combine(
- Path.GetTempPath(),
- "rackpeek-git-cfg-tests",
- Guid.NewGuid().ToString());
- Directory.CreateDirectory(_tempDir);
- }
- public void Dispose() {
- try {
- if (Directory.Exists(_tempDir))
- Directory.Delete(_tempDir, true);
- }
- catch {
- // ignore cleanup issues
- }
- }
- private static IConfiguration BuildConfig(Dictionary<string, string?> values) =>
- new ConfigurationBuilder()
- .AddInMemoryCollection(values)
- .Build();
- [Fact]
- public void Missing_Git_Token_Registers_NullGitRepository() {
- // Doc: GIT_TOKEN is required to enable the integration. Without it the
- // indicator never appears (RpkConstants.HasGitServices stays false) and
- // every git call is a no-op via NullGitRepository.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?>()), _tempDir);
- ServiceProvider provider = services.BuildServiceProvider();
- IGitRepository repo = provider.GetRequiredService<IGitRepository>();
- Assert.IsType<NullGitRepository>(repo);
- Assert.False(RpkConstants.HasGitServices);
- }
- [Fact]
- public void Empty_Git_Token_Registers_NullGitRepository() {
- // An empty/whitespace GIT_TOKEN must be treated the same as unset.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = " "
- }), _tempDir);
- ServiceProvider provider = services.BuildServiceProvider();
- IGitRepository repo = provider.GetRequiredService<IGitRepository>();
- Assert.IsType<NullGitRepository>(repo);
- Assert.False(RpkConstants.HasGitServices);
- }
- [Fact]
- public void Git_Token_Set_Registers_LibGit2GitRepository_And_Flips_HasGitServices() {
- // Doc: with GIT_TOKEN set, a Git status indicator appears in the
- // header. The header gates the indicator on RpkConstants.HasGitServices.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token",
- ["GIT_USERNAME"] = "octocat"
- }), _tempDir);
- ServiceProvider provider = services.BuildServiceProvider();
- IGitRepository repo = provider.GetRequiredService<IGitRepository>();
- Assert.IsType<LibGit2GitRepository>(repo);
- Assert.True(RpkConstants.HasGitServices);
- }
- [Fact]
- public void Git_Username_Defaults_To_git_When_Only_Token_Provided() {
- // Doc table says GIT_USERNAME is "required", but in practice the code
- // defaults it to the conventional "git" so users with personal access
- // tokens that don't care about the username (e.g. GitHub fine-grained
- // tokens) still authenticate correctly.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token"
- }), _tempDir);
- IGitCredentialsProvider creds = services.BuildServiceProvider()
- .GetRequiredService<IGitCredentialsProvider>();
- LibGit2Sharp.Handlers.CredentialsHandler handler = creds.GetHandler();
- var credentials = (UsernamePasswordCredentials)handler("https://example.com", null!,
- SupportedCredentialTypes.UsernamePassword);
- Assert.Equal("git", credentials.Username);
- Assert.Equal("ghp_test_token", credentials.Password);
- }
- [Fact]
- public void Insecure_Tls_Flag_Defaults_To_False() {
- // Doc: GIT_INSECURE_TLS is optional. Default behaviour must validate
- // certificates so we don't silently accept MITM on public hosts.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token"
- }), _tempDir);
- var repo = (LibGit2GitRepository)services.BuildServiceProvider()
- .GetRequiredService<IGitRepository>();
- Assert.False(repo.InsecureTls);
- }
- [Fact]
- public void Insecure_Tls_True_Is_Plumbed_Through_To_Repository() {
- // Doc: GIT_INSECURE_TLS=true skips TLS validation. The flag must
- // reach the repository instance that runs push/pull/fetch.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token",
- ["GIT_INSECURE_TLS"] = "true"
- }), _tempDir);
- var repo = (LibGit2GitRepository)services.BuildServiceProvider()
- .GetRequiredService<IGitRepository>();
- Assert.True(repo.InsecureTls);
- }
- [Fact]
- public void Insecure_Tls_String_Comparison_Is_Case_Insensitive() {
- // Common YAML/.env idiom is "True" or "TRUE"; the doc shows lowercase
- // but users will type whatever feels natural.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token",
- ["GIT_INSECURE_TLS"] = "TRUE"
- }), _tempDir);
- var repo = (LibGit2GitRepository)services.BuildServiceProvider()
- .GetRequiredService<IGitRepository>();
- Assert.True(repo.InsecureTls);
- }
- [Fact]
- public void Insecure_Tls_Any_Other_Value_Means_False() {
- // Only "true" enables the bypass — strings like "yes", "1", etc.
- // must NOT silently disable TLS.
- var services = new ServiceCollection();
- services.AddGitServices(BuildConfig(new Dictionary<string, string?> {
- ["GIT_TOKEN"] = "ghp_test_token",
- ["GIT_INSECURE_TLS"] = "yes"
- }), _tempDir);
- var repo = (LibGit2GitRepository)services.BuildServiceProvider()
- .GetRequiredService<IGitRepository>();
- Assert.False(repo.InsecureTls);
- }
- }
|