Files
govoplan/tests/test_devkit_release.py
zemion 2ffdb23f69
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s
feat(devkit): add resumable workspace automation and UI review tooling
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:17 +02:00

525 lines
27 KiB
Python
Executable File

"""Fixture-only devkit coverage of the real durable release API/store boundary."""
from __future__ import annotations
import argparse
from copy import deepcopy
import json
from pathlib import Path
import socket
import subprocess
import sys
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
ROOT = Path(__file__).resolve().parents[1]
for path in (ROOT / "tools/devkit", ROOT / "tools/release"):
if str(path) not in sys.path:
sys.path.insert(0, str(path))
from govoplan_devkit import release # noqa: E402
from govoplan_release.release_execution import ReleaseExecutionAmbiguous, ReleaseExecutionBlocked # noqa: E402
from govoplan_release.release_run import ReleaseRunCorrupt, ReleaseRunStore # noqa: E402
from govoplan_release.candidate_artifact import ( # noqa: E402
candidate_output_path, harden_private_candidate_tree, issue_candidate_receipt,
)
from server import app as api # noqa: E402
def receipt(repo="govoplan-core", *, target_tag="v1.2.3"):
return {
"kind": "repository_state", "repo": repo, "head": "a" * 40,
"branch": "main", "remote": "origin", "remote_sha256": "b" * 64,
"worktree_clean": True, "target_tag": target_tag, "tag_object": None,
}
def plan(*, catalog=False):
steps = [
("core:preflight", "govoplan-core", False),
("core:tag", "govoplan-core", True),
] if not catalog else [
("catalog:selective-generator", None, True),
("catalog:validate-sign-publish", None, True),
]
return {
"generated_at": "2026-09-08T00:00:00Z", "target_channel": "stable",
"status": "attention", "units": [{"repo": "govoplan-core", "target_version": "1.2.3"}],
"compatibility": [], "gate_findings": [], "recommended_action": {},
"source_preflight_ready": True, "notes": [],
"dry_run_steps": [
{"id": identity, "repo": repo, "mutating": mutating, "title": identity,
"detail": "Fixture-only operation.", "command": "fixture never executed",
"cwd": "/fixture", "status": "planned"}
for identity, repo, mutating in steps
],
}
def namespace(workspace, state, *arguments):
parser = argparse.ArgumentParser()
parser.set_defaults(workspace_root=workspace, state_dir=state, format="json", project=None)
release.register(parser.add_subparsers(required=True))
return parser.parse_args(["release", *arguments])
@pytest.fixture
def environment(tmp_path, monkeypatch):
workspace = tmp_path / "workspace"
workspace.mkdir()
state = tmp_path / "private-state"
plans = [plan()]
dashboard = Mock(return_value={"summary": {"status": "ready"}, "repositories": []})
planner = Mock(side_effect=lambda *args, **kwargs: deepcopy(plans[0]))
execute = Mock(return_value=({"status": "inspected"}, receipt()))
def bind(**kwargs):
result = kwargs["plan"]
for step in result["dry_run_steps"]:
if step.get("repo"):
step["source_binding"] = receipt(step["repo"])
elif step["id"] == "catalog:validate-sign-publish":
step["source_binding"] = receipt("addideas-govoplan-website", target_tag="")
return result
monkeypatch.setattr(api, "build_dashboard", dashboard)
monkeypatch.setattr(api, "build_selective_release_plan", planner)
monkeypatch.setattr(api, "require_trusted_release_runtime", Mock())
monkeypatch.setattr(api, "verify_release_runtime_binding", Mock())
monkeypatch.setattr(api, "bind_plan_source_states", bind)
monkeypatch.setattr(api, "verify_repository_preflight_binding", Mock(return_value=receipt()))
monkeypatch.setattr(api, "verify_repository_step_precondition", Mock(return_value=receipt()))
monkeypatch.setattr(api, "execute_repository_step", execute)
monkeypatch.setattr(api, "default_signing_keys", lambda: ())
def forbidden(*args, **kwargs):
raise AssertionError("Fixture test attempted a real subprocess or network connection")
monkeypatch.setattr(subprocess, "run", forbidden)
monkeypatch.setattr(socket, "create_connection", forbidden)
def call(*args, state_dir=state, workspace_root=workspace):
values = namespace(workspace_root, state_dir, *args)
return values.handler(values)
def create(request="devkit-create-request-0001"):
result = call("create", "--repo-version", "govoplan-core=1.2.3", "--request-id", request, "--apply")
assert result["_exit_code"] == 0, result
return result
return SimpleNamespace(
workspace=workspace, state=state, plans=plans, dashboard=dashboard,
planner=planner, executor=execute, call=call, create=create,
)
def test_registration_does_not_import_heavy_dependencies():
script = """
import argparse, builtins, sys
sys.path.insert(0, sys.argv[1])
original = builtins.__import__
def guarded(name, *args, **kwargs):
if name.split('.')[0] in {'httpx', 'fastapi', 'govoplan_core', 'govoplan_release'}:
raise AssertionError('Heavy import during help registration: ' + name)
return original(name, *args, **kwargs)
builtins.__import__ = guarded
from govoplan_devkit.release import register
parser = argparse.ArgumentParser()
register(parser.add_subparsers())
assert 'release' in parser.format_help()
"""
result = subprocess.run([sys.executable, "-c", script, str(ROOT / "tools/devkit")], capture_output=True, text=True, check=False)
assert result.returncode == 0, result.stderr
def test_plan_is_selective_offline_and_does_not_create_run(environment):
result = environment.call("plan", "--repo-version", "govoplan-core=1.2.3")
assert result["_exit_code"] == 0
assert result["dry_run"] is True
assert environment.planner.call_args.kwargs["selected_repos"] == ("govoplan-core",)
arguments = environment.dashboard.call_args.kwargs
assert arguments["online"] is False
assert arguments["check_remote_tags"] is False
assert arguments["check_public_catalog"] is False
assert arguments["include_migrations"] is False
assert not list(environment.state.rglob("rr-*.json"))
assert "release-console/workspace-" in result["state_location"]
environment.executor.assert_not_called()
def test_status_reports_blocked_exit_and_explicit_check_flags(environment):
environment.dashboard.return_value = {"summary": {"status": "blocked"}}
result = environment.call("status", "--online", "--include-migrations", "--include-website")
assert result["_exit_code"] == 1
assert environment.dashboard.call_args.kwargs["check_remote_tags"] is True
assert environment.dashboard.call_args.kwargs["check_public_catalog"] is True
assert environment.dashboard.call_args.kwargs["include_migrations"] is True
def test_plan_summary_exposes_attention_readiness_gates_and_next_action(environment):
fixture_plan = environment.plans[0]
fixture_plan["source_preflight_ready"] = False
fixture_plan["units"][0]["status"] = "attention"
fixture_plan["gate_findings"] = [{"code": "worktree_dirty", "repo": "govoplan-core", "message": "Uncommitted source changes need review."}]
fixture_plan["recommended_action"] = {"id": "prepare_changes", "title": "Prepare source changes", "remediation": "Review and commit the selected changes before preparing the release."}
result = environment.call("plan", "--repo-version", "govoplan-core=1.2.3")
summary = "\n".join(result["summary"])
assert "Release plan: attention." in summary
assert "Source preflight ready: false." in summary
assert "govoplan-core: attention; target 1.2.3." in summary
assert "Gate worktree_dirty (govoplan-core)" in summary
assert "Next: prepare_changes" in summary
assert "no run was created" in summary
assert "fixture never executed" not in summary
def test_summary_is_bounded_and_redacts_display_only_fields(monkeypatch):
monkeypatch.setenv("DEVKIT_FIXTURE_SECRET", "fixture-value-not-for-display")
fixture_plan = plan()
fixture_plan["gate_findings"] = [{"code": "fixture", "message": "fixture-value-not-for-display " + "x" * 1000}] * 20
fixture_plan["units"] = [{"repo": f"repo-{index}", "target_version": "1.2.3", "status": "ready"} for index in range(50)]
summary = "\n".join(release._summary_lines("plan", fixture_plan))
assert "38 more selected repositories" in summary
assert "16 more gate findings" in summary
assert "fixture-value-not-for-display" not in summary
assert "[redacted]" in summary
assert len(summary) < 3000
def test_run_and_preview_summary_exposes_steps_and_next_action(environment):
run = environment.create()["result"]
shown = environment.call("show", run["run_id"])
summary = "\n".join(shown["summary"])
assert "Steps: 2 pending." in summary
assert "Step core:preflight: pending." in summary
assert "Next: execute_step [core:preflight]" in summary
preview = environment.call("preview", run["run_id"], "core:tag")
assert "Release preview: pending." in preview["summary"]
assert any("Complete core:preflight first." in line for line in preview["summary"])
def test_status_summary_exposes_repository_counts(environment):
environment.dashboard.return_value = {"summary": {"status": "attention", "repository_count": 77, "dirty_count": 42, "ahead_count": 1, "behind_count": 0, "error_count": 0}}
result = environment.call("status")
assert "Release status: attention." in result["summary"]
assert any("77 repositories, 42 dirty, 1 ahead, 0 behind, 0 errors" in line for line in result["summary"])
def test_display_redaction_cannot_change_semantic_failure_exit(environment, monkeypatch):
monkeypatch.setenv("DEVKIT_FIXTURE_SECRET", "blocked")
environment.dashboard.return_value = {"summary": {"status": "blocked"}}
result = environment.call("status")
assert result["_exit_code"] == 1
assert "Release status: [redacted]." in result["summary"]
def test_create_defaults_to_preview_without_run_record(environment):
result = environment.call("create", "--repo", "govoplan-core", "--target-version", "1.2.3", "--request-id", "preview-create-request-0001")
assert result["_exit_code"] == 0 and result["dry_run"]
assert not list(environment.state.rglob("rr-*.json"))
environment.executor.assert_not_called()
def test_create_show_and_same_id_replay_use_durable_service(environment):
created = environment.create()
run_id = created["result"]["run_id"]
repeated = environment.create()
assert repeated["result"]["run_id"] == run_id
environment.planner.assert_called_once()
shown = environment.call("show", run_id)
assert shown["result"]["immutable"] == created["result"]["immutable"]
assert shown["result"]["state"]["steps"][0]["executor"]["confirmation"] == ""
assert len(list(environment.state.rglob("rr-*.json"))) == 1
def test_create_replay_rejects_changed_inputs(environment):
environment.create()
result = environment.call("create", "--repo-version", "govoplan-core=1.2.4", "--request-id", "devkit-create-request-0001", "--apply")
assert result["http_status"] == 409
environment.planner.assert_called_once()
@pytest.mark.parametrize("arguments", [
("plan",),
("create", "--repo", "govoplan-core", "--request-id", "missing-version-request"),
("plan", "--repo-version", "govoplan-core=1.2.3", "--repo-version", "govoplan-core=1.2.4"),
("plan", "--repo-version", "govoplan-core=not-a-version"),
])
def test_invalid_selection_is_rejected_before_service_collection(environment, arguments):
result = environment.call(*arguments)
assert result["_exit_code"] == 2
environment.dashboard.assert_not_called()
environment.executor.assert_not_called()
def test_runtime_trust_guard_cannot_be_bypassed_by_cli(environment, monkeypatch):
monkeypatch.setattr(api, "require_trusted_release_runtime", Mock(side_effect=ReleaseExecutionBlocked("Fixture untrusted runtime")))
result = environment.call("create", "--repo-version", "govoplan-core=1.2.3", "--request-id", "trust-create-request-0001", "--apply")
assert result["http_status"] == 409
assert not list(environment.state.rglob("rr-*.json"))
environment.planner.assert_not_called()
def test_dry_execute_and_generic_preview_never_claim_or_execute(environment):
run = environment.create()["result"]
dry = environment.call("execute", run["run_id"], "core:preflight", "--request-id", "dry-execute-request-0001")
preview = environment.call("preview", run["run_id"], "core:tag")
assert dry["dry_run"] and preview["dry_run"]
assert preview["result"]["state_step"]["executor"]["confirmation"] == "TAG"
assert preview["result"]["state_step"]["available"] is False
environment.executor.assert_not_called()
assert environment.call("show", run["run_id"])["result"]["state"]["steps"][0]["attempt_count"] == 0
def test_prerequisite_and_confirmation_guards_remain_enforced(environment):
run_id = environment.create()["result"]["run_id"]
blocked = environment.call("execute", run_id, "core:tag", "--request-id", "ordered-tag-request-0001", "--confirm", "TAG", "--apply")
assert blocked["http_status"] == 409
environment.executor.assert_not_called()
assert environment.call("execute", run_id, "core:preflight", "--request-id", "preflight-request-0001", "--apply")["_exit_code"] == 0
missing = environment.call("execute", run_id, "core:tag", "--request-id", "confirmed-tag-request-0001", "--apply")
assert missing["http_status"] == 409
assert environment.executor.call_count == 1
def test_execute_same_attempt_replays_without_repeating_effect(environment):
run_id = environment.create()["result"]["run_id"]
arguments = ("execute", run_id, "core:preflight", "--request-id", "exact-attempt-request-0001", "--apply")
first = environment.call(*arguments)
second = environment.call(*arguments)
assert first["_exit_code"] == second["_exit_code"] == 0
assert second["result"]["execution_result"]["status"] == "replayed"
environment.executor.assert_called_once()
assert environment.executor.call_args.kwargs["remote"] == "origin"
def test_lost_finish_write_is_interrupted_without_reexecuting_effect(environment, monkeypatch):
run_id = environment.create()["result"]["run_id"]
finish = ReleaseRunStore.finish_step
monkeypatch.setattr(ReleaseRunStore, "finish_step", Mock(side_effect=ReleaseRunCorrupt("Fixture durable write failure")))
arguments = ("execute", run_id, "core:preflight", "--request-id", "lost-finish-request-0001", "--apply")
interrupted = environment.call(*arguments)
assert interrupted["http_status"] == 409
monkeypatch.setattr(ReleaseRunStore, "finish_step", finish)
assert environment.call(*arguments)["http_status"] == 409
environment.executor.assert_called_once()
shown = environment.call("show", run_id)["result"]
assert shown["state"]["steps"][0]["state"] == "interrupted"
def test_source_guard_failure_does_not_call_executor(environment, monkeypatch):
run_id = environment.create()["result"]["run_id"]
monkeypatch.setattr(api, "verify_repository_preflight_binding", Mock(side_effect=ReleaseExecutionBlocked("Frozen HEAD/remote changed")))
result = environment.call("execute", run_id, "core:preflight", "--request-id", "changed-source-request-0001", "--apply")
assert result["_exit_code"] == 1
environment.executor.assert_not_called()
def test_interrupted_write_requires_reconciliation_not_retry(environment, monkeypatch):
environment.plans[0]["dry_run_steps"] = [environment.plans[0]["dry_run_steps"][1]]
environment.executor.side_effect = ReleaseExecutionAmbiguous("Fixture remote outcome uncertain")
run_id = environment.create()["result"]["run_id"]
execute = ("execute", run_id, "core:tag", "--request-id", "uncertain-tag-request-0001", "--confirm", "TAG", "--apply")
uncertain = environment.call(*execute)
assert uncertain["http_status"] == 409
assert environment.call(*execute)["http_status"] == 409
retry = environment.call("retry", run_id, "core:tag", "--request-id", "unsafe-retry-request-0001", "--apply")
assert retry["http_status"] == 409
environment.executor.assert_called_once()
invalid = environment.call("reconcile", run_id, "core:tag", "--request-id", "bad-reconcile-request-0001", "--outcome", "effect_absent", "--apply")
assert invalid["http_status"] == 409
reconciled = environment.call("reconcile", run_id, "core:tag", "--request-id", "reconcile-absent-request-0001", "--outcome", "effect_absent", "--confirm", "RECONCILE", "--apply")
assert reconciled["_exit_code"] == 0
assert reconciled["result"]["state"]["steps"][0]["state"] == "pending"
def test_effect_succeeded_reconciliation_keeps_independent_receipt_guard(environment, monkeypatch):
environment.plans[0]["dry_run_steps"] = [environment.plans[0]["dry_run_steps"][1]]
environment.executor.side_effect = ReleaseExecutionAmbiguous("Fixture interruption")
run_id = environment.create()["result"]["run_id"]
environment.call("execute", run_id, "core:tag", "--request-id", "receipt-tag-request-0001", "--confirm", "TAG", "--apply")
guard = Mock(side_effect=ReleaseExecutionBlocked("Remote annotation mismatch"))
monkeypatch.setattr(api, "reconciled_repository_receipt", guard)
result = environment.call("reconcile", run_id, "core:tag", "--request-id", "receipt-success-request-0001", "--outcome", "effect_succeeded", "--confirm", "RECONCILE", "--apply")
assert result["http_status"] == 409
guard.assert_called_once()
environment.executor.assert_called_once()
def test_resume_and_retry_reuse_the_existing_running_attempt_rules(environment):
created = environment.create()
run_id = created["result"]["run_id"]
store = ReleaseRunStore(Path(created["state_location"]), expected_workspace_fingerprint=api.release_workspace_fingerprint(environment.workspace))
store.claim_step(run_id, "core:preflight", attempt_id="lost-process-request-0001")
dry = environment.call("resume", run_id, "--request-id", "resume-process-request-0001")
assert dry["dry_run"]
assert store.get(run_id)["state"]["steps"][0]["state"] == "running"
resumed = environment.call("resume", run_id, "--request-id", "resume-process-request-0001", "--apply")
assert resumed["result"]["state"]["steps"][0]["state"] == "interrupted"
retried = environment.call("retry", run_id, "core:preflight", "--request-id", "retry-readonly-request-0001", "--apply")
assert retried["result"]["state"]["steps"][0]["state"] == "pending"
environment.executor.assert_not_called()
def test_workspace_scoping_and_corrupt_records_fail_closed(environment, tmp_path):
created = environment.create()
run_id = created["result"]["run_id"]
another = tmp_path / "another-workspace"
another.mkdir()
foreign = environment.call("show", run_id, workspace_root=another)
assert foreign["http_status"] == 404
path = Path(created["state_location"]) / f"{run_id}.json"
record = json.loads(path.read_text())
record["immutable"]["input"]["repo_versions"]["govoplan-core"] = "9.9.9"
path.write_text(json.dumps(record))
assert environment.call("show", run_id)["http_status"] == 409
def test_run_list_keeps_cursor_pagination(environment):
environment.create("page-create-request-0001")
environment.create("page-create-request-0002")
first = environment.call("list", "--limit", "1")["result"]
second = environment.call("list", "--limit", "1", "--cursor", first["next_cursor"])["result"]
assert len(first["runs"]) == len(second["runs"]) == 1
assert first["runs"][0]["run_id"] != second["runs"][0]["run_id"]
assert second["next_cursor"] is None
def test_catalog_preview_calls_only_existing_receipt_bound_preview(environment, monkeypatch, tmp_path):
environment.plans[0] = plan(catalog=True)
run_id = environment.create()["result"]["run_id"]
candidate = tmp_path / "candidate"
verify = Mock(return_value=candidate)
publish = Mock(return_value={"status": "planned", "apply": False})
monkeypatch.setattr(api, "verified_run_candidate", verify)
monkeypatch.setattr(api, "publish_catalog_candidate", publish)
result = environment.call("preview", run_id, "catalog:validate-sign-publish")
assert result["_exit_code"] == 0
verify.assert_called_once()
assert publish.call_args.kwargs["apply"] is False
assert publish.call_args.kwargs["candidate_dir"] == candidate
assert publish.call_args.kwargs["remote"] == "origin"
environment.executor.assert_not_called()
def test_catalog_generation_and_publication_use_exact_durable_receipts(environment, monkeypatch):
environment.plans[0] = plan(catalog=True)
created = environment.create()
run_id = created["result"]["run_id"]
candidate_root = Path(created["candidate_location"])
def generated(**kwargs):
candidate_id = kwargs["candidate_id"]
candidate = candidate_output_path(candidate_root, candidate_id)
channels = candidate / "channels"
channels.mkdir(parents=True)
(channels / "stable.json").write_text(json.dumps({"channel": "stable", "signatures": [{}]}))
harden_private_candidate_tree(candidate)
return {"status": "ready"}, issue_candidate_receipt(root=candidate_root, candidate_id=candidate_id, channel="stable")
def published(**kwargs):
candidate = kwargs["candidate_receipt"]
website = kwargs["expected_website_receipt"]
return {"status": "published"}, {
"kind": "catalog_publication", "candidate_id": candidate["candidate_id"],
"catalog_sha256": candidate["catalog_sha256"], "keyring_sha256": "c" * 64,
"publication_commit_sha": "d" * 40, "publication_tag_object_sha": "e" * 40,
"publication_tag_commit_sha": "d" * 40, "branch": website["branch"],
"tag_name": "catalog-stable-1", "remote": "origin", "remote_sha256": website["remote_sha256"],
}
generator = Mock(side_effect=generated)
publisher = Mock(side_effect=published)
website = receipt("addideas-govoplan-website", target_tag="")
monkeypatch.setattr(api, "generate_catalog_candidate", generator)
monkeypatch.setattr(api, "publish_received_candidate", publisher)
monkeypatch.setattr(api, "verify_catalog_publication_precondition", Mock(return_value=website))
generate = ("execute", run_id, "catalog:selective-generator", "--request-id", "generate-candidate-request-0001", "--confirm", "GENERATE", "--apply")
first = environment.call(*generate, "--signing-key", "fixture-key=/private/fixture-key.pem")
assert first["_exit_code"] == 0, first
replayed = environment.call(*generate)
assert replayed["result"]["execution_result"]["status"] == "replayed"
generator.assert_called_once()
assert generator.call_args.kwargs["signing_keys"] == ("fixture-key=/private/fixture-key.pem",)
assert "/private/fixture-key.pem" not in json.dumps(first)
record_text = next(environment.state.rglob("rr-*.json")).read_text()
assert "/private/fixture-key.pem" not in record_text
missing_confirmation = environment.call("execute", run_id, "catalog:validate-sign-publish", "--request-id", "publish-candidate-request-0001", "--apply")
assert missing_confirmation["http_status"] == 409
publisher.assert_not_called()
publish = ("execute", run_id, "catalog:validate-sign-publish", "--request-id", "publish-candidate-request-0001", "--confirm", "PUSH", "--apply")
complete = environment.call(*publish)
assert complete["_exit_code"] == 0, complete
assert complete["result"]["state"]["status"] == "completed"
frozen = first["result"]["state"]["steps"][0]["result_receipt"]
assert publisher.call_args.kwargs["candidate_path"] == candidate_root / frozen["candidate_id"]
assert publisher.call_args.kwargs["candidate_receipt"] == frozen
assert publisher.call_args.kwargs["expected_website_receipt"] == website
assert publisher.call_args.kwargs["remote"] == "origin"
assert environment.call(*publish)["result"]["execution_result"]["status"] == "replayed"
publisher.assert_called_once()
def test_portable_project_cannot_override_release_catalog(environment):
args = namespace(environment.workspace, environment.state, "plan", "--repo-version", "govoplan-core=1.2.3")
args.project = environment.workspace / "custom-project.json"
result = release.handle(args)
assert result["_exit_code"] == 2
assert "does not accept --project" in result["summary"][0]
environment.dashboard.assert_not_called()
def test_foreign_cached_release_package_is_rejected_before_import(environment, monkeypatch, tmp_path):
monkeypatch.setitem(sys.modules, "server.app", SimpleNamespace(__file__=str(tmp_path / "foreign/app.py")))
importer = Mock(side_effect=AssertionError("Foreign module import must not occur"))
monkeypatch.setattr(release.importlib, "import_module", importer)
result = environment.call("plan", "--repo-version", "govoplan-core=1.2.3")
assert result["_exit_code"] == 2
assert "foreign module" in result["summary"][0]
importer.assert_not_called()
environment.dashboard.assert_not_called()
def test_no_arbitrary_remote_or_legacy_publication_flags():
run_id = "rr-request-" + "a" * 64
with pytest.raises(SystemExit):
namespace(Path("/fixture"), None, "execute", run_id, "core:tag", "--request-id", "arbitrary-remote-request", "--remote", "untrusted")
with pytest.raises(SystemExit):
namespace(Path("/fixture"), None, "publish-candidate", "--candidate-dir", "/untrusted")
def test_unknown_step_and_malformed_paths_do_not_become_other_routes(environment):
run_id = environment.create()["result"]["run_id"]
assert environment.call("preview", run_id, "unknown:step")["http_status"] == 404
with pytest.raises(SystemExit):
namespace(environment.workspace, environment.state, "preview", run_id, "../repositories/push")
def test_signing_material_is_not_echoed_by_validation(environment):
run_id = environment.create()["result"]["run_id"]
secret = "PRIVATE-KEY-MATERIAL\nDO-NOT-ECHO"
result = environment.call("execute", run_id, "core:preflight", "--request-id", "secret-input-request-0001", "--signing-key", secret, "--apply")
assert result["_exit_code"] == 2
assert secret not in json.dumps(result)
assert "SECRET" not in release._error_detail({"detail": [{"loc": ["body", "signing_keys"], "msg": "Invalid input", "input": "SECRET"}]})
environment.executor.assert_not_called()
def test_default_state_matches_console_and_token_never_appears_in_output(environment, monkeypatch, tmp_path):
monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "xdg-state"))
monkeypatch.setattr(release.secrets, "token_urlsafe", lambda size: "ephemeral-do-not-print-token")
result = environment.call("plan", "--repo-version", "govoplan-core=1.2.3", state_dir=None)
assert result["state_location"] == str(api.default_release_run_root(environment.workspace))
assert "ephemeral-do-not-print-token" not in json.dumps(result)
def test_documentation_keeps_disabled_generic_mutations_and_recovery_explicit():
console = (ROOT / "docs/operations/RELEASE_CONSOLE.md").read_text()
usage = (ROOT / "docs/operations/DEVKIT_RELEASE.md").read_text()
assert "generic push, sync and prepare\nmutation endpoints are disabled" in console
assert "ASGI application inside" in usage
assert "effect_absent" in usage and "effect_succeeded" in usage and "unresolved" in usage
assert "does **not** stage arbitrary source" in usage