Files

147 lines
6.1 KiB
Python
Raw Permalink Normal View History

"""Real local Git pushes; never install in the project being developed."""
import os
import shutil
import subprocess
from pathlib import Path
import pytest
from test_push_runner import history
@pytest.mark.parametrize("prior_exit", [0, 7])
def test_existing_hook_stdin_remote_exit_and_removal(tmp_path, prior_exit):
root, base, head, git = history(tmp_path)
remote = tmp_path / "remote.git"
subprocess.run(["git", "init", "--bare", str(remote)], check=True, capture_output=True)
git("remote", "add", "origin", str(remote))
hooks = root / ".custom-hooks"
hooks.mkdir()
git("config", "core.hooksPath", ".custom-hooks")
hook = hooks / "pre-push"
prior = hooks / "pre-push.before-ousast"
log = tmp_path / "prior-input"
args = tmp_path / "prior-args"
prior.write_text(f'#!/bin/sh\nprintf "%s\\n" "$@" > "{args}"\ncat > "{log}"\nexit {prior_exit}\n')
prior.chmod(0o755)
shutil.copyfile(Path(__file__).resolve().parents[1] / "ops/pre-push", hook)
hook.chmod(0o755)
before = (root / ".git/index").read_bytes(), (root / "api.js").read_bytes(), git("rev-parse", "HEAD")
env = {
**os.environ,
"PATH": str(Path(".venv/bin").resolve()) + os.pathsep + os.environ["PATH"],
"OUSAST_ARTIFACT_DIR": str(tmp_path / "artifacts"),
"OUSAST_PUSH_DEADLINE": "0.1",
}
result = subprocess.run(["git", "-C", str(root), "push", "origin", "HEAD:refs/heads/test"], env=env, capture_output=True)
assert (result.returncode == 0) == (prior_exit == 0), result.stderr
assert log.read_text() == f"HEAD {head} refs/heads/test {'0' * 40}\n"
assert args.read_text().splitlines() == ["origin", str(remote)]
assert ((root / ".git/index").read_bytes(), (root / "api.js").read_bytes(), git("rev-parse", "HEAD")) == before
assert git("config", "core.hooksPath") == ".custom-hooks"
assert list((tmp_path / "artifacts").glob("*.json"))
# Explicit removal restores the prior hook byte-for-byte, without config/source/ref edits.
original = prior.read_bytes()
hook.unlink()
prior.rename(hook)
assert hook.read_bytes() == original
result = subprocess.run(["git", "-C", str(root), "push", "origin", "HEAD:refs/heads/after-removal"], env=env, capture_output=True)
assert (result.returncode == 0) == (prior_exit == 0)
assert "refs/heads/after-removal" in log.read_text()
def test_install_refuses_existing_and_honors_hooks_path(tmp_path):
root, _, _, git = history(tmp_path)
git("config", "core.hooksPath", ".custom-hooks")
installer = Path(__file__).resolve().parents[1] / "ops/install-pre-push"
first = subprocess.run([str(installer), str(root)], capture_output=True)
assert first.returncode == 0, first.stderr
hook = root / ".custom-hooks/pre-push"
hook.write_text("#!/bin/sh\nexit 23\n")
before = hook.read_bytes()
second = subprocess.run([str(installer), str(root)], capture_output=True)
assert second.returncode != 0
assert hook.read_bytes() == before
assert git("config", "core.hooksPath") == ".custom-hooks"
def test_chain_preserves_exact_nonzero_even_for_advisory(tmp_path):
import sys
root, _, _, _ = history(tmp_path)
prior = tmp_path / "prior"
prior.write_text("#!/bin/sh\ncat >/dev/null\nexit 23\n")
prior.chmod(0o755)
result = subprocess.run(
[
sys.executable,
"-m",
"openultrasast.cli",
"pre-push",
str(root),
"--artifact",
str(tmp_path / "result.json"),
"--prior-hook",
str(prior),
"--remote",
"origin",
"/tmp/remote",
],
input=b"",
capture_output=True,
timeout=10,
)
assert result.returncode == 23
def test_install_refuses_dangling_symlink(tmp_path):
root, _, _, git = history(tmp_path)
git("config", "core.hooksPath", ".custom-hooks")
hooks = root / ".custom-hooks"
hooks.mkdir()
target = tmp_path / "must-not-create"
(hooks / "pre-push").symlink_to(target)
installer = Path(__file__).resolve().parents[1] / "ops/install-pre-push"
result = subprocess.run([str(installer), str(root)], capture_output=True)
assert result.returncode != 0
assert not target.exists()
def test_missing_ousast_never_blocks_the_push(tmp_path):
"""17.1 / Req 9.1: a hook whose executable is absent allows the push and says the check did not run."""
root, _, head, git = history(tmp_path)
remote = tmp_path / "remote.git"
subprocess.run(["git", "init", "--bare", str(remote)], check=True, capture_output=True)
git("remote", "add", "origin", str(remote))
hooks = root / ".hooks"
hooks.mkdir()
git("config", "core.hooksPath", ".hooks")
shutil.copyfile(Path(__file__).resolve().parents[1] / "ops/pre-push", hooks / "pre-push")
(hooks / "pre-push").chmod(0o755)
env = {**os.environ, "OUSAST_COMMAND": "ousast-not-installed-anywhere", "OUSAST_ARTIFACT_DIR": str(tmp_path / "a")}
result = subprocess.run(["git", "-C", str(root), "push", "origin", "HEAD:refs/heads/main"], env=env, capture_output=True)
assert result.returncode == 0, result.stderr
assert b"pre-push check did not run" in result.stdout + result.stderr
assert git("ls-remote", str(remote)).startswith(head)
@pytest.mark.parametrize(
("extra", "expected"),
[
(["--deadline", "abc"], 0),
(["--cache-dir", "INSIDE"], 0),
(["--deadline", "abc", "--mode", "blocking"], 2),
],
)
def test_hook_mode_usage_errors_are_advisory_unless_blocking(tmp_path, extra, expected):
"""17.1 / Req 9.1: invalid settings in hook mode allow the push; explicit blocking keeps exit 2."""
import sys
root, _, _, _ = history(tmp_path)
extra = [str(root / "cache") if item == "INSIDE" else item for item in extra]
command = [sys.executable, "-m", "openultrasast.cli", "pre-push", str(root), "--artifact", str(tmp_path / "r.json")]
result = subprocess.run([*command, *extra, "--remote", "origin", "/tmp/remote"], input=b"", capture_output=True, timeout=60)
assert result.returncode == expected, result.stderr
if expected == 0:
assert b"pre-push check did not run" in result.stdout