Files
dashcaddy/ops/shipdeck-bridge/test_fleet_ops.py
T
DashCaddy Polish Loop 0dd8493f98 [grade=A] Shipdeck fleet module and manual deploy flow
Adds validated fleet install/lifecycle routes, bridge-backed Git and OCI workflows, persistent service cards, and the Local-tab Shipdeck deployment UI while preserving catalog and External flows.

Judge: urn:ump:if6udffdyelsf4qvskkr65ikhuprsjiajzij6h653fhf2zgyynzq
2026-09-15 11:13:29 -07:00

116 lines
6.1 KiB
Python

import json
import os
import tempfile
import unittest
from unittest import mock
import gh_install
import image_install
import bridge
class FleetOpsTests(unittest.TestCase):
def test_empty_bridge_token_fails_closed(self):
with mock.patch("builtins.open", mock.mock_open(read_data=" \n")):
with self.assertRaisesRegex(RuntimeError, "refusing to start unauthenticated"):
bridge.read_token()
def test_detects_go_node_python_at_requested_port(self):
gh_install._STATE.update(PORT=8977)
with mock.patch.object(gh_install, "_used_ports", return_value={8977}):
cases = {
"go": {"go.mod": "module x\n", "main.go": "package main\nfunc main(){}\n"},
"node": {"package.json": json.dumps({"main": "server.js"}), "server.js": ""},
"python": {"requirements.txt": "", "app.py": ""},
}
for i, (kind, files) in enumerate(cases.items()):
with tempfile.TemporaryDirectory() as d:
for name, body in files.items():
with open(os.path.join(d, name), "w", encoding="utf-8") as fh: fh.write(body)
got = gh_install._detect_and_emit(d, "demo-" + kind, "demo-" + kind, "100.121.150.22", 8100 + i)
self.assertEqual(got["port"], 8100 + i)
self.assertTrue(got["mode"].startswith(kind))
self.assertTrue(os.path.isfile(got["shipdeckfile"]))
def test_rejects_repository_controlled_go_package_shell_metachars(self):
gh_install._STATE.update(PORT=8977)
with tempfile.TemporaryDirectory() as d, mock.patch.object(
gh_install, "_used_ports", return_value={8977}):
os.mkdir(os.path.join(d, "cmd;touch-pwned"))
with open(os.path.join(d, "go.mod"), "w", encoding="utf-8") as fh:
fh.write("module x\n")
with open(os.path.join(d, "cmd;touch-pwned", "main.go"), "w", encoding="utf-8") as fh:
fh.write("package main\nfunc main(){}\n")
with self.assertRaisesRegex(RuntimeError, "unsafe characters"):
gh_install._detect_and_emit(d, "demo", "demo", "100.121.150.22", 8100)
def test_gitea_repo_listing_rejects_arbitrary_hosts_before_http(self):
with mock.patch("gh_install.urllib.request.urlopen") as urlopen:
code, body = gh_install.list_repos({"gitea_url": "https://127.0.0.1"})
self.assertEqual(code, 400)
self.assertIn("configured fleet Gitea", body["error"])
urlopen.assert_not_called()
def test_unknown_git_host_skips_metadata_http_but_remains_cloneable(self):
payload = {"repo_url": "https://code.example/owner/repo", "service": "demo"}
lock = mock.MagicMock()
lock.__enter__ = mock.Mock()
lock.__exit__ = mock.Mock(return_value=False)
gh_install._STATE.update(RE_SERVICE=gh_install.re.compile(r"^[a-z0-9][a-z0-9-]{0,62}$"),
REPOS_ROOT="/tmp", PORT=8977, LOCK=lock, RUN=mock.Mock())
with mock.patch("gh_install._http_json") as http_json, mock.patch(
"gh_install.os.path.exists", return_value=True):
code, _ = gh_install.gh_install(payload)
self.assertEqual(code, 409)
http_json.assert_not_called()
def test_git_token_is_env_only_never_clone_url_or_error(self):
secret = "ghp_private_secret"
lock = mock.MagicMock()
lock.__enter__ = mock.Mock()
lock.__exit__ = mock.Mock(return_value=False)
with tempfile.TemporaryDirectory() as root:
gh_install._STATE.update(RE_SERVICE=gh_install.re.compile(r"^[a-z0-9][a-z0-9-]{0,62}$"),
REPOS_ROOT=root, PORT=8977, LOCK=lock, RUN=mock.Mock())
failed = mock.Mock(returncode=1, stdout="", stderr="clone rejected " + secret)
with mock.patch.object(gh_install, "_http_json", return_value={"name": "repo", "owner": {}}), mock.patch(
"gh_install.subprocess.run", return_value=failed) as run:
code, body = gh_install.gh_install({"repo_url": "https://github.com/acme/repo", "service": "demo", "token": secret})
self.assertEqual(code, 400)
argv = run.call_args.args[0]
env = run.call_args.kwargs["env"]
self.assertEqual(argv[-2], "https://github.com/acme/repo")
self.assertNotIn(secret, " ".join(argv))
self.assertIn(secret, env["GIT_CONFIG_VALUE_0"])
self.assertNotIn(secret, json.dumps(body))
def test_image_install_pins_digest_and_never_returns_env_secret(self):
digest = "a" * 64
pull = {"digest": "sha256:" + digest, "config": {"config": {"Entrypoint": [], "Cmd": ["/bin/app"]}}}
calls = []
def run(args, timeout):
calls.append(args)
return (0, json.dumps(pull)) if args[0] == "pull" else (0, "DEPLOYED")
image_install.init_shared(mock.MagicMock(), run)
image_install._STATE["LOCK"].__enter__ = mock.Mock()
image_install._STATE["LOCK"].__exit__ = mock.Mock(return_value=False)
payload = {"image": "alpine:3.20", "name": "demo", "subdomain": "demo", "port": 8080, "env": {"API_TOKEN": "private-value"}}
with tempfile.TemporaryDirectory() as drafts, mock.patch.object(image_install, "DRAFT_ROOT", drafts), mock.patch("image_install.subprocess.run") as sp:
sp.return_value.stdout = "100.121.150.22\n"
code, body = image_install.install_image(payload)
self.assertEqual(code, 200)
self.assertNotIn("private-value", json.dumps(body))
self.assertEqual(calls[0][:2], ["pull", "--json"])
self.assertEqual(calls[1][0], "deploy")
self.assertIn("@sha256:" + digest, body["service"]["image"])
def test_image_install_rejects_traversal_before_pull(self):
run = mock.Mock()
image_install.init_shared(mock.MagicMock(), run)
code, _ = image_install.install_image({"image": "alpine:3.20", "name": "demo", "subdomain": "demo", "port": 8080, "mounts": [{"source": "/tmp/../etc", "target": "/data"}]})
self.assertEqual(code, 400)
run.assert_not_called()
if __name__ == "__main__": unittest.main()