feat(delivery): final report + reserved-label guard + Windows test fixes (v2 phase A3-final)

Gap-closing on top of the merged A3-3..A3-6 work:

- ProjectService.create_preview_domain now refuses a label that is a reserved
  platform name (git, mcp, api, panel, ...) via PROTECTED_HOST_LABELS. The rules
  set existed but only the owner-facing validate_extra_host consulted it, so the
  tenant path could reserve one.
- process.py: signal.SIGKILL is resolved through getattr with a SIGTERM
  fallback, so the module imports and type-checks on Windows where SIGKILL does
  not exist.
- Three more Windows test repairs: a git-created .git must be unlinked and
  recreated rather than overwritten in place; POSIX-only chmod and symlink
  assertions are gated on os.name (the security property they assert is checked
  everywhere, the platform-specific mechanics only where they apply).
- docs/plan/reports/agent-3-final.md: the integration hand-off — host
  requirements, every setting, every endpoint added or changed, the tables, the
  open CHANGE REQUESTS, a 12-step manual QA script and the known limitations.

Checks: ruff clean, mypy clean (136 files), 521 API tests pass, 83 web tests
pass, tsc clean, next lint clean.
This commit is contained in:
Agent 3
2026-10-14 12:07:10 +03:30
parent 5095a29df9
commit 22374f3e1c
5 changed files with 252 additions and 3 deletions
+5
View File
@@ -142,6 +142,11 @@ def test_safe_join_refuses_a_parent_escape(tmp_path):
safe_join(str(root), "a/b/../../../etc/passwd")
@pytest.mark.skipif(
os.name == "nt",
reason="creating a symlink on Windows requires SeCreateSymbolicLinkPrivilege "
"(admin or Developer Mode); the path-escape guard is covered on POSIX hosts",
)
def test_safe_join_refuses_a_symlink_that_escapes(tmp_path):
"""A symlink planted inside the work dir must not become a host read."""
root = tmp_path / "work"
+18 -2
View File
@@ -213,6 +213,11 @@ async def test_diff_reports_a_new_directory_thanks_to_uall(tmp_path):
assert diff.is_empty is False
@pytest.mark.skipif(
os.name == "nt",
reason="creating a symlink on Windows requires SeCreateSymbolicLinkPrivilege "
"(admin or Developer Mode); the adapter's guard is covered on POSIX hosts",
)
async def test_diff_detects_an_escaping_symlink(tmp_path):
remote = await _make_remote(tmp_path)
adapter = _adapter(tmp_path, remote)
@@ -485,7 +490,14 @@ async def test_a_tampered_dot_git_file_is_ignored(tmp_path):
decoy = tmp_path / "decoy"
await _git(["init", "--quiet", str(decoy)], cwd=str(tmp_path))
with open(os.path.join(worktree.host_path, ".git"), "w", encoding="utf-8") as handle:
# Replace rather than overwrite: on Windows a git-created ``.git`` cannot be
# written in place (it can only be unlinked and recreated). The assertion
# below is identical either way — what matters is the *content* we plant.
pointer = os.path.join(worktree.host_path, ".git")
if os.path.lexists(pointer):
os.unlink(pointer)
with open(pointer, "w", encoding="utf-8") as handle:
handle.write(f"gitdir: {decoy}\n")
with open(os.path.join(worktree.host_path, "a.txt"), "w", encoding="utf-8") as handle:
@@ -557,7 +569,11 @@ async def test_the_askpass_helper_is_private_and_holds_no_secret(tmp_path):
helper = tmp_path / "root" / "org1" / "proj1" / "private" / "askpass.sh"
assert helper.is_file()
assert oct(helper.stat().st_mode)[-3:] == "700"
# ``chmod`` is a no-op on Windows (NTFS has no POSIX mode bits), so the
# executable bit is only asserted where it exists. The security property
# that matters everywhere — no secret inside the helper — is checked below.
if os.name == "posix":
assert oct(helper.stat().st_mode)[-3:] == "700"
assert "s3cret-token-value" not in helper.read_text()