Mirror canonical repository storage

8e01231d1bdc · AtlantisPleb · · parent 160134fe14d2

Mirror canonical repository storage

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified lib/openagents/forge/mirror_watch.ex
  • modified lib/openagents/forge/pushes.ex
  • modified test/openagents/forge/mirror_watch_test.exs

Diff

3 files changed, +82 -3

lib/openagents/forge/mirror_watch.ex modified +1 -1

@@ -141,7 +141,7 @@ defmodule OpenAgents.Forge.MirrorWatch do

141 141
  end
142 142
143 143
  defp forge_main(repo) do
144
    case Repos.refs(repo) do
144
    case repo |> Pushes.mirror_storage_key() |> Repos.refs() do
145 145
      %{"refs/heads/main" => sha} when is_binary(sha) -> {:ok, sha}
146 146
      _other -> {:error, :no_main}
147 147
    end
lib/openagents/forge/pushes.ex modified +40 -2

@@ -23,6 +23,7 @@ defmodule OpenAgents.Forge.Pushes do

23 23
  alias OpenAgents.Analytics
24 24
  alias OpenAgents.Forge.{GitHTTP, PushReceipt, Repos, Sync, WAL}
25 25
  alias OpenAgents.Repo
26
  alias OpenAgents.Repositories.Repository
26 27
27 28
  @doc """
28 29
  Handle one `git-receive-pack` request body. Returns `{:ok, response_body}`

@@ -235,7 +236,7 @@ defmodule OpenAgents.Forge.Pushes do

235 236
        {:error, :mirror_unconfigured}
236 237
237 238
      url ->
238
        path = Repos.bare_path(repo)
239
        path = repo |> mirror_storage_key() |> Repos.bare_path()
239 240
240 241
        case Repos.git(path, ["push", "--mirror", url]) do
241 242
          {_, 0} ->

@@ -251,11 +252,48 @@ defmodule OpenAgents.Forge.Pushes do

251 252
  @doc "The configured mirror URL for a repo, or nil (config `:forge_mirror_urls`)."
252 253
  def mirror_url(repo) do
253 254
    case Application.get_env(:openagents, :forge_mirror_urls, %{}) do
254
      %{} = urls -> clean_mirror_url(urls[repo])
255
      %{} = urls -> clean_mirror_url(urls[repo] || urls[repository_name(repo)])
255 256
      _ -> nil
256 257
    end
257 258
  end
258 259
260
  @doc "Resolve a configured repository name or storage key to its bare-cache storage key."
261
  def mirror_storage_key(repo) when is_binary(repo) do
262
    storage_key_for_storage_key(repo) || storage_key_for_name(repo) || repo
263
  rescue
264
    _database_unavailable -> repo
265
  end
266
267
  def mirror_storage_key(repo), do: repo
268
269
  defp storage_key_for_storage_key(storage_key) do
270
    Repo.one(
271
      from repository in Repository,
272
        where: repository.storage_key == ^storage_key,
273
        select: repository.storage_key
274
    )
275
  end
276
277
  defp storage_key_for_name(name) do
278
    Repo.one(
279
      from repository in Repository,
280
        where: repository.name == ^name,
281
        select: repository.storage_key
282
    )
283
  end
284
285
  defp repository_name(storage_key) when is_binary(storage_key) do
286
    Repo.one(
287
      from repository in Repository,
288
        where: repository.storage_key == ^storage_key,
289
        select: repository.name
290
    )
291
  rescue
292
    _database_unavailable -> nil
293
  end
294
295
  defp repository_name(_storage_key), do: nil
296
259 297
  defp clean_mirror_url(nil), do: nil
260 298
261 299
  defp clean_mirror_url(url) when is_binary(url) do
test/openagents/forge/mirror_watch_test.exs modified +41

@@ -10,6 +10,7 @@ defmodule OpenAgents.Forge.MirrorWatchTest do

10 10
11 11
  alias OpenAgents.Forge.{MirrorWatch, Repos}
12 12
  alias OpenAgents.Repo
13
  alias OpenAgents.Repositories.{Namespace, Repository}
13 14
14 15
  setup do
15 16
    base = Path.join(System.tmp_dir!(), "mirror-#{System.unique_integer([:positive])}")

@@ -102,6 +103,46 @@ defmodule OpenAgents.Forge.MirrorWatchTest do

102 103
    assert MirrorWatch.state()["state"] == "current"
103 104
  end
104 105
106
  test "a logical repository name mirrors its canonical storage key", %{mirror: mirror} do
107
    namespace =
108
      Repo.insert!(%Namespace{
109
        provider: "github",
110
        provider_account_id: System.unique_integer([:positive]),
111
        slug: "MirrorTest",
112
        slug_key: "mirrortest",
113
        kind: "organization",
114
        provider_refreshed_at: DateTime.utc_now(),
115
        state: "active"
116
      })
117
118
    storage_key = Ecto.UUID.generate()
119
120
    Repo.insert!(%Repository{
121
      namespace_id: namespace.id,
122
      owner: namespace.slug,
123
      owner_key: namespace.slug_key,
124
      name: "mapped-repo",
125
      name_key: "mapped-repo",
126
      visibility: "public",
127
      default_branch: "main",
128
      lifecycle_state: "ready",
129
      provisioning_kind: "empty",
130
      storage_key: storage_key,
131
      ready_at: DateTime.utc_now()
132
    })
133
134
    Application.put_env(:openagents, :forge_mirror_urls, %{"mapped-repo" => mirror})
135
    path = Repos.ensure_repo!(storage_key)
136
    seed_commit!(path, "canonical")
137
138
    assert OpenAgents.Forge.Pushes.mirror_storage_key("mapped-repo") == storage_key
139
    assert :ok = OpenAgents.Forge.Pushes.mirror_now("mapped-repo")
140
141
    {forge_main, 0} = Repos.git(path, ["rev-parse", "refs/heads/main"])
142
    {mirror_main, 0} = System.cmd("git", ["--git-dir", mirror, "rev-parse", "refs/heads/main"])
143
    assert String.trim(forge_main) == String.trim(mirror_main)
144
  end
145
105 146
  test "sustained lag records ONE degraded incident per episode" do
106 147
    # Make the mirror un-pushable but still readable: replace it with a
107 148
    # bare repo whose receive hook rejects everything.

This page updates live while a promote is in flight · changelog