gabriel / muse public
test_domains_signing_identity.py python
151 lines 6.0 KB
Raw
sha256:c5d88af19bcd6c1e60fd829dea85a4fdd5a74f74c5617031ba5b2955ba6a5b95 fix: domains.py signing-identity resolution uses resolved h… Sonnet 5 patch 15 hours ago
1 """muse#20 Phase 1 — domains.py must resolve signing identity against the
2 target hub URL, not the repo's default [hub] url.
3
4 Regression for the same bug class as ls-remote's HTTP 401 (muse#20
5 background): `run_publish`/`run_update`/`run_delete` all computed
6 `resolved_hub` (from `--hub`, or the repo's `[hub] url`, or the
7 musehub.ai default) but then called `get_signing_identity(repo_root)`
8 without forwarding it — so the identity lookup used the repo's default
9 hub URL instead of the actual target, producing a wrong-hostname lookup
10 whenever `--hub` pointed somewhere else (e.g. staging while the repo's
11 default config points at localhost).
12
13 Mirrors the `TestSigningIdentityForwarding` pattern from
14 tests/test_cmd_ls_remote.py.
15 """
16 from __future__ import annotations
17
18 import pathlib
19 from unittest.mock import patch
20
21 from tests.cli_test_helper import CliRunner
22
23 cli = None
24 runner = CliRunner()
25
26 _OTHER_HUB = "https://staging.musehub.ai"
27
28
29 def _env(root: pathlib.Path) -> dict[str, str]:
30 return {"MUSE_REPO_ROOT": str(root)}
31
32
33 def _init_repo(tmp_path: pathlib.Path) -> pathlib.Path:
34 """A minimal repo whose default [hub] url deliberately differs from
35 the --hub target used in each test, so a wrong-hostname lookup would
36 be caught."""
37 import json
38 from muse.core.paths import muse_dir
39
40 dot_muse = muse_dir(tmp_path)
41 dot_muse.mkdir(parents=True, exist_ok=True)
42 (dot_muse / "repo.json").write_text(json.dumps({"repo_id": "test-repo", "domain": "code"}))
43 (dot_muse / "config.toml").write_text('[hub]\nurl = "https://localhost:1337"\n')
44 return tmp_path
45
46
47 class TestPublishSigningIdentityForwarding:
48 def test_resolved_hub_forwarded_to_signing_identity(self, tmp_path: pathlib.Path) -> None:
49 repo = _init_repo(tmp_path)
50 with patch("muse.cli.commands.domains.get_signing_identity") as mock_gsi:
51 mock_gsi.return_value = None
52 runner.invoke(
53 cli,
54 [
55 "domains", "publish",
56 "--author", "gabriel", "--slug", "genomics",
57 "--name", "Genomics", "--description", "desc",
58 "--viewer-type", "generic", "--hub", _OTHER_HUB,
59 ],
60 env=_env(repo),
61 )
62 mock_gsi.assert_called_once()
63 _, kwargs = mock_gsi.call_args
64 assert kwargs.get("remote_url") == _OTHER_HUB, (
65 f"get_signing_identity must be called with remote_url={_OTHER_HUB!r}; "
66 f"got {kwargs.get('remote_url')!r}. Without this, publish uses the "
67 "wrong signing key whenever --hub differs from the repo's default."
68 )
69
70
71 class TestUpdateSigningIdentityForwarding:
72 def test_resolved_hub_forwarded_to_signing_identity(self, tmp_path: pathlib.Path) -> None:
73 repo = _init_repo(tmp_path)
74 with patch("muse.cli.commands.domains.get_signing_identity") as mock_gsi:
75 mock_gsi.return_value = None
76 runner.invoke(
77 cli,
78 [
79 "domains", "update",
80 "--author", "gabriel", "--slug", "genomics",
81 "--name", "Genomics v2", "--hub", _OTHER_HUB,
82 ],
83 env=_env(repo),
84 )
85 mock_gsi.assert_called_once()
86 _, kwargs = mock_gsi.call_args
87 assert kwargs.get("remote_url") == _OTHER_HUB, (
88 f"get_signing_identity must be called with remote_url={_OTHER_HUB!r}; "
89 f"got {kwargs.get('remote_url')!r}."
90 )
91
92
93 class TestDeleteSigningIdentityForwarding:
94 def test_resolved_hub_forwarded_to_signing_identity(self, tmp_path: pathlib.Path) -> None:
95 repo = _init_repo(tmp_path)
96 with patch("muse.cli.commands.domains.get_signing_identity") as mock_gsi:
97 mock_gsi.return_value = None
98 runner.invoke(
99 cli,
100 [
101 "domains", "delete",
102 "--author", "gabriel", "--slug", "genomics",
103 "--hub", _OTHER_HUB,
104 ],
105 env=_env(repo),
106 )
107 mock_gsi.assert_called_once()
108 _, kwargs = mock_gsi.call_args
109 assert kwargs.get("remote_url") == _OTHER_HUB, (
110 f"get_signing_identity must be called with remote_url={_OTHER_HUB!r}; "
111 f"got {kwargs.get('remote_url')!r}."
112 )
113
114
115 class TestReleaseSigningIdentityForwarding:
116 """muse#20 Phase 2 — release.py's get_signing_identity calls, already
117 behaviorally correct (positional remote_url), are now explicit keyword
118 style. These tests pin behavior so a future positional-arg drift (e.g.
119 an accidental new positional parameter inserted before remote_url in
120 get_signing_identity's signature) cannot silently break identity
121 resolution without a loud test failure.
122 """
123
124 def test_release_list_forwards_resolved_remote_url(self, tmp_path: pathlib.Path) -> None:
125 import json
126 from muse.core.paths import muse_dir
127
128 repo = tmp_path
129 dot_muse = muse_dir(repo)
130 dot_muse.mkdir(parents=True, exist_ok=True)
131 (dot_muse / "repo.json").write_text(json.dumps({"repo_id": "test-repo", "domain": "code"}))
132 (dot_muse / "config.toml").write_text(
133 f'[hub]\nurl = "https://localhost:1337"\n'
134 f'[remotes.staging]\nurl = "{_OTHER_HUB}"\n'
135 )
136
137 with patch("muse.cli.commands.release.get_signing_identity") as mock_gsi:
138 mock_gsi.return_value = None
139 with patch("muse.cli.commands.release.make_transport") as mt:
140 mt.return_value.list_releases_remote.return_value = []
141 runner.invoke(
142 cli,
143 ["release", "list", "--remote", "staging", "--json"],
144 env=_env(repo),
145 )
146 mock_gsi.assert_called_once()
147 _, kwargs = mock_gsi.call_args
148 assert kwargs.get("remote_url") == _OTHER_HUB, (
149 f"get_signing_identity must be called with remote_url={_OTHER_HUB!r}; "
150 f"got {kwargs.get('remote_url')!r}."
151 )
File History 1 commit
sha256:c5d88af19bcd6c1e60fd829dea85a4fdd5a74f74c5617031ba5b2955ba6a5b95 fix: domains.py signing-identity resolution uses resolved h… Sonnet 5 patch 15 hours ago