Skip to content

Commit 92e142f

Browse files
authored
Merge pull request #314 from diazMelgarejo/cursor/guard-sync-parity-74e2
chore(git): sync attribution guards from orama canonical (PR #251 stack)
2 parents 63551b2 + 6fa134c commit 92e142f

5 files changed

Lines changed: 164 additions & 8 deletions

File tree

.cursor/commands/pr.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Reference these in the PR body if they exist.
8888
## Phase 3 — PUSH
8989

9090
```bash
91-
git push -u origin HEAD
91+
bash scripts/git/publish-clean-branch.sh "$(git branch --show-current)" <base> origin
9292
```
9393

9494
If push fails due to divergence:
@@ -99,7 +99,8 @@ git rebase origin/<base>
9999
bash scripts/git/publish-clean-branch.sh "$(git branch --show-current)" <base> origin
100100
```
101101

102-
Use the audited publisher after rebase — never raw `git push --force` or `--force-with-lease`.
102+
Use the audited publisher for every push path — never raw `git push`, `git push --force`,
103+
or `--force-with-lease`.
103104

104105
If rebase conflicts occur, stop and inform the user.
105106

scripts/git/reanchor_scan.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ if [ -n "$_TIMEOUT_BIN" ]; then
3737
exit 3
3838
fi
3939
else
40-
if ! git fetch --prune origin >/dev/null 2>&1; then
41-
echo " FAIL: git fetch --prune origin failed (offline) — scan aborted"
42-
exit 3
43-
fi
40+
# No gtimeout (macOS Homebrew coreutils) or timeout (Linux) available --
41+
# an unbounded `git fetch` here can hang indefinitely on a network stall,
42+
# with no deadline to recover from. Abort rather than risk that, same
43+
# failure message and exit code as the bounded-timeout failure path
44+
# above, so callers see one consistent "scan aborted" contract either
45+
# way.
46+
echo " FAIL: no gtimeout/timeout binary available — refusing an unbounded git fetch — scan aborted"
47+
exit 3
4448
fi
4549
MAIN=$(git rev-parse "$MAINREF") || { echo " no $MAINREF"; exit 0; }
4650
ROOT=$(git rev-list --max-parents=0 "$MAIN" | tail -1)

tests/test_check_no_pending_merge.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def test_check_no_pending_merge_blocks_pending_am_session(tmp_path: Path) -> Non
230230
assert "am --continue" in result.stderr
231231
assert "am --abort" in result.stderr
232232

233-
subprocess.run(["git", "am", "--abort"], cwd=repo, capture_output=True, text=True, encoding="utf-8")
233+
subprocess.run(["git", "am", "--abort"], cwd=repo, capture_output=True, text=True, encoding="utf-8", check=True)
234234

235235

236236
def test_check_no_pending_merge_blocks_merge_msg_marker(tmp_path: Path) -> None:
@@ -321,7 +321,7 @@ def test_check_no_pending_merge_blocks_rebase_marker(tmp_path: Path) -> None:
321321
assert "REBASE" in result.stderr
322322
assert "rebase --continue" in result.stderr
323323

324-
subprocess.run(["git", "rebase", "--abort"], cwd=repo, capture_output=True, text=True, encoding="utf-8")
324+
subprocess.run(["git", "rebase", "--abort"], cwd=repo, capture_output=True, text=True, encoding="utf-8", check=True)
325325

326326

327327
def test_check_no_pending_merge_blocks_pending_revert(tmp_path: Path) -> None:

tests/test_guard_sync_manifest.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""Guard sync manifest — single source of truth for attribution guard distribution."""
2+
from __future__ import annotations
3+
4+
import re
5+
import subprocess
6+
from pathlib import Path
7+
8+
import pytest
9+
10+
ROOT = Path(__file__).resolve().parents[1]
11+
GIT = ROOT / "scripts" / "git"
12+
MANIFEST = GIT / "guard-sync-manifest.sh"
13+
SYNC = GIT / "sync-attribution-guard-scripts.sh"
14+
VERIFY = GIT / "verify-guard-parity.sh"
15+
16+
17+
def _extract_sync_binding_pattern() -> str:
18+
"""Pull the actual grep -Eq pattern out of verify-guard-parity.sh's own
19+
SYNC BINDING check, rather than hardcoding a copy of it here. A
20+
hardcoded literal doesn't change when the production pattern does --
21+
this test would keep passing (or failing) against a stale definition
22+
while a real regression in the production check goes undetected.
23+
Reading it from the source means drift between the two is impossible
24+
by construction: there is only one pattern, extracted at test time."""
25+
text = VERIFY.read_text(encoding="utf-8")
26+
match = re.search(
27+
r"grep -Eq '(\^\[\[:space:\]\].*guard-sync-manifest\\\.sh)'",
28+
text,
29+
)
30+
assert match, (
31+
"could not find the SYNC BINDING grep pattern in "
32+
f"{VERIFY} -- verify-guard-parity.sh's check may have been "
33+
"rewritten in a way this extraction no longer matches"
34+
)
35+
return match.group(1)
36+
37+
38+
_SYNC_BINDING_PATTERN = _extract_sync_binding_pattern()
39+
40+
41+
def _run_sync_binding_check(sync_script: Path) -> subprocess.CompletedProcess[str]:
42+
"""Same grep as verify-guard-parity.sh SYNC BINDING check."""
43+
return subprocess.run(
44+
["grep", "-Eq", _SYNC_BINDING_PATTERN, str(sync_script)],
45+
capture_output=True,
46+
text=True,
47+
encoding="utf-8",
48+
)
49+
50+
51+
def _bash_array(name: str) -> list[str]:
52+
result = subprocess.run(
53+
[
54+
"bash",
55+
"-c",
56+
f'source "$1" && printf "%s\\n" "${{{name}[@]}}"',
57+
"_",
58+
str(MANIFEST),
59+
],
60+
cwd=ROOT,
61+
capture_output=True,
62+
text=True,
63+
encoding="utf-8",
64+
check=True,
65+
)
66+
return [line for line in result.stdout.splitlines() if line]
67+
68+
69+
@pytest.mark.unit
70+
def test_manifest_files_exist_on_disk() -> None:
71+
all_paths = _bash_array("GUARD_SYNC_EXECUTABLES") + _bash_array("GUARD_SYNC_DATA_FILES")
72+
missing = [rel for rel in all_paths if not (GIT / rel).is_file()]
73+
assert not missing, f"manifest lists missing files: {missing}"
74+
75+
76+
@pytest.mark.unit
77+
def test_parity_required_expands_in_bash() -> None:
78+
"""GUARD_PARITY_REQUIRED is assembled at source time from the two sync arrays."""
79+
parity = _bash_array("GUARD_PARITY_REQUIRED")
80+
expected = set(_bash_array("GUARD_SYNC_EXECUTABLES")) | set(
81+
_bash_array("GUARD_SYNC_DATA_FILES")
82+
)
83+
assert set(parity) == expected
84+
85+
86+
@pytest.mark.unit
87+
def test_sync_and_verify_source_manifest() -> None:
88+
pattern = r'^\s*(source|\.)\s+.*guard-sync-manifest\.sh'
89+
for script in (SYNC, VERIFY):
90+
body = script.read_text(encoding="utf-8")
91+
assert re.search(pattern, body, re.MULTILINE), (
92+
f"{script.name} must source guard-sync-manifest.sh via an uncommented command"
93+
)
94+
95+
96+
@pytest.mark.unit
97+
def test_verify_rejects_comment_only_manifest_reference(tmp_path: Path) -> None:
98+
"""Comment-only 'source guard-sync-manifest.sh' must not satisfy the binding check."""
99+
fake_sync = tmp_path / "sync-attribution-guard-scripts.sh"
100+
fake_sync.write_text(
101+
"# source guard-sync-manifest.sh\n",
102+
encoding="utf-8",
103+
)
104+
fake_result = _run_sync_binding_check(fake_sync)
105+
assert fake_result.returncode != 0, (
106+
"production binding grep must reject comment-only manifest reference"
107+
)
108+
real_result = _run_sync_binding_check(SYNC)
109+
assert real_result.returncode == 0, (
110+
"canonical sync-attribution-guard-scripts.sh must satisfy binding check"
111+
)
112+
113+
114+
@pytest.mark.unit
115+
def test_verify_guard_parity_passes_in_canonical_repo() -> None:
116+
result = subprocess.run(
117+
["bash", str(VERIFY)],
118+
cwd=ROOT,
119+
capture_output=True,
120+
text=True,
121+
encoding="utf-8",
122+
)
123+
assert result.returncode == 0, result.stdout + result.stderr

tests/test_verify_guard_parity.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Tests for scripts/git/verify-guard-parity.sh edge cases."""
2+
from __future__ import annotations
3+
4+
import shutil
5+
import subprocess
6+
from pathlib import Path
7+
8+
import pytest
9+
10+
ROOT = Path(__file__).resolve().parents[1]
11+
VERIFY = ROOT / "scripts" / "git" / "verify-guard-parity.sh"
12+
13+
pytestmark = pytest.mark.unit
14+
15+
16+
def test_verify_guard_parity_fails_on_inaccessible_target() -> None:
17+
bash = shutil.which("bash")
18+
assert bash is not None
19+
result = subprocess.run( # noqa: S603 — test controls all arguments
20+
[bash, str(VERIFY), "/path/does/not/exist"],
21+
cwd=ROOT,
22+
capture_output=True,
23+
text=True,
24+
encoding="utf-8",
25+
)
26+
assert result.returncode != 0
27+
assert "cannot access target repository" in result.stdout + result.stderr
28+
assert "FAIL" in result.stdout + result.stderr

0 commit comments

Comments
 (0)