From a9be4532affc667c8872248b61789e5789d4cfc3 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 17 Oct 2026 10:31:42 +0200 Subject: [PATCH] fix: report a refused forge as unread, not gone --- scripts/profile_sync.py | 18 ++++++++++++++++-- tests/test_profile_sync.py | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 6478a981..f3ae63cb 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -1840,10 +1840,24 @@ def build_report( f"annotated for version {other}, not the documented one", ) if flag: - return verify_at_pin( + result = verify_at_pin( part, fetch(PIN, part.path, part.start, tokens), tokens, hashes ) - return anchor_across_views(part, tokens) + else: + result = anchor_across_views(part, tokens) + # A forge that refused the request said nothing about the file: + # git.eden-emu.dev answers 403 to scripts, and nine citations of + # eden-nightly read "absent at HEAD" for a file that exists. + owner, _actual = resolve_path(part.path, part.start, tuple(tokens)) + if ( + result.status in ("GONE", "AMBIGUOUS") + and (owner.repo.host, owner.repo.slug) in mute + ): + return PartResult( + part, "UNCHECKED", None, None, None, [], + f"{owner.repo.host}/{owner.repo.slug} refused the request, not read", + ) + return result staged = [] for entry_name, ref, tokens, hashes, ref_parts, citation in refs: diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index d2c2d4c5..893ee18b 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -1219,6 +1219,19 @@ class TestBuildReport(unittest.TestCase): ], } + def test_a_refusing_forge_reads_as_unread_not_gone(self): + """git.eden-emu.dev answers 403 to scripts: the muted repository's + citations read "absent at HEAD" for files that exist.""" + def refuse(repo, sha, path, cache_dir, offline=False): + raise profile_sync.upstream.UpstreamError(f"{path}: HTTP 403") + + profile_sync.upstream.fetch_file = refuse + with contextlib.redirect_stderr(io.StringIO()): + report = build_report("test", self._profile(["a.c:2"]), self.dir) + statuses = [p.status for e in report.entries for p in e.parts] + self.assertEqual(statuses, ["UNCHECKED"]) + self.assertIn("refused", report.entries[0].parts[0].reason) + def test_counts_by_status(self): self.files[("pinsha", "a.c")] = ["x", "hit", "y"] self.files[("headsha", "a.c")] = ["pad", "x", "hit", "y"]