Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions .github/workflows/codeql-scan-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -580,5 +580,22 @@ jobs:
exit 1
fi

gh api -X POST "repos/${TARGET_REPOSITORY}/actions/jobs/${REQUIRED_JOB_ID}/rerun" >/dev/null
echo "Re-ran exact failed CodeQL job ${REQUIRED_JOB_ID} for ${REQUIRED_LANGUAGE} on ${HEAD_SHA}."
rerun_error="$(mktemp)"
if gh api -X POST "repos/${TARGET_REPOSITORY}/actions/jobs/${REQUIRED_JOB_ID}/rerun" >/dev/null 2>"$rerun_error"; then
rm -f "$rerun_error"
echo "Re-ran exact failed CodeQL job ${REQUIRED_JOB_ID} for ${REQUIRED_LANGUAGE} on ${HEAD_SHA}."
exit 0
fi
if grep -q "already running" "$rerun_error"; then
rm -f "$rerun_error"
echo "::notice::Exact CodeQL job ${REQUIRED_JOB_ID} rerun collided with a sibling language shard that already re-triggered the shared run; the required run is re-executing."
exit 0
Comment thread
seonghobae marked this conversation as resolved.
Outdated
fi
rerun_detail="$(head -n 1 "$rerun_error" | tr -d '\r' || true)"
rm -f "$rerun_error"
if [ -n "$rerun_detail" ]; then
echo "::error::Exact CodeQL job rerun did not succeed: $rerun_detail."
else
echo "::error::Exact CodeQL job rerun did not succeed."
fi
exit 1
43 changes: 43 additions & 0 deletions tests/test_codeql_scan_dispatch_workflow_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ def _run_wake_step(
pull: dict | None = None,
run: dict | None = None,
job: dict | None = None,
rerun_error: str | None = None,
) -> tuple[subprocess.CompletedProcess[str], Path]:
"""Execute the exact wake block against fixture-backed GitHub API responses."""
bash = shutil.which("bash")
Expand Down Expand Up @@ -623,6 +624,10 @@ def _run_wake_step(
'if [ "${2:-}" = "-X" ]; then\n'
' test "$3" = POST\n'
' printf \'%s\\n\' "$4" >>"$FAKE_POST_LOG"\n'
' if [ -n "$FAKE_RERUN_ERROR" ]; then\n'
' printf \'%s\\n\' "$FAKE_RERUN_ERROR" >&2\n'
' exit 1\n'
' fi\n'
" exit 0\n"
"fi\n"
'case "$2" in\n'
Expand All @@ -641,6 +646,7 @@ def _run_wake_step(
"FAKE_RUN_JSON": json.dumps(run),
"FAKE_JOB_JSON": json.dumps(job),
"FAKE_POST_LOG": str(post_log),
"FAKE_RERUN_ERROR": rerun_error or "",
"GH_TOKEN": "fake-token",
"WAKE_TOKEN_SOURCE": "PR_REVIEW_MERGE_TOKEN",
"TARGET_REPOSITORY": "ContextualWisdomLab/naruon",
Expand All @@ -661,6 +667,43 @@ def _run_wake_step(
return result, post_log


def test_dispatch_wake_tolerates_sibling_shard_rerun_race(tmp_path: Path) -> None:
"""A sibling language shard may re-trigger the shared run first.

Live evidence: ContextualWisdomLab/.github#1563 dispatch run 34297767440 —
the actions shard's rerun moved the shared CodeQL PR run back to
in_progress, so the python shard's own POST .../jobs/{id}/rerun was
rejected with HTTP 403 "already running". The required run is
re-executing either way, so that rejection is the desired end state,
not a wake failure.
"""
result, post_log = _run_wake_step(
tmp_path,
rerun_error="gh: The workflow run containing this job is already running (HTTP 403)",
)

assert result.returncode == 0, result.stderr
assert "already re-triggered the shared run" in result.stdout
assert post_log.read_text(encoding="utf-8").splitlines() == [
"repos/ContextualWisdomLab/naruon/actions/jobs/43/rerun"
]


def test_dispatch_wake_still_fails_closed_on_other_rerun_errors(
tmp_path: Path,
) -> None:
result, post_log = _run_wake_step(
tmp_path,
rerun_error="gh: Resource not accessible by integration (HTTP 403)",
)

assert result.returncode == 1
assert "rerun did not succeed" in result.stdout
assert post_log.read_text(encoding="utf-8").splitlines() == [
"repos/ContextualWisdomLab/naruon/actions/jobs/43/rerun"
]


def test_dispatch_wake_reruns_only_fixture_bound_exact_job(tmp_path: Path) -> None:
result, post_log = _run_wake_step(tmp_path)

Expand Down
Loading