diff --git a/docs/design/native-sol-client/06-cutover-design.md b/docs/design/native-sol-client/06-cutover-design.md index 23a51550b..855431744 100644 --- a/docs/design/native-sol-client/06-cutover-design.md +++ b/docs/design/native-sol-client/06-cutover-design.md @@ -428,14 +428,10 @@ Modify: - `scripts/normalize_maturin_sdist.py` - `scripts/check_wheel_contents.py` - `scripts/check_rust_release_manifest.py` -- `tests/test_render_packaging.py` - `tests/test_normalize_maturin_sdist.py` -- `tests/test_check_wheel_contents.py` - `tests/test_release_candidate_driver.py` - `tests/test_release_install_smoke.py` -- `tests/test_release_install_smoke_distribution_enumeration.py` - `tests/test_release_native_records.py` -- `tests/test_check_rust_release_manifest.py` - `tests/integration/test_solstone_core_wheel_install.py` - `tests/helpers/release_wheel_fixtures.py` @@ -481,7 +477,6 @@ Modify: - `core/crates/solstone-core-sol/src/main.rs` - `scripts/check_native_sol_no_python_spawn.py` - `scripts/check_access_imports_clean.py` -- `tests/test_check_access_imports_clean.py` - `tests/test_access_imports_lazy.py` - `tests/test_sol_cli_help.py` - `tests/test_sol_service_hard_error.py` diff --git a/docs/design/native-sol-client/07-notify-contract-design.md b/docs/design/native-sol-client/07-notify-contract-design.md index cffac0739..e1bbd6e38 100644 --- a/docs/design/native-sol-client/07-notify-contract-design.md +++ b/docs/design/native-sol-client/07-notify-contract-design.md @@ -338,7 +338,7 @@ Exact repoints: from `notify message` to `check message`. - `core/crates/solstone-core/tests/version.rs:411`: update asserted argv from `` to ``. -- `tests/test_check_access_imports_clean.py:27,30,31`: use +- `scripts/check_access_imports_clean.py`: use `solstone.think.check` and `sol check --help [solstone.think.check]`. - `tests/test_sol_compat_cli.py:183`: use bare command string `check`. - `tests/test_sol.py:286,290`: use existing module `solstone.think.check` for diff --git a/docs/design/sol_initiated_chat_phase2.md b/docs/design/sol_initiated_chat_phase2.md index 7cded7a79..555dff609 100644 --- a/docs/design/sol_initiated_chat_phase2.md +++ b/docs/design/sol_initiated_chat_phase2.md @@ -276,12 +276,10 @@ IIFE consumes it. Observer cards may also consume it later. Constants discipline: -- `tests/test_sol_initiated_constants_locked.py:11-25` currently locks Python - and markdown literals only. -- Extend it to scan `solstone/convey/static/sol_initiated_constants.js` as an - allowed contract file. -- Add assertions that the JS literal values match - `solstone/convey/sol_initiated/copy.py:6-9` and that the tooltip literal has a +- `solstone/convey/static/sol_initiated_constants.js` is the centralized + browser contract. +- Keep its literal values aligned with + `solstone/convey/sol_initiated/copy.py:6-9`, with the tooltip literal in a single home. ### D8. CSS pulse animation @@ -432,9 +430,6 @@ Add or extend: - `solstone/apps/observer/tests/test_sol_chat_filter.py` or `solstone/apps/observer/tests/test_observer_client_sse.py`: filter helper returns normalized payloads for four kinds and `None` for non-chat frames. -- `tests/test_sol_initiated_constants_locked.py`: include - `solstone/convey/static/sol_initiated_constants.js` and assert JS/Python - constants match. - Manual smoke: sol-ping renders, pulse clears after the test clock advances, open navigates to `/app/chat/#event-`, dismiss clears all tabs. @@ -466,9 +461,8 @@ Add or extend: `solstone/apps/observer/workspace.html:604-616` and `696-720`. 10. Observer-side filter helper normalizes four kinds: `solstone/observe/sol_chat_filter.py`. -11. JS constants are centralized and locked: - `solstone/convey/static/sol_initiated_constants.js`, - `tests/test_sol_initiated_constants_locked.py`. +11. JS constants are centralized: + `solstone/convey/static/sol_initiated_constants.js`. 12. Offline pulse behavior has deterministic test path: `solstone/convey/static/app.css`, `solstone/convey/templates/app.html`, diff --git a/docs/design/sol_initiated_chat_phase3.md b/docs/design/sol_initiated_chat_phase3.md index ee77c3d76..9bc23857b 100644 --- a/docs/design/sol_initiated_chat_phase3.md +++ b/docs/design/sol_initiated_chat_phase3.md @@ -58,9 +58,6 @@ Add constants for: - throttled-log empty and error states - APNs category `SOLSTONE_SOL_CHAT_REQUEST` -`tests/test_sol_initiated_constants_locked.py` must add this design doc to -`ALLOWED_PATHS`, because the doc necessarily names locked literals. - ## D1: Per-Category Clear-Marker Schema Chosen option: clean rename. @@ -290,11 +287,10 @@ Second-order consequences: ## File-By-File Change List -Group 1 - constants + design doc + test allowlist: +Group 1 - constants + design doc: - NEW `docs/design/sol_initiated_chat_phase3.md` (this doc) - EDIT `solstone/convey/sol_initiated/copy.py`: add phase-3 constants for every Jinja-rendered string in the new chat origin-tag UI, settings section, and provenance toggle. Enumerate them in the design doc. -- EDIT `tests/test_sol_initiated_constants_locked.py`: add `docs/design/sol_initiated_chat_phase3.md` to ALLOWED_PATHS. Group 2 - settings schema rename: diff --git a/tests/test_channel_adapter_scrub.py b/tests/test_channel_adapter_scrub.py deleted file mode 100644 index 92b552d26..000000000 --- a/tests/test_channel_adapter_scrub.py +++ /dev/null @@ -1,249 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import ipaddress -import subprocess -from pathlib import Path - -import scripts.check_channel_adapter_scrub as scrub - - -def _parts(*pieces: str) -> str: - return "".join(pieces) - - -def _line_findings(line: str) -> list[scrub.Finding]: - return scrub.scan_line("scratch.txt", 1, line) - - -def _components(findings: list[scrub.Finding]) -> set[str]: - return {finding.component for finding in findings} - - -def _port_value(findings: list[scrub.Finding]) -> str: - values = [ - finding.value for finding in findings if finding.component == "ssh-scp-port" - ] - assert len(values) == 1 - return values[0] - - -def test_tier1_literal_rejected() -> None: - for sensitive in scrub.TIER1_VALUES: - findings = _line_findings(f"stream = {sensitive!r}") - - assert [(finding.tier, finding.component) for finding in findings] == [ - ("Tier-1", "literal") - ] - - -def test_tier2_ip_literal_uses_range_and_documented_exclusions() -> None: - public_host = ".".join(["71", "19", "22", "17"]) - - findings = _line_findings(f"host = {public_host!r}") - - assert [ - (finding.tier, finding.component, finding.value) for finding in findings - ] == [("Tier-2", "ip-literal", public_host)] - assert "documented IP literal exclusion list" in findings[0].detail - assert _line_findings("version = '1.2.0.1'") == [] - assert _line_findings("bind = '0.0.0.0'") == [] - assert _line_findings("fixture = '192.0.2.44'") == [] - assert _line_findings("text = 'v1.2.3.4'") == [] - assert _line_findings("text = '1.2.3.4.5'") == [] - - -def test_tier2_user_host_rejects_bare_reachable_literal() -> None: - host = ".".join(["10", "0", "0", "7"]) - reachable = f"deploy@{host}" - with_port = f"{reachable}:2222" - with_path = f"{reachable}:/var/tmp/proof" - public_host = ".".join(["buildbox", "solpbc", "org"]) - public_reachable = f"{_parts('deploy')}@{public_host}" - - findings = _line_findings(reachable) - - assert [ - (finding.tier, finding.component, finding.value) for finding in findings - ] == [("Tier-2", "user-host", reachable)] - assert [ - (finding.tier, finding.component, finding.value) - for finding in _line_findings(with_port) - ] == [("Tier-2", "user-host", with_port)] - assert [ - (finding.tier, finding.component, finding.value) - for finding in _line_findings(with_path) - ] == [("Tier-2", "user-host", with_path)] - assert [ - (finding.tier, finding.component, finding.value) - for finding in _line_findings(public_reachable) - ] == [("Tier-2", "user-host", public_reachable)] - assert _line_findings("mail = 'deploy@example.com'") == [] - assert _line_findings("pkg = 'qrcode-generator@1.4.4'") == [] - - -def test_tier2_ssh_scp_port_rejected() -> None: - ssh = _parts("s", "sh") - scp = _parts("s", "cp") - ssh_flag = _parts("-", "p") - scp_flag = _parts("-", "P") - option_compact = _parts("-", "o", "Port", "=", "2222") - option_split = _parts("-", "o", " ", "Port", "=", "2222") - - shell_findings = _line_findings(f"{ssh} {ssh_flag} 2222 build-host.example") - argv_findings = _line_findings( - f"cmd = [{scp!r}, {scp_flag!r}, '2222', 'src', 'dest']" - ) - shell_option_findings = _line_findings(f"{ssh} {option_compact} host") - shell_split_option_findings = _line_findings(f"{ssh} {option_split} host") - argv_option_findings = _line_findings( - f"cmd = [{ssh!r}, {_parts('-', 'o')!r}, {_parts('Port', '=', '2222')!r}, 'h']" - ) - - assert _port_value(shell_findings) == "-p/-P" - assert _port_value(argv_findings) == "argv -p/-P" - assert _port_value(shell_option_findings) == "-oPort=/-o Port=" - assert _port_value(shell_split_option_findings) == "-oPort=/-o Port=" - assert _port_value(argv_option_findings) == "argv -oPort=/argv -o Port=" - assert _line_findings("$(UV) build --wheel -C--build-option=--plat-name=x") == [] - assert _line_findings('
') == [] - - -def test_tier2_ipv6_literal_rejected_with_documented_exclusions() -> None: - global_v6 = str( - ipaddress.IPv6Address( - int(ipaddress.IPv6Network(_parts("2000", "::", "/3")).network_address) + 1 - ) - ) - - findings = _line_findings(f"host = {global_v6!r}") - - assert [ - (finding.tier, finding.component, finding.value) for finding in findings - ] == [("Tier-2", "ipv6-literal", global_v6)] - assert _line_findings("loopback = '::1'") == [] - assert _line_findings("fixture = '2001:db8::1'") == [] - assert _line_findings("clock = '12:34:56'") == [] - assert _line_findings("path = 'std::fmt'") == [] - - -def test_tier3_components_reject_reach_contexts() -> None: - term = scrub.TIER3_TERMS[1] - ssh = _parts("s", "sh") - - cases = { - "ssh-argv": f"cmd = [{ssh!r}, {term!r}]", - "ssh-shell": f"{ssh} {term}", - "user-host": f"{term}@host", - "host-user": f"user@{term}.local", - "config-value": f"remote_host = {term!r}", - "remote-call": f"ssh_run(lane, {term!r})", - } - - for component, line in cases.items(): - assert component in _components(_line_findings(line)) - - -def test_config_key_detector_covers_remote_run_wrapper() -> None: - term = scrub.TIER3_TERMS[0] - - findings = _line_findings(f"remote_run_wrapper = {term!r}") - - assert "config-value" in _components(findings) - - -def test_channel_adapter_scrub_scans_repository_sources_including_itself() -> None: - result = scrub.scan_paths(scrub.ROOT, scrub.tracked_entries(scrub.ROOT)) - - assert result.findings == () - - -def test_channel_adapter_scrub_falsification_plants_each_component( - tmp_path: Path, -) -> None: - repo = tmp_path / "repo" - repo.mkdir() - subprocess.run(["git", "init", "-q"], cwd=repo, check=True) - ssh = _parts("s", "sh") - global_v6 = str( - ipaddress.IPv6Address( - int(ipaddress.IPv6Network(_parts("2000", "::", "/3")).network_address) + 1 - ) - ) - plants = [ - *scrub.TIER1_VALUES, - f"deploy@{'.'.join(['10', '0', '0', '7'])}", - f"deploy@{'.'.join(['10', '0', '0', '7'])}:2222", - f"{_parts('deploy')}@{'.'.join(['buildbox', 'solpbc', 'org'])}", - f"{ssh} {_parts('-', 'o', 'Port', '=', '2222')} host", - f"{ssh} {_parts('-', 'o', ' ', 'Port', '=', '2222')} host", - f"cmd = [{ssh!r}, {_parts('-', 'o')!r}, {_parts('Port', '=', '2222')!r}, 'h']", - global_v6, - f"{ssh} {scrub.TIER3_TERMS[0]}", - f"cmd = [{_parts('s', 'sh')!r}, {scrub.TIER3_TERMS[1]!r}]", - f"{scrub.TIER3_TERMS[2]}@host", - f"user@{scrub.TIER3_TERMS[3]}.local", - f"remote_host = {scrub.TIER3_TERMS[4]!r}", - f"ssh_run(lane, {scrub.TIER3_TERMS[5]!r})", - ] - scratch = repo / "scratch.txt" - scratch.write_text("\n".join(plants) + "\n", encoding="utf-8") - subprocess.run(["git", "add", "scratch.txt"], cwd=repo, check=True) - - result = scrub.scan_paths(repo, scrub.tracked_entries(repo)) - - assert len(result.findings) >= len(plants) - assert {finding.path for finding in result.findings} == {"scratch.txt"} - - -def test_channel_adapter_scrub_scans_raw_symlink_targets(tmp_path: Path) -> None: - repo = tmp_path / "repo" - repo.mkdir() - subprocess.run(["git", "init", "-q"], cwd=repo, check=True) - link = repo / "leaky-link" - link.symlink_to(scrub.TIER1_VALUES[0]) - subprocess.run(["git", "add", "leaky-link"], cwd=repo, check=True) - - result = scrub.scan_paths(repo, scrub.tracked_entries(repo)) - - assert [ - (finding.path, finding.line, finding.component) for finding in result.findings - ] == [("leaky-link", 1, "literal")] - - -def test_channel_adapter_scrub_reports_unreadable_tracked_regular_file( - tmp_path: Path, -) -> None: - repo = tmp_path / "repo" - repo.mkdir() - subprocess.run(["git", "init", "-q"], cwd=repo, check=True) - tracked = repo / "regular.txt" - tracked.write_text("clean\n", encoding="utf-8") - subprocess.run(["git", "add", "regular.txt"], cwd=repo, check=True) - tracked.unlink() - tracked.mkdir() - - result = scrub.scan_paths(repo, scrub.tracked_entries(repo)) - - assert [(finding.path, finding.component) for finding in result.findings] == [ - ("regular.txt", "tracked-io") - ] - assert "errno" in result.findings[0].detail - - -def test_channel_adapter_scrub_skips_deleted_tracked_regular_file( - tmp_path: Path, -) -> None: - repo = tmp_path / "repo" - repo.mkdir() - subprocess.run(["git", "init", "-q"], cwd=repo, check=True) - tracked = repo / "regular.txt" - tracked.write_text("clean\n", encoding="utf-8") - subprocess.run(["git", "add", "regular.txt"], cwd=repo, check=True) - tracked.unlink() - - result = scrub.scan_paths(repo, scrub.tracked_entries(repo)) - - assert result.findings == () diff --git a/tests/test_check_access_imports_clean.py b/tests/test_check_access_imports_clean.py deleted file mode 100644 index 2b9c73981..000000000 --- a/tests/test_check_access_imports_clean.py +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_access_imports_clean.py.""" - -from __future__ import annotations - -import subprocess -import sys -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_access_imports_clean.py" - - -def _run(*args: str) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [sys.executable, str(SCRIPT), *args], - capture_output=True, - text=True, - cwd=REPO_ROOT, - timeout=180, - ) - - -def test_injected_access_heavy_import_goes_red_and_names_offender() -> None: - result = _run("--inject-heavy-module", "solstone.think.check") - - assert result.returncode == 1 - assert "sol check --help [solstone.think.check]" in result.stderr - assert "solstone.think.check" in result.stderr - assert "numpy" in result.stderr diff --git a/tests/test_check_api_conventions.py b/tests/test_check_api_conventions.py deleted file mode 100644 index f0ae67e71..000000000 --- a/tests/test_check_api_conventions.py +++ /dev/null @@ -1,251 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_api_conventions.py. - -Drives the conventions check against throwaway good/bad fixture trees and -asserts the detector's classification and the script's pass/fail exit codes. -The bad fixture deliberately includes a violation only the return-style -classifier catches โ€” a JSON handler (returns ``jsonify(...)``) whose decorator -carries no ``/api/`` segment, mirroring the real ``apps/observer`` bare -``jsonify([...])`` shape โ€” so this proves the detector handles the repo's real -route topology rather than a URL/substring shortcut. -""" - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path - -import pytest - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_api_conventions.py" - - -def _load_checker(): - spec = importlib.util.spec_from_file_location("check_api_conventions", SCRIPT) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -cac = _load_checker() - - -# A clean route module: collections through respond_collection, creates through -# created, errors through error_response, pages through plain HTML/redirect. -GOOD_ROUTES = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from flask import Blueprint, redirect -from solstone.convey.utils import respond_collection, created, error_response -from solstone.convey.reasons import INVALID_DAY - -good_bp = Blueprint("app:goodapp", __name__, url_prefix="/app/goodapp") - - -@good_bp.route("/api/items") -def list_items(): - return respond_collection([{"id": 1}], total=1) - - -@good_bp.route("/api/items", methods=["POST"]) -def create_item(): - return created({"id": 2}, location="/app/goodapp/api/items/2") - - -@good_bp.route("/api/items/") -def get_item(item_id): - if not item_id: - return error_response(INVALID_DAY, detail="bad id") - return respond_collection([{"id": item_id}]) - - -@good_bp.route("/") -def page(day): - if not day: - return "", 404 - return "" - - -@good_bp.route("/old") -def old(): - return redirect("/app/goodapp/") -""" - -# A module with no Blueprint registration. Discovery must skip it even though it -# contains a violation-shaped expression, proving discovery is registration-led. -GOOD_HELPERS = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from flask import jsonify - - -def build_payload(): - return jsonify([]) -""" - -# A route module exercising every forbidden escape hatch. -BAD_ROUTES = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from flask import Blueprint, jsonify, render_template, abort - -bad_bp = Blueprint("app:badapp", __name__, url_prefix="/app/badapp") - - -@bad_bp.route("/segments/") -def list_segments(day): - # JSON handler, NO /api/ in the decorator: only the return-style classifier - # catches this bare top-level array (mirrors apps/observer.ingest_segments). - result = [] - result.append({"key": day}) - return jsonify(result) - - -@bad_bp.route("/empty") -def list_empty(): - return jsonify([]) - - -@bad_bp.route("/") -def page(day): - # Page route: render_template + bare "", 404 -> must NOT be flagged. - if not day: - return "", 404 - return render_template("page.html") - - -@bad_bp.route("/api/thing/") -def get_thing(thing_id): - if not thing_id: - abort(404) - if thing_id == "x": - return "", 400 - return jsonify({"error": "nope"}), 500 -""" - - -def _write_tree(root: Path, app_name: str, files: dict[str, str]) -> None: - app_dir = root / "solstone" / "apps" / app_name - app_dir.mkdir(parents=True, exist_ok=True) - for name, content in files.items(): - (app_dir / name).write_text(content, encoding="utf-8") - - -@pytest.fixture -def good_root(tmp_path) -> Path: - root = tmp_path / "good" - _write_tree(root, "goodapp", {"routes.py": GOOD_ROUTES, "helpers.py": GOOD_HELPERS}) - return root - - -@pytest.fixture -def bad_root(tmp_path) -> Path: - root = tmp_path / "bad" - _write_tree(root, "badapp", {"routes.py": BAD_ROUTES}) - return root - - -def _run(root: Path) -> subprocess.CompletedProcess: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(root)], - capture_output=True, - text=True, - ) - - -def test_good_fixture_exits_zero(good_root): - result = _run(good_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "api-conventions: pass" in result.stdout - - -def test_bad_fixture_exits_one(bad_root): - result = _run(bad_root) - assert result.returncode == 1, result.stdout + result.stderr - assert "NEW violations" in result.stderr - - -def test_discovery_is_blueprint_led(good_root): - # helpers.py registers no Blueprint -> it is not scanned. - modules = {p.as_posix() for p in cac.discover_modules(good_root)} - assert modules == {"solstone/apps/goodapp/routes.py"} - - -def test_classifier_flags_non_api_json_array(bad_root): - findings = cac.scan_file(bad_root / "solstone/apps/badapp/routes.py") - kinds_by_func: dict[str, set[str]] = {} - for _lineno, kind, func in findings: - kinds_by_func.setdefault(func, set()).add(kind) - - # The no-/api/ JSON handlers are flagged for their bare arrays. - assert "bare-array" in kinds_by_func["list_segments"] - assert "bare-array" in kinds_by_func["list_empty"] - # The page route's bare "", 404 is NOT flagged. - assert "page" not in kinds_by_func - # The JSON RPC handler's every escape hatch is flagged. - assert kinds_by_func["get_thing"] == {"abort", "bare-return", "inline-error"} - - -def test_render_template_scan_flags_flask_binding_forms(): - sources = [ - "from flask import render_template\n\n" - "def v():\n" - " return render_template('x.html')\n", - "from flask import render_template as rt\n\n" - "def v():\n" - " return rt('x.html')\n", - "import flask\n\ndef v():\n return flask.render_template('x.html')\n", - ] - - for source in sources: - assert cac.scan_render_templates(source) - - -def test_render_template_scan_ignores_local_helper(): - source = """ -def _render_template(template, provider): - return template.replace("{provider}", provider) - - -def v(): - return _render_template("a", "b") -""" - - assert cac.scan_render_templates(source) == [] - - -def test_render_template_allowlist_wires_real_tree(): - new, tracked = cac.evaluate(cac.ROOT, cac.ALLOWLIST) - - assert new == [] - assert "solstone/apps/news/routes.py: 1/1 render-template (allowlisted)" in tracked - assert ( - "solstone/apps/reflections/routes.py: 1/1 render-template (allowlisted)" - in tracked - ) - - -def test_ratchet_by_file_kind_count(bad_root): - # No allowlist -> every violation is new. - new, tracked = cac.evaluate(bad_root, {}) - assert new - assert tracked == [] - - # Allowlist the exact counts -> green, all tracked. - counts = cac.count_violations(bad_root) - new_exact, tracked_exact = cac.evaluate(bad_root, counts) - assert new_exact == [] - assert tracked_exact - - # Lower a single (file, kind) count below its actual occurrences -> fails. - key = next(iter(counts)) - ratcheted = dict(counts) - ratcheted[key] = counts[key] - 1 - new_over, _ = cac.evaluate(bad_root, ratcheted) - assert new_over diff --git a/tests/test_check_brain_health_cutover.py b/tests/test_check_brain_health_cutover.py deleted file mode 100644 index cfea7ceab..000000000 --- a/tests/test_check_brain_health_cutover.py +++ /dev/null @@ -1,149 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-tests for scripts/check_brain_health_cutover.py.""" - -from __future__ import annotations - -from pathlib import Path - -from scripts import check_brain_health_cutover as guard - - -def _write(root: Path, rel: str, text: str) -> None: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(text, encoding="utf-8") - - -def _run(root: Path) -> int: - return guard.main(["--root", str(root), "--all-files"]) - - -def test_guard_flags_legacy_health_file_literal(tmp_path, capsys) -> None: - legacy_file = "talents" + ".json" - _write(tmp_path, "docs/bad.md", f"old snapshot: {legacy_file}\n") - - assert _run(tmp_path) == 1 - assert "legacy-health-file" in capsys.readouterr().out - - -def test_guard_flags_provider_command_shapes(tmp_path, capsys) -> None: - provider_cmd = "journal " + "providers" + " check" - journal_token = "'" + "journal" + "'" - providers_token = "'" + "providers" + "'" - check_token = "'" + "check" + "'" - _write(tmp_path, "docs/bad.md", provider_cmd + "\n") - _write( - tmp_path, - "solstone/bad.py", - f"CMD = [{journal_token}, {providers_token}, {check_token}, '--targeted']\n", - ) - - assert _run(tmp_path) == 1 - output = capsys.readouterr().out - assert "legacy-provider-check-text" in output - assert "legacy-provider-check-cmd" in output - - -def test_guard_flags_owner_labels_and_quoted_payload_keys(tmp_path, capsys) -> None: - label = "Provider " + "Readiness" - quoted_key = '"' + "ai" + "_readiness" + '"' - _write(tmp_path, "solstone/bad.py", f"TITLE = {label!r}\nKEY = {quoted_key}\n") - - assert _run(tmp_path) == 1 - output = capsys.readouterr().out - assert "legacy-owner-label" in output - assert "legacy-payload-key" in output - - -def test_guard_allows_unquoted_provider_readiness_identifier(tmp_path) -> None: - _write(tmp_path, "solstone/good.py", "provider_readiness = {'ok': True}\n") - - assert _run(tmp_path) == 0 - - -def test_guard_flags_unauthorized_brain_reader_import(tmp_path, capsys) -> None: - _write( - tmp_path, - "solstone/think/work.py", - "from solstone.think.brain_health import build_brain_presentation\n", - ) - - assert _run(tmp_path) == 1 - assert "unauthorized-brain-health-reader" in capsys.readouterr().out - - -def test_guard_allows_declared_brain_reader_import(tmp_path) -> None: - _write( - tmp_path, - "solstone/think/top.py", - "from solstone.think.brain_health import build_brain_snapshot\n", - ) - - assert _run(tmp_path) == 0 - - -def test_guard_flags_process_local_attestation_calls_with_aliases( - tmp_path, - capsys, -) -> None: - _write( - tmp_path, - "solstone/apps/thinking/routes.py", - "\n".join( - [ - "from solstone.think.services import spp as service_spp", - "from solstone.think.providers.local_endpoint import probe_local_endpoint as probe", - "from solstone.think.services.spp_transport import recheck_confidential_attestation as recheck", - "def bad(endpoint):", - " service_spp.get_attestation_state()", - " probe(endpoint)", - " recheck()", - ] - ), - ) - - assert _run(tmp_path) == 1 - output = capsys.readouterr().out - assert "unauthorized-process-local-attestation" in output - assert "solstone.think.services.spp.get_attestation_state" in output - assert "solstone.think.providers.local_endpoint.probe_local_endpoint" in output - assert ( - "solstone.think.services.spp_transport.recheck_confidential_attestation" - in output - ) - - -def test_guard_allows_declared_process_local_attestation_callers(tmp_path) -> None: - _write( - tmp_path, - "solstone/think/brain_cli.py", - "\n".join( - [ - "from solstone.think.services import spp", - "from solstone.think.services.spp_transport import recheck_confidential_attestation", - "def refresh():", - " recheck_confidential_attestation()", - " spp.get_attestation_state()", - ] - ), - ) - _write( - tmp_path, - "solstone/think/providers/state.py", - "\n".join( - [ - "from solstone.think.providers.local_endpoint import probe_local_endpoint", - "def status(endpoint):", - " return probe_local_endpoint(endpoint)", - ] - ), - ) - _write( - tmp_path, - "tests/test_bad.py", - "from solstone.think.services import spp\nspp.get_attestation_state()\n", - ) - - assert _run(tmp_path) == 0 diff --git a/tests/test_check_cogitate_prompts.py b/tests/test_check_cogitate_prompts.py deleted file mode 100644 index 6cde83f76..000000000 --- a/tests/test_check_cogitate_prompts.py +++ /dev/null @@ -1,294 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_cogitate_prompts.py.""" - -from __future__ import annotations - -import importlib.util -import os -from pathlib import Path - -import frontmatter -import pytest - -import solstone.think.talent as talent_module -from solstone.think.prompts import PromptMetadataError - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_cogitate_prompts.py" - - -def _load_checker(): - spec = importlib.util.spec_from_file_location("check_cogitate_prompts", SCRIPT) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -ccp = _load_checker() - - -def _write_file(root: Path, rel: str, content: str) -> Path: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(content, encoding="utf-8") - return path - - -def _prompt(frontmatter_json: str, body: str) -> str: - return f"{frontmatter_json.strip()}\n\n{body.strip()}\n" - - -def _cogitate_prompt(body: str) -> str: - return _prompt('{\n "type": "cogitate"\n}', body) - - -def _patch_talent_dirs( - monkeypatch: pytest.MonkeyPatch, tmp_path: Path -) -> tuple[Path, Path]: - talent_dir = tmp_path / "talent" - apps_dir = tmp_path / "apps" - talent_dir.mkdir() - apps_dir.mkdir() - monkeypatch.setattr(talent_module, "TALENT_DIR", talent_dir) - monkeypatch.setattr(talent_module, "APPS_DIR", apps_dir) - return talent_dir, apps_dir - - -@pytest.mark.parametrize( - ("body", "kind"), - [ - ("Bad `journal navigate`.", "bare-journal"), - ("Bad `Bash`.", "cli-agent-tool"), - ("Bad `Write`.", "cli-agent-tool"), - ("Bad `Read('x')`.", "cli-agent-tool"), - ("Bad `cat foo`.", "shell-read"), - ("Bad `journal/chronicle/20260101/x.json`.", "raw-journal-path"), - ], -) -def test_lint_prompt_flags_cogitate_policy_violations(body: str, kind: str) -> None: - findings = ccp.lint_prompt(body) - assert kind in [finding[1] for finding in findings] - - -def test_bare_journal_flags_fenced_commands() -> None: - findings = ccp.lint_prompt("```sh\njournal supervisor\n```\n") - assert findings == [ - ( - 2, - "bare-journal", - f"forbidden `journal supervisor`; {ccp.JOURNAL_ALTERNATIVE}", - ) - ] - - -@pytest.mark.parametrize( - "body", - [ - "`journal health`", - "`journal talent logs --daily`", - "`sol doctor`", - "`sol call entities list`", - "`sol call facets list-candidates --json`", - "`read_file journal/chronicle/20260101/x.json`", - "`list_directory journal/chronicle`", - "`glob journal/chronicle/*`", - "`grep_search needle journal/chronicle`", - "`identity/partner.md`", - "`chronicle/20260101`", - "`## observations`", - "`write_file`", - "`replace`", - ], -) -def test_lint_prompt_ignores_sanctioned_forms(body: str) -> None: - assert ccp.lint_prompt(body) == [] - - -@pytest.mark.parametrize( - "body", - [ - "`sol call journal search x && sol call entities list`", - "`echo $(sol call support create --subject x)`", - "`bash -lc 'sol call journal search x'`", - ], -) -def test_lint_prompt_flags_shell_composition(body: str) -> None: - findings = ccp.lint_prompt(body) - assert [(line, kind) for line, kind, _detail in findings] == [ - (1, "shell-composition") - ] - - -def test_lint_prompt_allows_multiline_partner_value_example() -> None: - body = """```bash -journal identity partner --update-section 'work patterns' --value 'My partner tends to batch meetings before noon and protects afternoon blocks for focused work. Calendar data from March 25-31 shows 85% of meetings before 12:00 (sol://20260328/archon/091500_300). - -Deep work sessions typically run 2-3 hours โ€” calendar and activity signals show fewer interruptions during these blocks.' -``` -""" - - findings = ccp.lint_prompt(body) - - assert "shell-composition" not in [kind for _line, kind, _detail in findings] - - -@pytest.mark.parametrize( - "body", - [ - "`sol call activities list --source anticipated --from $day_YYYYMMDD --to <+7>`", - '`sol call journal search "" --day-to <+6> -a pulse -n 12`', - ], -) -def test_lint_prompt_allows_angle_placeholder_metavars(body: str) -> None: - findings = ccp.lint_prompt(body) - - assert "shell-composition" not in [kind for _line, kind, _detail in findings] - - -def test_prose_is_not_linted_as_command_context() -> None: - body = ( - "A prose sentence may mention journal, read, write, and agent. " - "It may also say never delegate to a sub-agent, as long as this is not " - "inside a markdown code span." - ) - assert ccp.lint_prompt(body) == [] - - -def test_extract_command_spans_scans_fences_per_line_without_inline_double_scan() -> ( - None -): - body = ( - "Before `journal navigate`.\n" - "```sh\n" - "journal supervisor\n" - "echo `journal health`\n" - "\n" - "```\n" - "After `journal identity partner`.\n" - ) - - assert ccp.extract_command_spans(body) == [ - (1, "journal navigate"), - (3, "journal supervisor"), - (4, "echo `journal health`"), - (7, "journal identity partner"), - ] - - findings = ccp.lint_prompt(body) - assert [(line, kind) for line, kind, _detail in findings] == [ - (1, "bare-journal"), - (3, "bare-journal"), - (4, "shell-composition"), - ] - - -def test_ratchet_by_file_kind_count( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - talent_dir, _apps_dir = _patch_talent_dirs(monkeypatch, tmp_path) - _write_file( - talent_dir, - "bad.md", - _cogitate_prompt("# Bad\n\n`journal navigate`"), - ) - - over, stale, tracked = ccp.evaluate({}) - assert over - assert stale == [] - assert tracked == [] - - counts = ccp.count_violations() - over_exact, stale_exact, tracked_exact = ccp.evaluate(counts) - assert over_exact == [] - assert stale_exact == [] - assert tracked_exact - - key = next(iter(counts)) - ratcheted = dict(counts) - ratcheted[key] = counts[key] - 1 - over_lowered, stale_lowered, _ = ccp.evaluate(ratcheted) - assert over_lowered - assert stale_lowered == [] - - -def test_stale_allowlist_entries_are_reported_for_vanished_keys( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - talent_dir, _apps_dir = _patch_talent_dirs(monkeypatch, tmp_path) - _write_file( - talent_dir, - "clean.md", - _cogitate_prompt("# Clean\n\n`journal health`"), - ) - allowlist = {("solstone/talent/vanished.md", "bare-journal"): 1} - - over, stale, tracked = ccp.evaluate(allowlist) - assert over == [] - assert any("solstone/talent/vanished.md" in line for line in stale) - assert tracked == [] - - -def test_discovery_uses_only_cogitate_talent_prompts( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - talent_dir, _apps_dir = _patch_talent_dirs(monkeypatch, tmp_path) - cogitate = _write_file( - talent_dir, - "clean.md", - _cogitate_prompt("# Clean\n\n`journal health`"), - ) - _write_file( - talent_dir, - "generate.md", - _prompt( - '{\n "type": "generate",\n "output": "md"\n}', - "# Generate\n\n`journal supervisor`\n\n`journal/x`", - ), - ) - _write_file( - talent_dir, - "SKILL.md", - "# Skill\n\n`journal supervisor`\n\n`journal/x`", - ) - - prompts = ccp.discover_prompts() - assert prompts == [ - ( - Path(os.path.relpath(cogitate, REPO_ROOT)).as_posix(), - "# Clean\n\n`journal health`", - ) - ] - assert ccp.evaluate({}) == ([], [], []) - - -def test_malformed_frontmatter_hard_fails_discovery( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - talent_dir, _apps_dir = _patch_talent_dirs(monkeypatch, tmp_path) - _write_file( - talent_dir, - "broken.md", - '{\n "type": "cogitate",\n}\n\n# Broken\n', - ) - - with pytest.raises(PromptMetadataError): - ccp.discover_prompts() - - -def test_discovery_floor_matches_cogitate_frontmatter() -> None: - expected: set[str] = set() - for path in sorted((REPO_ROOT / "solstone" / "talent").glob("*.md")): - post = frontmatter.load(path) - if post.metadata.get("type") == "cogitate": - expected.add(Path(os.path.relpath(path, REPO_ROOT)).as_posix()) - for path in sorted((REPO_ROOT / "solstone" / "apps").glob("*/talent/*.md")): - post = frontmatter.load(path) - if post.metadata.get("type") == "cogitate": - expected.add(Path(os.path.relpath(path, REPO_ROOT)).as_posix()) - - discovered = {rel for rel, _body in ccp.discover_prompts()} - assert expected - assert expected <= discovered diff --git a/tests/test_check_conversion_retirements.py b/tests/test_check_conversion_retirements.py deleted file mode 100644 index f3ef9b375..000000000 --- a/tests/test_check_conversion_retirements.py +++ /dev/null @@ -1,290 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-tests for the conversion-wave retirement CI contract.""" - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path - -import pytest - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_conversion_retirements.py" -MANIFEST = REPO_ROOT / "conversion-retirements.toml" - - -def _load_script_module(): - spec = importlib.util.spec_from_file_location( - "check_conversion_retirements", SCRIPT - ) - assert spec is not None - assert spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def _manifest( - root: Path, - *, - status: str = "done", - python_roots: tuple[str, ...] = (), -) -> Path: - manifest = root / "conversion-retirements.toml" - roots = ", ".join(f'"{path}"' for path in python_roots) - manifest.write_text( - "\n".join( - [ - "schema_version = 1", - 'dependency_files = ["pyproject.toml"]', - 'content_roots = ["solstone"]', - "content_exclusions = []", - "", - "[[waves]]", - 'id = "seeded-wave"', - f'status = "{status}"', - 'distribution = "scikit-learn"', - f"python_roots = [{roots}]", - 'import_roots = ["sklearn"]', - "test_only_dependency_locations = []", - "", - ] - ), - encoding="utf-8", - ) - return manifest - - -def _check( - root: Path, - *, - tracked_paths: list[str], - status: str = "done", - python_roots: tuple[str, ...] = (), -): - module = _load_script_module() - manifest = _manifest(root, status=status, python_roots=python_roots) - return module.check_repository( - root, - manifest, - tracked_paths=tracked_paths, - ) - - -def test_checked_in_manifest_passes() -> None: - result = subprocess.run( - [sys.executable, str(SCRIPT), "--manifest", str(MANIFEST)], - cwd=REPO_ROOT, - capture_output=True, - text=True, - timeout=60, - ) - - assert result.returncode == 0, result.stdout + result.stderr - assert "W1b-discovery-kernel" in result.stdout - - -@pytest.mark.parametrize("alias", ["scikit-learn", "scikit_learn", "sklearn"]) -def test_done_wave_fails_each_distribution_or_import_spelling( - tmp_path: Path, - alias: str, -) -> None: - runtime = tmp_path / "solstone" / "runtime.py" - runtime.parent.mkdir() - runtime.write_text(f'consumer = "{alias}"\n', encoding="utf-8") - (tmp_path / "pyproject.toml").write_text( - "[project]\ndependencies = []\n", - encoding="utf-8", - ) - - result = _check( - tmp_path, - tracked_paths=["pyproject.toml", "solstone/runtime.py"], - ) - - assert result.ok is False - assert any(alias in violation for violation in result.violations) - - -def test_done_wave_fails_alias_in_tracked_pathname(tmp_path: Path) -> None: - offender = tmp_path / "solstone" / "scikit_learn" / "runtime.py" - offender.parent.mkdir(parents=True) - offender.write_text("value = 1\n", encoding="utf-8") - (tmp_path / "pyproject.toml").write_text( - "[project]\ndependencies = []\n", - encoding="utf-8", - ) - - result = _check( - tmp_path, - tracked_paths=["pyproject.toml", "solstone/scikit_learn/runtime.py"], - ) - - assert result.ok is False - assert any("pathname" in violation for violation in result.violations) - - -@pytest.mark.parametrize( - "dependency", - ["scikit-learn>=1.3", "scikit_learn==1.8.0"], -) -def test_done_wave_fails_semantic_dependency_alias( - tmp_path: Path, - dependency: str, -) -> None: - (tmp_path / "pyproject.toml").write_text( - f'[project]\ndependencies = ["{dependency}"]\n', - encoding="utf-8", - ) - runtime = tmp_path / "solstone" / "__init__.py" - runtime.parent.mkdir() - runtime.write_text("", encoding="utf-8") - - result = _check( - tmp_path, - tracked_paths=["pyproject.toml", "solstone/__init__.py"], - ) - - assert result.ok is False - assert any("project.dependencies" in violation for violation in result.violations) - - -def test_done_wave_fails_declared_python_root_that_still_exists( - tmp_path: Path, -) -> None: - retired = tmp_path / "solstone" / "retired_kernel.py" - retired.parent.mkdir() - retired.write_text("value = 1\n", encoding="utf-8") - (tmp_path / "pyproject.toml").write_text( - "[project]\ndependencies = []\n", - encoding="utf-8", - ) - - result = _check( - tmp_path, - tracked_paths=["pyproject.toml", "solstone/retired_kernel.py"], - python_roots=("solstone/retired_kernel.py",), - ) - - assert result.ok is False - assert any( - "declared Python root still exists" in item for item in result.violations - ) - - -def test_in_progress_wave_does_not_claim_retirement(tmp_path: Path) -> None: - runtime = tmp_path / "solstone" / "runtime.py" - runtime.parent.mkdir() - runtime.write_text('consumer = "sklearn"\n', encoding="utf-8") - (tmp_path / "pyproject.toml").write_text( - '[project]\ndependencies = ["scikit-learn"]\n', - encoding="utf-8", - ) - - result = _check( - tmp_path, - tracked_paths=["pyproject.toml", "solstone/runtime.py"], - status="in_progress", - ) - - assert result.ok is True - assert result.checked_waves == () - - -def test_manifest_rejects_broad_content_exclusion(tmp_path: Path) -> None: - manifest = _manifest(tmp_path) - manifest.write_text( - manifest.read_text(encoding="utf-8").replace( - "content_exclusions = []", - 'content_exclusions = ["solstone/*"]', - ), - encoding="utf-8", - ) - module = _load_script_module() - - result = module.check_repository( - tmp_path, - manifest, - tracked_paths=["pyproject.toml"], - ) - - assert result.ok is False - assert result.violations == ( - "content_exclusions must be exact paths, not glob patterns", - ) - - -def test_done_wave_allows_explicit_test_only_oracle_dependency( - tmp_path: Path, -) -> None: - manifest = _manifest(tmp_path) - manifest.write_text( - manifest.read_text(encoding="utf-8").replace( - "test_only_dependency_locations = []", - ( - "test_only_dependency_locations = " - '["pyproject.toml:dependency-groups.dev"]' - ), - ), - encoding="utf-8", - ) - (tmp_path / "pyproject.toml").write_text( - '[dependency-groups]\ndev = ["scikit-learn>=1.3"]\n', - encoding="utf-8", - ) - runtime = tmp_path / "solstone" / "__init__.py" - runtime.parent.mkdir() - runtime.write_text("", encoding="utf-8") - module = _load_script_module() - - result = module.check_repository( - tmp_path, - manifest, - tracked_paths=["pyproject.toml", "solstone/__init__.py"], - ) - - assert result.ok is True - - -def test_done_wave_cannot_exempt_shipping_dependency_group( - tmp_path: Path, -) -> None: - manifest = _manifest(tmp_path) - manifest.write_text( - manifest.read_text(encoding="utf-8").replace( - "test_only_dependency_locations = []", - ( - "test_only_dependency_locations = " - '["pyproject.toml:project.optional-dependencies.journal-host"]' - ), - ), - encoding="utf-8", - ) - (tmp_path / "pyproject.toml").write_text( - ( - "[project]\n" - "[project.optional-dependencies]\n" - 'journal-host = ["scikit-learn>=1.3"]\n' - ), - encoding="utf-8", - ) - runtime = tmp_path / "solstone" / "__init__.py" - runtime.parent.mkdir() - runtime.write_text("", encoding="utf-8") - module = _load_script_module() - - result = module.check_repository( - tmp_path, - manifest, - tracked_paths=["pyproject.toml", "solstone/__init__.py"], - ) - - assert result.ok is False - assert any( - "test-only dependency exception is not a test group" in violation - for violation in result.violations - ) diff --git a/tests/test_check_convey_bind_imports_clean.py b/tests/test_check_convey_bind_imports_clean.py deleted file mode 100644 index acc176f96..000000000 --- a/tests/test_check_convey_bind_imports_clean.py +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_convey_bind_imports_clean.py.""" - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_convey_bind_imports_clean.py" -EXPECTED_HEAVY = { - "numpy", - "scipy", - "sklearn", - "onnxruntime", - "pyarrow", - "transformers", - "cv2", - "mlx", - "mlx_lm", - "av", - "faster_whisper", - "torch", - "pandas", - "huggingface_hub", - "litellm", -} - - -def _run(*args: str) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [sys.executable, str(SCRIPT), *args], - capture_output=True, - text=True, - cwd=REPO_ROOT, - timeout=180, - ) - - -def _load_script_module(): - spec = importlib.util.spec_from_file_location( - "check_convey_bind_imports_clean", SCRIPT - ) - assert spec is not None - assert spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def test_injected_heavy_import_goes_red_and_names_offender() -> None: - result = _run("--inject-heavy-module", "numpy") - - assert result.returncode == 1 - assert "numpy" in result.stdout + result.stderr - - -def test_heavy_constant_is_single_source_of_truth() -> None: - module = _load_script_module() - - assert len(module.HEAVY) == 15 - assert set(module.HEAVY) == EXPECTED_HEAVY diff --git a/tests/test_check_journal_config_owner.py b/tests/test_check_journal_config_owner.py deleted file mode 100644 index 154511e8b..000000000 --- a/tests/test_check_journal_config_owner.py +++ /dev/null @@ -1,189 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path -from types import ModuleType - -SCRIPT = ( - Path(__file__).resolve().parents[1] / "scripts" / "check_journal_config_owner.py" -) - - -def _load_gate() -> ModuleType: - spec = importlib.util.spec_from_file_location("check_journal_config_owner", SCRIPT) - assert spec is not None - assert spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def _kinds(findings: list[tuple[int, str, str]]) -> set[str]: - return {kind for _lineno, kind, _detail in findings} - - -def _write_bad_module(tmp_path: Path, source: str) -> None: - package = tmp_path / "solstone" - package.mkdir() - (package / "bad.py").write_text(source, encoding="utf-8") - - -def _run_gate(tmp_path: Path) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(tmp_path)], - check=False, - capture_output=True, - text=True, - ) - - -def test_scanner_flags_private_serializer_import_and_call() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "from solstone.think.journal_config import _write_journal_config as raw\n" - "raw({})\n" - ) - - assert "private_serializer" in _kinds(findings) - - -def test_scanner_flags_config_specific_atomic_replace() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "from solstone.think.journal_config import get_journal_config_path\n" - "from solstone.think.journal_io.atomic import atomic_replace\n" - "atomic_replace(get_journal_config_path(), '{}')\n" - ) - - assert "journal_config_replace" in _kinds(findings) - - -def test_scanner_flags_private_serializer_wrapper() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "import solstone.think.journal_config as jc\n" - "write_journal_config = jc._write_journal_config\n" - ) - - assert "private_serializer_wrapper" in _kinds(findings) - - -def test_scanner_flags_second_config_lock() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "from solstone.think.journal_config import get_journal_config_path\n" - "from solstone.think.journal_io.locking import hold_lock\n" - "with hold_lock(get_journal_config_path()):\n" - " pass\n" - ) - - assert "second_config_lock" in _kinds(findings) - - -def test_scanner_flags_hand_rolled_sidecar_flock() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "import fcntl\n" - "from pathlib import Path\n" - "lock_path = Path('journal') / 'config' / ('.' + 'journal.json' + '.lock')\n" - "lock_file = open(lock_path, 'w')\n" - "fcntl.flock(lock_file, fcntl.LOCK_EX)\n" - ) - - assert "second_config_lock" in _kinds(findings) - - -def test_scanner_allows_atomic_replace_on_non_config_domain() -> None: - gate = _load_gate() - - findings = gate.scan_source( - "from pathlib import Path\n" - "from solstone.think.journal_io.atomic import atomic_replace\n" - "atomic_replace(Path('config') / 'chat.json', '{}')\n" - ) - - assert findings == [] - - -def test_e2e_flags_private_serializer(tmp_path: Path) -> None: - _write_bad_module( - tmp_path, - "from solstone.think.journal_config import _write_journal_config as raw\n" - "raw({})\n", - ) - - result = _run_gate(tmp_path) - - assert result.returncode == 1 - assert "journal-config-owner: NEW violations:" in result.stderr - assert "private_serializer" in result.stderr - - -def test_e2e_flags_config_specific_atomic_replace(tmp_path: Path) -> None: - _write_bad_module( - tmp_path, - "from solstone.think.journal_config import get_journal_config_path\n" - "from solstone.think.journal_io.atomic import atomic_replace\n" - "atomic_replace(get_journal_config_path(), '{}')\n", - ) - - result = _run_gate(tmp_path) - - assert result.returncode == 1 - assert "journal-config-owner: NEW violations:" in result.stderr - assert "journal_config_replace" in result.stderr - - -def test_e2e_flags_private_serializer_wrapper(tmp_path: Path) -> None: - _write_bad_module( - tmp_path, - "import solstone.think.journal_config as jc\n" - "write_journal_config = jc._write_journal_config\n", - ) - - result = _run_gate(tmp_path) - - assert result.returncode == 1 - assert "journal-config-owner: NEW violations:" in result.stderr - assert "private_serializer_wrapper" in result.stderr - - -def test_e2e_flags_second_config_lock(tmp_path: Path) -> None: - _write_bad_module( - tmp_path, - "from solstone.think.journal_config import get_journal_config_path\n" - "from solstone.think.journal_io.locking import hold_lock\n" - "with hold_lock(get_journal_config_path()):\n" - " pass\n", - ) - - result = _run_gate(tmp_path) - - assert result.returncode == 1 - assert "journal-config-owner: NEW violations:" in result.stderr - assert "second_config_lock" in result.stderr - - -def test_e2e_allows_atomic_replace_on_non_config_domain(tmp_path: Path) -> None: - _write_bad_module( - tmp_path, - "from pathlib import Path\n" - "from solstone.think.journal_io.atomic import atomic_replace\n" - "atomic_replace(Path('config') / 'chat.json', '{}')\n", - ) - - result = _run_gate(tmp_path) - - assert result.returncode == 0 - assert "journal-config-owner: pass" in result.stdout - assert result.stderr == "" diff --git a/tests/test_check_journal_io_access.py b/tests/test_check_journal_io_access.py deleted file mode 100644 index 20c9d2492..000000000 --- a/tests/test_check_journal_io_access.py +++ /dev/null @@ -1,218 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_journal_io_access.py. - -Drives the journal_io access check against throwaway good/bad fixture trees and -asserts the detector's import-binding discrimination, owner exclusions, -non-gated symbol handling, and ratcheting allowlist behavior. -""" - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path - -import pytest - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_journal_io_access.py" - - -def _load_checker(): - spec = importlib.util.spec_from_file_location("check_journal_io_access", SCRIPT) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -cja = _load_checker() - - -BAD_IMPORT = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io import write_json - - -def persist(path): - write_json(path, {"ok": True}) -""" - -LOCAL_DISCRIMINATION = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - - -def write_json(path, payload): - return path, payload - - -def persist(path): - write_json(path, {"ok": True}) - path.write_text("ok", encoding="utf-8") -""" - -OWNER_IMPORT = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io import write_json - - -def persist(path): - write_json(path, {"ok": True}) -""" - -NON_GATED_IMPORTS = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io import contained_path, day_path, read_json - - -def inspect(root, path): - read_json(path) - contained_path(root, path) - day_path("20260606") -""" - -SUBMODULE_IMPORT = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io.atomic import write_json - - -def persist(path): - write_json(path, {"ok": True}) -""" - -NPZ_SUBMODULE_IMPORT = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io.npz import save_npz, update_npz - - -def persist(path, arrays, transform): - save_npz(path, arrays, expected_keys=("data",)) - update_npz(path, transform, expected_keys=("data",)) -""" - - -WRITE_NPZ_SUBMODULE_IMPORT = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -from solstone.think.journal_io.npz import write_npz - - -def persist(path, arrays): - write_npz(path, arrays, expected_keys=("data",)) -""" - - -def _write_file(root: Path, rel: str, content: str) -> None: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(content, encoding="utf-8") - - -@pytest.fixture -def bad_root(tmp_path) -> Path: - root = tmp_path / "bad" - _write_file(root, "solstone/apps/badapp/routes.py", BAD_IMPORT) - return root - - -@pytest.fixture -def local_root(tmp_path) -> Path: - root = tmp_path / "local" - _write_file(root, "solstone/apps/localapp/routes.py", LOCAL_DISCRIMINATION) - return root - - -@pytest.fixture -def owner_root(tmp_path) -> Path: - root = tmp_path / "owner" - _write_file(root, "solstone/think/entities/saving.py", OWNER_IMPORT) - return root - - -@pytest.fixture -def non_gated_root(tmp_path) -> Path: - root = tmp_path / "non-gated" - _write_file(root, "solstone/apps/reader/routes.py", NON_GATED_IMPORTS) - return root - - -def _run(root: Path) -> subprocess.CompletedProcess: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(root)], - capture_output=True, - text=True, - ) - - -def test_bad_import_exits_one_and_names_file_and_primitive(bad_root): - result = _run(bad_root) - assert result.returncode == 1, result.stdout + result.stderr - assert "solstone/apps/badapp/routes.py" in result.stderr - assert "write_json" in result.stderr - - -def test_local_same_name_and_path_write_text_are_not_violations(local_root): - result = _run(local_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-access: pass" in result.stdout - - -def test_owner_path_is_exempt(owner_root): - result = _run(owner_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-access: pass" in result.stdout - - -def test_non_gated_imports_are_not_violations(non_gated_root): - result = _run(non_gated_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-access: pass" in result.stdout - - -def test_submodule_import_is_flagged(): - findings = cja.scan_source(SUBMODULE_IMPORT) - assert findings == [(7, "write_json", "write_json")] - - -def test_npz_submodule_write_imports_are_flagged(): - findings = cja.scan_source(NPZ_SUBMODULE_IMPORT) - assert [(primitive, bound_name) for _lineno, primitive, bound_name in findings] == [ - ("save_npz", "save_npz"), - ("update_npz", "update_npz"), - ] - - -def test_write_npz_submodule_import_is_flagged(): - findings = cja.scan_source(WRITE_NPZ_SUBMODULE_IMPORT) - assert ("write_npz", "write_npz") in [ - (primitive, bound_name) for _lineno, primitive, bound_name in findings - ] - - -def test_ratchet_by_file_kind_count(bad_root): - # No allowlist -> every violation is new. - new, tracked = cja.evaluate(bad_root, {}) - assert new - assert tracked == [] - - # Allowlist the exact counts -> green, all tracked. - counts = cja.count_violations(bad_root) - new_exact, tracked_exact = cja.evaluate(bad_root, counts) - assert new_exact == [] - assert tracked_exact - - # Lower a single (file, kind) count below its actual occurrences -> fails. - key = next(iter(counts)) - ratcheted = dict(counts) - ratcheted[key] = counts[key] - 1 - new_over, _ = cja.evaluate(bad_root, ratcheted) - assert new_over diff --git a/tests/test_check_journal_io_mechanic.py b/tests/test_check_journal_io_mechanic.py deleted file mode 100644 index 5ba114b9f..000000000 --- a/tests/test_check_journal_io_mechanic.py +++ /dev/null @@ -1,337 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Self-test for scripts/check_journal_io_mechanic.py.""" - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path - -import pytest - -REPO_ROOT = Path(__file__).resolve().parents[1] -SCRIPT = REPO_ROOT / "scripts" / "check_journal_io_mechanic.py" - - -def _load_checker(): - spec = importlib.util.spec_from_file_location("check_journal_io_mechanic", SCRIPT) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -cjm = _load_checker() - - -BAD_OS_REPLACE = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -import os - - -def persist(tmp, path): - os.replace(tmp, path) -""" - -OWNER_OS_REPLACE = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -import os - - -def persist(tmp, path): - os.replace(tmp, path) -""" - -HOME_OS_REPLACE = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -import os - - -def atomic(tmp, path): - os.replace(tmp, path) -""" - -EXCLUDED_OS_REPLACE = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -import os - - -def persist(tmp, path): - os.replace(tmp, path) -""" - -TEST_OS_REPLACE = """\ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -import os - - -def test_raw_replace(tmp_path): - os.replace(tmp_path / "a", tmp_path / "b") -""" - - -def _write_file(root: Path, rel: str, content: str) -> None: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(content, encoding="utf-8") - - -@pytest.fixture -def bad_root(tmp_path) -> Path: - root = tmp_path / "bad" - _write_file(root, "solstone/apps/badapp/routes.py", BAD_OS_REPLACE) - return root - - -@pytest.fixture -def owner_root(tmp_path) -> Path: - root = tmp_path / "owner" - _write_file(root, "solstone/think/entities/saving.py", OWNER_OS_REPLACE) - return root - - -@pytest.fixture -def home_root(tmp_path) -> Path: - root = tmp_path / "home" - _write_file(root, "solstone/think/journal_io/custom.py", HOME_OS_REPLACE) - return root - - -@pytest.fixture -def excluded_root(tmp_path) -> Path: - root = tmp_path / "excluded" - _write_file(root, "solstone/think/scheduler.py", EXCLUDED_OS_REPLACE) - return root - - -@pytest.fixture -def test_root(tmp_path) -> Path: - root = tmp_path / "test" - _write_file(root, "solstone/apps/badapp/test_raw.py", TEST_OS_REPLACE) - return root - - -def _run(root: Path) -> subprocess.CompletedProcess: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(root)], - capture_output=True, - text=True, - ) - - -@pytest.mark.parametrize( - ("source", "kind"), - [ - ( - "import os\n\ndef persist(tmp, path):\n os.replace(tmp, path)\n", - "os.replace", - ), - ( - "import os as ops\n\ndef persist(tmp, path):\n ops.replace(tmp, path)\n", - "os.replace", - ), - ( - "from os import replace as swap\n\ndef persist(tmp, path):\n swap(tmp, path)\n", - "os.replace", - ), - ("def persist(tmp, path):\n tmp.replace(path)\n", "Path.replace"), - ( - "def persist(dest):\n dest.with_suffix('.tmp').replace(dest)\n", - "Path.replace", - ), - ( - "import tempfile\n\n" - "def persist(path):\n" - " fd, tmp_path = tempfile.mkstemp(dir=path.parent)\n" - " tmp_path.replace(path)\n", - "Path.replace", - ), - ( - "import fcntl\n\ndef lock(f):\n fcntl.flock(f, fcntl.LOCK_EX)\n", - "flock(LOCK_EX)", - ), - ( - "from fcntl import flock, LOCK_EX\n\ndef lock(f):\n flock(f, LOCK_EX)\n", - "flock(LOCK_EX)", - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' open(Path(get_journal()) / "config" / "schedules.json", "w")\n', - "open(write)", - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f(facet):\n" - " journal = Path(get_journal())\n" - ' target = journal / "facets" / facet / "facet.json"\n' - ' target.write_text("x")\n', - "Path.write_text", - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' Path(get_journal(), "talents", "day.jsonl").open("a")\n', - "Path.open(write)", - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f(day, seg):\n" - ' (Path(get_journal()) / "chronicle" / day / seg / "x.bin")' - '.write_bytes(b"x")\n', - "Path.write_bytes", - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - " root = get_journal()\n" - ' with open(Path(root, "config", "x.json"), "w") as fh:\n' - ' fh.write("x")\n', - "open(write)", - ), - ], -) -def test_scan_source_flags_raw_mechanics(source: str, kind: str) -> None: - findings = cjm.scan_source(source) - assert [finding[1] for finding in findings] == [kind] - - -@pytest.mark.parametrize( - "source", - [ - "def clean(s):\n return s.replace('a', 'b')\n", - "def clean(dt, tz):\n return dt.replace(tzinfo=tz)\n", - "def clean(path):\n return path.name.replace('_', ' ')\n", - "import fcntl\n\ndef lock(f):\n fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)\n", - "import fcntl\n\ndef unlock(f):\n fcntl.flock(f, fcntl.LOCK_UN)\n", - ( - "import tempfile\n" - "from solstone.think.journal_io import install_file\n\n" - "def persist(dest):\n" - " with tempfile.NamedTemporaryFile(delete=False) as tmp:\n" - " tmp.write(b'ok')\n" - " install_file(tmp.name, dest)\n" - ), - ( - "from solstone.think.journal_io import write_text\n" - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f(x):\n" - ' write_text(Path(get_journal()) / "facets" / x / "f.json", "data")\n' - ), - ( - "from solstone.think import journal_io\n" - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f(x):\n" - ' journal_io.write_text(Path(get_journal()) / "facets" / x, "data")\n' - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' open(Path(get_journal()) / "logs" / "audit.jsonl", "a")\n' - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' (Path(get_journal()) / "health" / "service.port")' - '.write_text("5015")\n' - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' open(Path(get_journal()) / "config" / "x.json", "r")\n' - ), - ( - "from solstone.think.utils import get_journal\n" - "from pathlib import Path\n\n" - "def f():\n" - ' Path(get_journal()).write_text("x")\n' - ), - "def save(path, data):\n path.write_text(data)\n", - ( - "def save(path, data):\n" - ' tmp = path.with_suffix(".tmp")\n' - " tmp.write_text(data)\n" - ), - ( - "from solstone.think.journal_io import contained_path\n" - "from solstone.think.utils import get_journal\n\n" - "def f(x):\n" - ' p = contained_path(get_journal(), "facets", x)\n' - ' p.write_text("data")\n' - ), - ( - "from solstone.think.utils import day_path\n\n" - "def f(day):\n" - ' (day_path(day) / "timeline.json").write_text("x")\n' - ), - ], -) -def test_scan_source_ignores_false_positive_surfaces(source: str) -> None: - assert cjm.scan_source(source) == [] - - -def test_bad_module_exits_one_and_names_file_and_kind(bad_root): - result = _run(bad_root) - assert result.returncode == 1, result.stdout + result.stderr - assert "solstone/apps/badapp/routes.py" in result.stderr - assert "os.replace" in result.stderr - - -def test_owner_path_is_scanned(owner_root): - result = _run(owner_root) - assert result.returncode == 1, result.stdout + result.stderr - assert "solstone/think/entities/saving.py" in result.stderr - assert "os.replace" in result.stderr - - -def test_journal_io_home_is_skipped(home_root): - result = _run(home_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-mechanic: pass" in result.stdout - - -def test_excluded_ops_path_is_skipped(excluded_root): - result = _run(excluded_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-mechanic: pass" in result.stdout - - -def test_test_modules_are_skipped(test_root): - result = _run(test_root) - assert result.returncode == 0, result.stdout + result.stderr - assert "journal-io-mechanic: pass" in result.stdout - - -def test_ratchet_by_file_kind_count(bad_root): - new, tracked = cjm.evaluate(bad_root, {}) - assert new - assert tracked == [] - - counts = cjm.count_violations(bad_root) - new_exact, tracked_exact = cjm.evaluate(bad_root, counts) - assert new_exact == [] - assert tracked_exact - - key = next(iter(counts)) - ratcheted = dict(counts) - ratcheted[key] = counts[key] - 1 - new_over, _ = cjm.evaluate(bad_root, ratcheted) - assert new_over diff --git a/tests/test_check_provider_install_owner.py b/tests/test_check_provider_install_owner.py deleted file mode 100644 index 5a8d0d616..000000000 --- a/tests/test_check_provider_install_owner.py +++ /dev/null @@ -1,191 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path -from types import ModuleType - -SCRIPT = ( - Path(__file__).resolve().parents[1] / "scripts" / "check_provider_install_owner.py" -) - - -def _load_checker() -> ModuleType: - spec = importlib.util.spec_from_file_location( - "check_provider_install_owner", SCRIPT - ) - assert spec is not None - assert spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def _write_file(root: Path, rel: str, source: str) -> Path: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(source, encoding="utf-8") - return path - - -def _run(root: Path) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(root)], - check=False, - capture_output=True, - text=True, - ) - - -def _kinds(findings: list[tuple[int, str, str]]) -> set[str]: - return {kind for _lineno, kind, _detail in findings} - - -checker = _load_checker() - - -def test_scan_flags_direct_status_replace() -> None: - findings = checker.scan_source( - "from pathlib import Path\n" - "from solstone.think.journal_io.atomic import atomic_replace\n" - "status = Path('journal') / 'health' / 'providers' / 'local.json'\n" - "atomic_replace(status, '{}')\n" - ) - - assert "provider_status_replace" in _kinds(findings) - - -def test_scan_flags_proof_cache_write() -> None: - findings = checker.scan_source( - "from solstone.think.providers.artifact_proof import proof_cache_path\n" - "path = proof_cache_path('local')\n" - "path.write_text('{}')\n" - ) - - assert "proof_cache_write" in _kinds(findings) - - -def test_scan_flags_raw_lease_open_and_flock() -> None: - findings = checker.scan_source( - "import fcntl\n" - "import os\n" - "from pathlib import Path\n" - "lease = Path('journal') / 'health' / 'providers' / 'local.lease'\n" - "fd = os.open(lease, os.O_RDWR)\n" - "fcntl.flock(fd, fcntl.LOCK_EX)\n" - ) - - kinds = _kinds(findings) - assert "provider_lease_raw_open" in kinds - assert "second_provider_install_lock" in kinds - - -def test_scan_flags_manifest_write() -> None: - findings = checker.scan_source( - "from pathlib import Path\n" - "manifest = Path('cache') / '.solstone-provider-manifest.json'\n" - "manifest.write_text('{}')\n" - ) - - assert "provider_manifest_write" in _kinds(findings) - - -def test_scan_flags_private_owner_alias() -> None: - findings = checker.scan_source( - "from solstone.think.providers.install_state import _read_current_unlocked as raw\n" - "writer = raw\n" - ) - - kinds = _kinds(findings) - assert "private_owner_symbol" in kinds - assert "private_owner_wrapper" in kinds - - -def test_scan_flags_providers_bundled_access() -> None: - findings = checker.scan_source( - "def f(config):\n" - " providers = config.get('providers', {})\n" - " return providers.get('bundled')\n" - ) - - assert "providers_bundled_operational" in _kinds(findings) - - -def test_scan_allows_owner_api_calls() -> None: - findings = checker.scan_source( - "from solstone.think.providers.install_lease import acquire_install_lease\n" - "from solstone.think.providers.install_state import write_install_status\n" - "lease = acquire_install_lease('local')\n" - "write_install_status(status)\n" - ) - - assert findings == [] - - -def test_e2e_flags_violation(tmp_path: Path) -> None: - _write_file( - tmp_path, - "solstone/bad.py", - "from pathlib import Path\n" - "p = Path('journal') / 'health' / 'providers' / 'local.json'\n" - "p.write_text('{}')\n", - ) - - result = _run(tmp_path) - - assert result.returncode == 1 - assert "provider-install-owner: violations:" in result.stderr - assert "provider_status_write" in result.stderr - - -def test_e2e_clean_source_passes(tmp_path: Path) -> None: - _write_file( - tmp_path, - "solstone/good.py", - "from solstone.think.providers.install_state import write_install_status\n" - "def f(status):\n" - " return write_install_status(status)\n", - ) - - result = _run(tmp_path) - - assert result.returncode == 0 - assert "provider-install-owner: pass" in result.stdout - assert result.stderr == "" - - -def test_allowlist_ratchet_and_stale_entry(tmp_path: Path) -> None: - _write_file( - tmp_path, - "solstone/bad.py", - "from pathlib import Path\n" - "p = Path('journal') / 'health' / 'providers' / 'local.json'\n" - "p.write_text('{}')\n", - ) - counts = checker.count_violations(tmp_path) - - over, stale, tracked = checker.evaluate(tmp_path, counts) - assert over == [] - assert stale == [] - assert tracked - - ratcheted = {next(iter(counts)): 0} - over, stale, _tracked = checker.evaluate(tmp_path, ratcheted) - assert over - assert stale == [] - - stale_allowlist = {("solstone/missing.py", "provider_status_write"): 1} - over, stale, _tracked = checker.evaluate(tmp_path, stale_allowlist) - assert over - assert stale - - -def test_landed_tree_is_clean() -> None: - over, stale, _tracked = checker.evaluate(checker.ROOT, checker.ALLOWLIST) - - assert over == [] - assert stale == [] diff --git a/tests/test_check_provider_start_commands.py b/tests/test_check_provider_start_commands.py deleted file mode 100644 index ab1ca6b8d..000000000 --- a/tests/test_check_provider_start_commands.py +++ /dev/null @@ -1,167 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import importlib.util -import subprocess -import sys -from pathlib import Path -from types import ModuleType - -import pytest - -SCRIPT = ( - Path(__file__).resolve().parents[1] / "scripts" / "check_provider_start_commands.py" -) - - -def _load_checker() -> ModuleType: - spec = importlib.util.spec_from_file_location( - "check_provider_start_commands", SCRIPT - ) - assert spec is not None - assert spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def _write_file(root: Path, rel: str, source: str) -> Path: - path = root / rel - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(source, encoding="utf-8") - return path - - -def _run(root: Path) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [sys.executable, str(SCRIPT), "--root", str(root)], - check=False, - capture_output=True, - text=True, - ) - - -def _kinds(findings: list[tuple[int, str, str]]) -> set[str]: - return {kind for _lineno, kind, _detail in findings} - - -checker = _load_checker() - - -def test_scan_flags_provider_start_commands() -> None: - findings = checker.scan_source( - "from solstone.think.callosum import callosum_send as send\n" - "def f(client):\n" - " send('supervisor', 'start_local')\n" - " client.emit(tract='supervisor', event='start_parakeet')\n" - " msg = {'tract': 'supervisor', 'event': 'start_local'}\n" - " return msg\n" - ) - - kinds = _kinds(findings) - assert "provider_start_command" in kinds - assert "provider_start_message" in kinds - - -@pytest.mark.parametrize( - "source", - [ - "from solstone.think import callosum\n" - "callosum.callosum_send('supervisor', 'start_local')\n", - "from solstone.think import callosum as bus\n" - "bus.callosum_send('supervisor', 'start_parakeet')\n", - "import solstone.think.callosum as callosum\n" - "callosum.callosum_send('supervisor', 'start_local')\n", - ], -) -def test_scan_flags_reasonable_callosum_import_spellings(source: str) -> None: - findings = checker.scan_source(source) - - assert _kinds(findings) == {"provider_start_command"} - - -def test_scan_flags_restored_handler_names() -> None: - findings = checker.scan_source( - "def _handle_supervisor_start_local(message):\n" - " return None\n" - "def _request_parakeet_server_start():\n" - " return None\n" - ) - - assert _kinds(findings) == {"provider_start_handler"} - - -def test_scan_allows_unrelated_callosum_traffic_and_raw_strings() -> None: - findings = checker.scan_source( - "def f(client):\n" - " client.emit('thinking', 'start_local')\n" - " client.emit('supervisor', 'restart')\n" - " msg = {'tract': 'thinking', 'event': 'start_parakeet'}\n" - " raw = 'start_local start_parakeet'\n" - " return msg, raw\n" - ) - - assert findings == [] - - -def test_e2e_flags_violation(tmp_path: Path) -> None: - _write_file( - tmp_path, - "solstone/bad.py", - "from solstone.think.callosum import callosum_send\n" - "callosum_send('supervisor', 'start_parakeet')\n", - ) - - result = _run(tmp_path) - - assert result.returncode == 1 - assert "provider-start-commands: violations:" in result.stderr - assert "provider_start_command" in result.stderr - - -def test_e2e_clean_source_passes(tmp_path: Path) -> None: - _write_file( - tmp_path, - "solstone/good.py", - "def f(client):\n client.emit('supervisor', 'restart')\n", - ) - - result = _run(tmp_path) - - assert result.returncode == 0 - assert "provider-start-commands: pass" in result.stdout - assert result.stderr == "" - - -def test_allowlist_is_empty_and_ratcheted(tmp_path: Path) -> None: - assert checker.ALLOWLIST == {} - _write_file( - tmp_path, - "solstone/bad.py", - "def _handle_supervisor_start_parakeet(message):\n return None\n", - ) - counts = checker.count_violations(tmp_path) - - over, stale, tracked = checker.evaluate(tmp_path, counts) - assert over == [] - assert stale == [] - assert tracked - - ratcheted = {next(iter(counts)): 0} - over, stale, _tracked = checker.evaluate(tmp_path, ratcheted) - assert over - assert stale == [] - - stale_allowlist = {("solstone/missing.py", "provider_start_handler"): 1} - over, stale, _tracked = checker.evaluate(tmp_path, stale_allowlist) - assert over - assert stale - - -def test_landed_tree_is_clean() -> None: - over, stale, _tracked = checker.evaluate(checker.ROOT, checker.ALLOWLIST) - - assert over == [] - assert stale == [] diff --git a/tests/test_check_release_preflight.py b/tests/test_check_release_preflight.py deleted file mode 100644 index c5517105f..000000000 --- a/tests/test_check_release_preflight.py +++ /dev/null @@ -1,601 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import subprocess -from pathlib import Path - -import pytest - -import scripts.check_release_preflight as preflight -import scripts.release_tool_pins as pins - - -def _completed(stdout: str, returncode: int = 0) -> subprocess.CompletedProcess[str]: - return subprocess.CompletedProcess( - args=[], - returncode=returncode, - stdout=stdout, - stderr="", - ) - - -def test_preflight_imports_release_tool_pins_from_authoritative_module() -> None: - assert preflight.ZIG_VERSION == pins.ZIG_VERSION - assert preflight.CARGO_DENY_VERSION == pins.CARGO_DENY_VERSION - - source = Path(preflight.__file__).read_text(encoding="utf-8") - assert "EXPECTED_ZIG_VERSION =" not in source - assert "EXPECTED_CARGO_DENY_VERSION =" not in source - - -def test_load_toolchain_spec(tmp_path: Path) -> None: - (tmp_path / "rust-toolchain.toml").write_text( - """ -[toolchain] -channel = "1.97.1" -profile = "minimal" -components = ["rustfmt", "clippy"] -targets = ["x86_64-unknown-linux-musl"] -""".lstrip(), - encoding="utf-8", - ) - - spec = preflight.load_toolchain_spec(tmp_path) - - assert spec.channel == "1.97.1" - assert spec.profile == "minimal" - assert spec.components == ("rustfmt", "clippy") - assert spec.targets == ("x86_64-unknown-linux-musl",) - - -def test_missing_toolchain_reports_repair_without_rustup_call(tmp_path: Path) -> None: - _toolchain_dir, failures = preflight.check_toolchain_installed( - "1.95.0", - tmp_path / "rustup-home", - ) - - assert failures - assert failures[0].expected == "installed rustup toolchain 1.95.0" - assert failures[0].repair == "rustup toolchain install 1.95.0" - - -def test_rustup_toolchain_override_must_match_pin() -> None: - failures = preflight.check_rustup_override( - "1.97.1", - {"RUSTUP_TOOLCHAIN": "1.96.0"}, - ) - - assert failures - assert failures[0].actual == "1.96.0" - - -def test_rustup_toolchain_override_accepts_exact_pin() -> None: - assert ( - preflight.check_rustup_override( - "1.97.1", - {"RUSTUP_TOOLCHAIN": "1.97.1"}, - ) - == [] - ) - - -def test_rustc_version_mismatch_reports_expected_actual_and_repair( - tmp_path: Path, -) -> None: - toolchain = tmp_path / "1.97.1-x86_64-unknown-linux-gnu" - (toolchain / "bin").mkdir(parents=True) - (toolchain / "bin" / "rustc").write_text("", encoding="utf-8") - - failures = preflight.check_rustc_version( - toolchain, - "1.97.1", - runner=lambda *_args, **_kwargs: _completed("rustc 1.96.0 (abc 2026-01-01)"), - ) - - assert failures - assert failures[0].expected == "rustc 1.97.1" - assert "rustc 1.96.0" in failures[0].actual - assert failures[0].repair == "rustup toolchain install 1.97.1" - - -def test_missing_toolchain_component_reports_repair(tmp_path: Path) -> None: - toolchain = tmp_path / "1.97.1-x86_64-unknown-linux-gnu" - (toolchain / "bin").mkdir(parents=True) - (toolchain / "bin" / "rustfmt").write_text("", encoding="utf-8") - - failures = preflight.check_toolchain_components( - toolchain, - "1.97.1", - ("rustfmt", "clippy"), - ) - - assert len(failures) == 1 - assert failures[0].error == "release toolchain component is not installed" - assert "clippy" in failures[0].expected - assert failures[0].actual == "missing" - assert failures[0].repair == "rustup component add --toolchain 1.97.1 clippy" - - -def test_missing_toolchain_target_reports_repair(tmp_path: Path) -> None: - toolchain = tmp_path / "1.97.1-x86_64-unknown-linux-gnu" - (toolchain / "lib" / "rustlib" / "x86_64-unknown-linux-musl" / "lib").mkdir( - parents=True - ) - - failures = preflight.check_toolchain_targets( - toolchain, - "1.97.1", - ("x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"), - ) - - assert len(failures) == 1 - assert failures[0].error == "release toolchain target is not installed" - assert "aarch64-unknown-linux-musl" in failures[0].expected - assert failures[0].actual == "missing" - assert ( - failures[0].repair - == "rustup target add --toolchain 1.97.1 aarch64-unknown-linux-musl" - ) - - -def test_missing_zig_reports_repair() -> None: - failures = preflight.check_zig(which=lambda _name: None) - - assert failures - assert failures[0].expected == f"zig {pins.ZIG_VERSION}" - assert failures[0].actual == "not found" - - -def test_mismatched_zig_reports_expected_actual_and_repair() -> None: - failures = preflight.check_zig( - which=lambda _name: "/usr/bin/zig", - runner=lambda *_args, **_kwargs: _completed("0.15.0"), - ) - - assert failures - assert failures[0].expected == pins.ZIG_VERSION - assert failures[0].actual == "0.15.0" - assert f"ziglang=={pins.ZIG_VERSION}" in failures[0].repair - - -def test_missing_cargo_deny_reports_force_install_repair() -> None: - failures = preflight.check_cargo_deny(which=lambda _name: None) - - assert failures - assert failures[0].expected == pins.CARGO_DENY_VERSION - assert failures[0].actual == "not found" - assert ( - failures[0].repair - == f"cargo install cargo-deny@{pins.CARGO_DENY_VERSION} --locked --force" - ) - - -def test_mismatched_cargo_deny_reports_expected_actual_and_repair() -> None: - failures = preflight.check_cargo_deny( - which=lambda _name: "/usr/bin/cargo-deny", - runner=lambda *_args, **_kwargs: _completed("cargo-deny 0.19.9"), - ) - - assert failures - assert failures[0].expected == pins.CARGO_DENY_VERSION - assert failures[0].actual == "cargo-deny 0.19.9" - assert ( - failures[0].repair - == f"cargo install cargo-deny@{pins.CARGO_DENY_VERSION} --locked --force" - ) - - -def test_dirty_local_status_names_offending_paths() -> None: - failures = preflight.check_local_clean_status( - " M core/Cargo.toml\n?? scratch.txt\n" - ) - - assert failures - assert "core/Cargo.toml" in failures[0].actual - assert "scratch.txt" in failures[0].actual - - -def test_remote_state_reports_ref_mismatch_and_dirty_tree() -> None: - failures = preflight.check_remote_state( - "abc123", - "def456", - "?? remote.txt\n", - label="mac-builder", - ) - - assert len(failures) == 2 - assert failures[0].expected == "abc123" - assert failures[0].actual == "def456" - assert ( - failures[0].repair - == "python3 scripts/check_release_preflight.py remote-state --help" - ) - assert "remote.txt" in failures[1].actual - - -def test_expected_lane_tool_evidence_uses_grounded_release_pins() -> None: - source = preflight.expected_lane_tool_evidence("source") - linux = preflight.expected_lane_tool_evidence("linux-aarch64-musl") - macos = preflight.expected_lane_tool_evidence("macos-arm64") - macos_presign = preflight.expected_presign_lane_tool_evidence("macos-arm64") - - assert source["python"] == pins.PYTHON_SOURCE_LINUX_VERSION - assert "zig" not in source - assert linux["zig"] == pins.ZIG_PIN - assert macos["python"] == pins.PYTHON_MACOS_VERSION - assert macos["swift"] == pins.MACOS_SWIFT_PIN - assert macos["codesign"] == pins.MACOS_CODESIGN_PUBLIC_PIN - assert macos["signing_mode"] == pins.MACOS_SIGNING_MODE - assert "signing_mode" not in macos_presign - - -@pytest.mark.parametrize("lane", tuple(preflight.LANE_TOOL_KEYS)) -def test_fixture_lane_tool_evidence_key_sets_match_expectations(lane: str) -> None: - assert set(pins.fixture_lane_tool_evidence(lane)) == set( - preflight.expected_lane_tool_evidence(lane) - ) - assert set(pins.fixture_presign_lane_tool_evidence(lane)) == set( - preflight.expected_presign_lane_tool_evidence(lane) - ) - - -def test_host_variant_tool_keys_include_swift_and_uv() -> None: - assert pins.HOST_VARIANT_TOOL_KEYS == frozenset(("uv", "swift")) - - -@pytest.mark.parametrize( - "uv_banner", - ( - pins.UV_LINUX_FIXTURE_BANNER, - pins.UV_MACOS_FIXTURE_BANNER, - ), -) -def test_host_variant_uv_evidence_accepts_strict_version(uv_banner: str) -> None: - source = pins.fixture_lane_tool_evidence("source") - source["uv"] = uv_banner - macos_presign = pins.fixture_presign_lane_tool_evidence("macos-arm64") - macos_presign["uv"] = uv_banner - - assert preflight.check_lane_tool_evidence("source", source) == [] - assert ( - preflight.check_presign_lane_tool_evidence("macos-arm64", macos_presign) == [] - ) - - -@pytest.mark.parametrize( - "uv_banner", - ( - "uv 0.10.0 (x86_64-unknown-linux-gnu)", - "not found", - "exit 1", - "", - " ", - f"{pins.UV_LINUX_FIXTURE_BANNER}\nextra", - "uvx 0.11.4 (x86_64-unknown-linux-gnu)", - "uv release channel stable", - pins.UV_PIN, - ), -) -def test_host_variant_uv_evidence_fails_closed(uv_banner: str) -> None: - evidence = pins.fixture_lane_tool_evidence("source") - evidence["uv"] = uv_banner - - failures = preflight.check_lane_tool_evidence("source", evidence) - - uv_failures = [ - failure - for failure in failures - if failure.error == "release lane tool uv is not pinned" - ] - assert len(uv_failures) == 1 - assert uv_failures[0].expected == pins.UV_PIN - - -@pytest.mark.parametrize("uv_value", (None, 123, True, {"a": 1})) -def test_host_variant_uv_non_string_evidence_fails_closed(uv_value: object) -> None: - lane_evidence: dict[str, object] = dict(pins.fixture_lane_tool_evidence("source")) - lane_evidence["uv"] = uv_value - presign_evidence: dict[str, object] = dict( - pins.fixture_presign_lane_tool_evidence("macos-arm64") - ) - presign_evidence["uv"] = uv_value - - lane_failures = preflight.check_lane_tool_evidence("source", lane_evidence) - presign_failures = preflight.check_presign_lane_tool_evidence( - "macos-arm64", presign_evidence - ) - - lane_uv_failures = [ - failure - for failure in lane_failures - if failure.error == "release lane tool uv is not pinned" - ] - presign_uv_failures = [ - failure - for failure in presign_failures - if failure.error == "pre-sign lane tool uv is not pinned" - ] - - assert len(lane_uv_failures) == 1 - assert lane_uv_failures[0].expected == pins.UV_PIN - assert lane_uv_failures[0].actual == str(uv_value) - assert len(presign_uv_failures) == 1 - assert presign_uv_failures[0].expected == pins.UV_PIN - assert presign_uv_failures[0].actual == str(uv_value) - - -@pytest.mark.parametrize( - "swift_banner", - ( - pins.MACOS_SWIFT_FIXTURE_BANNER, - pins.MACOS_SWIFT_PIN, - pins.MACOS_SWIFT_RAW_BANNER, - pins.MACOS_SWIFT_FLATTENED_BANNER, - ), -) -def test_host_variant_swift_evidence_accepts_strict_identity( - swift_banner: str, -) -> None: - lane_evidence = pins.fixture_lane_tool_evidence("macos-arm64") - lane_evidence["swift"] = swift_banner - presign_evidence = pins.fixture_presign_lane_tool_evidence("macos-arm64") - presign_evidence["swift"] = swift_banner - - assert preflight.check_lane_tool_evidence("macos-arm64", lane_evidence) == [] - assert ( - preflight.check_presign_lane_tool_evidence("macos-arm64", presign_evidence) - == [] - ) - - -@pytest.mark.parametrize( - "swift_banner", - ( - pins.MACOS_SWIFT_RAW_BANNER, - pins.MACOS_SWIFT_FLATTENED_BANNER, - ), -) -def test_parse_macos_swift_banner_accepts_real_host_forms( - swift_banner: str, -) -> None: - assert pins.parse_macos_swift_banner(swift_banner) == ( - "6.3.3", - "6.3.3.1.3", - "2100.1.1.101", - ) - assert ( - pins.check_host_variant_tool_pin("swift", pins.MACOS_SWIFT_PIN, swift_banner) - is True - ) - - -def test_check_host_variant_swift_pin_rejects_mutated_flattened_identity() -> None: - mutated = pins.MACOS_SWIFT_FLATTENED_BANNER.replace( - "Apple Swift version 6.3.3", "Apple Swift version 6.3.4" - ) - assert pins.parse_macos_swift_banner(mutated) == ( - "6.3.4", - "6.3.3.1.3", - "2100.1.1.101", - ) - assert ( - pins.check_host_variant_tool_pin("swift", pins.MACOS_SWIFT_PIN, mutated) - is False - ) - - -@pytest.mark.parametrize( - "swift_value", - ( - "not found", - "exit 1", - "", - " ", - "swift 6.3.3", - "swift-driver 1.148.6 Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)", - f"{pins.MACOS_SWIFT_FIXTURE_BANNER} extra", - f"{pins.MACOS_SWIFT_FIXTURE_BANNER} Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)", - "Apple Swift 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)", - pins.MACOS_SWIFT_FIXTURE_BANNER.replace( - "Apple Swift version 6.3.3", "Apple Swift version 6.3.4" - ), - pins.MACOS_SWIFT_FIXTURE_BANNER.replace( - "swiftlang-6.3.3.1.3", "swiftlang-6.3.3.1.4" - ), - pins.MACOS_SWIFT_FIXTURE_BANNER.replace( - "clang-2100.1.1.101", "clang-2100.1.1.102" - ), - None, - 123, - True, - {"a": 1}, - ), -) -def test_host_variant_swift_evidence_fails_closed(swift_value: object) -> None: - lane_evidence: dict[str, object] = dict( - pins.fixture_lane_tool_evidence("macos-arm64") - ) - lane_evidence["swift"] = swift_value - presign_evidence: dict[str, object] = dict( - pins.fixture_presign_lane_tool_evidence("macos-arm64") - ) - presign_evidence["swift"] = swift_value - - lane_failures = preflight.check_lane_tool_evidence("macos-arm64", lane_evidence) - presign_failures = preflight.check_presign_lane_tool_evidence( - "macos-arm64", presign_evidence - ) - - lane_swift_failures = [ - failure - for failure in lane_failures - if failure.error == "release lane tool swift is not pinned" - ] - presign_swift_failures = [ - failure - for failure in presign_failures - if failure.error == "pre-sign lane tool swift is not pinned" - ] - assert len(lane_swift_failures) == 1 - assert lane_swift_failures[0].expected == pins.MACOS_SWIFT_PIN - assert lane_swift_failures[0].actual == str(swift_value) - assert len(presign_swift_failures) == 1 - assert presign_swift_failures[0].expected == pins.MACOS_SWIFT_PIN - assert presign_swift_failures[0].actual == str(swift_value) - - -def test_notarytool_evidence_accepts_bare_grounded_output() -> None: - lane_evidence = pins.fixture_lane_tool_evidence("macos-arm64") - lane_evidence["notarytool"] = "1.1.2 (41)" - presign_evidence = pins.fixture_presign_lane_tool_evidence("macos-arm64") - presign_evidence["notarytool"] = "1.1.2 (41)" - - assert preflight.check_lane_tool_evidence("macos-arm64", lane_evidence) == [] - assert ( - preflight.check_presign_lane_tool_evidence("macos-arm64", presign_evidence) - == [] - ) - - -@pytest.mark.parametrize( - "notarytool_value", - ( - "notarytool 1.1.2 (41)", - "1.1.3 (41)", - "1.1.2 (42)", - ), -) -def test_notarytool_evidence_rejects_ungrounded_or_wrong_output( - notarytool_value: str, -) -> None: - lane_evidence = pins.fixture_lane_tool_evidence("macos-arm64") - lane_evidence["notarytool"] = notarytool_value - presign_evidence = pins.fixture_presign_lane_tool_evidence("macos-arm64") - presign_evidence["notarytool"] = notarytool_value - - lane_failures = preflight.check_lane_tool_evidence("macos-arm64", lane_evidence) - presign_failures = preflight.check_presign_lane_tool_evidence( - "macos-arm64", presign_evidence - ) - - assert any( - failure.error == "release lane tool notarytool is not pinned" - for failure in lane_failures - ) - assert any( - failure.error == "pre-sign lane tool notarytool is not pinned" - for failure in presign_failures - ) - - -def test_lane_tool_skew_fails_closed() -> None: - evidence = pins.fixture_lane_tool_evidence("macos-arm64") - evidence["swift"] = "swift 6.3.3" - - failures = preflight.check_lane_tool_evidence("macos-arm64", evidence) - - assert failures - assert failures[0].error == "release lane tool swift is not pinned" - assert failures[0].expected == pins.MACOS_SWIFT_PIN - - -def test_collect_lane_tools_normalizes_macos_observations() -> None: - outputs = { - "python": "Python 3.14.6", - "rustc": pins.RUSTC_VERSION_BANNER, - "cargo": pins.CARGO_VERSION_PIN, - "uv": pins.UV_MACOS_FIXTURE_BANNER, - "maturin": pins.MATURIN_PIN, - "cargo-deny": pins.CARGO_DENY_PIN, - "xcodebuild": f"Xcode {pins.MACOS_XCODE_VERSION}\nBuild version {pins.MACOS_XCODE_BUILD}\n", - "swift": f"{pins.MACOS_SWIFT_FIXTURE_BANNER}\nTarget: arm64-apple-macosx26.0\n", - "xcrun": pins.MACOS_NOTARYTOOL_PIN, - } - - def which(name: str) -> str | None: - if name == "codesign": - return pins.MACOS_CODESIGN_PATH - return f"/tools/{name}" if name in outputs else None - - def runner(argv, **_kwargs) -> subprocess.CompletedProcess[str]: - name = Path(argv[0]).name - if argv[0] == "python": - name = "python" - return _completed(outputs[name]) - - evidence = preflight.collect_lane_tool_evidence( - "macos-arm64", - which=which, - runner=runner, - python_executable="python", - ) - - assert "signing_mode" not in evidence - assert evidence["swift"] == pins.MACOS_SWIFT_FIXTURE_BANNER - assert preflight.check_presign_lane_tool_evidence("macos-arm64", evidence) == [] - failures = preflight.check_presign_lane_tool_evidence( - "macos-arm64", - {**evidence, "signing_mode": pins.MACOS_SIGNING_MODE}, - ) - assert any( - failure.error == "pre-sign lane tool evidence keys do not match lane" - for failure in failures - ) - assert ( - preflight.check_lane_tool_evidence( - "macos-arm64", - {**evidence, "signing_mode": pins.MACOS_SIGNING_MODE}, - ) - == [] - ) - - -def _native_record(role: str) -> dict[str, object]: - return { - "role": role, - "unsigned_members": {}, - "signing_mode": pins.MACOS_SIGNING_MODE, - "signing": { - "signer_pinned": True, - "team_pinned": True, - "hardened_runtime": True, - "trusted_timestamp": True, - }, - "notarization_status": "accepted", - } - - -def test_macos_tool_finalizer_requires_valid_native_records() -> None: - preflight_evidence = pins.fixture_presign_lane_tool_evidence("macos-arm64") - - final, failures = preflight.finalize_macos_tool_evidence( - preflight_evidence, - ( - _native_record("root"), - _native_record("core"), - _native_record("speakers-analyze"), - ), - ) - - assert failures == [] - assert final is not None - assert final["signing_mode"] == pins.MACOS_SIGNING_MODE - - bad_record = _native_record("root") - bad_record["notarization_status"] = "rejected" - final, failures = preflight.finalize_macos_tool_evidence( - preflight_evidence, - ( - bad_record, - _native_record("core"), - _native_record("speakers-analyze"), - ), - ) - - assert final is None - assert any( - failure.error == "macOS native record notarization is not accepted" - for failure in failures - ) diff --git a/tests/test_check_rust_release_manifest.py b/tests/test_check_rust_release_manifest.py deleted file mode 100644 index a73e1a20b..000000000 --- a/tests/test_check_rust_release_manifest.py +++ /dev/null @@ -1,1726 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import fcntl -import hashlib -import json -import os -import re -import subprocess -import sys -import tomllib -from dataclasses import replace -from pathlib import Path -from typing import Any - -import pytest - -import scripts.check_rust_release_manifest as checker -import scripts.release_tool_pins as pins - -SCRIPT = ( - Path(__file__).resolve().parents[1] / "scripts" / "check_rust_release_manifest.py" -) -VALID_COMMIT = checker.fixture_source_commit() -PYTHON_WHITESPACE_CODE_POINTS: tuple[int, ...] = ( - 0x09, - 0x0A, - 0x0B, - 0x0C, - 0x0D, - 0x1C, - 0x1D, - 0x1E, - 0x1F, - 0x20, - 0x85, - 0xA0, - 0x1680, - 0x2000, - 0x2001, - 0x2002, - 0x2003, - 0x2004, - 0x2005, - 0x2006, - 0x2007, - 0x2008, - 0x2009, - 0x200A, - 0x2028, - 0x2029, - 0x202F, - 0x205F, - 0x3000, -) -RUSTC_REJECTED_SEPARATOR_CODE_POINTS: tuple[int, ...] = tuple( - code_point for code_point in PYTHON_WHITESPACE_CODE_POINTS if code_point != 0x20 -) - - -def _errors(failures: list[checker.Failure]) -> set[str]: - return {failure.error for failure in failures} - - -def _assert_error(failures: list[checker.Failure], error: str) -> None: - assert error in _errors(failures) - - -def _assert_redacted( - failures: list[checker.Failure], forbidden: tuple[str, ...] -) -> None: - for failure in failures: - fields = (failure.error, failure.expected, failure.actual, failure.repair) - for needle in forbidden: - assert all(needle not in field for field in fields) - - -def _assert_formatted_redacted( - failures: list[checker.Failure], - forbidden: tuple[str, ...], - capsys: pytest.CaptureFixture[str], -) -> None: - checker._format_failures(failures) - stderr = capsys.readouterr().err - for needle in forbidden: - assert needle not in stderr - - -def _repo_root() -> Path: - return Path(__file__).resolve().parents[1] - - -def _rustc_lines(host: str = "x86_64-unknown-linux-gnu") -> list[str]: - return checker.fixture_rustc_verbose(host).split("\n") - - -def _rustc_line_mutant(canonical: str, line_index: int, replacement: str) -> str: - lines = canonical.split("\n") - lines[line_index] = replacement - return "\n".join(lines) - - -def _candidate( - tmp_path: Path, - *, - include_models: bool = False, - source_commit: str = VALID_COMMIT, -) -> Path: - release_dir = tmp_path / ("candidate-models" if include_models else "candidate") - failures = checker.write_inert_candidate( - release_dir, - include_models=include_models, - source_commit=source_commit, - ) - assert failures == [] - return release_dir - - -def test_release_manifest_imports_tool_pins_from_authoritative_module() -> None: - assert checker.RUSTC_VERSION_BANNER == pins.RUSTC_VERSION_BANNER - assert checker.RUSTC_BINARY_PIN == pins.RUSTC_BINARY_PIN - assert checker.RUSTC_COMMIT_HASH_PIN == pins.RUSTC_COMMIT_HASH_PIN - assert checker.RUSTC_COMMIT_DATE_PIN == pins.RUSTC_COMMIT_DATE_PIN - assert checker.RUSTC_RELEASE_PIN == pins.RUSTC_RELEASE_PIN - assert checker.RUSTC_LLVM_PIN == pins.RUSTC_LLVM_PIN - assert checker.CARGO_VERSION_PIN == pins.CARGO_VERSION_PIN - assert checker.CARGO_RELEASE_PIN == pins.CARGO_RELEASE_PIN - assert checker.CARGO_DENY_PIN == pins.CARGO_DENY_PIN - - source = Path(checker.__file__).read_text(encoding="utf-8") - assert "RUSTC_VERSION_BANNER =" not in source - assert "CARGO_DENY_PIN =" not in source - - -def test_macos_swift_pin_requires_exact_canonical_grounded_output() -> None: - exact = "Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)" - - assert pins.MACOS_SWIFT_PIN == exact - assert checker.validate_public_evidence_text("swift", pins.MACOS_SWIFT_PIN) == [] - assert ( - checker.validate_public_evidence_text("swift", pins.MACOS_SWIFT_RAW_BANNER) - == [] - ) - assert ( - checker.validate_public_evidence_text( - "swift", pins.MACOS_SWIFT_FLATTENED_BANNER - ) - == [] - ) - assert not any( - line.startswith("MACOS_SWIFT_VERSION") - for line in Path(pins.__file__).read_text(encoding="utf-8").splitlines() - ) - - skewed_observations = ( - "6.3.3", - "swift 6.3.3", - "Apple Swift 6.3.3", - "Apple Swift 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.102)", - "Apple Swift 6.3.3 (swiftlang-6.3.3.1.4 clang-2100.1.1.101)", - "Apple Swift version 6.3.4 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)", - "Apple Swift version 6.3.3 (swiftlang-6.3.3.1.4 clang-2100.1.1.101)", - "Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.102)", - f" {exact}", - f"{exact} ", - ) - assert all(observed != pins.MACOS_SWIFT_PIN for observed in skewed_observations) - - -def test_build_system_pins_match_release_tool_pins() -> None: - root = _repo_root() - setuptools_projects = ( - root / "pyproject.toml", - root / "packages" / "solstone-journal" / "pyproject.toml", - root / "packages" / "solstone-journal-cuda" / "pyproject.toml", - root / "packages" / "solstone-journal-models" / "pyproject.toml", - ) - for path in setuptools_projects: - data = tomllib.loads(path.read_text(encoding="utf-8")) - assert data["build-system"]["requires"] == list(pins.SETUPTOOLS_BUILD_REQUIRES) - - core_data = tomllib.loads( - (root / "packages" / "solstone-core" / "pyproject.toml").read_text( - encoding="utf-8" - ) - ) - assert core_data["build-system"]["requires"] == [pins.MATURIN_REQUIREMENT] - - -def test_all_macos_maturin_invocations_are_locked() -> None: - makefile = (_repo_root() / "Makefile").read_text(encoding="utf-8") - assignments = re.findall( - r'MATURIN_PEP517_ARGS="([^"]*aarch64-apple-darwin[^"]*)"', makefile - ) - - assert assignments - assert all("--locked" in args.split() for args in assignments) - - -def _manifest_for_lane(release_dir: Path, lane: checker.LaneName) -> Path: - for artifact_name, ( - artifact_lane, - _target, - ) in checker.rust_artifact_targets().items(): - if artifact_lane == lane: - return release_dir / f"{artifact_name}.rust-release-manifest.json" - raise AssertionError(f"no artifact for lane {lane}") - - -def _artifact_for_lane(release_dir: Path, lane: checker.LaneName) -> Path: - manifest = _manifest_for_lane(release_dir, lane) - return release_dir / manifest.name.removesuffix(".rust-release-manifest.json") - - -def _source_artifact(tmp_path: Path) -> Path: - release_dir = tmp_path / "source-artifact" - checker.write_inert_packages(release_dir, include_models=False) - return _artifact_for_lane(release_dir, "source") - - -def _assert_malformed_redacted( - failures: list[checker.Failure], - forbidden: tuple[str, ...], - capsys: pytest.CaptureFixture[str], -) -> None: - assert failures - _assert_error(failures, "rustc_verbose is malformed") - for failure in failures: - assert failure.actual == "redacted" - _assert_redacted(failures, forbidden) - _assert_formatted_redacted(failures, forbidden, capsys) - - -def _assert_rustc_mutant_rejected( - artifact_path: Path, - capsys: pytest.CaptureFixture[str], - *, - mutant: str, - forbidden: tuple[str, ...], -) -> None: - parsed, parse_failures = checker.parse_rustc_verbose(mutant) - assert parsed is None - _assert_malformed_redacted(parse_failures, forbidden, capsys) - - evidence = checker.fixture_evidence_by_lane()["source"] - generated, generate_failures = checker.generate_manifest( - artifact_path, - lane="source", - evidence=replace(evidence, rustc_verbose=mutant), - cohort=checker._default_cohort(VALID_COMMIT), - ) - assert generated is None - _assert_malformed_redacted(generate_failures, forbidden, capsys) - - -def _assert_rustc_line_mutant_rejected( - artifact_path: Path, - capsys: pytest.CaptureFixture[str], - *, - canonical: str, - mutant: str, - line_index: int, -) -> None: - canonical_lines = canonical.split("\n") - mutant_lines = mutant.split("\n") - assert len(mutant_lines) == len(canonical_lines) - assert mutant_lines[line_index] != canonical_lines[line_index] - for index, line in enumerate(canonical_lines): - if index != line_index: - assert mutant_lines[index] == line - _assert_rustc_mutant_rejected( - artifact_path, - capsys, - mutant=mutant, - forbidden=(mutant, mutant_lines[line_index]), - ) - - -def _assert_rustc_lf_separator_mutant_rejected( - artifact_path: Path, - capsys: pytest.CaptureFixture[str], - *, - canonical: str, - mutant: str, - line_index: int, -) -> None: - canonical_lines = canonical.split("\n") - label, value = canonical_lines[line_index].split(": ", 1) - mutant_lines = mutant.split("\n") - assert len(mutant_lines) == len(canonical_lines) + 1 - assert mutant_lines[:line_index] == canonical_lines[:line_index] - assert mutant_lines[line_index : line_index + 2] == [f"{label}:", value] - assert mutant_lines[line_index + 2 :] == canonical_lines[line_index + 1 :] - _assert_rustc_mutant_rejected( - artifact_path, - capsys, - mutant=mutant, - forbidden=(mutant, f"{label}:\n{value}"), - ) - - -def _load_manifest(path: Path) -> dict: - return json.loads(path.read_text(encoding="utf-8")) - - -def _write_manifest(path: Path, payload: dict) -> None: - path.write_bytes(checker.canonical_json_bytes(payload)) - - -def _replace_manifest_artifact(manifest_path: Path, artifact_name: str) -> None: - artifact = manifest_path.parent / artifact_name - digest = hashlib.sha256(artifact.read_bytes()).hexdigest() - payload = _load_manifest(manifest_path) - payload["artifacts"] = [ - { - "path": artifact_name, - "sha256": digest, - "bytes": artifact.stat().st_size, - } - ] - _write_manifest(manifest_path, payload) - - -def _source_dist(tmp_path: Path, *, include_models: bool = False) -> Path: - dist = tmp_path / "dist" - checker.write_inert_packages(dist, include_models=include_models) - return dist - - -def _build_ready( - tmp_path: Path, - *, - include_models: bool = False, - hook=None, -) -> tuple[Path, list[checker.Failure]]: - ready = tmp_path / "ready" - failures = checker.build_and_promote_candidate( - _source_dist(tmp_path, include_models=include_models), - ready, - source_commit=VALID_COMMIT, - evidence_by_lane=checker.fixture_evidence_by_lane(), - include_models=include_models, - _post_promote_hook=hook, - ) - return ready, failures - - -def test_python_whitespace_code_point_table_is_explicit() -> None: - assert len(PYTHON_WHITESPACE_CODE_POINTS) == 29 - assert set(PYTHON_WHITESPACE_CODE_POINTS) == { - 0x09, - 0x0A, - 0x0B, - 0x0C, - 0x0D, - 0x1C, - 0x1D, - 0x1E, - 0x1F, - 0x20, - 0x85, - 0xA0, - 0x1680, - 0x2000, - 0x2001, - 0x2002, - 0x2003, - 0x2004, - 0x2005, - 0x2006, - 0x2007, - 0x2008, - 0x2009, - 0x200A, - 0x2028, - 0x2029, - 0x202F, - 0x205F, - 0x3000, - } - - -def test_script_runs_without_site_packages_from_outside_repo(tmp_path: Path) -> None: - env = os.environ.copy() - env.pop("PYTHONPATH", None) - env.pop("VIRTUAL_ENV", None) - - result = subprocess.run( - [sys.executable, "-S", "-E", str(SCRIPT), "--help"], - cwd=tmp_path, - env=env, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode == 0 - assert "Rust release manifests" in result.stdout - - -def test_vendored_schema_digest_and_trailing_newline() -> None: - data = checker.SCHEMA_PATH.read_bytes() - - assert len(data) == 4416 - assert data.endswith(b"\n") - assert hashlib.sha256(data).hexdigest() == checker.SCHEMA_SHA256 - - -def test_load_schema_checks_draft_2020_12_and_format_checker() -> None: - schema = checker.load_schema() - - assert schema["$id"] == checker.SCHEMA_ID - assert schema["$schema"] == checker.SCHEMA_DRAFT - - -def test_validate_manifest_rejects_schema_level_invalid_payload( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["unexpected"] = "not in schema" - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "manifest does not match Rust release manifest schema") - - -def test_main_mode_selection_fixtures_manifest_release_dir(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - - assert checker.main([], env={}) == 0 - assert checker.main([], env={"MANIFEST": str(manifest)}) == 0 - assert ( - checker.main( - [], - env={"RELEASE_DIR": str(release_dir), "SOURCE_COMMIT": VALID_COMMIT}, - ) - == 0 - ) - - -def test_main_rejects_conflicting_env_modes(tmp_path: Path) -> None: - assert ( - checker.main( - [], - env={ - "MANIFEST": str(tmp_path / "manifest.json"), - "RELEASE_DIR": str(tmp_path), - }, - ) - == 1 - ) - assert ( - checker.main( - [], - env={ - "RELEASE_DIR": str(tmp_path), - "SOURCE_COMMIT": "abc", - }, - ) - == 1 - ) - assert ( - checker.main( - [], - env={ - "MANIFEST": str(tmp_path / "manifest.json"), - "SOURCE_COMMIT": VALID_COMMIT, - }, - ) - == 1 - ) - - -@pytest.mark.parametrize( - "lane", - ["source", "linux-x86_64-musl", "linux-aarch64-musl", "macos-arm64"], -) -def test_generate_manifest_valid_lane_shapes( - tmp_path: Path, lane: checker.LaneName -) -> None: - artifact_name = next( - name - for name, (artifact_lane, _target) in checker.rust_artifact_targets().items() - if artifact_lane == lane - ) - artifact_path = tmp_path / artifact_name - artifact_path.write_bytes(b"artifact bytes\n") - - generated, failures = checker.generate_manifest( - artifact_path, - lane=lane, - evidence=checker.fixture_evidence_by_lane()[lane], - cohort=checker.CohortInputs( - product=checker.PRODUCT, - version=checker._current_version(), - source_commit=VALID_COMMIT, - source_dirty=False, - active_exceptions=(), - ), - ) - - assert failures == [] - assert generated is not None - assert generated.bytes.endswith(b"\n") - assert ( - generated.payload["target"] == checker.rust_artifact_targets()[artifact_name][1] - ) - - -def _expected_release_file_count(*, include_models: bool) -> int: - return len(checker.expected_package_names(include_models=include_models)) + 4 - - -def test_release_dir_accepts_exact_without_models(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - - assert len(list(release_dir.iterdir())) == _expected_release_file_count( - include_models=False - ) - assert ( - checker.validate_release_dir(release_dir, expected_source_commit=VALID_COMMIT) - == [] - ) - - -def test_release_dir_accepts_exact_with_models(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path, include_models=True) - - assert len(list(release_dir.iterdir())) == _expected_release_file_count( - include_models=True - ) - assert ( - checker.validate_release_dir(release_dir, expected_source_commit=VALID_COMMIT) - == [] - ) - - -def test_release_dir_rejects_one_file_models_set(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - model_name = sorted(checker._models_expected_names())[0] - (release_dir / model_name).write_bytes(b"leftover model\n") - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "release directory contains exactly one models archive") - - -def test_release_dir_rejects_wrong_model_version_pair(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - (release_dir / "solstone_journal_models-0.0.0.tar.gz").write_bytes(b"wrong\n") - (release_dir / "solstone_journal_models-0.0.0-py3-none-any.whl").write_bytes( - b"wrong\n" - ) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error( - failures, "models archive names do not match current models version pair" - ) - - -def test_release_dir_rejects_skipped_model_leftover(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - for name in list(checker.expected_package_names(include_models=False))[:2]: - (release_dir / name).unlink() - for name in checker._models_expected_names(): - (release_dir / name).write_bytes(b"skipped model\n") - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "models-skipped candidate contains models archive leftover") - - -def test_release_dir_rejects_unknown_missing_extra_assets_and_case_collision( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path) - (release_dir / "unknown.whl").write_bytes(b"unknown\n") - (release_dir / checker.expected_package_names(include_models=False)[0]).unlink() - for name in checker._models_expected_names(): - (release_dir / name).write_bytes(b"extra\n") - (release_dir / "CASE.txt").write_bytes(b"a\n") - (release_dir / "case.TXT").write_bytes(b"b\n") - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "release directory contains unknown asset") - _assert_error(failures, "release directory is missing required assets") - _assert_error(failures, "release directory contains extra assets") - _assert_error(failures, "release directory contains case-colliding filenames") - - -def test_release_dir_rejects_special_file_entry(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - package = release_dir / checker.expected_package_names(include_models=False)[0] - package.unlink() - package.mkdir() - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "release file is not a regular non-symlink file") - - -def test_release_dir_rejects_extra_or_pure_package_manifest(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - pure_artifact = next( - name - for name in checker.expected_package_names(include_models=False) - if name.startswith("solstone-") - ) - manifest = release_dir / f"{pure_artifact}.rust-release-manifest.json" - source_payload = _load_manifest(_manifest_for_lane(release_dir, "source")) - source_payload["target"] = {"kind": "source"} - digest = hashlib.sha256((release_dir / pure_artifact).read_bytes()).hexdigest() - source_payload["artifacts"] = [ - { - "path": pure_artifact, - "sha256": digest, - "bytes": (release_dir / pure_artifact).stat().st_size, - } - ] - _write_manifest(manifest, source_payload) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "manifest covers a non-Rust release artifact") - _assert_error( - failures, "release directory must contain exactly four Rust manifests" - ) - - -def test_release_dir_rejects_duplicate_coverage(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - original = _manifest_for_lane(release_dir, "source") - duplicate = release_dir / "duplicate.rust-release-manifest.json" - duplicate.write_bytes(original.read_bytes()) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "Rust artifact is covered by multiple manifests") - - -def test_release_dir_rejects_unmanifested_rust_artifact(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - _manifest_for_lane(release_dir, "macos-arm64").unlink() - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "Rust artifact is not covered by any manifest") - - -def test_release_dir_rejects_artifact_target_swap(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "linux-x86_64-musl") - payload = _load_manifest(manifest) - payload["target"] = checker.rust_artifact_targets()[ - _artifact_for_lane(release_dir, "macos-arm64").name - ][1] - _write_manifest(manifest, payload) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "artifact target does not match release lane") - - -def test_release_dir_rejects_mixed_cohort_including_advisory_time( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["dependency_policy"]["advisory_checked_at"] = "2026-07-21T00:00:00Z" - _write_manifest(manifest, payload) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "Rust release manifests do not agree on cohort fields") - - -def test_release_dir_rejects_false_source_commit(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit="b" * 40 - ) - - _assert_error(failures, "source_commit does not match SOURCE_COMMIT") - - -def test_rustc_verbose_allows_only_lane_bound_host_difference(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - - assert ( - checker.validate_release_dir(release_dir, expected_source_commit=VALID_COMMIT) - == [] - ) - - source_manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(source_manifest) - payload["rust"]["rustc_verbose"] = checker.fixture_rustc_verbose( - "aarch64-apple-darwin" - ) - _write_manifest(source_manifest, payload) - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - _assert_error(failures, "rustc host is not an allowed build host") - - -def test_rustc_host_mismatch_redacts_host_value( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - host = "buildhost01" - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = checker.fixture_rustc_verbose(host) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "rustc host is not an allowed build host") - _assert_redacted(failures, (host,)) - _assert_formatted_redacted(failures, (host,), capsys) - - -@pytest.mark.parametrize("code_point", RUSTC_REJECTED_SEPARATOR_CODE_POINTS) -def test_rustc_verbose_rejects_non_space_separator_code_points( - tmp_path: Path, - capsys: pytest.CaptureFixture[str], - code_point: int, -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - canonical_lines = canonical.split("\n") - artifact_path = _source_artifact(tmp_path) - - for line_index in range(1, len(canonical_lines)): - label, value = canonical_lines[line_index].split(": ", 1) - mutant_line = f"{label}:{chr(code_point)}{value}" - mutant = _rustc_line_mutant(canonical, line_index, mutant_line) - if code_point == 0x0A: - _assert_rustc_lf_separator_mutant_rejected( - artifact_path, - capsys, - canonical=canonical, - mutant=mutant, - line_index=line_index, - ) - else: - _assert_rustc_line_mutant_rejected( - artifact_path, - capsys, - canonical=canonical, - mutant=mutant, - line_index=line_index, - ) - - -@pytest.mark.parametrize( - "spacing_case", ("zero", "two", "three", "pre_colon", "trailing") -) -def test_rustc_verbose_rejects_noncanonical_space_counts( - tmp_path: Path, - capsys: pytest.CaptureFixture[str], - spacing_case: str, -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - canonical_lines = canonical.split("\n") - artifact_path = _source_artifact(tmp_path) - - for line_index in range(1, len(canonical_lines)): - label, value = canonical_lines[line_index].split(": ", 1) - if spacing_case == "zero": - mutant_line = f"{label}:{value}" - elif spacing_case == "two": - mutant_line = f"{label}: {value}" - elif spacing_case == "three": - mutant_line = f"{label}: {value}" - elif spacing_case == "pre_colon": - mutant_line = f"{label} : {value}" - else: - mutant_line = f"{label}: {value} " - mutant = _rustc_line_mutant(canonical, line_index, mutant_line) - _assert_rustc_line_mutant_rejected( - artifact_path, - capsys, - canonical=canonical, - mutant=mutant, - line_index=line_index, - ) - - -def test_rustc_verbose_rejects_crlf_line_boundary( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = canonical.replace("\n", "\r\n", 1) - assert "\r\n" in mutant - assert mutant.replace("\r\n", "\n", 1) == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"{lines[0]}\r\n{lines[1]}"), - ) - - -def test_rustc_verbose_rejects_lone_cr_line_boundary( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = canonical.replace("\n", "\r", 1) - assert "\r" in mutant - assert mutant.replace("\r", "\n", 1) == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"{lines[0]}\r{lines[1]}"), - ) - - -@pytest.mark.parametrize("separator", ("\u0085", "\u2028", "\u2029")) -def test_rustc_verbose_rejects_unicode_line_boundary_replacements( - tmp_path: Path, - capsys: pytest.CaptureFixture[str], - separator: str, -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = canonical.replace("\n", separator, 1) - assert separator in mutant - assert mutant.replace(separator, "\n", 1) == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"{lines[0]}{separator}{lines[1]}"), - ) - - -def test_rustc_verbose_rejects_doubled_lf_line_boundary( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = canonical.replace("\n", "\n\n", 1) - assert mutant.count("\n") == canonical.count("\n") + 1 - assert mutant.replace("\n\n", "\n", 1) == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"{lines[0]}\n\n{lines[1]}"), - ) - - -def test_rustc_verbose_rejects_leading_lf( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = "\n" + canonical - assert mutant.startswith("\n") - assert mutant.count("\n") == canonical.count("\n") + 1 - assert mutant.removeprefix("\n") == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"\n{lines[0]}"), - ) - - -def test_rustc_verbose_rejects_trailing_lf( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - mutant = canonical + "\n" - assert mutant.endswith("\n") - assert mutant.count("\n") == canonical.count("\n") + 1 - assert mutant.removesuffix("\n") == canonical - _assert_rustc_mutant_rejected( - _source_artifact(tmp_path), - capsys, - mutant=mutant, - forbidden=(mutant, f"{lines[-1]}\n"), - ) - - -@pytest.mark.parametrize( - ("name", "separator"), (("nbsp", "\u00a0"), ("zero", ""), ("two", " ")) -) -def test_rustc_verbose_separator_rejections_cover_file_and_candidate_channels( - tmp_path: Path, - capsys: pytest.CaptureFixture[str], - name: str, - separator: str, -) -> None: - canonical = checker.fixture_rustc_verbose("x86_64-unknown-linux-gnu") - lines = canonical.split("\n") - label, value = lines[1].split(": ", 1) - mutant_line = f"{label}:{separator}{value}" - mutant = _rustc_line_mutant(canonical, 1, mutant_line) - - release_dir = _candidate(tmp_path / f"file-{name}") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = mutant - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_malformed_redacted(failures, (mutant, mutant_line), capsys) - - evidence = checker.fixture_evidence_by_lane() - mutated_evidence = dict(evidence) - mutated_evidence["source"] = replace(evidence["source"], rustc_verbose=mutant) - failures = checker.write_inert_candidate( - tmp_path / f"generated-{name}", - include_models=False, - evidence_by_lane=mutated_evidence, - ) - _assert_malformed_redacted(failures, (mutant, mutant_line), capsys) - - -@pytest.mark.parametrize( - ("lane", "host"), - ( - ("source", "x86_64-unknown-linux-gnu"), - ("macos-arm64", "aarch64-apple-darwin"), - ), -) -def test_rustc_verbose_canonical_evidence_is_byte_exact( - tmp_path: Path, - lane: str, - host: str, -) -> None: - canonical = checker.fixture_rustc_verbose(host) - parsed, parse_failures = checker.parse_rustc_verbose(canonical) - assert parse_failures == [] - assert parsed is not None - - release_dir = tmp_path / lane - checker.write_inert_packages(release_dir, include_models=False) - artifact_path = _artifact_for_lane(release_dir, lane) - evidence = checker.fixture_evidence_by_lane()[lane] - assert evidence.rustc_verbose == canonical - - generated, generate_failures = checker.generate_manifest( - artifact_path, - lane=lane, - evidence=evidence, - cohort=checker._default_cohort(VALID_COMMIT), - ) - assert generate_failures == [] - assert generated is not None - manifest_bytes = checker.canonical_json_bytes(generated.payload) - assert manifest_bytes == generated.bytes - - decoded = json.loads(manifest_bytes) - rustc_verbose = decoded["rust"]["rustc_verbose"] - assert rustc_verbose == canonical - assert rustc_verbose.encode("utf-8") == canonical.encode("utf-8") - - manifest_path = release_dir / generated.manifest_name - manifest_path.write_bytes(manifest_bytes) - assert checker.validate_manifest_file(manifest_path) == [] - - -def test_rustc_verbose_rejects_malformed_spoof_and_mixed_labeled_lines( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "macos-arm64") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = checker.fixture_rustc_verbose( - "x86_64-unknown-linux-gnu" - ) - _write_manifest(manifest, payload) - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - _assert_error(failures, "rustc host is not an allowed build host") - - release_dir = _candidate(tmp_path / "malformed") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = "rustc nope" - _write_manifest(manifest, payload) - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - _assert_error(failures, "rustc_verbose is malformed") - - release_dir = _candidate(tmp_path / "mixed") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = payload["rust"]["rustc_verbose"].replace( - f"LLVM version: {checker.RUSTC_LLVM_PIN}", "LLVM version: 22.0.0" - ) - _write_manifest(manifest, payload) - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - _assert_error(failures, "rustc_verbose is malformed") - - -def test_rust_evidence_rejects_uniformly_wrong_toolchain_pins(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - wrong_rustc = "\n".join( - [ - "rustc 1.96.0 (111111111 2026-01-01)", - "binary: rustc", - "commit-hash: 1111111111111111111111111111111111111111", - "commit-date: 2026-01-01", - "host: x86_64-unknown-linux-gnu", - "release: 1.96.0", - "LLVM version: 21.0.0", - ] - ) - for lane in checker.LANES: - manifest = _manifest_for_lane(release_dir, lane) - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = wrong_rustc.replace( - "x86_64-unknown-linux-gnu", checker.LANE_HOSTS[lane] - ) - payload["rust"]["cargo_version"] = "cargo 1.96.0 (222222222 2026-01-01)" - payload["dependency_policy"]["cargo_deny_version"] = "cargo-deny 0.1.0" - _write_manifest(manifest, payload) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - _assert_error(failures, "rustc_verbose is malformed") - _assert_error(failures, "cargo_version is malformed") - _assert_error(failures, "cargo_deny_version is not pinned") - - -def test_rustc_verbose_rejects_wrong_binary(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = payload["rust"]["rustc_verbose"].replace( - f"binary: {checker.RUSTC_BINARY_PIN}", "binary: rustdoc" - ) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "rustc_verbose is malformed") - - -def test_rustc_verbose_rejects_missing_duplicate_unknown_labels( - tmp_path: Path, -) -> None: - cases: tuple[tuple[str, list[str]], ...] = ( - ("missing", _rustc_lines()[:3] + _rustc_lines()[4:]), - ( - "duplicate", - [ - *_rustc_lines()[:4], - f"commit-date: {checker.RUSTC_COMMIT_DATE_PIN}", - *_rustc_lines()[5:], - ], - ), - ( - "unknown", - [ - *_rustc_lines()[:5], - "channel: stable", - _rustc_lines()[6], - ], - ), - ) - for name, lines in cases: - release_dir = _candidate(tmp_path / name) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = "\n".join(lines) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "rustc_verbose is malformed") - - -def test_rustc_verbose_rejects_wrong_commit_date_release_llvm_and_bad_host( - tmp_path: Path, -) -> None: - replacements = ( - ( - "commit", - f"commit-hash: {checker.RUSTC_COMMIT_HASH_PIN}", - "commit-hash: " + "b" * 40, - ), - ( - "date", - f"commit-date: {checker.RUSTC_COMMIT_DATE_PIN}", - "commit-date: 2026-01-01", - ), - ("release", f"release: {checker.RUSTC_RELEASE_PIN}", "release: 1.96.0"), - ("llvm", f"LLVM version: {checker.RUSTC_LLVM_PIN}", "LLVM version: 21.0.0"), - ) - for name, old, new in replacements: - release_dir = _candidate(tmp_path / name) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = payload["rust"]["rustc_verbose"].replace( - old, new - ) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "rustc_verbose is malformed") - - release_dir = _candidate(tmp_path / "host") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = checker.fixture_rustc_verbose("localhost") - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "rustc_verbose contains disallowed content") - _assert_error(failures, "rustc host is not an allowed build host") - - -def test_rustc_verbose_rejects_blank_interstitial_reordered_and_extra_lines( - tmp_path: Path, -) -> None: - lines = _rustc_lines() - cases: tuple[tuple[str, list[str]], ...] = ( - ("blank", [*lines[:3], "", *lines[3:]]), - ("reordered", [lines[0], lines[2], lines[1], *lines[3:]]), - ("extra", [*lines, "extra: public"]), - ) - for name, rustc_lines in cases: - release_dir = _candidate(tmp_path / name) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = "\n".join(rustc_lines) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "rustc_verbose is malformed") - - -def test_rust_evidence_redacts_canaries_from_failures_and_formatted_output( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - token = "sk-abcdefghijklmnopqrstuvwx" - private_path = "/Users/jer/.cargo/bin" - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["rustc_verbose"] = "\n".join( - [*_rustc_lines(), f"leak: {token} {private_path}"] - ) - _write_manifest(manifest, payload) - - failures = checker.validate_release_dir( - release_dir, expected_source_commit=VALID_COMMIT - ) - - assert failures - _assert_error(failures, "rustc_verbose contains disallowed content") - _assert_redacted(failures, (token, private_path)) - _assert_formatted_redacted(failures, (token, private_path), capsys) - - -def test_cargo_and_cargo_deny_pins_are_enforced_without_echoing_input( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - token = "sk-abcdefghijklmnopqrstuvwx" - private_path = "/Users/jer/.cargo/bin" - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["cargo_version"] = f"cargo 1.96.0 ({token} 2026-01-01)" - payload["dependency_policy"]["cargo_deny_version"] = ( - f"cargo-deny 0.1.0 {private_path} {token}" - ) - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "cargo_version is malformed") - _assert_error(failures, "cargo_deny_version is not pinned") - _assert_error(failures, "cargo_version contains disallowed content") - _assert_error(failures, "cargo_deny_version contains disallowed content") - _assert_redacted(failures, (token, private_path)) - _assert_formatted_redacted(failures, (token, private_path), capsys) - - -def test_cargo_and_cargo_deny_reject_surrounding_whitespace_and_control( - tmp_path: Path, -) -> None: - cargo_variants = ( - " " + checker.CARGO_VERSION_PIN, - checker.CARGO_VERSION_PIN + " ", - checker.CARGO_VERSION_PIN + "\n", - checker.CARGO_VERSION_PIN + "\t", - checker.CARGO_VERSION_PIN + "\x00", - ) - for index, variant in enumerate(cargo_variants): - release_dir = _candidate(tmp_path / f"cargo-{index}") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["rust"]["cargo_version"] = variant - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "cargo_version is malformed") - _assert_redacted(failures, (variant,)) - - cargo_deny_variants = ( - " " + checker.CARGO_DENY_PIN, - checker.CARGO_DENY_PIN + " ", - checker.CARGO_DENY_PIN + "\n", - checker.CARGO_DENY_PIN + "\t", - checker.CARGO_DENY_PIN + "\x00", - ) - for index, variant in enumerate(cargo_deny_variants): - release_dir = _candidate(tmp_path / f"deny-{index}") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["dependency_policy"]["cargo_deny_version"] = variant - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "cargo_deny_version is not pinned") - _assert_redacted(failures, (variant,)) - - -def test_generate_rejects_cargo_and_cargo_deny_surrounding_whitespace_and_redacts( - tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - evidence = checker.fixture_evidence_by_lane() - cargo_evidence = dict(evidence) - cargo_evidence["source"] = replace( - evidence["source"], cargo_version=checker.CARGO_VERSION_PIN + " " - ) - - failures = checker.write_inert_candidate( - tmp_path / "gen-cargo", - include_models=False, - evidence_by_lane=cargo_evidence, - ) - - assert failures - _assert_error(failures, "cargo_version is malformed") - - deny_evidence = dict(evidence) - deny_evidence["source"] = replace( - evidence["source"], cargo_deny_version=" " + checker.CARGO_DENY_PIN - ) - - failures = checker.write_inert_candidate( - tmp_path / "gen-deny", - include_models=False, - evidence_by_lane=deny_evidence, - ) - - assert failures - _assert_error(failures, "cargo_deny_version is not pinned") - - private_path = "/Users/jer/.cargo" - token = "sk-abcdefghijklmnopqrstuvwx" - deny_canary_evidence = dict(evidence) - deny_canary_evidence["source"] = replace( - evidence["source"], - cargo_deny_version=f"{checker.CARGO_DENY_PIN} {private_path} {token}", - ) - - failures = checker.write_inert_candidate( - tmp_path / "gen-deny-canary", - include_models=False, - evidence_by_lane=deny_canary_evidence, - ) - - assert failures - _assert_error(failures, "cargo_deny_version is not pinned") - _assert_error(failures, "cargo_deny_version contains disallowed content") - _assert_redacted(failures, (private_path, token)) - _assert_formatted_redacted(failures, (private_path, token), capsys) - - -def test_rust_evidence_accepts_pinned_linux_and_macos_hosts() -> None: - cases: tuple[tuple[checker.LaneName, str], ...] = ( - ("source", "x86_64-unknown-linux-gnu"), - ("macos-arm64", "aarch64-apple-darwin"), - ) - for lane, host in cases: - rustc, cargo, failures = checker._validate_rust_for_lane( - lane, - { - "rustc_verbose": checker.fixture_rustc_verbose(host), - "cargo_version": checker.CARGO_VERSION_PIN, - }, - ) - - assert failures == [] - assert rustc is not None - assert rustc.host == host - assert cargo == checker.CARGO_RELEASE_PIN - - -def test_native_tools_allowlists_by_lane() -> None: - evidence = checker.fixture_evidence_by_lane() - - for lane, lane_evidence in evidence.items(): - assert checker.validate_native_tools(lane, lane_evidence.native_tools) == [] - - failures = checker.validate_native_tools( - "source", - {"uv": pins.UV_PIN, "maturin": pins.MATURIN_PIN, "zig": pins.ZIG_PIN}, - ) - _assert_error(failures, "native_tools keys do not match lane allowlist") - - failures = checker.validate_native_tools("source", {"uv": pins.UV_PIN}) - _assert_error(failures, "native_tools keys do not match lane allowlist") - - failures = checker.validate_native_tools( - "macos-arm64", - { - "uv": pins.UV_PIN, - "maturin": pins.MATURIN_PIN, - "xcode": pins.MACOS_XCODE_PIN, - "codesign": pins.MACOS_CODESIGN_PUBLIC_PIN, - "notarytool": pins.MACOS_NOTARYTOOL_PIN, - "signing_mode": "unsigned", - }, - ) - _assert_error(failures, "macOS signing_mode is not signed-verified") - - -@pytest.mark.parametrize( - ("value", "error"), - [ - ( - f"{pins.UV_PIN}\nPATH=/tmp/bin", - "native_tools value is not a normalized public single-line string", - ), - ( - "TOKEN=abc123", - "native_tools value is not a normalized public single-line string", - ), - ("secret token abc123", "native_tools value contains secret/token canary"), - ( - "built on build-host.local", - "native_tools value contains private host, IP, or path", - ), - ( - "reachable at 192.168.1.10", - "native_tools value contains private host, IP, or path", - ), - ( - "installed in /Users/jer/bin", - "native_tools value contains private host, IP, or path", - ), - ("owner@example.com", "native_tools value contains email address"), - ( - "Developer ID Application: sol pbc", - "native_tools value contains signing identity", - ), - ( - "submission 123e4567-e89b-12d3-a456-426614174000", - "native_tools value contains notarization submission ID", - ), - ], -) -def test_native_tools_rejects_canaries(value: str, error: str) -> None: - tools = {"uv": value, "maturin": pins.MATURIN_PIN} - - failures = checker.validate_native_tools("source", tools) - - _assert_error(failures, error) - - -@pytest.mark.parametrize( - "bad_path", ["../artifact.whl", "/tmp/artifact.whl", "a\\b.whl"] -) -def test_validate_manifest_rejects_path_traversal_absolute_backslash( - tmp_path: Path, bad_path: str -) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["artifacts"][0]["path"] = bad_path - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "artifact path is not a safe relative basename") - - -def test_validate_manifest_rejects_control_character_artifact_path( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["artifacts"][0]["path"] = "bad" + chr(10) + ".whl" - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "artifact path is not a safe relative basename") - - -def test_validate_manifest_rejects_symlink_missing_empty_and_hash_mismatch( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path / "missing") - manifest = _manifest_for_lane(release_dir, "source") - _artifact_for_lane(release_dir, "source").unlink() - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "manifest artifact is missing") - - release_dir = _candidate(tmp_path / "empty") - manifest = _manifest_for_lane(release_dir, "source") - _artifact_for_lane(release_dir, "source").write_bytes(b"") - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "manifest artifact is empty") - - release_dir = _candidate(tmp_path / "hash") - manifest = _manifest_for_lane(release_dir, "source") - _artifact_for_lane(release_dir, "source").write_bytes(b"mutated\n") - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "artifact sha256 does not match manifest") - - release_dir = _candidate(tmp_path / "symlink") - manifest = _manifest_for_lane(release_dir, "source") - artifact = _artifact_for_lane(release_dir, "source") - artifact.unlink() - artifact.symlink_to( - release_dir / checker.expected_package_names(include_models=False)[0] - ) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "release file is not a regular non-symlink file") - - -def test_validate_manifest_rejects_invalid_time_hash_commit_target_features( - tmp_path: Path, -) -> None: - release_dir = _candidate(tmp_path / "time") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["dependency_policy"]["advisory_checked_at"] = "2026-07-20T00:00:00-06:00" - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "advisory timestamp is not RFC3339 UTC") - - release_dir = _candidate(tmp_path / "hash") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["artifacts"][0]["sha256"] = "ABC" - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "sha256 is not lowercase hex") - - release_dir = _candidate(tmp_path / "commit") - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["source_commit"] = "abc" - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "source_commit is not a full lowercase commit") - - release_dir = _candidate(tmp_path / "target") - manifest = _manifest_for_lane(release_dir, "linux-x86_64-musl") - payload = _load_manifest(manifest) - payload["target"]["profile"] = "debug" - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "artifact target does not match release lane") - - release_dir = _candidate(tmp_path / "features") - manifest = _manifest_for_lane(release_dir, "linux-x86_64-musl") - payload = _load_manifest(manifest) - payload["target"]["features"] = ["extra"] - _write_manifest(manifest, payload) - failures = checker.validate_manifest_file(manifest) - _assert_error(failures, "artifact target does not match release lane") - - -def test_validate_manifest_rejects_non_finite_json(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - text = manifest.read_text(encoding="utf-8").replace( - '"schema_version":1', '"schema_version":NaN' - ) - manifest.write_text(text, encoding="utf-8") - - failures = checker.validate_manifest_file(manifest) - - _assert_error(failures, "manifest JSON is invalid or non-finite") - - -def test_validate_manifest_accepts_historical_utc_timestamp(tmp_path: Path) -> None: - release_dir = _candidate(tmp_path) - manifest = _manifest_for_lane(release_dir, "source") - payload = _load_manifest(manifest) - payload["dependency_policy"]["advisory_checked_at"] = "2020-01-01T00:00:00+00:00" - _write_manifest(manifest, payload) - - failures = checker.validate_manifest_file(manifest) - - assert failures == [] - - -def test_canonical_json_fixed_input_bytes_are_deterministic() -> None: - payload = { - "b": {"features": ["z", "a"]}, - "active_exceptions": ["z", "a"], - "a": 1, - } - - first = checker.canonical_json_bytes(payload) - second = checker.canonical_json_bytes(payload) - - assert first == second - assert first.endswith(b"\n") - assert b'"active_exceptions":["a","z"]' in first - with pytest.raises(ValueError, match="non-finite"): - checker.canonical_json_bytes({"x": float("nan")}) - - -def test_build_and_promote_candidate_success_is_whole_directory_rename( - tmp_path: Path, -) -> None: - ready, failures = _build_ready(tmp_path) - - assert failures == [] - assert ready.is_dir() - assert not (tmp_path / "ready.staging").exists() - assert len(list(ready.iterdir())) == _expected_release_file_count( - include_models=False - ) - assert ( - checker.validate_release_dir(ready, expected_source_commit=VALID_COMMIT) == [] - ) - - -def test_build_and_promote_candidate_rejects_lock_contention(tmp_path: Path) -> None: - dist = _source_dist(tmp_path) - ready = tmp_path / "ready" - lock = (tmp_path / ".rust-release-candidate.lock").open("a+") - try: - fcntl.flock(lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) - failures = checker.build_and_promote_candidate( - dist, - ready, - source_commit=VALID_COMMIT, - evidence_by_lane=checker.fixture_evidence_by_lane(), - include_models=False, - ) - finally: - fcntl.flock(lock.fileno(), fcntl.LOCK_UN) - lock.close() - - _assert_error(failures, "release candidate lock is already held") - assert not ready.exists() - assert not (tmp_path / "ready.staging").exists() - - -def test_build_and_promote_candidate_rolls_back_staging_on_pre_promotion_failure( - tmp_path: Path, -) -> None: - dist = _source_dist(tmp_path) - (dist / checker.expected_package_names(include_models=False)[0]).unlink() - ready = tmp_path / "ready" - - failures = checker.build_and_promote_candidate( - dist, - ready, - source_commit=VALID_COMMIT, - evidence_by_lane=checker.fixture_evidence_by_lane(), - include_models=False, - ) - - _assert_error(failures, "manifest artifact is missing") - assert not ready.exists() - assert not (tmp_path / "ready.staging").exists() - - -def test_build_and_promote_candidate_removes_ready_on_post_promotion_failure( - tmp_path: Path, -) -> None: - def mutate(path: Path) -> None: - artifact = next(iter(sorted(checker._rust_artifact_names()))) - (path / artifact).write_bytes(b"mutated\n") - - ready, failures = _build_ready(tmp_path, hook=mutate) - - _assert_error(failures, "artifact sha256 does not match manifest") - assert not ready.exists() - assert not (tmp_path / "ready.quarantine").exists() - - -def test_build_and_promote_candidate_quarantines_ready_when_post_promote_hook_raises( - tmp_path: Path, -) -> None: - ready = tmp_path / "ready" - - def fail_after_promote(_path: Path) -> None: - raise RuntimeError("hook boom") - - with pytest.raises(RuntimeError, match="hook boom"): - _build_ready(tmp_path, hook=fail_after_promote) - - assert not ready.exists() - assert not (tmp_path / "ready.staging").exists() - assert not (tmp_path / "ready.quarantine").exists() - - ready, failures = _build_ready(tmp_path) - assert failures == [] - assert ready.is_dir() - - -def test_build_and_promote_candidate_quarantines_ready_when_final_validator_raises( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - ready = tmp_path / "ready" - - def fail_final_validator( - _release_dir: Path, - *, - expected_source_commit: str | None, - schema_path: Path = checker.SCHEMA_PATH, - ) -> list[checker.Failure]: - raise RuntimeError("validator boom") - - monkeypatch.setattr(checker, "_final_validate_release_dir", fail_final_validator) - with pytest.raises(RuntimeError, match="validator boom"): - _build_ready(tmp_path) - - assert not ready.exists() - assert not (tmp_path / "ready.staging").exists() - assert not (tmp_path / "ready.quarantine").exists() - - monkeypatch.undo() - ready, failures = _build_ready(tmp_path) - assert failures == [] - assert ready.is_dir() - - -def test_build_and_promote_candidate_leaves_quarantine_not_ready_when_quarantine_delete_fails( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - ready = tmp_path / "ready" - quarantine = tmp_path / "ready.quarantine" - hook_error = RuntimeError("hook boom") - real_rmtree = checker.shutil.rmtree - - def fail_after_promote(_path: Path) -> None: - raise hook_error - - def rmtree(path: Path, *args: Any, **kwargs: Any) -> None: - if Path(path) == quarantine: - raise OSError("delete failed") - real_rmtree(path, *args, **kwargs) - - monkeypatch.setattr(checker.shutil, "rmtree", rmtree) - with pytest.raises( - RuntimeError, match="release candidate quarantine could not be removed" - ) as exc_info: - _build_ready(tmp_path, hook=fail_after_promote) - - assert exc_info.value.__cause__ is hook_error - assert not ready.exists() - assert not (tmp_path / "ready.staging").exists() - assert quarantine.is_dir() - assert checker.validate_release_dir(ready, expected_source_commit=VALID_COMMIT) - new_ready = tmp_path / "new-ready" - failures = checker.build_and_promote_candidate( - _source_dist(tmp_path / "retry"), - new_ready, - source_commit=VALID_COMMIT, - evidence_by_lane=checker.fixture_evidence_by_lane(), - include_models=False, - ) - assert failures == [] - assert new_ready.is_dir() - - -def test_fixtures_mode_runs_without_tree_artifacts() -> None: - before = {path.name for path in checker.ROOT.iterdir()} - - failures = checker.run_fixtures_mode() - - after = {path.name for path in checker.ROOT.iterdir()} - assert failures == [] - assert after == before diff --git a/tests/test_check_wheel_contents.py b/tests/test_check_wheel_contents.py deleted file mode 100644 index a1edea51a..000000000 --- a/tests/test_check_wheel_contents.py +++ /dev/null @@ -1,891 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import os -import re -import subprocess -import sys -import tarfile -import zipfile -from dataclasses import replace -from io import BytesIO -from pathlib import Path - -import scripts.check_wheel_contents as checker -from tests.helpers.release_wheel_fixtures import ( - NVATTEST_AUTHORITY_BYTES, - ROOT_LAUNCHER_BYTES, - minimal_elf, - minimal_fat_macho, - minimal_macho, - record_hash, - speakers_analyze_elf, - speakers_analyze_macho, - write_core_wheel, - write_platform_base_wheel, - write_speakers_analyze_wheel, -) - -SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "check_wheel_contents.py" -ROOT = Path(__file__).resolve().parents[1] -CPU_TYPE_X86_64 = 0x01000007 -SPEAKERS_LIBRARY = b"fixture libonnxruntime.so.1 GLIBC_2.27\n" -SPEAKERS_LICENSE = b"fixture license\n" -SPEAKERS_THIRD_PARTY_NOTICE = b"fixture third party notice\n" - - -def _write_member( - wheel: zipfile.ZipFile, - name: str, - content: bytes, - *, - mode: int = 0o644, -) -> None: - info = zipfile.ZipInfo(name) - info.external_attr = mode << 16 - wheel.writestr(info, content) - - -def _patch_speakers_fixture_hashes( - monkeypatch, - *, - target: str = "linux-x86_64", - runtime_bytes: bytes = SPEAKERS_LIBRARY, - patch_runtime: bool = True, -) -> None: - spec = checker.SPEAKERS_ANALYZE_TARGETS[target] - notices = ( - replace( - spec.notices[0], - sha256=checker.hashlib.sha256(SPEAKERS_LICENSE).hexdigest(), - ), - replace( - spec.notices[1], - sha256=checker.hashlib.sha256(SPEAKERS_THIRD_PARTY_NOTICE).hexdigest(), - ), - ) - replacement = replace(spec, notices=notices) - if patch_runtime: - replacement = replace( - replacement, - runtime_sha256=checker.hashlib.sha256(runtime_bytes).hexdigest(), - ) - monkeypatch.setitem(checker.SPEAKERS_ANALYZE_TARGETS, target, replacement) - - -def test_script_runs_without_site_packages_from_outside_repo(tmp_path: Path) -> None: - env = os.environ.copy() - env.pop("PYTHONPATH", None) - env.pop("VIRTUAL_ENV", None) - - result = subprocess.run( - [sys.executable, "-S", "-E", str(SCRIPT), "--help"], - cwd=tmp_path, - env=env, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode == 0, result.stderr - assert "usage:" in result.stdout - - -def test_production_imports_do_not_reach_deleted_speaker_plane_or_oracle() -> None: - assert checker.forbidden_production_imports(ROOT) == [] - - -def test_forbidden_production_imports_catches_sklearn_prefixes(tmp_path: Path) -> None: - source_dir = tmp_path / "solstone" / "apps" / "speakers" - source_dir.mkdir(parents=True) - (source_dir / "direct.py").write_text("import sklearn\n", encoding="utf-8") - (source_dir / "from_import.py").write_text( - "from sklearn.cluster import HDBSCAN\n", - encoding="utf-8", - ) - - violations = checker.forbidden_production_imports(tmp_path) - - assert violations == [ - "solstone/apps/speakers/direct.py imports sklearn", - "solstone/apps/speakers/from_import.py imports sklearn.cluster", - ] - - -def test_core_wheel_validator_accepts_static_manylinux_wheel(tmp_path: Path) -> None: - wheel = write_core_wheel(tmp_path) - - assert checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) == [] - - -def test_core_wheel_validator_rejects_wrong_script_member(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - script_names=( - "solstone_core-1.2.3.data/scripts/sol", - "solstone_core-1.2.3.data/scripts/solstone", - "solstone_core-1.2.3.data/scripts/solstone-core-renamed", - ), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("wrong solstone-core script member set" in error for error in errors) - - -def test_core_wheel_validator_rejects_bare_linux_tag(tmp_path: Path) -> None: - wheel = write_core_wheel(tmp_path, tag="linux_x86_64") - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("unsupported solstone-core wheel tag" in error for error in errors) - assert any("bare linux tag" in error for error in errors) - - -def test_core_wheel_validator_rejects_tag_outside_probe_constants( - tmp_path: Path, -) -> None: - wheel = write_core_wheel(tmp_path, tag="manylinux_2_28_x86_64") - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("unsupported solstone-core wheel tag" in error for error in errors) - - -def test_core_wheel_validator_rejects_non_executable_binary( - tmp_path: Path, -) -> None: - wheel = write_core_wheel(tmp_path, executable=False) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("not executable" in error for error in errors) - - -def test_core_wheel_validator_rejects_record_drift(tmp_path: Path) -> None: - wheel = write_core_wheel(tmp_path, record_ok=False) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("RECORD hash mismatch" in error for error in errors) - - -def test_core_wheel_validator_rejects_extra_root_member(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - extra_members={"solstone-core.signing-facts.json": b"{}"}, - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("solstone-core wheel member set is wrong" in error for error in errors) - - -def test_core_wheel_validator_rejects_wrong_binary_format(tmp_path: Path) -> None: - wheel = write_core_wheel(tmp_path, binary=b"not an elf") - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("ELF binary is too short" in error for error in errors) - - -def test_core_wheel_validator_rejects_wrong_elf_architecture(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - tag="manylinux_2_17_aarch64.manylinux2014_aarch64", - binary=minimal_elf(checker.ELF_MACHINE["x86_64"]), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("ELF machine does not match wheel tag" in error for error in errors) - - -def test_core_wheel_validator_rejects_elf_interp(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - binary=minimal_elf( - checker.ELF_MACHINE["x86_64"], program_type=checker.PT_INTERP - ), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("ELF binary has PT_INTERP" in error for error in errors) - - -def test_core_wheel_validator_rejects_elf_needed_entry(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - binary=minimal_elf( - checker.ELF_MACHINE["x86_64"], - program_type=checker.PT_DYNAMIC, - dynamic_needed=True, - ), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("ELF binary has DT_NEEDED" in error for error in errors) - - -def test_core_wheel_validator_rejects_wrong_macho_architecture(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - tag="macosx_14_0_arm64", - binary=minimal_macho(CPU_TYPE_X86_64), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("Mach-O cputype does not match wheel tag" in error for error in errors) - - -def test_core_wheel_validator_accepts_fat_macho_with_arm64(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - tag="macosx_14_0_arm64", - binary=minimal_fat_macho([CPU_TYPE_X86_64, checker.CPU_TYPE_ARM64]), - ) - - assert checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) == [] - - -def test_core_wheel_validator_rejects_fat_macho_without_arm64(tmp_path: Path) -> None: - wheel = write_core_wheel( - tmp_path, - tag="macosx_14_0_arm64", - binary=minimal_fat_macho([CPU_TYPE_X86_64]), - ) - - errors = checker.check_core_wheel(wheel, checker.MAX_CORE_WHEEL_BYTES) - - assert any("fat Mach-O has no arm64 slice" in error for error in errors) - - -def test_speakers_analyze_wheel_validator_accepts_pinned_layout( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - assert checker.check_speakers_analyze_wheel(wheel) == [] - - -def test_speakers_analyze_macos_signed_dylib_bytes_are_allowed( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes( - monkeypatch, - target="macos-arm64", - patch_runtime=False, - ) - wheel = write_speakers_analyze_wheel( - tmp_path, - tag=checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_PLATFORM_TAGS[("darwin", "arm64")], - library=minimal_macho(checker.CPU_TYPE_ARM64), - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - assert checker.check_speakers_analyze_wheel(wheel) == [] - - -def test_speakers_analyze_macos_runtime_rpath_is_checked_with_specific_diagnostic( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes( - monkeypatch, - target="macos-arm64", - patch_runtime=False, - ) - wheel = write_speakers_analyze_wheel( - tmp_path, - tag=checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_PLATFORM_TAGS[("darwin", "arm64")], - binary=speakers_analyze_macho( - rpath="$ORIGIN/../lib/solstone-core-speakers-analyze" - ), - library=minimal_macho(checker.CPU_TYPE_ARM64), - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "speakers analyze Mach-O RPATH is wrong" in error - and "expected: @loader_path/../lib/solstone-core-speakers-analyze" in error - and "actual: $ORIGIN/../lib/solstone-core-speakers-analyze" in error - and "repair command: make wheel-macos" in error - for error in errors - ) - - -def test_speakers_analyze_macos_missing_rpath_is_rejected_with_specific_diagnostic( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes( - monkeypatch, - target="macos-arm64", - patch_runtime=False, - ) - wheel = write_speakers_analyze_wheel( - tmp_path, - tag=checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_PLATFORM_TAGS[("darwin", "arm64")], - binary=speakers_analyze_macho(rpath=None), - library=minimal_macho(checker.CPU_TYPE_ARM64), - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "speakers analyze Mach-O RPATH is wrong" in error - and "expected: @loader_path/../lib/solstone-core-speakers-analyze" in error - and "actual: " in error - and "repair command: make wheel-macos" in error - for error in errors - ) - - -def test_speakers_analyze_macos_bad_load_command_rejects_even_with_correct_rpath( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes( - monkeypatch, - target="macos-arm64", - patch_runtime=False, - ) - bad_load = ( - "@loader_path/../lib/solstone-core-speakers-analyze/libonnxruntime.1.25.0.dylib" - ) - wheel = write_speakers_analyze_wheel( - tmp_path, - tag=checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_PLATFORM_TAGS[("darwin", "arm64")], - binary=speakers_analyze_macho(load_dylib=bad_load), - library=minimal_macho(checker.CPU_TYPE_ARM64), - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "ONNX Runtime load command is outside bundled sibling-library contract" in error - and "expected: LC_LOAD_DYLIB @rpath/libonnxruntime.1.25.0.dylib" in error - and f"actual: {bad_load}" in error - and "repair command: make wheel-macos" in error - for error in errors - ) - - -def test_speakers_analyze_runtime_link_contract_matches_build_script() -> None: - contracts = checker.SPEAKERS_ANALYZE_RUNTIME_LINK_CONTRACTS - assert set(contracts) == set( - checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_COVERED_PLATFORMS - ) - assert contracts[("linux", "x86_64")] == contracts[("linux", "aarch64")] - assert ( - contracts[("linux", "x86_64")].rpath - == "$ORIGIN/../lib/solstone-core-speakers-analyze" - ) - assert ( - contracts[("darwin", "arm64")].rpath - == "@loader_path/../lib/solstone-core-speakers-analyze" - ) - assert contracts[("linux", "x86_64")].rpath != contracts[("darwin", "arm64")].rpath - build_rs = ( - Path(__file__).resolve().parents[1] - / "core" - / "crates" - / "solstone-core-speakers-analyze" - / "build.rs" - ).read_text(encoding="utf-8") - rpaths_by_target_os = dict( - re.findall(r'"(linux|macos)"\s*=>\s*"([^"]+)"', build_rs) - ) - assert rpaths_by_target_os == { - "linux": contracts[("linux", "x86_64")].rpath, - "macos": contracts[("darwin", "arm64")].rpath, - } - - -def test_speakers_analyze_runtime_load_contract_matches_staged_runtime_name() -> None: - for ( - platform_tuple, - contract, - ) in checker.SPEAKERS_ANALYZE_RUNTIME_LINK_CONTRACTS.items(): - target_key = checker.SPEAKERS_ANALYZE_PLATFORM_TARGETS[platform_tuple] - staged_name = checker.SPEAKERS_ANALYZE_TARGETS[target_key].runtime_staged_name - expected_load = ( - f"@rpath/{staged_name}" if platform_tuple[0] == "darwin" else staged_name - ) - assert contract.runtime_load == expected_load - - -def test_speakers_analyze_linux_rejects_substituted_runtime_library( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=b"substituted libonnxruntime.so.1 GLIBC_2.27\n", - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "speakers analyze ONNX Runtime library digest mismatch" in error - for error in errors - ) - - -def test_speakers_analyze_wheel_validator_requires_exact_member_set( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - extra_members={"unexpected.txt": b"x"}, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "speakers analyze wheel member set is wrong" in error for error in errors - ) - - -def test_speakers_analyze_wheel_validator_requires_sbom( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - omit_member=( - "solstone_core_speakers_analyze-1.2.3.dist-info/sboms/" - "solstone-core-speakers-analyze.cyclonedx.json" - ), - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any( - "speakers analyze wheel member set is wrong" in error for error in errors - ) - - -def test_speakers_analyze_wheel_validator_rejects_provider_libraries( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - extra_members={ - "solstone_core_speakers_analyze-1.2.3.data/data/lib/" - "solstone-core-speakers-analyze/libonnxruntime_providers_shared.so": b"x" - }, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any("contains unproven provider library" in error for error in errors) - - -def test_speakers_analyze_wheel_validator_rejects_notice_hash_drift( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=b"changed license\n", - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any("notice digest mismatch" in error for error in errors) - - -def test_speakers_analyze_wheel_validator_requires_dynamic_elf_contract( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - binary = speakers_analyze_elf( - checker.ELF_MACHINE["x86_64"], - needed=("libc.so.6",), - runpath="/wrong", - include_interp=False, - ) - wheel = write_speakers_analyze_wheel( - tmp_path, - binary=binary, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any("missing PT_INTERP" in error for error in errors) - assert any("does not need ONNX Runtime" in error for error in errors) - assert any("RUNPATH is wrong" in error for error in errors) - - -def test_speakers_analyze_wheel_validator_rejects_understated_glibc_floor( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - wheel = write_speakers_analyze_wheel( - tmp_path, - binary=speakers_analyze_elf(checker.ELF_MACHINE["x86_64"], glibc="2.34"), - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_speakers_analyze_wheel(wheel) - - assert any("wheel tag understates GLIBC floor" in error for error in errors) - - -def test_speakers_analyze_helper_only_dist_is_checkable( - tmp_path: Path, monkeypatch -) -> None: - _patch_speakers_fixture_hashes(monkeypatch) - write_speakers_analyze_wheel( - tmp_path, - library=SPEAKERS_LIBRARY, - license_notice=SPEAKERS_LICENSE, - third_party_notice=SPEAKERS_THIRD_PARTY_NOTICE, - ) - - errors = checker.check_dist(tmp_path, {}, checker.MAX_BASE_WHEEL_BYTES) - - assert errors == [] - - -def test_base_wheel_validator_rejects_tests_path_segment(tmp_path: Path) -> None: - clean = _write_minimal_wheel(tmp_path, "solstone") - - clean_errors = checker.check_base_wheel(clean, checker.MAX_BASE_WHEEL_BYTES) - assert not [ - error for error in clean_errors if "base wheel ships test path" in error - ] - - dirty = _write_minimal_wheel(tmp_path, "solstone_dirty") - test_member = "solstone/apps/search/tests/test_routes.py" - with zipfile.ZipFile(dirty, "a") as wheel: - _write_member(wheel, test_member, b"") - - dirty_errors = checker.check_base_wheel(dirty, checker.MAX_BASE_WHEEL_BYTES) - assert any( - f"base wheel ships test path {test_member}" in error for error in dirty_errors - ) - - -def test_base_wheel_platform_cap_allows_bundled_helper(tmp_path: Path) -> None: - within = write_platform_base_wheel( - tmp_path, - extra_payload_size=5 * 1024 * 1024, - ) - within_errors = checker.check_base_wheel(within, checker.MAX_BASE_WHEEL_BYTES) - assert not [error for error in within_errors if "base wheel is" in error] - - oversized = write_platform_base_wheel( - tmp_path / "oversized", - extra_payload_size=7 * 1024 * 1024, - ) - oversized_errors = checker.check_base_wheel(oversized, checker.MAX_BASE_WHEEL_BYTES) - assert any("base wheel is" in error for error in oversized_errors) - - -def test_base_wheel_validator_rejects_missing_platform_helper( - tmp_path: Path, -) -> None: - wheel = write_platform_base_wheel(tmp_path, helper_name=None) - - errors = checker.check_base_wheel(wheel, checker.MAX_BASE_WHEEL_BYTES) - - assert any("wrong parakeet helper member count" in error for error in errors) - - -def test_base_wheel_validator_rejects_renamed_platform_helper( - tmp_path: Path, -) -> None: - wheel = write_platform_base_wheel( - tmp_path, - helper_name=f"{checker.PARAKEET_HELPER_MEMBER}-renamed", - ) - - errors = checker.check_base_wheel(wheel, checker.MAX_BASE_WHEEL_BYTES) - - assert any("wrong parakeet helper member count" in error for error in errors) - - -def test_base_wheel_validator_rejects_wrong_arch_platform_helper( - tmp_path: Path, -) -> None: - wheel = write_platform_base_wheel( - tmp_path, - helper_binary=minimal_macho(CPU_TYPE_X86_64), - ) - - errors = checker.check_base_wheel(wheel, checker.MAX_BASE_WHEEL_BYTES) - - assert any( - "parakeet helper" in error - and checker.PARAKEET_HELPER_MEMBER in error - and "Mach-O cputype" in error - for error in errors - ) - - -def test_dist_check_accepts_identical_nvattest_authority_in_root_wheels( - tmp_path: Path, -) -> None: - _write_minimal_dist(tmp_path) - write_core_wheel(tmp_path) - write_platform_base_wheel(tmp_path) - - errors = checker.check_dist(tmp_path, {}, checker.MAX_BASE_WHEEL_BYTES) - - assert not [error for error in errors if "nvattest authority" in error] - - -def test_dist_check_rejects_missing_nvattest_authority_from_root_wheel( - tmp_path: Path, -) -> None: - _write_minimal_dist(tmp_path) - write_core_wheel(tmp_path) - write_platform_base_wheel(tmp_path, nvattest_authority_bytes=None) - - errors = checker.check_dist(tmp_path, {}, checker.MAX_BASE_WHEEL_BYTES) - - assert any( - "missing nvattest authority member" in error - and checker.NVATTEST_AUTHORITY_MEMBER in error - for error in errors - ) - - -def test_dist_check_rejects_mismatched_nvattest_authority_bytes( - tmp_path: Path, -) -> None: - _write_minimal_dist(tmp_path) - write_core_wheel(tmp_path) - write_platform_base_wheel(tmp_path, nvattest_authority_bytes=b"different\n") - - errors = checker.check_dist(tmp_path, {}, checker.MAX_BASE_WHEEL_BYTES) - - assert any( - "nvattest authority member digest mismatch" in error - and "expected" in error - and "actual" in error - for error in errors - ) - - -def _add_tar_member(archive: tarfile.TarFile, name: str) -> None: - content = b"x" - info = tarfile.TarInfo(name) - info.size = len(content) - archive.addfile(info, BytesIO(content)) - - -def _write_core_sdist(path: Path, *, missing: str | None = None) -> Path: - sdist = path / "solstone_core-1.2.3.tar.gz" - with tarfile.open(sdist, "w:gz") as archive: - for member in sorted(checker.CORE_REQUIRED_SDIST_MEMBERS): - if member == missing: - continue - _add_tar_member(archive, f"solstone_core-1.2.3/{member}") - return sdist - - -def _write_minimal_wheel( - path: Path, - name: str, - *, - nvattest_authority_bytes: bytes | None = NVATTEST_AUTHORITY_BYTES, -) -> Path: - wheel_path = path / f"{name}-1.2.3-py3-none-any.whl" - with zipfile.ZipFile(wheel_path, "w") as wheel: - members = { - f"{name}-1.2.3.dist-info/METADATA": ( - f"Name: {name}\nVersion: 1.2.3\n".encode() - ) - } - if name.startswith("solstone") and not name.startswith("solstone_journal"): - members[f"{name}-1.2.3.dist-info/WHEEL"] = b"Wheel-Version: 1.0\n" - for launcher, content in ROOT_LAUNCHER_BYTES.items(): - members[f"{name}-1.2.3.data/scripts/{launcher}"] = content - if nvattest_authority_bytes is not None and name == "solstone": - members[checker.NVATTEST_AUTHORITY_MEMBER] = nvattest_authority_bytes - record_name = f"{name}-1.2.3.dist-info/RECORD" - record = "\n".join( - f"{member},{record_hash(content)},{len(content)}" - for member, content in members.items() - ) - members[record_name] = f"{record}\n{record_name},,".encode("utf-8") - for member, content in members.items(): - mode = 0o755 if Path(member).name in checker.ROOT_LAUNCHER_NAMES else 0o644 - _write_member(wheel, member, content, mode=mode) - return wheel_path - - -def _write_minimal_dist(path: Path) -> None: - _write_minimal_wheel(path, "solstone") - _write_minimal_wheel(path, "solstone_journal_models") - _write_core_sdist(path) - - -def test_dist_check_requires_requested_core_platform(tmp_path: Path) -> None: - _write_minimal_dist(tmp_path) - write_core_wheel(tmp_path) - - errors = checker.check_dist( - tmp_path, - {}, - checker.MAX_BASE_WHEEL_BYTES, - required_core_platforms=(("darwin", "arm64"),), - ) - - assert any("darwin/arm64" in error for error in errors) - assert any("macosx_14_0_arm64" in error for error in errors) - - -def test_dist_check_accepts_requested_core_platform(tmp_path: Path) -> None: - _write_minimal_dist(tmp_path) - write_core_wheel(tmp_path) - write_core_wheel(tmp_path, tag="macosx_14_0_arm64") - - errors = checker.check_dist( - tmp_path, - {}, - checker.MAX_BASE_WHEEL_BYTES, - required_core_platforms=(("darwin", "arm64"),), - ) - - assert not [error for error in errors if "darwin/arm64" in error] - - -def test_release_artifact_manifest_requires_core_targets(tmp_path: Path) -> None: - errors = checker.check_release_artifacts( - tmp_path, - release_scope="all-hosts", - models_decision="skip", - ) - - assert any("core wheel for linux/x86_64" in error for error in errors) - assert any("core wheel for linux/aarch64" in error for error in errors) - assert any("core wheel for darwin/arm64" in error for error in errors) - - -def test_release_artifacts_derive_core_tags_from_probe(tmp_path: Path) -> None: - artifacts = checker.release_artifacts( - tmp_path, - release_scope="all-hosts", - models_decision="skip", - ) - artifact_names = {path.name for path in artifacts} - - for tag in checker.SOLSTONE_CORE_PLATFORM_TAGS.values(): - assert any( - name.startswith("solstone_core-") and name.endswith(f"-py3-none-{tag}.whl") - for name in artifact_names - ) - - -def test_release_artifacts_derive_speakers_analyze_tags_from_probe( - tmp_path: Path, -) -> None: - artifacts = checker.release_artifacts( - tmp_path, - release_scope="all-hosts", - models_decision="skip", - ) - artifact_names = {path.name for path in artifacts} - - for tag in checker.SOLSTONE_CORE_SPEAKERS_ANALYZE_PLATFORM_TAGS.values(): - assert any( - name.startswith("solstone_core_speakers_analyze-") - and name.endswith(f"-py3-none-{tag}.whl") - for name in artifact_names - ) - - -def test_release_artifacts_include_models_only_when_gate_publishes( - tmp_path: Path, -) -> None: - publish_artifacts = checker.release_artifacts( - tmp_path, - release_scope="linux", - models_decision="publish", - ) - skip_artifacts = checker.release_artifacts( - tmp_path, - release_scope="linux", - models_decision="skip", - ) - - assert any( - path.name.startswith("solstone_journal_models-") for path in publish_artifacts - ) - assert not any( - path.name.startswith("solstone_journal_models-") for path in skip_artifacts - ) - - -def test_release_artifacts_exclude_core_unsupported_tombstone( - tmp_path: Path, -) -> None: - artifacts = checker.release_artifacts( - tmp_path, - release_scope="all-hosts", - models_decision="skip", - ) - - assert not any( - path.name.startswith("solstone_core_unsupported_platform-") - for path in artifacts - ) - - -def test_core_sdist_validator_requires_rust_workspace_sources( - tmp_path: Path, -) -> None: - sdist = _write_core_sdist(tmp_path) - - assert checker.check_core_sdist(sdist) == [] - - -def test_core_sdist_validator_rejects_missing_workspace_source( - tmp_path: Path, -) -> None: - sdist = _write_core_sdist(tmp_path, missing="core/crates/solstone-core/src/main.rs") - - errors = checker.check_core_sdist(sdist) - - assert any("missing Rust workspace members" in error for error in errors) diff --git a/tests/test_cogitate_contract.py b/tests/test_cogitate_contract.py index e25f2285c..9368ebaa9 100644 --- a/tests/test_cogitate_contract.py +++ b/tests/test_cogitate_contract.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-only # Copyright (c) 2026 sol pbc -import ast from pathlib import Path import pytest @@ -205,44 +204,3 @@ def test_cogitate_doc_preamble_block_matches_source_constant(): assert closing_fence assert block == COGITATE_RUNTIME_PREAMBLE.rstrip("\n") - - -def test_cogitate_journal_command_vocabulary_not_retyped(): - repo_root = Path(__file__).resolve().parents[1] - allowed = { - Path("solstone/think/cogitate_contract.py"), - Path("tests/test_cogitate_contract.py"), - } - roots = [repo_root / "solstone", repo_root / "scripts", repo_root / "tests"] - findings: list[str] = [] - family_set = set(COGITATE_JOURNAL_COMMANDS) - list_markers = ( - "identity, health, talent", - "{identity, health, talent}", - "identity|health|talent", - ) - - for root in roots: - for path in sorted(root.rglob("*.py")): - rel = path.relative_to(repo_root) - if rel in allowed: - continue - text = path.read_text(encoding="utf-8") - tree = ast.parse(text, filename=str(rel)) - for node in ast.walk(tree): - if isinstance(node, ast.Constant) and isinstance(node.value, str): - if any(marker in node.value for marker in list_markers): - findings.append(f"{rel}:{node.lineno}") - elif isinstance(node, (ast.Tuple, ast.List, ast.Set)): - values = { - elt.value - for elt in node.elts - if isinstance(elt, ast.Constant) and isinstance(elt.value, str) - } - if family_set <= values: - findings.append(f"{rel}:{node.lineno}") - - assert findings == [], ( - "render from `COGITATE_JOURNAL_COMMANDS` in " - "solstone/think/cogitate_contract.py: " + ", ".join(findings) - ) diff --git a/tests/test_core_compile_inputs.py b/tests/test_core_compile_inputs.py deleted file mode 100644 index 00c6b5890..000000000 --- a/tests/test_core_compile_inputs.py +++ /dev/null @@ -1,146 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -from pathlib import Path - -import pytest - -from scripts.core_compile_inputs import ( - CoreCompileInputError, - discover_core_compile_inputs, -) - -REPO_ROOT = Path(__file__).resolve().parents[1] - - -def test_real_tree_discovers_only_shipping_root_contract() -> None: - assets = discover_core_compile_inputs(REPO_ROOT) - - assert len(assets) == 1 - asset = assets[0] - assert ( - asset.source_file - == REPO_ROOT / "core/crates/solstone-core-sol-client-cli/src/help.rs" - ) - assert asset.line == 8 - assert asset.sdist_path == "core/fixtures/native-sol/root-contract-v1.json" - excluded_sources = { - REPO_ROOT / "core/crates/solstone-core-indexer-store/src/db.rs", - REPO_ROOT / "core/crates/solstone-core-indexer/src/chunker.rs", - REPO_ROOT / "core/crates/solstone-core-sol-client-cli/tests/parity.rs", - REPO_ROOT - / "core/crates/solstone-core-sol-client-cli/src/bin/resolve_parity_leaves.rs", - } - assert asset.source_file not in excluded_sources - - -def test_target_conditional_module_is_discovered_on_non_matching_host( - tmp_path: Path, -) -> None: - _write_workspace( - tmp_path, - helper_lib='#[cfg(target_os = "definitely_not_solstone")] mod gated;\n', - extra={ - "core/crates/solstone-core-helper/src/gated.rs": ( - 'const ASSET: &str = include_str!("asset.txt");\n' - ), - "core/crates/solstone-core-helper/src/asset.txt": "asset\n", - }, - ) - - assets = discover_core_compile_inputs(tmp_path) - - assert [asset.sdist_path for asset in assets] == [ - "core/crates/solstone-core-helper/src/asset.txt" - ] - - -def test_cfg_test_regions_are_removed_before_include_scan(tmp_path: Path) -> None: - _write_workspace( - tmp_path, - helper_lib=( - "#[cfg(test)]\n" - "mod tests {\n" - ' const TEST_ONLY: &str = r#"{"path":"missing.txt"}"#;\n' - ' const IGNORED: &str = include_str!("missing.txt");\n' - "}\n" - 'const ASSET: &str = include_str!("asset.txt");\n' - ), - extra={"core/crates/solstone-core-helper/src/asset.txt": "asset\n"}, - ) - - assets = discover_core_compile_inputs(tmp_path) - - assert [asset.sdist_path for asset in assets] == [ - "core/crates/solstone-core-helper/src/asset.txt" - ] - - -@pytest.mark.parametrize( - ("helper_lib", "message"), - [ - ( - 'const ASSET: &str = include_str!(concat!("asset", ".txt"));\n', - "unsupported-include-argument", - ), - ( - 'const ASSET: &str = include_str!("../../../../../outside.txt");\n', - "outside-repo", - ), - ('const ASSET: &str = include_str!("missing.txt");\n', "compile-input-missing"), - ('#[path = "missing.rs"] mod missing;\n', "path-module-missing"), - ], -) -def test_discovery_failures_are_loud( - tmp_path: Path, helper_lib: str, message: str -) -> None: - _write_workspace(tmp_path, helper_lib=helper_lib) - - with pytest.raises(CoreCompileInputError, match=message): - discover_core_compile_inputs(tmp_path) - - -def test_unterminated_cfg_test_region_fails_loudly(tmp_path: Path) -> None: - _write_workspace(tmp_path, helper_lib="#[cfg(test)]\nmod tests {\n") - - with pytest.raises(CoreCompileInputError, match="delimiter-match-failed"): - discover_core_compile_inputs(tmp_path) - - -def _write_workspace( - root: Path, - *, - helper_lib: str, - extra: dict[str, str] | None = None, -) -> None: - _write( - root / "core/Cargo.toml", - ( - '[workspace]\nmembers = ["crates/solstone-core", ' - '"crates/solstone-core-helper"]\nresolver = "3"\n\n' - "[workspace.dependencies]\n" - 'solstone-core-helper = { path = "crates/solstone-core-helper" }\n' - ), - ) - _write( - root / "core/crates/solstone-core/Cargo.toml", - ( - '[package]\nname = "solstone-core"\nversion = "1.2.3"\n' - "\n[dependencies]\nsolstone-core-helper.workspace = true\n" - ), - ) - _write(root / "core/crates/solstone-core/src/main.rs", "fn main() {}\n") - _write( - root / "core/crates/solstone-core-helper/Cargo.toml", - '[package]\nname = "solstone-core-helper"\nversion = "1.2.3"\n', - ) - _write(root / "core/crates/solstone-core-helper/src/lib.rs", helper_lib) - for relative, content in (extra or {}).items(): - _write(root / relative, content) - - -def _write(path: Path, text: str) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(text, encoding="utf-8") diff --git a/tests/test_fixture_leak_detector.py b/tests/test_fixture_leak_detector.py deleted file mode 100644 index fdb50609f..000000000 --- a/tests/test_fixture_leak_detector.py +++ /dev/null @@ -1,129 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -"""Canary for the fixture-leak detector in the project-root conftest.py.""" - -from __future__ import annotations - -import subprocess -import sys -from pathlib import Path - -import pytest - -pytest_plugins = ["pytester"] -pytestmark = pytest.mark.xdist_group("fixture_leak_detector") - -_ROOT_CONFTEST = Path(__file__).resolve().parent.parent / "conftest.py" - - -def _prime_git_repo(project_dir: Path) -> None: - """Initialise a miniature git repo with one tracked file under tests/fixtures/.""" - subprocess.run(["git", "init", "-q"], cwd=project_dir, check=True) - subprocess.run( - [ - "git", - "-c", - "commit.gpgsign=false", - "-c", - "user.email=canary@example.invalid", - "-c", - "user.name=canary", - "commit", - "--allow-empty", - "-q", - "-m", - "init", - ], - cwd=project_dir, - check=True, - ) - fixtures_dir = project_dir / "tests" / "fixtures" - fixtures_dir.mkdir(parents=True, exist_ok=True) - (fixtures_dir / "keep").write_text("kept\n", encoding="utf-8") - subprocess.run(["git", "add", "tests/fixtures/keep"], cwd=project_dir, check=True) - subprocess.run( - [ - "git", - "-c", - "commit.gpgsign=false", - "-c", - "user.email=canary@example.invalid", - "-c", - "user.name=canary", - "commit", - "-q", - "-m", - "fixtures", - ], - cwd=project_dir, - check=True, - ) - - -def _install_detector(pytester: pytest.Pytester) -> None: - """Copy the real root conftest.py into the pytester project root.""" - pytester.makepyfile(conftest=_ROOT_CONFTEST.read_text(encoding="utf-8")) - - -def _run_nested(pytester: pytest.Pytester) -> pytest.RunResult: - basetemp = pytester.path / "basetemp" - return pytester.run( - sys.executable, - "-mpytest", - "-q", - "-p", - "no:cacheprovider", - "--basetemp", - str(basetemp), - ) - - -@pytest.mark.timeout(30) -def test_detector_fires_on_leaked_file(pytester: pytest.Pytester) -> None: - _install_detector(pytester) - _prime_git_repo(pytester.path) - pytester.makepyfile( - test_leak=""" - from pathlib import Path - - def test_writes_into_fixtures(tmp_path): - Path("tests/fixtures/leak_probe.tmp").write_text("x") - """ - ) - result = _run_nested(pytester) - assert result.ret != 0, result.stderr.str() + result.stdout.str() - combined = result.stderr.str() + result.stdout.str() - assert "solstone fixture-leak detector" in combined - assert "tests/fixtures/leak_probe.tmp" in combined - assert "journal_copy fixture" in combined - - -@pytest.mark.timeout(30) -def test_detector_silent_on_clean(pytester: pytest.Pytester) -> None: - _install_detector(pytester) - _prime_git_repo(pytester.path) - pytester.makepyfile( - test_clean=""" - def test_noop(): - assert True - """ - ) - result = _run_nested(pytester) - assert result.ret == 0, result.stderr.str() + result.stdout.str() - combined = result.stderr.str() + result.stdout.str() - assert "fixture-leak detector" not in combined - - -@pytest.mark.timeout(30) -def test_detector_skips_without_git_repo(pytester: pytest.Pytester) -> None: - _install_detector(pytester) - pytester.makepyfile( - test_clean=""" - def test_noop(): - assert True - """ - ) - result = _run_nested(pytester) - assert result.ret == 0, result.stderr.str() + result.stdout.str() - combined = result.stderr.str() + result.stdout.str() - assert "git unavailable" in combined diff --git a/tests/test_no_implicit_cloud.py b/tests/test_no_implicit_cloud.py index 67786e322..425991682 100644 --- a/tests/test_no_implicit_cloud.py +++ b/tests/test_no_implicit_cloud.py @@ -3,7 +3,6 @@ from __future__ import annotations -import ast import asyncio import hashlib import importlib @@ -31,17 +30,6 @@ from solstone.think.services.spp_attest.cadence import AttestationSession from tests.helpers.journal_config import seed_journal_config -def _dotted_name(node: ast.AST) -> str | None: - if isinstance(node, ast.Name): - return node.id - if isinstance(node, ast.Attribute): - base = _dotted_name(node.value) - if base is None: - return None - return f"{base}.{node.attr}" - return None - - @pytest.fixture(autouse=True) def _clear_confidential_transport_state(): from solstone.think.services import spp, spp_transport @@ -288,108 +276,6 @@ def _install_stt_backend_mocks( return mocks -def test_stt_backend_dispatch_chokepoint_is_exclusive() -> None: - from solstone.observe.transcribe import BACKEND_REGISTRY - - repo_root = Path(__file__).resolve().parents[1] - solstone_root = repo_root / "solstone" - package_dispatcher = Path("observe/transcribe/__init__.py") - backend_module_paths = set(BACKEND_REGISTRY.values()) - backend_module_names = { - module_path.rsplit(".", maxsplit=1)[-1] for module_path in backend_module_paths - } - violations: list[str] = [] - - for path in sorted(solstone_root.rglob("*.py")): - relative = path.relative_to(solstone_root) - if relative == package_dispatcher: - continue - - tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) - backend_aliases = set(backend_module_paths) - backend_function_aliases: set[str] = set() - get_backend_aliases = {"get_backend"} - get_backend_results: set[str] = set() - package_aliases = {"solstone.observe.transcribe"} - - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - target = alias.asname or alias.name - if alias.name in backend_module_paths: - backend_aliases.add(target) - elif alias.name == "solstone.observe.transcribe": - package_aliases.add(target) - elif isinstance(node, ast.ImportFrom): - module = node.module or "" - if module == "solstone.observe.transcribe": - for alias in node.names: - target = alias.asname or alias.name - if alias.name in backend_module_names: - backend_aliases.add(target) - elif alias.name == "get_backend": - get_backend_aliases.add(target) - elif module in backend_module_paths: - for alias in node.names: - if alias.name == "transcribe": - backend_function_aliases.add(alias.asname or alias.name) - - def is_get_backend_call(call: ast.Call) -> bool: - name = _dotted_name(call.func) - if name in get_backend_aliases: - return True - if name in {f"{alias}.get_backend" for alias in package_aliases}: - return True - return name == "solstone.observe.transcribe.get_backend" - - for node in ast.walk(tree): - if isinstance(node, ast.Assign) and isinstance(node.value, ast.Call): - if is_get_backend_call(node.value): - for target in node.targets: - if isinstance(target, ast.Name): - get_backend_results.add(target.id) - elif ( - isinstance(node, ast.AnnAssign) - and isinstance(node.target, ast.Name) - and isinstance(node.value, ast.Call) - and is_get_backend_call(node.value) - ): - get_backend_results.add(node.target.id) - - for node in ast.walk(tree): - if not isinstance(node, ast.Call): - continue - func = node.func - if isinstance(func, ast.Name) and func.id in backend_function_aliases: - violations.append( - f"{relative.as_posix()}:{node.lineno} direct backend " - f"transcribe() import bypasses the STT egress chokepoint" - ) - continue - if not isinstance(func, ast.Attribute) or func.attr != "transcribe": - continue - receiver = _dotted_name(func.value) - if receiver in backend_aliases or receiver in get_backend_results: - violations.append( - f"{relative.as_posix()}:{node.lineno} calls " - f"{receiver}.transcribe() outside the package dispatcher" - ) - continue - if isinstance(func.value, ast.Call) and is_get_backend_call(func.value): - violations.append( - f"{relative.as_posix()}:{node.lineno} calls " - "get_backend(...).transcribe() outside the package dispatcher" - ) - - assert not violations, ( - "Raw-audio STT backend dispatch must pass through " - "solstone.observe.transcribe.transcribe() so the deny-by-default " - "confidential egress gate is the single chokepoint. Move dispatch " - "through the package function instead of calling backend transcribe() " - "directly:\n" + "\n".join(violations) - ) - - def _assert_attestation_failed( exc: AttestationFailedError, reason_code: str = "gateway_unreachable", diff --git a/tests/test_observer_client_bundle.py b/tests/test_observer_client_bundle.py index 799de89d4..7c45f098d 100644 --- a/tests/test_observer_client_bundle.py +++ b/tests/test_observer_client_bundle.py @@ -151,27 +151,6 @@ EXPECTED_GENERATOR_INPUTS = [ ("reason_codes", "solstone/convey/reasons.py", "vocabulary_source"), ] -EXPECTED_GENERATOR_INPUT_IDS = { - "bundle.projection_builder", - "bundle.recording", - "extension.observer_sse_error_frame", - "extension.root_chat_native_subset", - "fragment.chat", - "fragment.link", - "fragment.observer", - "fragment.root", - "openapi.assembler", - "producer.chat_routes", - "producer.chat_sol_initiated_copy", - "producer.chat_sol_initiated_events", - "producer.chat_stream", - "producer.observer_routes", - "producer.observer_utils", - "producer.protocol", - "producer.root_sse", - "reason_codes", -} - EXPECTED_BUNDLE_PAYLOAD_SHA256 = { observer_bundle.CONSUMER_AUDIT_REL: ( "f3562062aeb971c9dc95ae5d14333566b28431758bcd232c33c093757df7bc18" @@ -791,36 +770,6 @@ def test_observer_client_bundle_manifest_file_inventory( assert set(vector["pointer_hashes"]) == set(vector["pointers"]) -def test_observer_client_bundle_pins_exact_generator_inputs( - bundle_files: dict[Path, str], -) -> None: - manifest = _json_file(bundle_files, observer_bundle.MANIFEST_REL) - repo_root = observer_bundle._repo_root(None) - fixture_tree = Path("tests/fixtures/journal") - - assert {item["id"] for item in manifest["generator_inputs"]} == ( - EXPECTED_GENERATOR_INPUT_IDS - ) - assert len(manifest["generator_inputs"]) == 18 - for item in manifest["generator_inputs"]: - rel_path = Path(item["path"]) - assert rel_path != fixture_tree - assert fixture_tree not in rel_path.parents - assert not (repo_root / rel_path).is_dir() - - -def test_observer_client_bundle_pins_non_manifest_payload_hashes( - bundle_files: dict[Path, str], -) -> None: - repo_root = observer_bundle._repo_root(None) - - for rel_path, expected_sha in EXPECTED_BUNDLE_PAYLOAD_SHA256.items(): - assert _sha256_text((repo_root / rel_path).read_text(encoding="utf-8")) == ( - expected_sha - ) - assert _sha256_text(bundle_files[rel_path]) == expected_sha - - def test_observer_client_bundle_old_fixture_tree_absence_and_residue_do_not_affect_outputs( tmp_path: Path, ) -> None: diff --git a/tests/test_preflight.py b/tests/test_preflight.py index 862e9bd41..4ac1e3464 100644 --- a/tests/test_preflight.py +++ b/tests/test_preflight.py @@ -4,8 +4,6 @@ from __future__ import annotations import json -import subprocess -import sys from pathlib import Path from types import SimpleNamespace from unittest.mock import Mock @@ -14,8 +12,6 @@ import pytest from tests.helpers.module_mocks import module_mock -ROOT = Path(__file__).resolve().parent.parent - @pytest.fixture def preflight(): @@ -291,85 +287,3 @@ def test_main_returns_one_when_uv_missing( assert rc == 1 assert payload["summary"]["failed"] >= 1 - - -def stdlib_guard_code(import_body: str) -> str: - return f""" -import builtins -_real = builtins.__import__ -_blocked = {{"numpy", "PIL", "flask"}} -def _guard(name, g=None, l=None, fromlist=(), level=0): - if level == 0 and name.split(".", 1)[0] in _blocked: - raise ModuleNotFoundError(f"No module named {{name.split('.', 1)[0]!r}}") - return _real(name, g, l, fromlist, level) -builtins.__import__ = _guard -import sys -sys.path.insert(0, {str(ROOT)!r}) -{import_body} -""" - - -def test_preflight_runs_under_stdlib_import_guard(): - result = subprocess.run( - [ - sys.executable, - "-c", - stdlib_guard_code( - "from solstone.think import probe\n" - "from solstone.think.preflight import main\n" - 'raise SystemExit(main(["--json"]))' - ), - ], - cwd=ROOT, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode in {0, 1} - assert "ModuleNotFoundError" not in result.stderr - assert "flask" not in result.stderr - - -def test_doctor_fails_under_same_stdlib_import_guard(): - result = subprocess.run( - [ - sys.executable, - "-c", - stdlib_guard_code("from solstone.convey.cli import main\nprint(main)"), - ], - cwd=ROOT, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode != 0 - assert "ModuleNotFoundError" in result.stderr - assert "flask" in result.stderr - - -def test_install_dry_run_runs_preflight_before_uv_sync(): - result = subprocess.run( - ["make", "--dry-run", "-B", "install"], - cwd=ROOT, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode == 0 - lines = result.stdout.splitlines() - preflight_index = next( - index - for index, line in enumerate(lines) - if "python3 scripts/preflight.py" in line - ) - uv_sync_index = next(index for index, line in enumerate(lines) if "uv sync" in line) - assert preflight_index < uv_sync_index - assert any("python3 scripts/preflight.py" in line for line in lines) - assert any("uv sync" in line for line in lines) - assert all("python3 scripts/doctor.py" not in line for line in lines) diff --git a/tests/test_release_install_smoke_distribution_enumeration.py b/tests/test_release_install_smoke_distribution_enumeration.py deleted file mode 100644 index 49d4636d4..000000000 --- a/tests/test_release_install_smoke_distribution_enumeration.py +++ /dev/null @@ -1,451 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -"""Real distribution enumeration coverage for install-proof isolation. - -This is intentionally in the unit lane despite AGENTS.md/CLAUDE.md ยง6's normal -mock-process-boundary rule: it creates local scratch venvs, installs tiny local -wheels with --no-index --no-deps, performs no network access, and touches no -journal state. The install proof needs a real importlib.metadata probe because -Fedora/RHEL venvs can expose one site-packages directory under both lib64 and -lib spellings. Each test chdirs to tmp_path because python -c puts cwd on -sys.path, and the repo root's editable solstone.egg-info would otherwise be -enumerated as a real solstone distribution. -""" - -from __future__ import annotations - -import base64 -import csv -import hashlib -import json -import os -import shlex -import shutil -import subprocess -import sys -import zipfile -from collections import Counter, defaultdict -from collections.abc import Mapping, Sequence -from io import StringIO -from pathlib import Path - -import pytest - -import scripts.check_wheel_contents as wheel_checker -import scripts.release_install_smoke as smoke - - -def _env_python(env_root: Path) -> Path: - if sys.platform == "win32": - return env_root / "Scripts" / "python.exe" - return env_root / "bin" / "python" - - -def _run( - argv: Sequence[Path | str], - *, - cwd: Path, - env: dict[str, str] | None = None, -) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [str(token) for token in argv], - cwd=cwd, - env=env, - capture_output=True, - text=True, - check=False, - ) - - -def _record_hash(content: bytes) -> str: - digest = hashlib.sha256(content).digest() - encoded = base64.urlsafe_b64encode(digest).decode("ascii").rstrip("=") - return f"sha256={encoded}" - - -def _write_py3_wheel( - wheel_dir: Path, - distribution: str, - version: str, - *, - scripts: Mapping[str, bytes] | None = None, -) -> Path: - wheel_dir.mkdir(parents=True, exist_ok=True) - normalized = distribution.replace("-", "_") - dist_info = f"{normalized}-{version}.dist-info" - wheel_path = wheel_dir / f"{normalized}-{version}-py3-none-any.whl" - members = { - f"{dist_info}/METADATA": ( - f"Metadata-Version: 2.1\nName: {distribution}\nVersion: {version}\n".encode() - ), - f"{dist_info}/WHEEL": ( - b"Wheel-Version: 1.0\n" - b"Generator: solstone test\n" - b"Root-Is-Purelib: true\n" - b"Tag: py3-none-any\n" - ), - } - for script_name, script_content in (scripts or {}).items(): - members[f"{normalized}-{version}.data/scripts/{script_name}"] = script_content - rows = [ - f"{name},{_record_hash(content)},{len(content)}" - for name, content in members.items() - ] - rows.append(f"{dist_info}/RECORD,,") - with zipfile.ZipFile(wheel_path, "w") as wheel: - for name, content in members.items(): - info = zipfile.ZipInfo(name) - info.create_system = 3 - info.external_attr = ( - 0o100755 << 16 if ".data/scripts/" in name else 0o100644 << 16 - ) - wheel.writestr(info, content) - wheel.writestr(f"{dist_info}/RECORD", "\n".join(rows) + "\n") - return wheel_path - - -def _env_bin(env_root: Path, name: str) -> Path: - if sys.platform == "win32": - return env_root / "Scripts" / f"{name}.exe" - return env_root / "bin" / name - - -def _script_bytes(env_root: Path, names: Sequence[str]) -> dict[str, bytes]: - return {name: _env_bin(env_root, name).read_bytes() for name in names} - - -def _record_script_paths(wheel_path: Path) -> set[str]: - with zipfile.ZipFile(wheel_path) as wheel: - record_name = next( - name for name in wheel.namelist() if name.endswith(".dist-info/RECORD") - ) - rows = csv.reader(StringIO(wheel.read(record_name).decode("utf-8"))) - return {row[0] for row in rows if ".data/scripts/" in row[0]} - - -def _installed_script_owners( - env_python: Path, - scripts: Sequence[str], - *, - cwd: Path, -) -> dict[str, str]: - script = """ -import csv -import importlib.metadata as metadata -import json -from pathlib import PurePosixPath - -targets = set(json.loads(__import__("os").environ["SCRIPT_NAMES"])) -owners = {} -for dist in metadata.distributions(): - name = dist.metadata.get("Name", "") - path = getattr(dist, "_path", None) - if path is None: - continue - record = path / "RECORD" - if not record.exists(): - continue - with record.open(newline="") as handle: - for row in csv.reader(handle): - if not row: - continue - basename = PurePosixPath(row[0].replace("\\\\", "/")).name - if basename.endswith(".exe"): - basename = basename[:-4] - if basename in targets: - owners.setdefault(basename, []).append(name) -print(json.dumps({key: sorted(value) for key, value in owners.items()}, sort_keys=True)) -""" - result = _run( - (env_python, "-c", script), - cwd=cwd, - env={ - **smoke.SCRUBBED_COMMAND_ENV, - "SCRIPT_NAMES": json.dumps(list(scripts)), - }, - ) - assert result.returncode == 0, result.stderr or result.stdout - raw = json.loads(result.stdout) - return {name: owners[0] for name, owners in raw.items() if len(owners) == 1} - - -def _create_venv(interpreter: Path, env_root: Path) -> bool: - script = ( - "import os, venv; " - "venv.EnvBuilder(with_pip=True, symlinks=False).create(os.environ['ENV_ROOT'])" - ) - env = {**os.environ, "ENV_ROOT": str(env_root)} - result = _run((interpreter, "-c", script), cwd=env_root.parent, env=env) - return result.returncode == 0 - - -def _candidate_interpreters() -> tuple[Path, ...]: - raw = [Path("/usr/bin/python3")] - discovered = shutil.which("python3") - if discovered is not None: - raw.append(Path(discovered)) - raw.append(Path(sys.executable)) - - selected: list[Path] = [] - seen: set[str] = set() - for candidate in raw: - if not candidate.exists() or not os.access(candidate, os.X_OK): - continue - real = os.path.realpath(candidate) - if real in seen: - continue - seen.add(real) - selected.append(candidate) - return tuple(selected) - - -def _site_paths(env_python: Path, *, cwd: Path) -> tuple[str, ...] | None: - script = ( - "import json, sys; " - "print(json.dumps([path for path in sys.path if 'site-packages' in path]))" - ) - result = _run( - (env_python, "-c", script), - cwd=cwd, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - if result.returncode != 0: - return None - return tuple(json.loads(result.stdout)) - - -def _has_dual_spelling_site_paths(paths: Sequence[str]) -> bool: - by_realpath: dict[str, set[str]] = defaultdict(set) - for path in paths: - by_realpath[os.path.realpath(path)].add(path) - return any(len(spellings) > 1 for spellings in by_realpath.values()) - - -def _select_dual_spelling_venv(tmp_path: Path) -> Path: - for index, interpreter in enumerate(_candidate_interpreters()): - env_root = tmp_path / f"probe-{index}" - if not _create_venv(interpreter, env_root): - continue - paths = _site_paths(_env_python(env_root), cwd=tmp_path) - if paths is not None and _has_dual_spelling_site_paths(paths): - return env_root - - pytest.skip( - "no candidate interpreter produced dual-spelling site-packages topology" - ) - - -def _wrapper_for_pythonpath( - path: Path, - site_paths: Sequence[Path], -) -> Path: - wrapper = path / "python-wrapper" - pythonpath = ":".join(str(site_path) for site_path in site_paths) - wrapper.write_text( - "#!/bin/sh\n" - f"PYTHONPATH={shlex.quote(pythonpath)} " - f'exec {shlex.quote(sys.executable)} -S "$@"\n' - ) - wrapper.chmod(0o755) - return wrapper - - -def _write_dist_info(site_path: Path, distribution: str, version: str) -> Path: - normalized = distribution.replace("-", "_") - dist_info = site_path / f"{normalized}-{version}.dist-info" - dist_info.mkdir(parents=True) - (dist_info / "METADATA").write_text( - f"Metadata-Version: 2.1\nName: {distribution}\nVersion: {version}\n" - ) - return dist_info - - -def _distribution_pairs( - observed: Sequence[Mapping[str, str]], -) -> Counter[tuple[str, str]]: - return Counter((str(entry["name"]), str(entry["version"])) for entry in observed) - - -def test_solstone_distributions_deduplicates_real_dual_spelling_venv( - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, -) -> None: - monkeypatch.chdir(tmp_path) - env_root = _select_dual_spelling_venv(tmp_path) - env_python = _env_python(env_root) - wheel_dir = tmp_path / "wheels" - expected = { - ("solstone-probe-one", "0.1.0"), - ("solstone-probe-two", "0.2.0"), - ("solstone-probe-three", "0.3.0"), - ("solstone-probe-four", "0.4.0"), - } - wheels = [ - _write_py3_wheel(wheel_dir, distribution, version) - for distribution, version in sorted(expected) - ] - - result = _run( - (env_python, "-m", "pip", "install", "--no-index", "--no-deps", *wheels), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - - assert result.returncode == 0, result.stderr or result.stdout - observed = smoke._solstone_distributions(env_python) - assert len(observed) == 4 - assert _distribution_pairs(observed) == Counter({pair: 1 for pair in expected}) - - -def test_solstone_distributions_deduplicates_symlinked_dist_info( - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, -) -> None: - monkeypatch.chdir(tmp_path) - site = tmp_path / "site" - alias = tmp_path / "site-alias" - _write_dist_info(site, "solstone-symlinked", "1.0.0") - alias.symlink_to(site, target_is_directory=True) - wrapper = _wrapper_for_pythonpath(tmp_path, (site, alias)) - - observed = smoke._solstone_distributions(wrapper) - - assert observed == ({"name": "solstone-symlinked", "version": "1.0.0"},) - - -def test_solstone_distributions_preserves_distinct_duplicate_dist_infos( - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, -) -> None: - monkeypatch.chdir(tmp_path) - site_one = tmp_path / "site-one" - site_two = tmp_path / "site-two" - _write_dist_info(site_one, "solstone", "1.0.0") - _write_dist_info(site_two, "solstone", "1.0.0") - wrapper = _wrapper_for_pythonpath(tmp_path, (site_one, site_two)) - - observed = smoke._solstone_distributions(wrapper) - - assert len(observed) == 2 - assert _distribution_pairs(observed) == Counter({("solstone", "1.0.0"): 2}) - - -@pytest.mark.parametrize( - "target", - ("linux-x86_64-musl", "linux-aarch64-musl", "macos-arm64"), -) -@pytest.mark.parametrize("reverse_order", (False, True)) -def test_script_ownership_is_order_independent_and_reinstall_stable( - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, - target: str, - reverse_order: bool, -) -> None: - monkeypatch.chdir(tmp_path) - env_root = tmp_path / f"env-{target}-{'reverse' if reverse_order else 'forward'}" - if not _create_venv(Path(sys.executable), env_root): - pytest.skip("could not create scratch venv") - wheel_dir = tmp_path / "wheels" - version = "1.2.3" - root_scripts = { - name: f"#!/bin/sh\necho 'sol (solstone) {version}'\n".encode() - for name in wheel_checker.ROOT_LAUNCHER_NAMES - } - core_scripts = { - name: f"#!/bin/sh\necho solstone-core {version}\n".encode() - for name in wheel_checker.CORE_SCRIPT_NAMES - } - core_wheel = _write_py3_wheel( - wheel_dir, - "solstone-core", - version, - scripts=core_scripts, - ) - base_wheel = _write_py3_wheel( - wheel_dir, - "solstone", - version, - scripts=root_scripts, - ) - - overlap = _record_script_paths(core_wheel) & _record_script_paths(base_wheel) - assert overlap == set() - - env_python = _env_python(env_root) - install_order = ( - (core_wheel, base_wheel) if reverse_order else (base_wheel, core_wheel) - ) - result = _run( - (env_python, "-m", "pip", "install", "--no-index", "--no-deps", *install_order), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - assert result.returncode == 0, result.stderr or result.stdout - - root_names = wheel_checker.ROOT_LAUNCHER_NAMES - core_names = wheel_checker.CORE_SCRIPT_NAMES - script_names = root_names + core_names - expected_owners = { - **{name: "solstone" for name in root_names}, - **{name: "solstone-core" for name in core_names}, - } - assert ( - _installed_script_owners(env_python, script_names, cwd=tmp_path) - == expected_owners - ) - before_core = _script_bytes(env_root, core_names) - for name in script_names: - output = _run((_env_bin(env_root, name), "--version"), cwd=tmp_path) - assert output.returncode == 0 - assert output.stdout.strip().endswith(version) - - reinstall = _run( - ( - env_python, - "-m", - "pip", - "install", - "--force-reinstall", - "--no-index", - "--no-deps", - core_wheel, - ), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - assert reinstall.returncode == 0, reinstall.stderr or reinstall.stdout - assert _script_bytes(env_root, core_names) == before_core - assert ( - _installed_script_owners(env_python, script_names, cwd=tmp_path) - == expected_owners - ) - - uninstall_base = _run( - (env_python, "-m", "pip", "uninstall", "-y", "solstone"), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - assert uninstall_base.returncode == 0, ( - uninstall_base.stderr or uninstall_base.stdout - ) - assert not any(_env_bin(env_root, name).exists() for name in root_names) - assert all(_env_bin(env_root, name).exists() for name in core_names) - - reinstall_base = _run( - (env_python, "-m", "pip", "install", "--no-index", "--no-deps", base_wheel), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - assert reinstall_base.returncode == 0, ( - reinstall_base.stderr or reinstall_base.stdout - ) - uninstall_core = _run( - (env_python, "-m", "pip", "uninstall", "-y", "solstone-core"), - cwd=tmp_path, - env=dict(smoke.SCRUBBED_COMMAND_ENV), - ) - assert uninstall_core.returncode == 0, ( - uninstall_core.stderr or uninstall_core.stdout - ) - assert not any(_env_bin(env_root, name).exists() for name in core_names) - assert all(_env_bin(env_root, name).exists() for name in root_names) diff --git a/tests/test_render_packaging.py b/tests/test_render_packaging.py deleted file mode 100644 index b04e11ccb..000000000 --- a/tests/test_render_packaging.py +++ /dev/null @@ -1,493 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import importlib.util -import os -import subprocess -import sys -import tomllib -from pathlib import Path -from textwrap import dedent - -import pytest - -from solstone.think.probe import ( - SOLSTONE_CORE_PLATFORM_MARKERS, - solstone_core_speakers_analyze_marker_pins, - solstone_core_unsupported_platform_pin, -) - -SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "render_packaging.py" -SPEC = importlib.util.spec_from_file_location("render_packaging", SCRIPT) -assert SPEC is not None -render_packaging = importlib.util.module_from_spec(SPEC) -assert SPEC.loader is not None -SPEC.loader.exec_module(render_packaging) - - -def test_script_runs_without_site_packages_from_outside_repo(tmp_path: Path) -> None: - env = os.environ.copy() - env.pop("PYTHONPATH", None) - env.pop("VIRTUAL_ENV", None) - - result = subprocess.run( - [sys.executable, "-S", "-E", str(SCRIPT), "--check"], - cwd=tmp_path, - env=env, - capture_output=True, - text=True, - check=False, - timeout=15, - ) - - assert result.returncode == 0, result.stderr - assert "packaging metadata is up to date" in result.stdout - - -def test_live_lock_authorities_match_root_project_version() -> None: - root = SCRIPT.parents[1] - root_pyproject = tomllib.loads( - (root / "pyproject.toml").read_text(encoding="utf-8") - ) - root_version = root_pyproject["project"]["version"] - - cargo_workspace = tomllib.loads( - (root / "core" / "Cargo.toml").read_text(encoding="utf-8") - ) - assert cargo_workspace["workspace"]["package"]["version"] == root_version - cargo_member_names = { - tomllib.loads( - (root / "core" / member / "Cargo.toml").read_text(encoding="utf-8") - )["package"]["name"] - for member in cargo_workspace["workspace"]["members"] - } - cargo_lock = tomllib.loads( - (root / "core" / "Cargo.lock").read_text(encoding="utf-8") - ) - cargo_lock_versions = { - package["name"]: package["version"] - for package in cargo_lock["package"] - if package["name"] in cargo_member_names - } - assert cargo_lock_versions == { - name: root_version for name in sorted(cargo_member_names) - } - - uv_lock = tomllib.loads((root / "uv.lock").read_text(encoding="utf-8")) - uv_workspace_names = { - "solstone", - "solstone-core", - "solstone-journal", - "solstone-journal-cuda", - } - uv_lock_versions = { - package["name"]: package["version"] - for package in uv_lock["package"] - if package["name"] in uv_workspace_names - } - assert uv_lock_versions == { - name: root_version for name in sorted(uv_workspace_names) - } - assert not any( - package["name"] == "solstone-core-speakers-analyze" - for package in uv_lock["package"] - ) - overrides = { - override["name"]: override for override in uv_lock["manifest"]["overrides"] - } - assert ( - overrides["solstone-core-unsupported-platform"]["specifier"] - == f"=={root_version}" - ) - assert overrides["solstone-journal-host"]["specifier"] == "==0.7.0" - helper_override = overrides["solstone-core-speakers-analyze"] - assert helper_override["marker"] == "python_full_version < '3.12'" - assert helper_override["editable"] == "packages/solstone-core-speakers-analyze" - assert ( - f"solstone-core-speakers-analyze=={root_version}; python_version < '3.12'" - in root_pyproject["tool"]["uv"]["override-dependencies"] - ) - - -def test_journal_host_excludes_sklearn_and_scipy_with_dev_sklearn_only() -> None: - root = SCRIPT.parents[1] - root_pyproject = tomllib.loads( - (root / "pyproject.toml").read_text(encoding="utf-8") - ) - - journal_host = root_pyproject["project"]["optional-dependencies"]["journal-host"] - dev_group = root_pyproject["dependency-groups"]["dev"] - - assert not any(dep.startswith("scikit-learn") for dep in journal_host) - assert not any(dep.startswith("scipy") for dep in journal_host) - assert [dep for dep in dev_group if dep.startswith("scikit-learn")] == [ - "scikit-learn>=1.3" - ] - - -def _write(path: Path, text: str) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(dedent(text).lstrip(), encoding="utf-8") - - -def _fixture_root(tmp_path: Path, *, root_version: str = "1.2.3") -> Path: - core_pins = "\n".join( - f' "solstone-core==0.0.1; {marker}",' - for marker in SOLSTONE_CORE_PLATFORM_MARKERS - ) - unsupported_pin = solstone_core_unsupported_platform_pin("0.0.1") - speakers_analyze_pins = "\n".join( - f' "{pin}",' - for pin in solstone_core_speakers_analyze_marker_pins("0.0.1") - ) - _write( - tmp_path / "pyproject.toml", - f""" - [project] - name = "solstone" - version = "{root_version}" - dependencies = [ - {core_pins} - "{unsupported_pin}", - ] - - [project.optional-dependencies] - journal-host = [ - "solstone-journal-models==1.0.0", - ] - journal = ["solstone-journal-host==0.7.0"] - journal-cuda = ["solstone-journal-host==0.7.0"] - - [tool.uv] - override-dependencies = [ - "solstone-core-unsupported-platform==0.0.1; python_version < '3.12'", - "solstone-core-speakers-analyze==0.0.1; python_version < '3.12'", - ] - """, - ) - for package_name in ("solstone-journal", "solstone-journal-cuda"): - _write( - tmp_path / "packages" / package_name / "pyproject.toml", - f""" - [project] - name = "{package_name}" - version = "0.0.1" - dependencies = [ - "solstone[journal-host]==0.0.1", -{speakers_analyze_pins} - ] - """, - ) - _write( - tmp_path / "packages" / "solstone-core" / "pyproject.toml", - """ - [build-system] - requires = ["maturin==1.14.1"] - build-backend = "maturin" - - [project] - name = "solstone-core" - version = "0.0.1" - - [tool.maturin] - bindings = "bin" - manifest-path = "../../core/crates/solstone-core/Cargo.toml" - profile = "release" - strip = true - """, - ) - _write( - tmp_path / "packages" / "solstone-core-speakers-analyze" / "pyproject.toml", - """ - [build-system] - requires = ["maturin==1.14.1"] - build-backend = "maturin" - - [project] - name = "solstone-core-speakers-analyze" - version = "0.0.1" - - [tool.maturin] - bindings = "bin" - manifest-path = "../../core/crates/solstone-core-speakers-analyze/Cargo.toml" - profile = "release" - strip = true - data = "wheel-data" - """, - ) - _write( - tmp_path - / "scripts" - / "solstone-core-unsupported-platform-tombstone" - / "setup.py", - """ - TOMBSTONE_VERSION = "0.0.1" - """, - ) - _write( - tmp_path / "core" / "Cargo.toml", - """ - [workspace] - members = ["crates/solstone-core", "crates/solstone-core-cli", "crates/solstone-core-journal"] - resolver = "3" - - [workspace.package] - version = "0.0.1" - edition = "2024" - rust-version = "1.95" - license = "AGPL-3.0-only" - - [workspace.dependencies] - solstone-core-cli = { path = "crates/solstone-core-cli" } - """, - ) - _write( - tmp_path / "core" / "crates" / "solstone-core" / "Cargo.toml", - """ - [package] - name = "solstone-core" - version.workspace = true - edition.workspace = true - rust-version.workspace = true - license.workspace = true - """, - ) - _write( - tmp_path / "core" / "crates" / "solstone-core-cli" / "Cargo.toml", - """ - [package] - name = "solstone-core-cli" - version.workspace = true - edition.workspace = true - rust-version.workspace = true - license.workspace = true - """, - ) - _write( - tmp_path / "core" / "crates" / "solstone-core-journal" / "Cargo.toml", - """ - [package] - name = "solstone-core-journal" - version.workspace = true - edition.workspace = true - rust-version.workspace = true - license.workspace = true - """, - ) - _write_cargo_lock(tmp_path, _cargo_lock_text()) - return tmp_path - - -def _write_cargo_lock(root: Path, text: str) -> None: - _write(root / "core" / "Cargo.lock", text) - - -def _cargo_lock_text( - *, - cli_block: str | None = None, - journal_block: str | None = None, -) -> str: - if cli_block is None: - cli_block = """ - [[package]] - name = "solstone-core-cli" - version = "0.0.1" - """ - if journal_block is None: - journal_block = """ - [[package]] - name = "solstone-core-journal" - version = "0.0.1" - """ - core_block = dedent( - """ - # This file is automatically @generated by Cargo. - # It is not intended for manual editing. - version = 4 - - [[package]] - name = "solstone-core" - version = "0.0.1" - dependencies = [ - "solstone-core-cli", - "solstone-core-journal", - ] - """ - ).lstrip() - return ( - f"{core_block}\n" - f"{dedent(cli_block).strip()}\n\n" - f"{dedent(journal_block).strip()}\n" - ) - - -def test_render_updates_python_leaves_and_cargo_lockstep(tmp_path: Path) -> None: - root = _fixture_root(tmp_path, root_version="2.3.4") - - rendered = render_packaging.render(root) - - assert 'version = "2.3.4"' in rendered[root / "core" / "Cargo.toml"] - assert ( - 'name = "solstone-core"\nversion = "2.3.4"' - in rendered[root / "core" / "Cargo.lock"] - ) - assert ( - 'name = "solstone-core-cli"\nversion = "2.3.4"' - in rendered[root / "core" / "Cargo.lock"] - ) - assert ( - 'name = "solstone-core-journal"\nversion = "2.3.4"' - in rendered[root / "core" / "Cargo.lock"] - ) - for package_name in ("solstone-journal", "solstone-journal-cuda"): - leaf = rendered[root / "packages" / package_name / "pyproject.toml"] - assert 'version = "2.3.4"' in leaf - assert '"solstone[journal-host]==2.3.4"' in leaf - for pin in solstone_core_speakers_analyze_marker_pins("2.3.4"): - assert f'"{pin}"' in leaf - core_leaf = rendered[root / "packages" / "solstone-core" / "pyproject.toml"] - assert 'version = "2.3.4"' in core_leaf - assert "solstone[journal-host]==" not in core_leaf - speakers_analyze_leaf = rendered[ - root / "packages" / "solstone-core-speakers-analyze" / "pyproject.toml" - ] - assert 'version = "2.3.4"' in speakers_analyze_leaf - assert "solstone[journal-host]==" not in speakers_analyze_leaf - root_pyproject = rendered[root / "pyproject.toml"] - for marker in SOLSTONE_CORE_PLATFORM_MARKERS: - assert f'"solstone-core==2.3.4; {marker}"' in root_pyproject - assert f'"{solstone_core_unsupported_platform_pin("2.3.4")}"' in root_pyproject - assert ( - '"solstone-core-unsupported-platform==2.3.4; python_version < ' - "'3.12'\"" in root_pyproject - ) - assert ( - '"solstone-core-speakers-analyze==2.3.4; python_version < ' - "'3.12'\"" in root_pyproject - ) - assert '"solstone-journal-models==1.0.0"' in root_pyproject - tombstone = rendered[ - root / "scripts" / "solstone-core-unsupported-platform-tombstone" / "setup.py" - ] - assert 'TOMBSTONE_VERSION = "2.3.4"' in tombstone - - -def test_check_reports_synthetic_packaging_drift( - tmp_path: Path, - capsys: pytest.CaptureFixture[str], -) -> None: - root = _fixture_root(tmp_path, root_version="2.3.4") - - rc = render_packaging.check(root) - - assert rc == 1 - out = capsys.readouterr().out - assert "packaging metadata is stale" in out - assert "drifted: pyproject.toml" in out - assert "drifted: packages/solstone-core/pyproject.toml" in out - assert "drifted: packages/solstone-core-speakers-analyze/pyproject.toml" in out - assert ( - "drifted: scripts/solstone-core-unsupported-platform-tombstone/setup.py" in out - ) - assert "drifted: core/Cargo.lock" in out - - -def test_render_raises_when_cargo_lock_is_missing_member_block(tmp_path: Path) -> None: - root = _fixture_root(tmp_path) - _write_cargo_lock(root, _cargo_lock_text(cli_block="")) - - with pytest.raises(render_packaging.PackagingRenderError, match="missing"): - render_packaging.render(root) - - -def test_render_raises_when_leaf_speakers_analyze_pin_is_missing( - tmp_path: Path, -) -> None: - root = _fixture_root(tmp_path) - leaf_path = root / "packages" / "solstone-journal" / "pyproject.toml" - pin = solstone_core_speakers_analyze_marker_pins("0.0.1")[0] - line = f' "{pin}",\n' - text = leaf_path.read_text(encoding="utf-8") - leaf_path.write_text(text.replace(line, "", 1), encoding="utf-8") - - with pytest.raises( - render_packaging.PackagingRenderError, - match="speakers-analyze", - ): - render_packaging.render(root) - - -def test_render_raises_when_leaf_speakers_analyze_pin_is_duplicated( - tmp_path: Path, -) -> None: - root = _fixture_root(tmp_path) - leaf_path = root / "packages" / "solstone-journal" / "pyproject.toml" - pin = solstone_core_speakers_analyze_marker_pins("0.0.1")[0] - line = f' "{pin}",\n' - text = leaf_path.read_text(encoding="utf-8") - leaf_path.write_text(text.replace(line, line + line, 1), encoding="utf-8") - - with pytest.raises( - render_packaging.PackagingRenderError, - match="speakers-analyze", - ): - render_packaging.render(root) - - -def test_render_raises_when_cargo_lock_member_block_has_no_version( - tmp_path: Path, -) -> None: - root = _fixture_root(tmp_path) - _write_cargo_lock( - root, - _cargo_lock_text( - cli_block=""" - [[package]] - name = "solstone-core-cli" - """, - ), - ) - - with pytest.raises(render_packaging.PackagingRenderError, match="version line"): - render_packaging.render(root) - - -def test_render_raises_when_cargo_lock_member_block_has_source( - tmp_path: Path, -) -> None: - root = _fixture_root(tmp_path) - _write_cargo_lock( - root, - _cargo_lock_text( - cli_block=""" - [[package]] - name = "solstone-core-cli" - version = "0.0.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - """, - ), - ) - - with pytest.raises(render_packaging.PackagingRenderError, match="source-less"): - render_packaging.render(root) - - -def test_render_raises_when_cargo_lock_has_duplicate_member_block( - tmp_path: Path, -) -> None: - root = _fixture_root(tmp_path) - duplicate = """ - [[package]] - name = "solstone-core-cli" - version = "0.0.1" - - [[package]] - name = "solstone-core-cli" - version = "0.0.1" - """ - _write_cargo_lock(root, _cargo_lock_text(cli_block=duplicate)) - - with pytest.raises(render_packaging.PackagingRenderError, match="duplicate"): - render_packaging.render(root) diff --git a/tests/test_repo_inventory.py b/tests/test_repo_inventory.py deleted file mode 100644 index 4b0e88f23..000000000 --- a/tests/test_repo_inventory.py +++ /dev/null @@ -1,283 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import os -from pathlib import Path - -import pytest - -from tests._repo_inventory import ( - EXCLUDED_RUNTIME_DIR_NAMES, - assert_inventory_unchanged, - format_inventory_diff, - repository_inventory, -) - -DEPTHS = ("root", "nested") -EXCLUDED_NAMES = tuple(sorted(EXCLUDED_RUNTIME_DIR_NAMES)) -SIMILAR_NAMES = ("not__pycache__data", "__pycache__.bak", ".venvish", ".gitignore") - - -def _subject_path(root: Path, name: str, depth: str) -> Path: - if depth == "root": - return root / name - parent = root / "ordinary" / "nested" - parent.mkdir(parents=True, exist_ok=True) - return parent / name - - -def _assert_diff_mentions(diff: str, rel_path: str, *fields: str) -> None: - assert rel_path in diff - for field in fields: - assert f"{field}:" in diff - - -@pytest.mark.parametrize("cache_name", EXCLUDED_NAMES) -@pytest.mark.parametrize("depth", DEPTHS) -@pytest.mark.parametrize("operation", ("create", "mutate", "remove")) -def test_excluded_cache_file_lifecycle_is_ignored( - tmp_path: Path, - cache_name: str, - depth: str, - operation: str, -) -> None: - cache_dir = _subject_path(tmp_path, cache_name, depth) - cache_dir.mkdir(parents=True) - cache_file = cache_dir / "entry.pyc" - if operation in {"mutate", "remove"}: - cache_file.write_bytes(b"before\n") - - before = repository_inventory(tmp_path) - if operation == "create": - cache_file.write_bytes(b"after\n") - elif operation == "mutate": - cache_file.write_bytes(b"after changed\n") - else: - cache_file.unlink() - after = repository_inventory(tmp_path) - - assert_inventory_unchanged(before, after) - - -@pytest.mark.parametrize("cache_name", EXCLUDED_NAMES) -@pytest.mark.parametrize("depth", DEPTHS) -def test_excluded_cache_directory_first_creation_is_ignored( - tmp_path: Path, - cache_name: str, - depth: str, -) -> None: - cache_dir = _subject_path(tmp_path, cache_name, depth) - assert not cache_dir.exists() - - before = repository_inventory(tmp_path) - cache_dir.mkdir(parents=True) - (cache_dir / "entry.pyc").write_bytes(b"created with cache dir\n") - after = repository_inventory(tmp_path) - - assert_inventory_unchanged(before, after) - - -@pytest.mark.parametrize("name", EXCLUDED_NAMES) -def test_excluded_basename_regular_file_stays_visible( - tmp_path: Path, - name: str, -) -> None: - path = tmp_path / name - path.write_text("before\n", encoding="utf-8") - - before = repository_inventory(tmp_path) - assert before[name].kind == "file" - path.write_text("after changed\n", encoding="utf-8") - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, name, "size") - - -@pytest.mark.parametrize("name", EXCLUDED_NAMES) -def test_excluded_basename_symlink_stays_visible( - tmp_path: Path, - name: str, -) -> None: - path = tmp_path / name - os.symlink("target-a", path) - - before = repository_inventory(tmp_path) - path.unlink() - os.symlink("target-b", path) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, name, "target") - - -@pytest.mark.parametrize("name", EXCLUDED_NAMES) -def test_excluded_basename_fifo_stays_visible(tmp_path: Path, name: str) -> None: - path = tmp_path / name - os.mkfifo(path) - - before = repository_inventory(tmp_path) - current_mode = path.lstat().st_mode & 0o777 - path.chmod(0o600 if current_mode != 0o600 else 0o644) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, name, "mode") - - -@pytest.mark.parametrize("name", EXCLUDED_NAMES) -def test_excluded_basename_symlink_is_not_followed( - tmp_path: Path, - name: str, -) -> None: - root = tmp_path / "root" - external = tmp_path / "external" - root.mkdir() - external.mkdir() - (external / "external.txt").write_text("outside\n", encoding="utf-8") - os.symlink(external, root / name) - - inventory = repository_inventory(root) - - assert inventory[name].kind == "symlink" - assert all(not path.startswith(f"{name}/") for path in inventory) - - -@pytest.mark.parametrize("name", SIMILAR_NAMES) -def test_similar_but_different_names_stay_visible( - tmp_path: Path, - name: str, -) -> None: - visible_dir = tmp_path / name - visible_dir.mkdir() - child = visible_dir / "child.txt" - child.write_text("before\n", encoding="utf-8") - - before = repository_inventory(tmp_path) - assert name in before - assert f"{name}/child.txt" in before - child.write_text("after changed\n", encoding="utf-8") - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, f"{name}/child.txt", "size") - - -@pytest.mark.parametrize("operation", ("create", "mutate", "remove")) -def test_ordinary_file_writes_are_reported( - tmp_path: Path, - operation: str, -) -> None: - path = tmp_path / "ordinary.txt" - if operation in {"mutate", "remove"}: - path.write_text("before\n", encoding="utf-8") - - before = repository_inventory(tmp_path) - if operation == "create": - path.write_text("created\n", encoding="utf-8") - elif operation == "mutate": - path.write_text("after changed\n", encoding="utf-8") - else: - path.unlink() - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - assert "ordinary.txt" in diff - assert {"create": "added:", "mutate": "changed:", "remove": "removed:"}[ - operation - ] in diff - - -def test_same_length_rewrite_with_mtime_restored_is_reported_by_ctime( - tmp_path: Path, -) -> None: - path = tmp_path / "same-length.txt" - path.write_text("aaaa\n", encoding="utf-8") - original_stat = path.stat() - before = repository_inventory(tmp_path) - - path.write_text("bbbb\n", encoding="utf-8") - os.utime(path, ns=(original_stat.st_atime_ns, original_stat.st_mtime_ns)) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, "same-length.txt", "ctime_ns") - - -def test_regular_file_chmod_only_is_reported(tmp_path: Path) -> None: - path = tmp_path / "mode.txt" - path.write_text("content\n", encoding="utf-8") - - before = repository_inventory(tmp_path) - path.chmod(0o600) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, "mode.txt", "mode") - - -def test_real_directory_chmod_only_is_reported_without_directory_timestamps( - tmp_path: Path, -) -> None: - path = tmp_path / "directory" - path.mkdir() - - before = repository_inventory(tmp_path) - path.chmod(0o700) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, "directory", "mode") - assert "mtime_ns" not in diff - assert "ctime_ns" not in diff - - -@pytest.mark.parametrize("operation", ("create", "remove")) -def test_empty_non_cache_directory_create_and_remove_are_reported( - tmp_path: Path, - operation: str, -) -> None: - path = tmp_path / "empty-dir" - if operation == "remove": - path.mkdir() - - before = repository_inventory(tmp_path) - if operation == "create": - path.mkdir() - else: - path.rmdir() - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - assert "empty-dir" in diff - assert {"create": "added:", "remove": "removed:"}[operation] in diff - - -def test_special_entry_appearance_is_reported(tmp_path: Path) -> None: - before = repository_inventory(tmp_path) - os.mkfifo(tmp_path / "ordinary-fifo") - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - assert "ordinary-fifo" in diff - assert "kind='fifo'" in diff - - -def test_symlink_target_replacement_is_reported(tmp_path: Path) -> None: - path = tmp_path / "ordinary-link" - os.symlink("target-a", path) - - before = repository_inventory(tmp_path) - path.unlink() - os.symlink("target-b", path) - after = repository_inventory(tmp_path) - - diff = format_inventory_diff(before, after) - _assert_diff_mentions(diff, "ordinary-link", "target") - - -def test_root_itself_is_not_inventoried(tmp_path: Path) -> None: - assert "" not in repository_inventory(tmp_path) - assert "." not in repository_inventory(tmp_path) diff --git a/tests/test_responsiveness_wiring.py b/tests/test_responsiveness_wiring.py deleted file mode 100644 index f6e549e5d..000000000 --- a/tests/test_responsiveness_wiring.py +++ /dev/null @@ -1,237 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import ast -import asyncio -import io -from pathlib import Path -from types import SimpleNamespace -from unittest.mock import AsyncMock, MagicMock - -import pytest -from PIL import Image - -import solstone.think.models as models_module -from solstone.think.responsiveness import ( - NON_RESPONSIVE_OUTPUT_MESSAGE, - NON_RESPONSIVE_REASON_CODE, - NonResponsiveOutputError, -) - -_REFUSAL = "I cannot describe this screen." -_USAGE = { - "input_tokens": 1, - "output_tokens": 1, - "total_tokens": 2, -} - - -def _png_bytes() -> bytes: - image_bytes = io.BytesIO() - Image.new("RGB", (8, 8), "white").save(image_bytes, format="PNG") - return image_bytes.getvalue() - - -def _describe_frame(frame_id: int, frame_bytes: bytes) -> dict: - return { - "frame_id": frame_id, - "timestamp": float(frame_id), - "frame_bytes": frame_bytes, - "aruco": None, - } - - -def _describe_processor(video_path: Path, frames: list[dict], monkeypatch) -> object: - from solstone.observe import describe as describe_module - - processor = describe_module.VideoProcessor.__new__(describe_module.VideoProcessor) - processor.video_path = video_path - processor.first_hash = None - processor.last_hash = None - processor.qualified_count = len(frames) - processor.qualified_frames = [] - monkeypatch.setattr(processor, "process", lambda: frames) - return processor - - -def _declining_result() -> dict: - return { - "text": _REFUSAL, - "model": "provider-model", - "finish_reason": "stop", - "usage": dict(_USAGE), - } - - -def _install_declining_provider(monkeypatch: pytest.MonkeyPatch) -> SimpleNamespace: - import solstone.think.providers as providers_package - from solstone.think import batch as batch_module - - provider_module = SimpleNamespace( - run_generate=MagicMock(return_value=_declining_result()), - run_agenerate=AsyncMock(return_value=_declining_result()), - ) - monkeypatch.setattr( - models_module, - "resolve_provider", - lambda _interface: ("fake", "provider-model"), - ) - monkeypatch.setattr( - providers_package, - "get_provider_module", - lambda _provider: provider_module, - ) - monkeypatch.setattr( - batch_module, - "resolve_provider", - lambda _interface: ("fake", "provider-model"), - ) - return provider_module - - -def _collect_provider_interface_call_sites() -> set[tuple[str, str, str]]: - root_paths = [Path("solstone"), Path("core"), Path("packages"), Path("observers")] - call_sites: set[tuple[str, str, str]] = set() - for root in root_paths: - if not root.exists(): - continue - for path in root.rglob("*.py"): - if "tests" in path.parts: - continue - tree = ast.parse(path.read_text(encoding="utf-8")) - parents: dict[ast.AST, ast.AST] = {} - for node in ast.walk(tree): - for child in ast.iter_child_nodes(node): - parents[child] = node - for node in ast.walk(tree): - if not isinstance(node, ast.Call): - continue - func = node.func - call_name = None - if isinstance(func, ast.Attribute): - call_name = func.attr - elif isinstance(func, ast.Name): - call_name = func.id - if call_name is None or not call_name.endswith( - ("run_generate", "run_agenerate") - ): - continue - owner = "module" - current = node - while current in parents: - current = parents[current] - if isinstance(current, ast.FunctionDef | ast.AsyncFunctionDef): - owner = current.name - break - if path == Path("solstone/think/models.py"): - continue - if owner in {"run_generate", "run_agenerate"}: - continue - call_sites.add((str(path), owner, call_name)) - return call_sites - - -def test_generate_provider_calls_outside_gate_are_only_known_probes(): - assert _collect_provider_interface_call_sites() == { - ("solstone/think/providers/openhands.py", "_probe", "_run_generate"), - ("solstone/think/providers/local.py", "validate_key", "run_generate"), - } - - -def test_no_second_non_responsive_signal_table(): - identifiers = [ - "_NON_RESPONSIVE_" + suffix for suffix in ("NEGATION_HEADS", "LEAD_INS") - ] - matches: set[Path] = set() - for path in Path("solstone").rglob("*.py"): - text = path.read_text(encoding="utf-8") - if any(identifier in text for identifier in identifiers): - matches.add(path) - - assert matches == {Path("solstone/think/responsiveness.py")} - - -def test_no_per_path_guard_non_responsive_property(tmp_path, monkeypatch): - _install_declining_provider(monkeypatch) - - import solstone.think.providers as providers_package - from solstone.observe import describe as describe_module - from solstone.think import talents - from solstone.think.importers import documents, images - - provider_module = providers_package.get_provider_module("fake") - - with pytest.raises(NonResponsiveOutputError): - images._describe_image(Image.new("RGB", (8, 8), "red")) - - raster_path = tmp_path / "page.png" - Image.new("RGB", (8, 8), "white").save(raster_path) - document_outcome = documents._generate_for_page( - prompt="describe this page", - raster_path=raster_path, - context="import.document.describe", - stats=documents._RenderStats(), - ) - assert document_outcome.text is None - assert document_outcome.reason - - monkeypatch.setattr(talents, "_read_runtime_fingerprint", lambda: None) - events: list[dict] = [] - config = { - "name": "responsiveness-property", - "output": "md", - "output_path": str(tmp_path / "talent.md"), - "prompt": "describe the screen", - } - asyncio.run(talents._execute_generate(config, events.append)) - assert not (tmp_path / "talent.md").exists() - assert [event.get("event") for event in events] == ["error"] - assert events[0]["reason_code"] == NON_RESPONSIVE_REASON_CODE - - provider_module.run_agenerate = AsyncMock( - side_effect=[ - _declining_result(), - { - "text": ( - '{"visual_description":"A code editor is open.",' - '"primary":"code","secondary":"none","overlap":true}' - ), - "model": "provider-model", - "finish_reason": "stop", - }, - ] - ) - video_path = ( - tmp_path / "chronicle" / "20250101" / "default" / "143022_300" / "screen.webm" - ) - video_path.parent.mkdir(parents=True) - video_path.write_text("video", encoding="utf-8") - frame_bytes = _png_bytes() - processor = _describe_processor( - video_path, - [_describe_frame(1, frame_bytes), _describe_frame(2, frame_bytes)], - monkeypatch, - ) - monkeypatch.setattr(describe_module, "callosum_send", lambda *args, **kwargs: True) - monkeypatch.setattr( - describe_module, - "select_frames_for_extraction", - lambda *_args, **_kwargs: [], - ) - output_path = video_path.with_suffix(".jsonl") - - asyncio.run( - processor.process_with_vision( - max_concurrent=1, - output_path=output_path, - work_key="20250101/143022_300/screen", - ) - ) - - rows = [ - line for line in output_path.read_text(encoding="utf-8").splitlines() if line - ] - assert provider_module.run_agenerate.await_count == 2 - assert any(NON_RESPONSIVE_OUTPUT_MESSAGE in row for row in rows[1:]) diff --git a/tests/test_schedule_config_static.py b/tests/test_schedule_config_static.py deleted file mode 100644 index 3a3f45c1c..000000000 --- a/tests/test_schedule_config_static.py +++ /dev/null @@ -1,155 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -"""Static guard for direct durable writes to config/schedules.json. - -Known limitation: this detects direct durable-write sinks to a schedules path, not -writes routed through a generic helper that receives the path as an opaque -parameter. That indirect case is closed by the journal_io access gate and the -raw-mechanic gate, which together require any new writer to surface. -""" - -from __future__ import annotations - -import ast -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -WRITE_PRIMITIVES = { - "atomic_replace", - "install_file", - "write_json", - "write_jsonl", - "write_text", -} -WRITE_MODE_CHARS = frozenset({"w", "a", "x", "+"}) - - -def _production_modules() -> list[Path]: - return sorted( - path - for path in (ROOT / "solstone").rglob("*.py") - if path.is_file() - and "__pycache__" not in path.parts - and "tests" not in path.parts - and path.relative_to(ROOT).as_posix() != "solstone/think/schedule_config.py" - ) - - -def _call_name(node: ast.AST) -> str | None: - if isinstance(node, ast.Name): - return node.id - if isinstance(node, ast.Attribute): - return node.attr - return None - - -def _is_schedules_path_expr(node: ast.AST, schedules_vars: set[str]) -> bool: - if isinstance(node, ast.Name): - return node.id in schedules_vars - if isinstance(node, ast.Call): - return _call_name(node.func) == "get_schedules_path" - if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Div): - return ( - isinstance(node.right, ast.Constant) - and node.right.value == "schedules.json" - ) - return False - - -def _is_write_mode(node: ast.AST | None) -> bool: - if node is None: - return False - if isinstance(node, ast.Constant) and isinstance(node.value, str): - return any(char in node.value for char in WRITE_MODE_CHARS) - return False - - -def _open_mode(call: ast.Call) -> ast.AST | None: - if len(call.args) >= 2: - return call.args[1] - for keyword in call.keywords: - if keyword.arg == "mode": - return keyword.value - return None - - -class SchedulesWriteVisitor(ast.NodeVisitor): - def __init__(self, path: Path) -> None: - self.path = path - self.schedules_vars: set[str] = set() - self.violations: list[str] = [] - - def visit_Assign(self, node: ast.Assign) -> None: - if _is_schedules_path_expr(node.value, self.schedules_vars): - for target in node.targets: - if isinstance(target, ast.Name): - self.schedules_vars.add(target.id) - self.generic_visit(node) - - def visit_AnnAssign(self, node: ast.AnnAssign) -> None: - if ( - node.value is not None - and isinstance(node.target, ast.Name) - and _is_schedules_path_expr(node.value, self.schedules_vars) - ): - self.schedules_vars.add(node.target.id) - self.generic_visit(node) - - def visit_Call(self, node: ast.Call) -> None: - self._check_open(node) - self._check_path_open(node) - self._check_write_primitive(node) - self._check_replace(node) - self.generic_visit(node) - - def _record(self, node: ast.AST, kind: str) -> None: - rel = self.path.relative_to(ROOT) - self.violations.append(f"{rel}:{node.lineno}: {kind}") - - def _check_open(self, node: ast.Call) -> None: - if _call_name(node.func) != "open" or not node.args: - return - if _is_schedules_path_expr( - node.args[0], self.schedules_vars - ) and _is_write_mode(_open_mode(node)): - self._record(node, "open-write") - - def _check_path_open(self, node: ast.Call) -> None: - if not isinstance(node.func, ast.Attribute) or node.func.attr != "open": - return - if _is_schedules_path_expr( - node.func.value, self.schedules_vars - ) and _is_write_mode(_open_mode(node)): - self._record(node, "Path.open-write") - - def _check_write_primitive(self, node: ast.Call) -> None: - if _call_name(node.func) not in WRITE_PRIMITIVES or not node.args: - return - if _is_schedules_path_expr(node.args[0], self.schedules_vars): - self._record(node, _call_name(node.func) or "write-primitive") - - def _check_replace(self, node: ast.Call) -> None: - if isinstance(node.func, ast.Attribute) and node.func.attr == "replace": - if len(node.args) >= 2 and _is_schedules_path_expr( - node.args[1], self.schedules_vars - ): - self._record(node, "os.replace") - return - if node.args and _is_schedules_path_expr(node.args[0], self.schedules_vars): - self._record(node, "Path.replace") - return - if _call_name(node.func) == "replace" and len(node.args) >= 2: - if _is_schedules_path_expr(node.args[1], self.schedules_vars): - self._record(node, "os.replace") - - -def test_only_schedule_config_directly_writes_schedules_json() -> None: - violations: list[str] = [] - for path in _production_modules(): - tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) - visitor = SchedulesWriteVisitor(path) - visitor.visit(tree) - violations.extend(visitor.violations) - - assert violations == [] diff --git a/tests/test_sol_initiated_constants_locked.py b/tests/test_sol_initiated_constants_locked.py deleted file mode 100644 index 3786b9035..000000000 --- a/tests/test_sol_initiated_constants_locked.py +++ /dev/null @@ -1,138 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc - -from __future__ import annotations - -import ast -import io -import re -import tokenize -from pathlib import Path - -from solstone.convey.sol_initiated import copy - -LOCKED_LITERALS = ( - "sol_chat_request", - "sol_chat_request_superseded", - "owner_chat_open", - "owner_chat_dismissed", - "sol_initiated", - "SOLSTONE_SOL_CHAT_REQUEST", -) - -ALLOWED_PATHS = { - Path("docs/design/sol_initiated_chat_phase1.md"), - Path("docs/design/sol_initiated_chat_phase2.md"), - Path("docs/design/sol_initiated_chat_phase3.md"), - Path("docs/design/openapi-client-contract.md"), - Path("solstone/convey/README.md"), - Path("solstone/convey/chat_contract.py"), - Path("solstone/convey/chat_stream.py"), - Path("solstone/convey/contract/assemble.py"), - Path("solstone/convey/contract/observer_bundle.py"), - Path("solstone/convey/contract/observer_bundle_recording.py"), - Path("solstone/convey/contract/observer_bundle_verification.py"), - Path("solstone/convey/sol_initiated/copy.py"), - Path("solstone/convey/static/chat_render.js"), - Path("solstone/convey/static/sol_initiated_constants.js"), - Path("tests/test_observer_client_bundle.py"), - Path("tests/test_openapi_contract.py"), - Path("tests/test_sol_initiated_constants_locked.py"), -} - -SEARCH_ROOTS = ( - Path("solstone"), - Path("tests"), - Path("docs/design"), -) - - -def test_locked_literals_stay_in_the_contract_files() -> None: - hits: list[str] = [] - - for path in _iter_files(): - if path in ALLOWED_PATHS: - continue - for line_no, literal in _locked_literal_hits(path): - hits.append(f"{path}:{line_no}: {literal}") - - assert hits == [] - - -def test_browser_constants_match_python_contract() -> None: - text = Path("solstone/convey/static/sol_initiated_constants.js").read_text( - encoding="utf-8" - ) - - assert _js_constant(text, "KIND_SOL_CHAT_REQUEST") == copy.KIND_SOL_CHAT_REQUEST - assert ( - _js_constant(text, "KIND_SOL_CHAT_REQUEST_SUPERSEDED") - == copy.KIND_SOL_CHAT_REQUEST_SUPERSEDED - ) - assert _js_constant(text, "KIND_OWNER_CHAT_OPEN") == copy.KIND_OWNER_CHAT_OPEN - assert ( - _js_constant(text, "KIND_OWNER_CHAT_DISMISSED") - == copy.KIND_OWNER_CHAT_DISMISSED - ) - assert 'SURFACE_CONVEY: "convey"' in text - assert _js_constant(text, "SURFACE_CONVEY") == copy.SURFACE_CONVEY - assert ( - _js_constant(text, "SOL_PINGED_OFFLINE_TOOLTIP") - == copy.SOL_PINGED_OFFLINE_TOOLTIP - ) - - -def _iter_files() -> list[Path]: - files: list[Path] = [] - for root in SEARCH_ROOTS: - if not root.exists(): - continue - files.extend( - path - for path in root.rglob("*") - if path.is_file() - and "__pycache__" not in path.parts - and path.suffix in {".py", ".md", ".js"} - ) - return sorted(files) - - -def _js_constant(text: str, name: str) -> str: - match = re.search(rf'{name}: "([^"]*)"', text) - assert match is not None, name - return match.group(1).encode("utf-8").decode("unicode_escape") - - -def _locked_literal_hits(path: Path) -> list[tuple[int, str]]: - if path.suffix == ".py": - return _python_string_literal_hits(path) - - hits: list[tuple[int, str]] = [] - for line_no, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1): - for literal in LOCKED_LITERALS: - if literal in line: - hits.append((line_no, literal)) - return hits - - -def _python_string_literal_hits(path: Path) -> list[tuple[int, str]]: - hits: list[tuple[int, str]] = [] - text = path.read_text(encoding="utf-8") - tokens = tokenize.generate_tokens(io.StringIO(text).readline) - for token in tokens: - if token.type != tokenize.STRING: - continue - value = _literal_value(token.string) - if not isinstance(value, str): - value = token.string - for literal in LOCKED_LITERALS: - if literal in value: - hits.append((token.start[0], literal)) - return hits - - -def _literal_value(raw: str) -> object: - try: - return ast.literal_eval(raw) - except (SyntaxError, ValueError): - return raw diff --git a/tests/test_tmpdir_fallback.py b/tests/test_tmpdir_fallback.py deleted file mode 100644 index 0c46dbf14..000000000 --- a/tests/test_tmpdir_fallback.py +++ /dev/null @@ -1,205 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-only -# Copyright (c) 2026 sol pbc -"""Canary tests for the root conftest TMPDIR fallback prelude.""" - -from __future__ import annotations - -import os -import subprocess -import sys -from pathlib import Path - -import pytest - -pytest_plugins = ["pytester"] - -_ROOT_CONFTEST = Path(__file__).resolve().parent.parent / "conftest.py" -_NOTICE = ( - "solstone: pytest invoked without TMPDIR export; routing tmp dirs to " - "/var/tmp. Prefer 'make test' to set TMPDIR at the shell level.\n" -) - - -def _install_root_conftest(pytester: pytest.Pytester) -> None: - pytester.makepyfile(conftest=_ROOT_CONFTEST.read_text(encoding="utf-8")) - - -def _run_nested( - pytester: pytest.Pytester, - env_overrides: dict[str, str | None] | None = None, -) -> subprocess.CompletedProcess[str]: - basetemp = pytester.path / "basetemp" - env = os.environ.copy() - env.pop("TMPDIR", None) - env.pop("_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED", None) - env.pop("_SOLSTONE_TMPDIR_FALLBACK_TARGET", None) - if env_overrides: - for key, value in env_overrides.items(): - if value is None: - env.pop(key, None) - else: - env[key] = value - return subprocess.run( - [ - sys.executable, - "-m", - "pytest", - "-q", - "-p", - "no:cacheprovider", - "--basetemp", - str(basetemp), - ], - cwd=pytester.path, - env=env, - capture_output=True, - text=True, - check=False, - ) - - -def test_prelude_redirects_to_var_tmp(pytester: pytest.Pytester) -> None: - _install_root_conftest(pytester) - pytester.makepyfile( - test_tmpdir=""" - import os - import tempfile - - def test_redirects_to_var_tmp(): - assert tempfile.gettempdir() == "/var/tmp" - assert os.environ["TMPDIR"] == "/var/tmp" - """ - ) - - result = _run_nested(pytester) - - assert result.returncode == 0, result.stderr + result.stdout - assert "1 passed" in result.stdout - - -def test_notice_present_when_tmpdir_unset(pytester: pytest.Pytester) -> None: - _install_root_conftest(pytester) - pytester.makepyfile( - test_notice=""" - def test_noop(): - assert True - """ - ) - - result = _run_nested(pytester) - combined = result.stderr + result.stdout - - assert result.returncode == 0, combined - assert _NOTICE in combined - - -def test_notice_absent_when_tmpdir_already_set(pytester: pytest.Pytester) -> None: - _install_root_conftest(pytester) - pytester.makepyfile( - test_notice=""" - import os - import tempfile - - def test_uses_existing_tmpdir(): - assert tempfile.gettempdir() == "/tmp" - assert os.environ["TMPDIR"] == "/tmp" - """ - ) - - result = _run_nested(pytester, {"TMPDIR": "/tmp"}) - combined = result.stderr + result.stdout - - assert result.returncode == 0, combined - assert "solstone: pytest invoked without TMPDIR" not in combined - - -def test_notice_single_fire_across_workers(pytester: pytest.Pytester) -> None: - _install_root_conftest(pytester) - pytester.makepyfile( - test_notice=""" - def test_noop(): - assert True - """ - ) - - first = _run_nested(pytester) - second = _run_nested(pytester, {"_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED": "1"}) - combined = first.stderr + first.stdout + second.stderr + second.stdout - - assert first.returncode == 0, combined - assert second.returncode == 0, combined - assert combined.count(_NOTICE) == 1 - - -def test_unwritable_target_degrades_visibly( - pytester: pytest.Pytester, tmp_path: Path -) -> None: - _install_root_conftest(pytester) - pytester.makepyfile( - test_notice=""" - import os - - def test_tmpdir_stays_unset(): - assert os.environ.get("TMPDIR") is None - """ - ) - blocked = tmp_path / "blocked" - blocked.mkdir() - os.chmod(blocked, 0) - - try: - result = _run_nested( - pytester, {"_SOLSTONE_TMPDIR_FALLBACK_TARGET": str(blocked)} - ) - finally: - os.chmod(blocked, 0o700) - - combined = result.stderr + result.stdout - notice = ( - "solstone: pytest invoked without TMPDIR export and fallback target " - f"{blocked} is not writable; leaving TMPDIR unset.\n" - ) - - assert result.returncode == 0, combined - assert notice in combined - assert "routing tmp dirs to" not in combined - - -def test_subprocess_pytest_lands_in_var_tmp(pytester: pytest.Pytester) -> None: - _install_root_conftest(pytester) - test_path = pytester.makepyfile( - test_subprocess=""" - import os - import tempfile - - def test_redirects_in_fresh_subprocess(): - assert tempfile.gettempdir() == "/var/tmp" - assert os.environ["TMPDIR"] == "/var/tmp" - """ - ) - env = os.environ.copy() - env.pop("TMPDIR", None) - env.pop("_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED", None) - env.pop("_SOLSTONE_TMPDIR_FALLBACK_TARGET", None) - - result = subprocess.run( - [ - sys.executable, - "-m", - "pytest", - "-q", - "-p", - "no:cacheprovider", - "--basetemp", - str(pytester.path / "basetemp"), - str(test_path), - ], - cwd=pytester.path, - env=env, - capture_output=True, - text=True, - check=False, - ) - - assert result.returncode == 0, result.stderr + result.stdout - assert "1 passed" in result.stdout