Skip to content

Commit 340fef4

Browse files
committed
test(registry): add private-registry auto-login integration test
1 parent 02f5572 commit 340fef4

1 file changed

Lines changed: 61 additions & 1 deletion

File tree

modules/registry/tests/test_registry.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
import base64
2+
import json
3+
4+
import pytest
15
from requests import Response, get
26
from requests.auth import HTTPBasicAuth
3-
from testcontainers.registry import DockerRegistryContainer
47

8+
from testcontainers.core.config import testcontainers_config
9+
from testcontainers.core.docker_client import DockerClient
10+
from testcontainers.core.utils import is_mac
11+
from testcontainers.registry import DockerRegistryContainer
512

613
REGISTRY_USERNAME: str = "foo"
714
REGISTRY_PASSWORD: str = "bar"
@@ -25,3 +32,56 @@ def test_registry_with_authentication() -> None:
2532
response: Response = get(url, auth=HTTPBasicAuth(REGISTRY_USERNAME, REGISTRY_PASSWORD))
2633

2734
assert response.status_code == 200
35+
36+
37+
@pytest.mark.skipif(
38+
is_mac(),
39+
reason="Docker Desktop on macOS does not support insecure private registries without daemon reconfiguration",
40+
)
41+
def test_registry_login(monkeypatch) -> None:
42+
"""DockerClient auto-logs-in via DOCKER_AUTH_CONFIG, proven by pulling a private image.
43+
44+
Works against remote (SSH) Docker hosts too: the registry is addressed via
45+
``127.0.0.1:<published_port>``, which the daemon treats as insecure-by-default
46+
(the ``127.0.0.0/8`` range), so the login/push/pull happen over plain HTTP
47+
without reconfiguring the daemon's ``insecure-registries``.
48+
"""
49+
image: str = "hello-world"
50+
tag: str = "latest"
51+
52+
with DockerRegistryContainer(username=REGISTRY_USERNAME, password=REGISTRY_PASSWORD) as registry_container:
53+
# Address the registry over the daemon's loopback (works for both local
54+
# and remote/SSH daemons) so HTTP is allowed without insecure-registries.
55+
port: str = registry_container.get_exposed_port(registry_container.port)
56+
registry_url: str = f"127.0.0.1:{port}"
57+
private_ref: str = f"{registry_url}/{image}:{tag}"
58+
59+
creds: str = base64.b64encode(f"{REGISTRY_USERNAME}:{REGISTRY_PASSWORD}".encode()).decode()
60+
auth_config: str = json.dumps({"auths": {registry_url: {"auth": creds}}})
61+
62+
# Seed the private registry with an image (push authenticated explicitly),
63+
# then drop the local tag so the later pull must hit the registry. Reuse
64+
# the container's own client (it sets ``use_ssh_client`` for SSH hosts,
65+
# avoiding paramiko's stdin clash with pytest output capture).
66+
seed_client = registry_container.get_docker_client().client
67+
seed_image = seed_client.images.pull(image, tag=tag)
68+
seed_image.tag(f"{registry_url}/{image}", tag=tag)
69+
seed_client.images.push(
70+
f"{registry_url}/{image}",
71+
tag=tag,
72+
auth_config={"username": REGISTRY_USERNAME, "password": REGISTRY_PASSWORD},
73+
)
74+
seed_client.images.remove(private_ref)
75+
76+
# DockerClient.__init__ logs in using the auth config below. Pulling the
77+
# private image without explicit credentials only succeeds if that
78+
# auto-login actually happened, so this exercises testcontainers' wiring
79+
# rather than docker-py's login() directly.
80+
monkeypatch.setattr(testcontainers_config, "docker_auth_config", auth_config)
81+
client = DockerClient()
82+
try:
83+
pulled = client.client.images.pull(private_ref)
84+
assert pulled is not None
85+
finally:
86+
client.client.images.remove(private_ref)
87+
client.client.close()

0 commit comments

Comments
 (0)