Skip to content

Commit

Permalink
Add --no-ssl-verify to bbs2gh commands (#870)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArinGhazarian authored Mar 11, 2023
1 parent 9bbd350 commit d1ea833
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 24 deletions.
3 changes: 2 additions & 1 deletion RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- Fix `gh bbs2gh grant-migrator-role` so it doesn't throw `System.InvalidOperationException`
- Rename `AWS_ACCESS_KEY` and `AWS_SECRET_KEY` environment variables to `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` respectively to align with the environment variables that the AWS CLI already uses. Old environment variables are still supported but they will be removed in future.
- Send a `User-Agent` header with the current CLI version when downloading migration archives from GitHub Enterprise Server
- Add support for migration archives larger than 2GB when using the blob storage flow
- Add support for migration archives larger than 2GB when using the blob storage flow
- Add `--no-ssh-verify` option to `gh bbs2gh generate-script` and `gh bbs2gh migrate-repo` commands to support migrating from a Bitbucket Server or Bitbucket Data Center instance that uses a self-signed SSL certificate
34 changes: 34 additions & 0 deletions src/OctoshiftCLI.Tests/bbs2gh/BbsApiFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,39 @@ public void Should_Create_BbsApi_For_Source_Bbs_Api_With_Default()
githubApi.Should().NotBeNull();
httpClient.DefaultRequestHeaders.Accept.First().MediaType.Should().Be("application/json");
}

[Fact]
public void Should_Create_BbsApi_With_No_Ssl_Verify()
{
using var httpClient = new HttpClient();

_mockHttpClientFactory
.Setup(x => x.CreateClient("NoSSL"))
.Returns(httpClient);

// Act
var githubApi = _bbsApiFactory.Create(BBS_SERVER_URL, "user", "pass", true);

// Assert
githubApi.Should().NotBeNull();
httpClient.DefaultRequestHeaders.Accept.First().MediaType.Should().Be("application/json");
}

[Fact]
public void Should_Create_BbsApi_With_Kerberos_And_No_Ssl_Verify()
{
using var httpClient = new HttpClient();

_mockHttpClientFactory
.Setup(x => x.CreateClient("KerberosNoSSL"))
.Returns(httpClient);

// Act
var githubApi = _bbsApiFactory.CreateKerberos(BBS_SERVER_URL, true);

// Assert
githubApi.Should().NotBeNull();
httpClient.DefaultRequestHeaders.Accept.First().MediaType.Should().Be("application/json");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void Should_Have_Options()
{
_command.Should().NotBeNull();
_command.Name.Should().Be("generate-script");
_command.Options.Count.Should().Be(17);
_command.Options.Count.Should().Be(18);

TestHelpers.VerifyCommandOption(_command.Options, "bbs-server-url", true);
TestHelpers.VerifyCommandOption(_command.Options, "github-org", true);
Expand All @@ -54,6 +54,7 @@ public void Should_Have_Options()
TestHelpers.VerifyCommandOption(_command.Options, "aws-bucket-name", false);
TestHelpers.VerifyCommandOption(_command.Options, "aws-region", false);
TestHelpers.VerifyCommandOption(_command.Options, "keep-archive", false);
TestHelpers.VerifyCommandOption(_command.Options, "no-ssl-verify", false);
}

[Fact]
Expand All @@ -67,11 +68,44 @@ public void It_Gets_A_Kerberos_HttpClient_When_Kerberos_Is_True()

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL));
_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL, false));
}

[Fact]
public void It_Gets_A_Default_HttpClient_When_Kerberos_Is_Not_Set()
public void It_Gets_A_Kerberos_With_No_Ssl_Verify_HttpClient_When_Kerberos_And_No_Ssl_Verify_Are_True()
{
var args = new GenerateScriptCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
Kerberos = true,
NoSslVerify = true
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL, true));
}

[Fact]
public void It_Gets_A_Default_HttpClient_When_Kerberos_And_No_Ssl_Verify_Are_Not_Set()
{
var bbsTestUser = "user";
var bbsTestPassword = "password";

var args = new GenerateScriptCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
BbsUsername = bbsTestUser,
BbsPassword = bbsTestPassword
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, bbsTestUser, bbsTestPassword, false));
}

[Fact]
public void It_Gets_A_No_Ssl_Verify_HttpClient_When_No_Ssl_Verify_Is_Set()
{
var bbsTestUser = "user";
var bbsTestPassword = "password";
Expand All @@ -81,10 +115,11 @@ public void It_Gets_A_Default_HttpClient_When_Kerberos_Is_Not_Set()
BbsServerUrl = BBS_SERVER_URL,
BbsUsername = bbsTestUser,
BbsPassword = bbsTestPassword,
NoSslVerify = true
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, bbsTestUser, bbsTestPassword));
_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, bbsTestUser, bbsTestPassword, true));
}
}
44 changes: 38 additions & 6 deletions src/OctoshiftCLI.Tests/bbs2gh/Commands/MigrateRepoCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void Should_Have_Options()
var command = new MigrateRepoCommand();
command.Should().NotBeNull();
command.Name.Should().Be("migrate-repo");
command.Options.Count.Should().Be(27);
command.Options.Count.Should().Be(28);

TestHelpers.VerifyCommandOption(command.Options, "bbs-server-url", false);
TestHelpers.VerifyCommandOption(command.Options, "bbs-project", false);
Expand Down Expand Up @@ -80,6 +80,7 @@ public void Should_Have_Options()
TestHelpers.VerifyCommandOption(command.Options, "kerberos", false, true);
TestHelpers.VerifyCommandOption(command.Options, "verbose", false);
TestHelpers.VerifyCommandOption(command.Options, "keep-archive", false);
TestHelpers.VerifyCommandOption(command.Options, "no-ssl-verify", false);
}

[Fact]
Expand Down Expand Up @@ -137,7 +138,7 @@ public void BuildHandler_Creates_The_Handler()
handler.Should().NotBeNull();

_mockGithubApiFactory.Verify(m => m.Create(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
_mockBbsApiFactory.Verify(m => m.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Never);
_mockBbsApiFactory.Verify(m => m.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()), Times.Never);
_mockBbsArchiveDownloaderFactory.Verify(m => m.CreateSshDownloader(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>()), Times.Never);
_mockBbsArchiveDownloaderFactory.Verify(m => m.CreateSmbDownloader(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Never);
_mockAzureApiFactory.Verify(m => m.Create(It.IsAny<string>()), Times.Never);
Expand Down Expand Up @@ -180,7 +181,7 @@ public void BuildHandler_Creates_Bbs_Api_When_Bbs_Server_Url_Is_Provided()
// Assert
handler.Should().NotBeNull();

_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, BBS_USERNAME, BBS_PASSWORD));
_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, BBS_USERNAME, BBS_PASSWORD, false));
}

[Fact]
Expand Down Expand Up @@ -229,21 +230,52 @@ public void It_Gets_A_Kerberos_HttpClient_When_Kerberos_Is_True()

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL));
_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL, false));
}

[Fact]
public void It_Gets_A_Default_HttpClient_When_Kerberos_Is_Not_Set()
public void It_Gets_A_Kerberos_With_No_Ssl_Verify_HttpClient_When_Kerberos_And_No_Ssl_Verify_Are_True()
{
var args = new MigrateRepoCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
Kerberos = true,
NoSslVerify = true
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.CreateKerberos(BBS_SERVER_URL, true));
}

[Fact]
public void It_Gets_A_Default_HttpClient_When_Kerberos_And_No_Ssl_Verify_Are_Not_Set()
{
var args = new MigrateRepoCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
BbsUsername = BBS_USERNAME,
BbsPassword = BBS_PASSWORD
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, BBS_USERNAME, BBS_PASSWORD, false));
}

[Fact]
public void It_Gets_A_No_Ssl_Verify_HttpClient_When_No_Ssl_Verify_Is_True()
{
var args = new MigrateRepoCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
BbsUsername = BBS_USERNAME,
BbsPassword = BBS_PASSWORD,
NoSslVerify = true
};

_command.BuildHandler(args, _mockServiceProvider.Object);

_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, BBS_USERNAME, BBS_PASSWORD));
_mockBbsApiFactory.Verify(m => m.Create(BBS_SERVER_URL, BBS_USERNAME, BBS_PASSWORD, true));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using OctoshiftCLI.BbsToGithub.Commands;
using OctoshiftCLI.BbsToGithub.Handlers;
Expand Down Expand Up @@ -238,6 +239,42 @@ public async Task One_Repo_With_Kerberos()
_mockFileSystemProvider.Verify(m => m.WriteAllTextAsync(It.IsAny<string>(), It.Is<string>(script => script.Contains(migrateRepoCommand))));
}

[Fact]
public async Task One_Repo_With_No_Ssl_Verify()
{
// Arrange
_mockBbsApi.Setup(m => m.GetProjects()).ReturnsAsync(new[]
{
(Id: 1, Key: BBS_FOO_PROJECT_KEY, Name: BBS_FOO_PROJECT_NAME),
});
_mockBbsApi.Setup(m => m.GetRepos(BBS_FOO_PROJECT_KEY)).ReturnsAsync(new[]
{
(Id: 1, Slug: BBS_FOO_REPO_1_SLUG, Name: BBS_FOO_REPO_1_NAME),
});

var migrateRepoCommand = $"Exec {{ gh bbs2gh migrate-repo --bbs-server-url \"{BBS_SERVER_URL}\" --bbs-username \"{BBS_USERNAME}\" --bbs-shared-home \"{BBS_SHARED_HOME}\" --bbs-project \"{BBS_FOO_PROJECT_KEY}\" --bbs-repo \"{BBS_FOO_REPO_1_SLUG}\" --ssh-user \"{SSH_USER}\" --ssh-private-key \"{SSH_PRIVATE_KEY}\" --ssh-port {SSH_PORT} --github-org \"{GITHUB_ORG}\" --github-repo \"{BBS_FOO_PROJECT_KEY}-{BBS_FOO_REPO_1_SLUG}\" --verbose --wait --no-ssl-verify }}";

// Act
var args = new GenerateScriptCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
GithubOrg = GITHUB_ORG,
BbsUsername = BBS_USERNAME,
BbsPassword = BBS_PASSWORD,
BbsSharedHome = BBS_SHARED_HOME,
SshUser = SSH_USER,
SshPrivateKey = SSH_PRIVATE_KEY,
SshPort = SSH_PORT,
Output = new FileInfo(OUTPUT),
Verbose = true,
NoSslVerify = true
};
await _handler.Handle(args);

// Assert
_mockFileSystemProvider.Verify(m => m.WriteAllTextAsync(It.IsAny<string>(), It.Is<string>(script => script.Contains(migrateRepoCommand))));
}

[Fact]
public async Task One_Repo_With_Smb()
{
Expand Down Expand Up @@ -385,6 +422,22 @@ public async Task One_Repo_With_Aws_Bucket_Name_And_Region()
_mockFileSystemProvider.Verify(m => m.WriteAllTextAsync(It.IsAny<string>(), It.Is<string>(script => script.Contains(migrateRepoCommand))));
}

[Fact]
public async Task It_Throws_If_BbsServer_Url_Is_Not_Provided_But_No_Ssl_Verify_Is_Provided()
{
// Act
var args = new GenerateScriptCommandArgs
{
NoSslVerify = true
};

// Assert
await _handler.Invoking(x => x.Handle(args))
.Should()
.ThrowExactlyAsync<OctoshiftCliException>()
.WithMessage("*--no-ssl-verify*--bbs-server-url*");
}

private string TrimNonExecutableLines(string script, int skipFirst = 9, int skipLast = 0)
{
var lines = script.Split(new[] { Environment.NewLine, "\n" }, StringSplitOptions.RemoveEmptyEntries).AsEnumerable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,25 @@ await _handler.Invoking(x => x.Handle(args))
.WithMessage("*--bbs-username*--bbs-password*--bbs-server-url*");
}

[Fact]
public async Task Errors_If_BbsServer_Url_Not_Provided_But_No_Ssl_Verify_Is_Provided()
{
// Act
var args = new MigrateRepoCommandArgs
{
ArchivePath = ARCHIVE_PATH,
GithubOrg = GITHUB_ORG,
GithubRepo = GITHUB_REPO,
NoSslVerify = true
};

// Assert
await _handler.Invoking(x => x.Handle(args))
.Should()
.ThrowExactlyAsync<OctoshiftCliException>()
.WithMessage("*--no-ssl-verify*--bbs-server-url*");
}

[Fact]
public async Task Errors_If_BbsServer_Url_Not_Provided_But_Ssh_User_Is_Provided()
{
Expand Down
8 changes: 4 additions & 4 deletions src/bbs2gh/BbsApiFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ public BbsApiFactory(OctoLogger octoLogger, IHttpClientFactory clientFactory, En
_retryPolicy = retryPolicy;
}

public virtual BbsApi Create(string bbsServerUrl, string bbsUsername, string bbsPassword)
public virtual BbsApi Create(string bbsServerUrl, string bbsUsername, string bbsPassword, bool noSsl = false)
{
bbsUsername ??= _environmentVariableProvider.BbsUsername();
bbsPassword ??= _environmentVariableProvider.BbsPassword();

var httpClient = _clientFactory.CreateClient("Default");
var httpClient = noSsl ? _clientFactory.CreateClient("NoSSL") : _clientFactory.CreateClient("Default");

var bbsClient = new BbsClient(_octoLogger, httpClient, _versionProvider, _retryPolicy, bbsUsername, bbsPassword);
return new BbsApi(bbsClient, bbsServerUrl, _octoLogger);
}

public virtual BbsApi CreateKerberos(string bbsServerUrl)
public virtual BbsApi CreateKerberos(string bbsServerUrl, bool noSsl = false)
{
var httpClient = _clientFactory.CreateClient("Kerberos");
var httpClient = noSsl ? _clientFactory.CreateClient("KerberosNoSSL") : _clientFactory.CreateClient("Kerberos");

var bbsClient = new BbsClient(_octoLogger, httpClient, _versionProvider, _retryPolicy);
return new BbsApi(bbsClient, bbsServerUrl, _octoLogger);
Expand Down
11 changes: 10 additions & 1 deletion src/bbs2gh/Commands/GenerateScriptCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public GenerateScriptCommand() : base(
AddOption(AwsBucketName);
AddOption(AwsRegion);
AddOption(KeepArchive);
AddOption(NoSslVerify);
}

public Option<string> BbsServerUrl { get; } = new(
Expand Down Expand Up @@ -108,6 +109,11 @@ public GenerateScriptCommand() : base(
name: "--keep-archive",
description: "Keeps the downloaded export archive after successfully uploading it. By default, it will be automatically deleted.");

public Option<bool> NoSslVerify { get; } = new(
name: "--no-ssl-verify",
description: "Disables SSL verification when communicating with your Bitbucket Server/Data Center instance. All other migration steps will continue to verify SSL. " +
"If your Bitbucket instance has a self-signed SSL certificate then setting this flag will allow the migration archive to be exported.");

public override GenerateScriptCommandHandler BuildHandler(GenerateScriptCommandArgs args, IServiceProvider sp)
{
if (args is null)
Expand All @@ -126,7 +132,9 @@ public override GenerateScriptCommandHandler BuildHandler(GenerateScriptCommandA
var environmentVariableProvider = sp.GetRequiredService<EnvironmentVariableProvider>();

var bbsApiFactory = sp.GetRequiredService<BbsApiFactory>();
var bbsApi = args.Kerberos ? bbsApiFactory.CreateKerberos(args.BbsServerUrl) : bbsApiFactory.Create(args.BbsServerUrl, args.BbsUsername, args.BbsPassword);
var bbsApi = args.Kerberos
? bbsApiFactory.CreateKerberos(args.BbsServerUrl, args.NoSslVerify)
: bbsApiFactory.Create(args.BbsServerUrl, args.BbsUsername, args.BbsPassword, args.NoSslVerify);

return new GenerateScriptCommandHandler(log, versionProvider, fileSystemProvider, bbsApi, environmentVariableProvider);
}
Expand All @@ -151,4 +159,5 @@ public class GenerateScriptCommandArgs
public string AwsBucketName { get; set; }
public string AwsRegion { get; set; }
public bool KeepArchive { get; set; }
public bool NoSslVerify { get; set; }
}
Loading

0 comments on commit d1ea833

Please sign in to comment.