Skip to content
This repository was archived by the owner on Sep 30, 2025. It is now read-only.

Commit b3fc711

Browse files
committed
fix: sanitizing agent name before pushing to docker registry (ENG-672)
1 parent 096c257 commit b3fc711

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

dreadnode_cli/agent/cli.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,15 @@ def push(
255255
print()
256256
print(f":wrench: Building agent from [b]{directory}[/] ...")
257257
image = docker.build(directory, force_rebuild=rebuild)
258-
repository = f"{registry}/{server_config.username}/agents/{agent_config.project_name}"
258+
agent_name = docker.sanitized_agent_name(agent_config.project_name)
259+
260+
if not agent_name:
261+
raise Exception("Failed to sanitize agent name, please use a different name")
262+
263+
elif agent_name != agent_config.project_name:
264+
print(f":four_leaf_clover: Agent name normalized to [bold magenta]{agent_name}[/]")
265+
266+
repository = f"{registry}/{server_config.username}/agents/{agent_name}"
259267
tag = tag or image.id[-8:]
260268

261269
print()

dreadnode_cli/agent/docker.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pathlib
2+
import re
23
import typing as t
34

45
import docker # type: ignore
@@ -63,6 +64,23 @@ def login(registry: str, username: str, password: str) -> None:
6364
client.api.login(username=username, password=password, registry=registry)
6465

6566

67+
def sanitized_agent_name(name: str) -> str:
68+
"""
69+
Sanitizes an agent name to be used as a Docker repository name.
70+
"""
71+
72+
# convert to lowercase
73+
name = name.lower()
74+
# replace non-alphanumeric characters with hyphens
75+
name = re.sub(r"[^\w\s-]", "", name)
76+
# replace one or more whitespace characters with a single hyphen
77+
name = re.sub(r"[-\s]+", "-", name)
78+
# remove leading or trailing hyphens
79+
name = name.strip("-")
80+
81+
return name
82+
83+
6684
def build(directory: str | pathlib.Path, *, force_rebuild: bool = False) -> Image:
6785
if client is None:
6886
raise Exception("Docker not available")

dreadnode_cli/agent/tests/test_docker.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,28 @@ def test_get_registry_custom_platform_base_domain() -> None:
174174

175175
config = _create_test_server_config("dev-crucible.example.com")
176176
assert docker.get_registry(config) == "dev-registry.example.com"
177+
178+
179+
def test_sanitized_agent_name() -> None:
180+
# Test basic name
181+
assert docker.sanitized_agent_name("test-agent") == "test-agent"
182+
assert docker.sanitized_agent_name("test- agent") == "test-agent"
183+
assert docker.sanitized_agent_name("test_agent") == "test_agent"
184+
185+
# Test spaces
186+
assert docker.sanitized_agent_name("test agent") == "test-agent"
187+
assert docker.sanitized_agent_name("test multiple spaces") == "test-multiple-spaces"
188+
189+
# Test special characters
190+
assert docker.sanitized_agent_name("test!@#$%^&*()agent") == "testagent"
191+
assert docker.sanitized_agent_name("test_agent.123") == "test_agent123"
192+
assert docker.sanitized_agent_name("test/agent\\path") == "testagentpath"
193+
194+
# Test mixed case
195+
assert docker.sanitized_agent_name("TestAgent") == "testagent"
196+
assert docker.sanitized_agent_name("TEST AGENT") == "test-agent"
197+
198+
# Test edge cases
199+
assert docker.sanitized_agent_name(" spaced name ") == "spaced-name"
200+
assert docker.sanitized_agent_name("!!!###") == ""
201+
assert docker.sanitized_agent_name("123 456") == "123-456"

0 commit comments

Comments
 (0)