G11 / I-4: continuous off-site mirror, and a namespace bug fixed
I-4 said 'never a one-way door' and had no implementation. Now it does.
- ensure the GitHub counterpart exists (idempotent), then ask Gitea to keep
it in step with sync_on_commit=True. An hourly timer means an hour of work
can be the thing you lose, and that window is invisible until it costs you.
- mirror status reports what is TRUE including 'we do not know'. An
unconfigured mirror reports unconfigured, NEVER healthy — same posture as
me-fleet.ts refusing to say 'online' when it only knows 'registered'.
- lag past the threshold is a P2, not a shrug. A mirror nobody checks is a
belief, not a backup, and this ecosystem already lost 37 days to a canary
everyone assumed was fine.
Gitea owns the replication rather than a hand-rolled loop, because a background
job that fails silently is exactly how the registry's integrity refresh spent
its entire life calling a 404 and incrementing a counter instead of raising.
Also fixes a real bug I had written myself: list_versions derived the Gitea
namespace from the CALLER, which is correct only while the caller is the owner
and addresses the wrong namespace the moment a collaborator asks — surfacing as
'not found', which is the hardest kind of bug to see. Now derived from the repo,
with a test that keeps it that way.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -349,3 +349,37 @@ def test_g55_shelter_strings_avoid_developer_vocabulary():
|
||||
low = s.lower()
|
||||
for jargon in ("commit", "repository", "branch", "sha", "push"):
|
||||
assert jargon not in low, f"developer vocabulary in a user string: {s!r}"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# I-4 — never a one-way door
|
||||
# --------------------------------------------------------------------------
|
||||
def test_i04_mirror_syncs_on_every_save_not_just_a_timer():
|
||||
"""An hourly window means an hour of work can be the thing you lose, and the
|
||||
window is invisible until it costs you."""
|
||||
src = (ROOT / "api" / "app" / "services" / "mirror.py").read_text()
|
||||
assert '"sync_on_commit": True' in src
|
||||
|
||||
|
||||
def test_i04_unconfigured_mirror_is_never_reported_healthy():
|
||||
"""A mirror nobody checks is a belief, not a backup. An unconfigured one
|
||||
reports 'unconfigured' — never 'healthy'."""
|
||||
src = (ROOT / "api" / "app" / "services" / "mirror.py").read_text()
|
||||
assert '"state": "unconfigured"' in src
|
||||
assert "if not self.configured:" in src
|
||||
|
||||
|
||||
def test_i04_mirror_lag_threshold_is_set():
|
||||
from api.app.config import Settings
|
||||
|
||||
assert Settings().mirror_lag_p2_seconds == 3600
|
||||
|
||||
|
||||
def test_owner_namespace_is_derived_from_the_repo_not_the_caller():
|
||||
"""Deriving the namespace from the caller is right only while the caller is
|
||||
the owner, and addresses the wrong namespace the moment a collaborator asks
|
||||
— surfacing as 'not found', which is the hardest kind of bug to see."""
|
||||
src = (ROOT / "api" / "app" / "routes" / "repos.py").read_text()
|
||||
body = src[src.index("async def list_versions") : src.index("async def create_grant")]
|
||||
assert "_repo_owner_login(repo)" in body
|
||||
assert "_owner_login(caller)" not in body
|
||||
|
||||
Reference in New Issue
Block a user