"""Live Gitea round trip in a repository of the run's own: push a branch, open a PR, comment, and prove the L8 reconciler reads external truth correctly, and that protection holds against the agent (D4). """ import uuid from pathlib import Path import pytest from e2e_support import fresh_repo, operator_gitea from nisse_dev.agent import remote_url from nisse_dev.config import AgentConfig from nisse_dev.execution import SSHHost from nisse_dev.git import GitError, GitRepo, SSHKey from nisse_dev.gitea import GiteaClient, pull_request_reconciler from nisse_dev.state import Intent pytestmark = pytest.mark.integration def intent_for(branch: str) -> Intent: return Intent( id=1, kind="open_pr", payload={"branch": branch}, status="pending", created_at="t", resolved_at=None, ) def test_push_open_pr_and_reconcile( tmp_path: Path, live_config: AgentConfig, gitea: GiteaClient, ssh_host: SSHHost ) -> None: client = gitea with fresh_repo( operator_gitea(live_config.gitea_url), uuid.uuid4().hex[:8], tmp_path / "keys", agent=client.whoami(), ) as fresh: _round_trip( tmp_path, client, ssh_host, fresh.name, SSHKey(fresh.push_key.read_text()) ) def _round_trip( tmp_path: Path, client: GiteaClient, ssh_host: SSHHost, repo_path: str, key: SSHKey ) -> None: account = client.whoami() assert "testing" in account, ( f"live tests must run as a testing account, not {account}" ) branch = f"live-test-{uuid.uuid4().hex[:8]}" reconcile = pull_request_reconciler(client, repo_path) # Before the PR exists, external truth says the effect has not happened. assert reconcile(intent_for(branch)) is False # Pushed the way the agent does: from the build VM (here the throwaway # sshd), with the repository's deploy key, never the API token. url = remote_url(client, repo_path, key) repo = GitRepo(ssh_host, tmp_path / "work", known_hosts=str(tmp_path / "kh")) repo.init() repo._git("fetch", "-q", url, "main", credential=key) repo._git("checkout", "-q", "-B", "work", "FETCH_HEAD") repo.configure_identity(account, f"{account}@example.test") (repo.root / f"{branch}.txt").write_text("live test artifact\n") assert repo.commit_all("Live test commit") is not None pr = None try: repo.push(url, branch, credential=key) pr = client.open_pull_request( repo_path, head=branch, base="main", title=f"live test {branch}", body="Opened by the nisse-dev live test suite.", ) assert pr.head == branch client.post_comment(repo_path, pr.number, "live test comment") bodies = [c.body for c in client.list_comments(repo_path, pr.number)] assert "live test comment" in bodies # Now the same reconciler must see the effect and refuse to repeat it. assert reconcile(intent_for(branch)) is True # D4 is only real if the server enforces it. The agent's own token # must not be able to merge the PR it just opened, and its push credential # must not be able to push to the protected default branch at all. merged = client._http.post( f"/repos/{repo_path}/pulls/{pr.number}/merge", json={"Do": "merge"} ) assert merged.status_code >= 400, ( "the agent merged its own PR: branch protection is not enforcing " "the human gate" ) with pytest.raises(GitError): repo.push(url, "main", credential=key) finally: if pr is not None: client.close_pull_request(repo_path, pr.number) client.close()