Inherit Forge queue response ownership

943a7b8e7733 · AtlantisPleb · · parent d7dee614af2e

Inherit Forge queue response ownership

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/build_protocol.ex
  • modified lib/openagents/forge/build_worker.ex
  • modified test/openagents/forge/build_worker_test.exs

Diff

3 files changed, +17 -1

lib/openagents/forge/build_protocol.ex modified +10

@@ -149,12 +149,14 @@ defmodule OpenAgents.Forge.BuildProtocol do

149 149
  @spec atomic_write(Path.t(), iodata(), keyword()) :: :ok | {:error, term()}
150 150
  def atomic_write(path, contents, opts \\ []) do
151 151
    mode = Keyword.get(opts, :mode, 0o600)
152
    inherit_parent_owner? = Keyword.get(opts, :inherit_parent_owner, false)
152 153
    tmp = path <> ".tmp-" <> Base.url_encode64(:crypto.strong_rand_bytes(12), padding: false)
153 154
    lock = path <> ".publish-lock"
154 155
155 156
    with :ok <- File.mkdir_p(Path.dirname(path)),
156 157
         :ok <- File.write(tmp, contents, [:binary]),
157 158
         :ok <- File.chmod(tmp, mode),
159
         :ok <- maybe_inherit_parent_owner(tmp, path, inherit_parent_owner?),
158 160
         {:ok, lock_io} <- File.open(lock, [:write, :exclusive]) do
159 161
      try do
160 162
        if File.exists?(path),

@@ -172,6 +174,14 @@ defmodule OpenAgents.Forge.BuildProtocol do

172 174
    |> tap(fn _result -> File.rm(tmp) end)
173 175
  end
174 176
177
  defp maybe_inherit_parent_owner(_tmp, _path, false), do: :ok
178
179
  defp maybe_inherit_parent_owner(tmp, path, true) do
180
    with {:ok, %{uid: uid, gid: gid}} <- File.stat(Path.dirname(path)) do
181
      with :ok <- File.chown(tmp, uid), do: File.chgrp(tmp, gid)
182
    end
183
  end
184
175 185
  @doc "Canonical JSON used by signed/digested protocol documents."
176 186
  @spec canonical_json(term()) :: binary()
177 187
  def canonical_json(term) do
lib/openagents/forge/build_worker.ex modified +2 -1

@@ -491,7 +491,8 @@ defmodule OpenAgents.Forge.BuildWorker do

491 491
      BuildProtocol.atomic_write(
492 492
        Path.join([queue, "responses", response["build_id"] <> ".json"]),
493 493
        encoded,
494
        mode: 0o640
494
        mode: 0o640,
495
        inherit_parent_owner: true
495 496
      )
496 497
    end
497 498
  end
test/openagents/forge/build_worker_test.exs modified +5

@@ -48,6 +48,11 @@ defmodule OpenAgents.Forge.BuildWorkerTest do

48 48
    assert {:ok, response} = response_path |> File.read!() |> BuildProtocol.decode_response()
49 49
    assert response["status"] == "ok"
50 50
    assert response["build_id"] == build_id
51
    assert {:ok, response_stat} = File.stat(response_path)
52
    assert {:ok, response_dir_stat} = File.stat(Path.dirname(response_path))
53
    assert Bitwise.band(response_stat.mode, 0o777) == 0o640
54
    assert response_stat.uid == response_dir_stat.uid
55
    assert response_stat.gid == response_dir_stat.gid
51 56
52 57
    artifact_path = Path.join(artifacts, response["artifact_ref"])
53 58

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