mirror of
https://github.com/cirruslabs/tart.git
synced 2026-09-30 03:01:12 +02:00
* Use registry-1.docker.io for Docker Hub's docker.io host docker.io doesn't serve the registry API: https://docker.io/v2/ redirects to https://www.docker.com/, which URLSession follows, getting back an HTML page with HTTP 200. As a result, pushing fails with UnexpectedHTTPStatusCode("pushing blob (POST)", 200, ...), pulling fails to parse the manifest and "tart login docker.io" accepts any credentials, because ping() never gets an authentication challenge. Send the API requests for docker.io to registry-1.docker.io instead, while still using docker.io for the pushed image names and for the credentials lookup, so that credentials saved with "tart login docker.io" keep working. Fixes #1275 * Match docker.io case insensitively * Recognize Docker Hub with an explicit port * Parse the registry host once and keep it normalized Using the host exactly as specified for naming and credentials lookup changed the behavior for other registries too. For example, "127.0.0.1:05000" used to find credentials stored for "127.0.0.1:5000", but didn't anymore. Parse the URL once instead, take the normalized host and port from it like before, and only replace the URL's host with registry-1.docker.io for Docker Hub.
89 lines
3.5 KiB
Swift
89 lines
3.5 KiB
Swift
import XCTest
|
|
@testable import tart
|
|
|
|
final class RegistryHostTests: XCTestCase {
|
|
func testDockerHub() throws {
|
|
let credentialsProvider = RecordingCredentialsProvider()
|
|
let registry = try Registry(host: "docker.io", namespace: "org/repo",
|
|
credentialsProviders: [credentialsProvider])
|
|
|
|
// docker.io redirects to Docker's website, so the API
|
|
// requests should go to registry-1.docker.io instead
|
|
XCTAssertEqual(registry.baseURL, URL(string: "https://registry-1.docker.io/v2/"))
|
|
|
|
// ...while naming and credentials lookup should still use the host specified by the user
|
|
XCTAssertEqual(registry.host, "docker.io")
|
|
XCTAssertNil(try registry.lookupCredentials())
|
|
XCTAssertEqual(credentialsProvider.requestedHosts, ["docker.io"])
|
|
}
|
|
|
|
func testDockerHubIsMatchedCaseInsensitively() throws {
|
|
let credentialsProvider = RecordingCredentialsProvider()
|
|
let registry = try Registry(host: "Docker.IO", namespace: "org/repo",
|
|
credentialsProviders: [credentialsProvider])
|
|
|
|
XCTAssertEqual(registry.baseURL, URL(string: "https://registry-1.docker.io/v2/"))
|
|
XCTAssertEqual(registry.host, "Docker.IO")
|
|
XCTAssertNil(try registry.lookupCredentials())
|
|
XCTAssertEqual(credentialsProvider.requestedHosts, ["Docker.IO"])
|
|
}
|
|
|
|
func testDockerHubWithExplicitPort() throws {
|
|
for host in ["docker.io:443", "DOCKER.IO:443"] {
|
|
let registry = try Registry(host: host, namespace: "org/repo")
|
|
|
|
XCTAssertEqual(registry.baseURL, URL(string: "https://registry-1.docker.io:443/v2/"))
|
|
XCTAssertEqual(registry.host, host)
|
|
}
|
|
}
|
|
|
|
func testOtherHostsAreUnchanged() throws {
|
|
for host in ["ghcr.io", "index.docker.io", "registry-1.docker.io", "registry.hub.docker.com", "127.0.0.1:8080"] {
|
|
let registry = try Registry(host: host, namespace: "org/repo")
|
|
|
|
XCTAssertEqual(registry.baseURL, URL(string: "https://\(host)/v2/"))
|
|
XCTAssertEqual(registry.host, host)
|
|
}
|
|
|
|
let registry = try Registry(host: "127.0.0.1:5000", namespace: "org/repo", insecure: true)
|
|
XCTAssertEqual(registry.baseURL, URL(string: "http://127.0.0.1:5000/v2/"))
|
|
XCTAssertEqual(registry.host, "127.0.0.1:5000")
|
|
}
|
|
|
|
func testHostPortIsNormalized() throws {
|
|
// Credentials stored for "127.0.0.1:5000" should still be found
|
|
// when the port is written with a leading zero
|
|
let credentialsProvider = RecordingCredentialsProvider(credentials: ["127.0.0.1:5000": ("user", "password")])
|
|
let registry = try Registry(host: "127.0.0.1:05000", namespace: "org/repo", insecure: true,
|
|
credentialsProviders: [credentialsProvider])
|
|
|
|
XCTAssertEqual(registry.baseURL, URL(string: "http://127.0.0.1:05000/v2/"))
|
|
XCTAssertEqual(registry.host, "127.0.0.1:5000")
|
|
|
|
let (user, password) = try XCTUnwrap(registry.lookupCredentials())
|
|
XCTAssertEqual(user, "user")
|
|
XCTAssertEqual(password, "password")
|
|
XCTAssertEqual(credentialsProvider.requestedHosts, ["127.0.0.1:5000"])
|
|
}
|
|
}
|
|
|
|
fileprivate class RecordingCredentialsProvider: CredentialsProvider {
|
|
let userFriendlyName = "recording credentials provider"
|
|
|
|
let credentials: [String: (String, String)]
|
|
var requestedHosts: [String] = []
|
|
|
|
init(credentials: [String: (String, String)] = [:]) {
|
|
self.credentials = credentials
|
|
}
|
|
|
|
func retrieve(host: String) throws -> (String, String)? {
|
|
requestedHosts.append(host)
|
|
|
|
return credentials[host]
|
|
}
|
|
|
|
func store(host: String, user: String, password: String) throws {
|
|
}
|
|
}
|