From 1f0434bffc01b174b3659bec8ce30004fb27e733 Mon Sep 17 00:00:00 2001 From: codex Date: Thu, 28 May 2026 19:44:51 -0400 Subject: [PATCH] fix(manifest): allow ip git upstreams --- bot_bottle/manifest.py | 14 +++++++++++++- tests/unit/test_manifest_git.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bot_bottle/manifest.py b/bot_bottle/manifest.py index ed760fe..e856a3a 100644 --- a/bot_bottle/manifest.py +++ b/bot_bottle/manifest.py @@ -143,7 +143,11 @@ class GitEntry: user, host, port, path = _parse_git_upstream( upstream, f"bottle '{bottle_name}' {label} '{name}' Upstream" ) - if host_key is not None and host_key != host: + if ( + host_key is not None + and host_key != host + and not _is_ip_literal(host) + ): die( f"bottle '{bottle_name}' git.remotes key {host_key!r} " f"does not match Upstream host {host!r}" @@ -963,6 +967,14 @@ def _parse_git_upstream(url: str, label: str) -> tuple[str, str, str, str]: return (user, host, port, path) +def _is_ip_literal(value: str) -> bool: + try: + ipaddress.ip_address(value) + except ValueError: + return False + return True + + def _validate_egress_routes( bottle_name: str, routes: tuple[EgressRoute, ...], diff --git a/tests/unit/test_manifest_git.py b/tests/unit/test_manifest_git.py index c926423..90d22a2 100644 --- a/tests/unit/test_manifest_git.py +++ b/tests/unit/test_manifest_git.py @@ -205,6 +205,21 @@ class TestGitEntryCrossValidation(unittest.TestCase): "agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}}, }) + def test_remote_key_can_name_logical_host_for_ip_upstream(self): + m = Manifest.from_json_obj({ + "bottles": {"dev": {"git": {"remotes": { + "gitea.dideric.is": { + "Name": "bot-bottle", + "Upstream": "ssh://git@100.78.141.42:30009/didericis/bot-bottle.git", + "IdentityFile": "/dev/null", + }, + }}}}, + "agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}}, + }) + e = m.bottles["dev"].git[0] + self.assertEqual("100.78.141.42", e.UpstreamHost) + self.assertEqual("30009", e.UpstreamPort) + def test_legacy_ssh_field_dies_with_hint(self): # PRD 0009: bottle.ssh is removed; manifests carrying it must # fail loudly with a hint pointing at bottle.git.