neiam /gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Packages
⭐
Log in to mark this repository.
Fix two flaky tests that made full-suite runs unreliable
4d4bd06 · Gabriel Morell · 2026-09-10 15:50
Message
{commit_body(@commit)}
Files changed
modified
test/git_gud/forks_test.exs
+28
−12
@@ -115,7 +115,7 @@ defmodule GitGud.ForksTest do
| 115 | 115 | {:ok, fork} = Repositories.fork(upstream, forker, forker) |
| 116 | 116 | |
| 117 | 117 | # Upstream advances; fork stays put. |
| 118 | − seed_two_commits_on_main(upstream) | |
| 118 | + advance_upstream_main(upstream) | |
| 119 | 119 | |
| 120 | 120 | assert {:ok, %{behind: behind, ahead: 0, fast_forward?: true}} = |
| 121 | 121 | Repositories.fork_status(fork, "main") |
@@ -151,7 +151,7 @@ defmodule GitGud.ForksTest do
| 151 | 151 | |
| 152 | 152 | :ok = Git.update_ref(fork.disk_path, "refs/heads/main", fork_new, fork_main) |
| 153 | 153 | |
| 154 | − seed_two_commits_on_main(upstream) | |
| 154 | + advance_upstream_main(upstream) | |
| 155 | 155 | |
| 156 | 156 | assert {:ok, %{ahead: 1}} = Repositories.fork_status(fork, "main") |
| 157 | 157 | assert {:error, {:diverged, _}} = Repositories.sync_fork(fork, "main", forker) |
@@ -164,7 +164,7 @@ defmodule GitGud.ForksTest do
| 164 | 164 | |
| 165 | 165 | forker = user_fixture() |
| 166 | 166 | {:ok, fork} = Repositories.fork(upstream, forker, forker) |
| 167 | − seed_two_commits_on_main(upstream) | |
| 167 | + advance_upstream_main(upstream) | |
| 168 | 168 | |
| 169 | 169 | stranger = user_fixture() |
| 170 | 170 | assert {:error, :forbidden} = Repositories.sync_fork(fork, "main", stranger) |
@@ -182,7 +182,7 @@ defmodule GitGud.ForksTest do
| 182 | 182 | test "pushing to the fork's PR branch updates refs/pull/N/head on upstream" do |
| 183 | 183 | {_upstream_user, upstream} = repository_fixture() |
| 184 | 184 | {:ok, upstream} = Repositories.update_repository(upstream, %{"visibility" => "public"}) |
| 185 | − seed_two_commits_on_main(upstream) | |
| 185 | + advance_upstream_main(upstream) | |
| 186 | 186 | |
| 187 | 187 | forker = user_fixture() |
| 188 | 188 | {:ok, fork} = Repositories.fork(upstream, forker, forker) |
@@ -268,7 +268,7 @@ defmodule GitGud.ForksTest do
| 268 | 268 | test "create + mergeable + merge against a fork's branch" do |
| 269 | 269 | {upstream_user, upstream} = repository_fixture() |
| 270 | 270 | {:ok, upstream} = Repositories.update_repository(upstream, %{"visibility" => "public"}) |
| 271 | − seed_two_commits_on_main(upstream) | |
| 271 | + advance_upstream_main(upstream) | |
| 272 | 272 | |
| 273 | 273 | forker = user_fixture() |
| 274 | 274 | {:ok, fork} = Repositories.fork(upstream, forker, forker) |
@@ -314,18 +314,34 @@ defmodule GitGud.ForksTest do
| 314 | 314 | commit_sha |
| 315 | 315 | end |
| 316 | 316 | |
| 317 | − defp seed_two_commits_on_main(repo) do | |
| 318 | − sha1 = seed_commit(repo) | |
| 317 | + # Move main forward one commit from wherever it already points. | |
| 318 | + # | |
| 319 | + # This used to re-run `seed_commit/1` first, which builds a *root* | |
| 320 | + # commit from fixed content: within the same second as the original | |
| 321 | + # seed that reproduced the identical SHA and main didn't move, but | |
| 322 | + # across a second boundary it created a different root and rewrote | |
| 323 | + # history under any fork — turning an expected ahead/behind of 1/1 | |
| 324 | + # into 2/2. Building on the existing tip is deterministic. | |
| 325 | + defp advance_upstream_main(repo) do | |
| 326 | + # Some callers hand this a repo with no main yet and rely on it to | |
| 327 | + # create one; others have already seeded it and just want it moved | |
| 328 | + # on. Both end up one commit further along than they started. | |
| 329 | + base = | |
| 330 | + case Git.resolve(repo.disk_path, "main") do | |
| 331 | + {:ok, sha} -> sha | |
| 332 | + _ -> seed_commit(repo) | |
| 333 | + end | |
| 334 | + | |
| 319 | 335 | blob = write_blob(repo.disk_path, "v2\n") |
| 320 | − tree = make_tree(repo.disk_path, sha1, "README.md", blob) | |
| 336 | + tree = make_tree(repo.disk_path, base, "README.md", blob) | |
| 321 | 337 | |
| 322 | − {:ok, sha2} = | |
| 323 | − Git.commit_tree(repo.disk_path, tree, [sha1], "second", | |
| 338 | + {:ok, sha} = | |
| 339 | + Git.commit_tree(repo.disk_path, tree, [base], "second", | |
| 324 | 340 | author: {"t", "t@t", DateTime.utc_now(:second)} |
| 325 | 341 | ) |
| 326 | 342 | |
| 327 | − :ok = Git.update_ref(repo.disk_path, "refs/heads/main", sha2, sha1) | |
| 328 | − sha2 | |
| 343 | + :ok = Git.update_ref(repo.disk_path, "refs/heads/main", sha, base) | |
| 344 | + sha | |
| 329 | 345 | end |
| 330 | 346 | |
| 331 | 347 | defp add_feature_branch(repo) do |
modified
test/git_gud/workflows/runner_jwt_test.exs
+11
−2
@@ -48,8 +48,17 @@ defmodule GitGud.Workflows.RunnerJwtTest do
| 48 | 48 | test "tampered token fails verify", %{job: job, run: run} do |
| 49 | 49 | token = RunnerJwt.mint(job, run) |
| 50 | 50 | [h, p, s] = String.split(token, ".") |
| 51 | − # Flip one byte of the signature | |
| 52 | − tampered = h <> "." <> p <> "." <> String.slice(s, 0..-2//1) <> "X" | |
| 51 | + # Flip the *first* character of the signature. The last one is a | |
| 52 | + # poor choice: 32 bytes encode to 43 base64url chars, so the final | |
| 53 | + # char carries 4 significant bits and 2 of padding — four different | |
| 54 | + # characters decode to the same bytes, and swapping between them | |
| 55 | + # leaves the signature genuinely unaltered. Every bit of the first | |
| 56 | + # character counts. | |
| 57 | + <<first::binary-size(1), rest::binary>> = s | |
| 58 | + replacement = if first == "A", do: "B", else: "A" | |
| 59 | + tampered = h <> "." <> p <> "." <> replacement <> rest | |
| 60 | + | |
| 61 | + assert tampered != token | |
| 53 | 62 | assert {:error, _} = RunnerJwt.verify(tampered) |
| 54 | 63 | end |
| 55 | 64 |
Parents: a7fb497