guards: skip a commit the sync hasn't fetched yet, quietly (race, not error)
The bridge reads PR/default heads from GitHub after the sync's fetch; a push in between isn't in the clone until the next cycle. Both guards logged a CalledProcessError for it (windy-pro main 40 s after the fetch). Now None = nothing posted this cycle; the next one scans it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -182,3 +182,12 @@ def test_code_with_a_trailing_comment_still_counts():
|
|||||||
def test_windy_pro_desktop_is_byok_but_the_account_server_is_not():
|
def test_windy_pro_desktop_is_byok_but_the_account_server_is_not():
|
||||||
assert cg.allowed("windy-pro", "src/client/desktop/main.js", ALLOW)
|
assert cg.allowed("windy-pro", "src/client/desktop/main.js", ALLOW)
|
||||||
assert not cg.allowed("windy-pro", "account-server/src/routes/translations.ts", ALLOW)
|
assert not cg.allowed("windy-pro", "account-server/src/routes/translations.ts", ALLOW)
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_commit_not_fetched_yet_is_skipped_not_an_error(tmp_path, monkeypatch):
|
||||||
|
bare, sha = _repo(tmp_path, {"app/llm.py": "import anthropic\n"})
|
||||||
|
monkeypatch.setattr(cg, "WORK", tmp_path)
|
||||||
|
monkeypatch.setattr(cg, "CACHE", tmp_path / "cache.json")
|
||||||
|
(tmp_path / "windy-chat.git").symlink_to(bare)
|
||||||
|
assert cg.check("windy-chat", "f" * 40, "main", True) is None # pushed after the fetch
|
||||||
|
assert [f.kind for f in cg.check("windy-chat", sha, "main", True)] == ["provider SDK"]
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ def scan_line(path: str, text: str) -> list[tuple[str, str]]:
|
|||||||
|
|
||||||
def check(repo: str, sha: str, default_branch: str, is_default_head: bool):
|
def check(repo: str, sha: str, default_branch: str, is_default_head: bool):
|
||||||
bare = cg.WORK / f"{repo}.git"
|
bare = cg.WORK / f"{repo}.git"
|
||||||
if not bare.is_dir():
|
if not bare.is_dir() or not cg.fetched(bare, sha): # pushed after the fetch: next cycle
|
||||||
return None
|
return None
|
||||||
allow = cg.load_allow(ALLOW_FILE)
|
allow = cg.load_allow(ALLOW_FILE)
|
||||||
rules = hashlib.sha256((PREFILTER + INCLUDE.pattern + EXACT_PY.pattern + EXACT_NPM.pattern).encode()).hexdigest()[:8]
|
rules = hashlib.sha256((PREFILTER + INCLUDE.pattern + EXACT_PY.pattern + EXACT_NPM.pattern).encode()).hexdigest()[:8]
|
||||||
|
|||||||
@@ -225,10 +225,21 @@ def cached_scan(key: str, fn) -> list[Finding]:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def fetched(bare: Path, sha: str) -> bool:
|
||||||
|
"""Is `sha` in the sync clone yet? The bridge learns PR / default heads from
|
||||||
|
GitHub's API AFTER the sync fetched, so a push in between is simply not here
|
||||||
|
until the next 5-min cycle. That is a race, not an error: skip quietly."""
|
||||||
|
try:
|
||||||
|
_git(bare, "cat-file", "-e", f"{sha}^{{commit}}")
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check(repo: str, sha: str, default_branch: str, is_default_head: bool) -> list[Finding] | None:
|
def check(repo: str, sha: str, default_branch: str, is_default_head: bool) -> list[Finding] | None:
|
||||||
"""Findings for one commit, or None when the guard can't run (never a fake OK)."""
|
"""Findings for one commit, or None when the guard can't run (never a fake OK)."""
|
||||||
bare = WORK / f"{repo}.git"
|
bare = WORK / f"{repo}.git"
|
||||||
if not bare.is_dir():
|
if not bare.is_dir() or not fetched(bare, sha):
|
||||||
return None
|
return None
|
||||||
allow = load_allow()
|
allow = load_allow()
|
||||||
fp = _fingerprint(allow)
|
fp = _fingerprint(allow)
|
||||||
|
|||||||
Reference in New Issue
Block a user