From 63db173c759dc858779d78d9a2677478b5199e78 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 22 Oct 2024 18:27:06 +0200 Subject: [PATCH 1/3] Improve parsing of docker.io credentials --- .../UnitTests/Core/CredentialsTests.cs | 40 ++++++++++++++++--- Source/Bake/Core/Credentials.cs | 15 +++++-- Source/Bake/ValueObjects/ContainerTag.cs | 2 - 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/Source/Bake.Tests/UnitTests/Core/CredentialsTests.cs b/Source/Bake.Tests/UnitTests/Core/CredentialsTests.cs index abd91226..87853035 100644 --- a/Source/Bake.Tests/UnitTests/Core/CredentialsTests.cs +++ b/Source/Bake.Tests/UnitTests/Core/CredentialsTests.cs @@ -20,11 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using Bake.Core; +using Bake.Services; using Bake.Tests.Helpers; using FluentAssertions; using NUnit.Framework; @@ -36,7 +33,7 @@ public class CredentialsTests : TestFor [TestCase( "http://localhost:5555/v3/index.json", "bake_credentials_nuget_localhost_apikey", "acd0b30512ac4fa39f62eb7a61fcf56c")] - public async Task GetNuGetApiKeyAsync( + public async Task GetNuGetApiKey( string url, string environmentKey, string expectedCredentials) @@ -56,5 +53,38 @@ public async Task GetNuGetApiKeyAsync( // Assert credentials.Should().Be(expectedCredentials); } + + [TestCase( + "docker.io/rasmus/debug", + "dockerhub")] + [TestCase( + "artifactory.example.io/rasmus/debug", + "bake_credentials_docker_artifactory_example_io")] + public async Task GetDockerLogin( + string containerTagStr, + string environmentKeyPrefix) + { + // Arrange + var username = A(); + var password = A(); + Inject(A()); + Inject(new TestEnvironmentVariables(new Dictionary(StringComparer.OrdinalIgnoreCase) + { + [$"{environmentKeyPrefix}_username"] = username, + [$"{environmentKeyPrefix}_password"] = password + })); + var containerTagParser = new ContainerTagParser(); + containerTagParser.TryParse(containerTagStr, out var containerTag).Should().BeTrue(); + + // Act + var credentials = await Sut.TryGetDockerLoginAsync( + containerTag!, + CancellationToken.None); + + // Assert + credentials!.Username.Should().Be(username); + credentials!.Password.Should().Be(password); + } + } } diff --git a/Source/Bake/Core/Credentials.cs b/Source/Bake/Core/Credentials.cs index d2f64ac5..2ccf5d52 100644 --- a/Source/Bake/Core/Credentials.cs +++ b/Source/Bake/Core/Credentials.cs @@ -155,18 +155,18 @@ public async Task TryGetOctopusDeployApiKeyAsync( { var environmentVariables = await _environmentVariables.GetAsync(cancellationToken); - if (containerTag.HostAndPort.StartsWith("ghcr.io/") && + if (string.Equals(containerTag.HostAndPort, "ghcr.io", StringComparison.OrdinalIgnoreCase) && environmentVariables.TryGetValue("github_token", out var githubToken)) { return new DockerLogin( - containerTag.HostAndPort.Split('/', StringSplitOptions.RemoveEmptyEntries)[1], + containerTag.HostAndPort, githubToken, "ghcr.io"); } var possibilities = new List<(string, string)>(); - if (string.IsNullOrEmpty(containerTag.HostAndPort)) + if (string.IsNullOrEmpty(containerTag.HostAndPort) || string.Equals(containerTag.HostAndPort, "docker.io", StringComparison.OrdinalIgnoreCase)) { possibilities.Add(("dockerhub", string.Empty)); } @@ -183,6 +183,15 @@ public async Task TryGetOctopusDeployApiKeyAsync( var username = environmentVariables.TryGetValue($"{e}_username", out var u) ? u : string.Empty; var password = environmentVariables.TryGetValue($"{e}_password", out var p) ? p : string.Empty; + if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) + { + _logger.LogInformation($"Did not find any Docker credentials at '{e}_(username/password)'"); + } + else + { + _logger.LogInformation($"Found Docker credentials at '{e}_(username/password)'"); + } + return !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) ? new DockerLogin(username, password, s) : null; diff --git a/Source/Bake/ValueObjects/ContainerTag.cs b/Source/Bake/ValueObjects/ContainerTag.cs index ee14f096..e20cc4db 100644 --- a/Source/Bake/ValueObjects/ContainerTag.cs +++ b/Source/Bake/ValueObjects/ContainerTag.cs @@ -20,8 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; - namespace Bake.ValueObjects { public class ContainerTag From f84997354b33c9fa8e8461a989e92bed089602cd Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 22 Oct 2024 18:38:46 +0200 Subject: [PATCH 2/3] Fix Docker hub tag parsing when no host --- .../UnitTests/Services/ContainerTagParserTests.cs | 12 ++++++++++++ Source/Bake/Services/ContainerTagParser.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/Bake.Tests/UnitTests/Services/ContainerTagParserTests.cs b/Source/Bake.Tests/UnitTests/Services/ContainerTagParserTests.cs index 2d74b49b..dab6591f 100644 --- a/Source/Bake.Tests/UnitTests/Services/ContainerTagParserTests.cs +++ b/Source/Bake.Tests/UnitTests/Services/ContainerTagParserTests.cs @@ -31,6 +31,12 @@ namespace Bake.Tests.UnitTests.Services { public class ContainerTagParserTests : TestFor { + [TestCase( + "rasmus/debug:latest", + "", + "rasmus", + "debug", + "latest")] [TestCase( "registry", "", @@ -49,6 +55,12 @@ public class ContainerTagParserTests : TestFor "path", "image", "latest")] + [TestCase( + "127.0.0.1/path/image:2", + "127.0.0.1", + "path", + "image", + "2")] [TestCase( "localhost/path/image:2", "localhost", diff --git a/Source/Bake/Services/ContainerTagParser.cs b/Source/Bake/Services/ContainerTagParser.cs index ce5cf2ff..11d66b8c 100644 --- a/Source/Bake/Services/ContainerTagParser.cs +++ b/Source/Bake/Services/ContainerTagParser.cs @@ -30,7 +30,7 @@ public class ContainerTagParser : IContainerTagParser { private static readonly Regex ImageParser = new( @"^ - (?[a-z\-0-9\.]+(:[0-9]+){0,1}/){0,1} + (?([a-z\-0-9]+\.[a-z\-0-9\.]+|localhost)(:[0-9]+){0,1}/){0,1} (?[a-z\-0-9/]+/){0,1} (?[a-z\-0-9]+) (:(?