personal memory agent
1# SPDX-License-Identifier: AGPL-3.0-only
2# Copyright (c) 2026 sol pbc
3
4from __future__ import annotations
5
6import hashlib
7import tarfile
8import tomllib
9from io import BytesIO
10from pathlib import Path
11
12import pytest
13
14from scripts.normalize_maturin_sdist import (
15 SdistLockError,
16 normalize_core_sdist_workspace_lock,
17)
18
19
20def _source_workspace(root: Path) -> None:
21 members = (
22 "crates/solstone-core",
23 "crates/solstone-core-journal",
24 "crates/solstone-core-sol",
25 "crates/solstone-core-sol-client",
26 "crates/solstone-core-sol-client-cli",
27 "crates/solstone-core-unused",
28 )
29 (root / "core").mkdir(parents=True)
30 (root / "core" / "Cargo.toml").write_text(
31 "[workspace]\nmembers = [\n"
32 + "".join(f' "{member}",\n' for member in members)
33 + ']\nresolver = "3"\n',
34 encoding="utf-8",
35 )
36 for member in members:
37 path = root / "core" / member
38 path.mkdir(parents=True)
39 (path / "Cargo.toml").write_text(
40 f'[package]\nname = "{Path(member).name}"\nversion = "1.2.3"\n',
41 encoding="utf-8",
42 )
43 main = root / "core" / "crates" / "solstone-core" / "src" / "main.rs"
44 main.parent.mkdir(parents=True)
45 main.write_text("fn main() {}\n", encoding="utf-8")
46
47
48def _archive(root: Path, *, pruned_source: bool = False) -> Path:
49 archive = root / "dist" / "solstone_core-1.2.3.tar.gz"
50 archive.parent.mkdir()
51 manifest = (
52 "[workspace]\n"
53 'members = ["crates/solstone-core", "crates/solstone-core-journal", '
54 '"crates/solstone-core-sol", "crates/solstone-core-sol-client", '
55 '"crates/solstone-core-sol-client-cli"]\n'
56 'resolver = "3"\n'
57 ).encode()
58 source_line = (
59 '\nsource = "registry+https://github.com/rust-lang/crates.io-index"'
60 if pruned_source
61 else ""
62 )
63 lock = (
64 "version = 4\n\n"
65 '[[package]]\nname = "serde"\nversion = "1.0.228"\n'
66 'source = "registry+https://github.com/rust-lang/crates.io-index"\n\n'
67 '[[package]]\nname = "ureq"\nversion = "3.1.4"\n'
68 'source = "registry+https://github.com/rust-lang/crates.io-index"\n\n'
69 '[[package]]\nname = "solstone-core"\nversion = "1.2.3"\n'
70 'dependencies = ["serde"]\n\n'
71 '[[package]]\nname = "solstone-core-journal"\nversion = "1.2.3"\n\n'
72 '[[package]]\nname = "solstone-core-sol"\nversion = "1.2.3"\n\n'
73 '[[package]]\nname = "solstone-core-sol-client"\nversion = "1.2.3"\n'
74 'dependencies = ["ureq"]\n\n'
75 '[[package]]\nname = "solstone-core-sol-client-cli"\nversion = "1.2.3"\n'
76 'dependencies = ["solstone-core-sol-client"]\n\n'
77 f'[[package]]\nname = "solstone-core-unused"\nversion = "1.2.3"{source_line}\n'
78 ).encode()
79 with tarfile.open(archive, mode="w:gz") as target:
80 for name, data in (
81 ("solstone_core-1.2.3/PKG-INFO", b"metadata\n"),
82 ("solstone_core-1.2.3/core/Cargo.toml", manifest),
83 ("solstone_core-1.2.3/core/Cargo.lock", lock),
84 ):
85 member = tarfile.TarInfo(name)
86 member.mode = 0o644
87 member.mtime = 1_784_800_000
88 member.size = len(data)
89 target.addfile(member, BytesIO(data))
90 return archive
91
92
93def _members(archive: Path) -> dict[str, bytes]:
94 with tarfile.open(archive, mode="r:gz") as source:
95 return {
96 member.name: source.extractfile(member).read() # type: ignore[union-attr]
97 for member in source.getmembers()
98 if member.isfile()
99 }
100
101
102def test_normalizer_retains_now_reachable_sol_workspace_records(
103 tmp_path: Path,
104) -> None:
105 _source_workspace(tmp_path)
106 archive = _archive(tmp_path)
107 before = _members(archive)
108
109 removed = normalize_core_sdist_workspace_lock(tmp_path, archive)
110
111 assert removed == ("solstone-core-unused",)
112 after = _members(archive)
113 assert after.keys() == before.keys()
114 assert (
115 after["solstone_core-1.2.3/PKG-INFO"] == before["solstone_core-1.2.3/PKG-INFO"]
116 )
117 assert (
118 after["solstone_core-1.2.3/core/Cargo.toml"]
119 == before["solstone_core-1.2.3/core/Cargo.toml"]
120 )
121 packages = tomllib.loads(after["solstone_core-1.2.3/core/Cargo.lock"].decode())[
122 "package"
123 ]
124 assert [package["name"] for package in packages] == [
125 "serde",
126 "ureq",
127 "solstone-core",
128 "solstone-core-journal",
129 "solstone-core-sol",
130 "solstone-core-sol-client",
131 "solstone-core-sol-client-cli",
132 ]
133
134 digest = hashlib.sha256(archive.read_bytes()).hexdigest()
135 assert normalize_core_sdist_workspace_lock(tmp_path, archive) == ()
136 assert hashlib.sha256(archive.read_bytes()).hexdigest() == digest
137
138
139def test_normalizer_refuses_to_remove_registry_package_record(tmp_path: Path) -> None:
140 _source_workspace(tmp_path)
141 archive = _archive(tmp_path, pruned_source=True)
142
143 with pytest.raises(SdistLockError, match="is not a workspace package"):
144 normalize_core_sdist_workspace_lock(tmp_path, archive)
145
146
147def test_normalizer_injects_native_sol_sources(tmp_path: Path) -> None:
148 _source_workspace(tmp_path)
149 source = tmp_path / "solstone" / "apps" / "sample" / "native" / "command.rs"
150 source.parent.mkdir(parents=True)
151 source.write_text("// native source\n", encoding="utf-8")
152 authority = source.with_name("authority.toml")
153 authority.write_text("# native authority\n", encoding="utf-8")
154 archive = _archive(tmp_path)
155
156 normalize_core_sdist_workspace_lock(tmp_path, archive)
157
158 after = _members(archive)
159 assert (
160 after["solstone_core-1.2.3/solstone/apps/sample/native/command.rs"]
161 == b"// native source\n"
162 )
163 assert (
164 after["solstone_core-1.2.3/solstone/apps/sample/native/authority.toml"]
165 == b"# native authority\n"
166 )
167
168 digest = hashlib.sha256(archive.read_bytes()).hexdigest()
169 assert normalize_core_sdist_workspace_lock(tmp_path, archive) == ()
170 assert hashlib.sha256(archive.read_bytes()).hexdigest() == digest
171
172
173def test_normalizer_injects_derived_compile_inputs(tmp_path: Path) -> None:
174 _source_workspace(tmp_path)
175 main = tmp_path / "core" / "crates" / "solstone-core" / "src" / "main.rs"
176 main.write_text(
177 'const CONTRACT: &str = include_str!("../../../fixtures/sample-contract.json");\n'
178 "fn main() {}\n",
179 encoding="utf-8",
180 )
181 asset = tmp_path / "core" / "fixtures" / "sample-contract.json"
182 asset.parent.mkdir(parents=True)
183 asset.write_text('{"ok":true}\n', encoding="utf-8")
184 archive = _archive(tmp_path)
185
186 normalize_core_sdist_workspace_lock(tmp_path, archive)
187
188 after = _members(archive)
189 assert (
190 after["solstone_core-1.2.3/core/fixtures/sample-contract.json"]
191 == b'{"ok":true}\n'
192 )
193
194 digest = hashlib.sha256(archive.read_bytes()).hexdigest()
195 assert normalize_core_sdist_workspace_lock(tmp_path, archive) == ()
196 assert hashlib.sha256(archive.read_bytes()).hexdigest() == digest