From c6dbcce887b5c48465f8aa68e1f6d9ce027355d2 Mon Sep 17 00:00:00 2001 From: Cassie Meharry Date: Tue, 28 Sep 2021 18:14:04 +0000 Subject: [PATCH 1/6] Allow Bors to sign commits This adds a new `committer.signing_key` entry to `bors.toml`. When specified, Bors will sign commits with `gpg`. The referenced secret key must be installed in the local gpg key store, making this patch unsuitable for public deployment. Future development could include adding a page to Bors's web UI to upload a private key for signing operations. --- config/test.exs | 2 + lib/github/github.ex | 13 +++-- lib/github/github/server.ex | 49 +++++++++++++++-- lib/github/github/signature.ex | 98 +++++++++++++++++++++++++++++++++ lib/worker/batcher.ex | 27 +++++++-- lib/worker/batcher/bors_toml.ex | 20 ++++--- test/github_signature_test.exs | 61 ++++++++++++++++++++ 7 files changed, 249 insertions(+), 21 deletions(-) create mode 100644 lib/github/github/signature.ex create mode 100644 test/github_signature_test.exs diff --git a/config/test.exs b/config/test.exs index 6ff8afa4d..3ddb002cb 100644 --- a/config/test.exs +++ b/config/test.exs @@ -28,4 +28,6 @@ config :bors, :server, BorsNG.GitHub.ServerMock config :bors, :oauth2, BorsNG.GitHub.OAuth2Mock config :bors, :is_test, true +config :bors, :test_gpg_key_id, {:system, "BORS_TEST_GPG_KEY_ID", ""} + config :bors, :celebrate_new_year, false diff --git a/lib/github/github.ex b/lib/github/github.ex index e913d5fa6..6f74fd00b 100644 --- a/lib/github/github.ex +++ b/lib/github/github.ex @@ -198,12 +198,12 @@ defmodule BorsNG.GitHub do parents: [bitstring], commit_message: bitstring, committer: tcommitter | nil - }) :: binary - def synthesize_commit!(repo_conn, info) do + }, bitstring | nil) :: binary + def synthesize_commit!(repo_conn, info, signing_key \\ nil) do {:ok, sha} = GenServer.call( BorsNG.GitHub, - {:synthesize_commit, repo_conn, {info}}, + {:synthesize_commit, repo_conn, {info, signing_key}}, Confex.fetch_env!(:bors, :api_github_timeout) ) @@ -214,13 +214,14 @@ defmodule BorsNG.GitHub do tree: bitstring, parents: [bitstring], commit_message: bitstring, + author: tcommitter | nil, committer: tcommitter | nil - }) :: binary - def create_commit!(repo_conn, info) do + }, bitstring | nil) :: binary + def create_commit!(repo_conn, info, signing_key \\ nil) do {:ok, sha} = GenServer.call( BorsNG.GitHub, - {:create_commit, repo_conn, {info}}, + {:create_commit, repo_conn, {info, signing_key}}, Confex.fetch_env!(:bors, :api_github_timeout) ) diff --git a/lib/github/github/server.ex b/lib/github/github/server.ex index 6b38d5841..5e93d1181 100644 --- a/lib/github/github/server.ex +++ b/lib/github/github/server.ex @@ -282,8 +282,9 @@ defmodule BorsNG.GitHub.Server do tree: tree, parents: parents, commit_message: commit_message, + author: author, committer: committer - }} + }, signing_key} ) do msg = %{parents: parents, tree: tree, message: commit_message} @@ -291,12 +292,36 @@ defmodule BorsNG.GitHub.Server do if is_nil(committer) do msg else - Map.put(msg, "author", %{ + Map.put(msg, :committer, %{ name: committer.name, email: committer.email }) end + msg = + if is_nil(author) do + msg + else + Map.put(msg, :author, author) + end + + msg = + cond do + is_nil(signing_key) -> + Logger.debug("Not signing commit in create_commit because signing_key is nil") + msg + is_nil(author) -> + Logger.debug("Not signing commit in create_commit because author is nil") + msg + is_nil(committer) -> + Logger.debug("Not signing commit in create_commit because committer is nil") + msg + true -> + msg + |> GitHub.Signature.add_timestamp(DateTime.utc_now()) + |> GitHub.Signature.sign!(signing_key) + end + resp = repo_conn |> post!("git/commits", Poison.encode!(msg)) @@ -333,7 +358,7 @@ defmodule BorsNG.GitHub.Server do parents: parents, commit_message: commit_message, committer: committer - }} + }, signing_key} ) do msg = %{parents: parents, tree: tree, message: commit_message} @@ -341,10 +366,26 @@ defmodule BorsNG.GitHub.Server do if is_nil(committer) do msg else - Map.put(msg, "author", %{ + msg + |> Map.put(:author, %{ name: committer.name, email: committer.email }) + |> Map.put(:committer, committer) + end + + msg = + cond do + is_nil(signing_key) -> + Logger.debug("Not signing commit in synthesize_commit because signing_key is nil") + msg + is_nil(committer) -> + Logger.debug("Not signing commit in synthesize_commit because committer is nil") + msg + true -> + msg + |> GitHub.Signature.add_timestamp(DateTime.utc_now()) + |> GitHub.Signature.sign!(signing_key) end repo_conn diff --git a/lib/github/github/signature.ex b/lib/github/github/signature.ex new file mode 100644 index 000000000..d9af10f10 --- /dev/null +++ b/lib/github/github/signature.ex @@ -0,0 +1,98 @@ +require Logger + +defmodule BorsNG.GitHub.Signature do + @moduledoc """ + Provides the ability to sign commits using gpg2. + """ + + @type tcommit_no_ts :: %{ + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary}, + committer: %{name: binary, email: binary} + } + + @type tcommit :: %{ + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary, date: binary}, + committer: %{name: binary, email: binary, date: binary} + } + + @type tcommit_sig :: %{ + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary, date: binary}, + committer: %{name: binary, email: binary, date: binary}, + signature: binary + } + + @spec add_timestamp(tcommit_no_ts, DateTime.t) :: tcommit + def add_timestamp(commit, dt) do + ts = DateTime.to_iso8601(dt) + commit + |> Map.put(:author, Map.put(commit[:author], :date, ts)) + |> Map.put(:committer, Map.put(commit[:committer], :date, ts)) + end + + @spec format_commit(tcommit) :: binary + def format_commit(commit) do + {:ok, author_date, _} = DateTime.from_iso8601(commit[:author][:date]) + author_ts = DateTime.to_unix(author_date, :second) |> Integer.to_string() + {:ok, committer_date, _} = DateTime.from_iso8601(commit[:committer][:date]) + committer_ts = DateTime.to_unix(committer_date, :second) |> Integer.to_string() + gpg_sig = + case Map.fetch(commit, :signature) do + {:ok, sig} -> + lines = String.split(sig, "\n") + |> Enum.intersperse("\n ") + |> Enum.to_list() + ["gpgsig ", lines, "\n"] + :error -> + [] + end + + IO.iodata_to_binary([ + ["tree ", commit[:tree], "\n"], + Enum.map(commit[:parents], fn parent -> ["parent ", parent, "\n"] end), + ["author ", commit[:author][:name], " <", commit[:author][:email], "> ", author_ts, " +0000\n"], + ["committer ", commit[:committer][:name], " <", commit[:committer][:email], "> ", committer_ts, " +0000\n"], + gpg_sig, + "\n", + commit[:message], + ]) + end + + @spec sign!(tcommit, binary) :: tcommit_sig + def sign!(commit, key_id) do + Logger.info("Signing commit #{inspect(commit)} with key #{inspect(key_id)}") + + path = System.find_executable("gpg") + if is_nil(path) do + throw :missing_gpg + end + + commit_to_sign = format_commit(commit) + Logger.debug("Commit to sign: #{inspect commit_to_sign}") + + tmp_dir = System.tmp_dir!() + tmp_filename = Path.join(tmp_dir, "bors_commit_signing.#{commit[:tree]}.txt") + sig_filename = Path.join(tmp_dir, "bors_commit_signing.#{commit[:tree]}.txt.asc") + try do + _ = File.rm(sig_filename) + File.write!(tmp_filename, commit_to_sign, [:write, :binary, :sync]) + args = ["--batch", "--with-colons", "--status-fd", "2", "--armor", "--local-user", key_id, "--detach-sign", tmp_filename] + Logger.debug("Calling #{path} #{Enum.join(args, " ")}") + {output, 0} = System.cmd(path, args) + Logger.debug("Output from gpg: #{inspect output}") + sig = File.read!(sig_filename) + Map.put(commit, :signature, sig) + after + _ = File.rm(tmp_filename) + _ = File.rm(sig_filename) + end + end +end diff --git a/lib/worker/batcher.ex b/lib/worker/batcher.ex index 350f0b367..bada0e7ef 100644 --- a/lib/worker/batcher.ex +++ b/lib/worker/batcher.ex @@ -395,6 +395,17 @@ defmodule BorsNG.Worker.Batcher do batch.into_branch ) + toml = repo_conn + |> Batcher.GetBorsToml.get(base.commit) + |> case do + {:ok, toml} -> toml + {:error, message} -> + message = Batcher.Message.generate_bors_toml_error(message) + patches = Enum.map(patch_links, & &1.patch) + send_message(repo_conn, patches, {:config, message}) + nil + end + tbase = %{ tree: base.tree, commit: @@ -406,7 +417,12 @@ defmodule BorsNG.Worker.Batcher do parents: [base.commit], commit_message: "[ci skip][skip ci][skip netlify]", committer: nil - } + }, + if is_nil(toml) do + nil + else + toml.signing_key + end ) } @@ -535,8 +551,10 @@ defmodule BorsNG.Worker.Batcher do tree: merge_commit.tree, parents: [prev_head], commit_message: commit_message, - committer: %{name: user.name || user.login, email: user_email} - } + author: %{name: user.name || user.login, email: user_email}, + committer: toml.committer + }, + toml.signing_key ) Logger.info("Commit Sha #{inspect(cpt)}") @@ -574,7 +592,8 @@ defmodule BorsNG.Worker.Batcher do parents: parents, commit_message: commit_message, committer: toml.committer - } + }, + toml.signing_key ) end diff --git a/lib/worker/batcher/bors_toml.ex b/lib/worker/batcher/bors_toml.ex index bce94125b..29a9d68ee 100644 --- a/lib/worker/batcher/bors_toml.ex +++ b/lib/worker/batcher/bors_toml.ex @@ -30,7 +30,8 @@ defmodule BorsNG.Worker.Batcher.BorsToml do use_codeowners: false, committer: nil, commit_title: "Merge ${PR_REFS}", - update_base_for_deletes: false + update_base_for_deletes: false, + signing_key: nil @type tcommitter :: %{ name: binary, @@ -51,7 +52,8 @@ defmodule BorsNG.Worker.Batcher.BorsToml do use_codeowners: boolean, committer: tcommitter, commit_title: binary, - update_base_for_deletes: boolean + update_base_for_deletes: boolean, + signing_key: binary | nil } @type err :: @@ -81,18 +83,18 @@ defmodule BorsNG.Worker.Batcher.BorsToml do committer = Map.get(toml, "committer", nil) - committer = + {committer, signing_key} = case committer do nil -> - nil + {nil, nil} _ -> c = to_map(committer) - %{ + {%{ name: Map.get(c, "name", nil), email: Map.get(c, "email", nil) - } + }, Map.get(c, "signing_key", nil)} end toml = %BorsNG.Worker.Batcher.BorsToml{ @@ -124,7 +126,8 @@ defmodule BorsNG.Worker.Batcher.BorsToml do ), committer: committer, commit_title: Map.get(toml, "commit_title", "Merge ${PR_REFS}"), - update_base_for_deletes: Map.get(toml, "update_base_for_deletes", false) + update_base_for_deletes: Map.get(toml, "update_base_for_deletes", false), + signing_key: signing_key, } case toml do @@ -159,6 +162,9 @@ defmodule BorsNG.Worker.Batcher.BorsToml do %{commit_title: msg} when not is_binary(msg) and not is_nil(msg) -> {:error, :commit_title} + %{signing_key: k} when not is_binary(k) and not is_nil(k) -> + {:error, :signing_key} + toml -> status = toml.status diff --git a/test/github_signature_test.exs b/test/github_signature_test.exs new file mode 100644 index 000000000..60bc32b87 --- /dev/null +++ b/test/github_signature_test.exs @@ -0,0 +1,61 @@ +require Logger + +defmodule BorsNG.GitHub.GitHubSignatureTest do + use BorsNG.ConnCase + alias BorsNG.GitHub.Signature + + test "can gpg-sign a commit" do + key_id = Confex.fetch_env!(:bors, :test_gpg_key_id) + cond do + is_nil(System.find_executable("gpg")) -> + Logger.info("Skipping GPG signing test because gpg is not installed") + key_id == "" -> + Logger.info("Skipping GPG signing test because test key was not set (see `config/test.exs`)") + true -> + date = DateTime.utc_now() + commit_to_sign = %{ + tree: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + parents: ["bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"], + author: %{ + name: "Author Name", + email: "author@example.com", + date: DateTime.to_iso8601(date), + }, + committer: %{ + name: "Committer Name", + email: "committer@example.com", + date: DateTime.to_iso8601(date), + }, + message: "Example commit" + } + + commit_with_sig = Signature.sign!(commit_to_sign, key_id) + raw_with_sig = Signature.format_commit(commit_with_sig) + + # Create a temporary git repo, insert the raw commit, and verify it with + # `git-verify-commit`. + git = System.find_executable("git") + tmp_dir = Path.join(System.tmp_dir!(), "git-signature-test.#{Enum.random(10000..99999)}") + :ok = File.mkdir!(tmp_dir) + try do + # create empty git repo + Logger.debug("Creating temporary git repository at #{tmp_dir}") + {_, 0} = System.cmd(git, ["init"], cd: tmp_dir, stderr_to_stdout: true) + # insert raw commit object + Logger.debug("Inserting raw commit object") + raw_obj_path = Path.join(tmp_dir, "raw-commit.txt") + :ok = File.write!(raw_obj_path, raw_with_sig, [:write, :binary, :sync]) + {raw_hash, 0} = System.cmd( + git, ["hash-object", "-t", "commit", "-w", raw_obj_path], + cd: tmp_dir, stderr_to_stdout: true + ) + hash = String.trim(raw_hash) + # verify commit + Logger.debug("Verifying commit #{inspect hash}") + {_, 0} = System.cmd(git, ["verify-commit", "--verbose", hash], cd: tmp_dir) + after + File.rm_rf!(tmp_dir) + end + end + end +end From e1e2c2eb0d1687554ab4c1c0a8ed1f9a9e009470 Mon Sep 17 00:00:00 2001 From: Cassie Meharry Date: Tue, 28 Sep 2021 18:29:28 +0000 Subject: [PATCH 2/6] Formatting --- lib/github/github.ex | 36 ++++++++----- lib/github/github/server.ex | 13 +++-- lib/github/github/signature.ex | 93 +++++++++++++++++++++++---------- lib/worker/batcher.ex | 25 +++++---- lib/worker/batcher/bors_toml.ex | 8 +-- test/github_signature_test.exs | 28 +++++++--- 6 files changed, 135 insertions(+), 68 deletions(-) diff --git a/lib/github/github.ex b/lib/github/github.ex index 6f74fd00b..6265c7c98 100644 --- a/lib/github/github.ex +++ b/lib/github/github.ex @@ -192,13 +192,17 @@ defmodule BorsNG.GitHub do commit end - @spec synthesize_commit!(tconn, %{ - branch: bitstring, - tree: bitstring, - parents: [bitstring], - commit_message: bitstring, - committer: tcommitter | nil - }, bitstring | nil) :: binary + @spec synthesize_commit!( + tconn, + %{ + branch: bitstring, + tree: bitstring, + parents: [bitstring], + commit_message: bitstring, + committer: tcommitter | nil + }, + bitstring | nil + ) :: binary def synthesize_commit!(repo_conn, info, signing_key \\ nil) do {:ok, sha} = GenServer.call( @@ -210,13 +214,17 @@ defmodule BorsNG.GitHub do sha end - @spec create_commit!(tconn, %{ - tree: bitstring, - parents: [bitstring], - commit_message: bitstring, - author: tcommitter | nil, - committer: tcommitter | nil - }, bitstring | nil) :: binary + @spec create_commit!( + tconn, + %{ + tree: bitstring, + parents: [bitstring], + commit_message: bitstring, + author: tcommitter | nil, + committer: tcommitter | nil + }, + bitstring | nil + ) :: binary def create_commit!(repo_conn, info, signing_key \\ nil) do {:ok, sha} = GenServer.call( diff --git a/lib/github/github/server.ex b/lib/github/github/server.ex index 5e93d1181..61234c153 100644 --- a/lib/github/github/server.ex +++ b/lib/github/github/server.ex @@ -310,16 +310,19 @@ defmodule BorsNG.GitHub.Server do is_nil(signing_key) -> Logger.debug("Not signing commit in create_commit because signing_key is nil") msg + is_nil(author) -> Logger.debug("Not signing commit in create_commit because author is nil") msg + is_nil(committer) -> Logger.debug("Not signing commit in create_commit because committer is nil") msg + true -> msg - |> GitHub.Signature.add_timestamp(DateTime.utc_now()) - |> GitHub.Signature.sign!(signing_key) + |> GitHub.Signature.add_timestamp(DateTime.utc_now()) + |> GitHub.Signature.sign!(signing_key) end resp = @@ -379,13 +382,15 @@ defmodule BorsNG.GitHub.Server do is_nil(signing_key) -> Logger.debug("Not signing commit in synthesize_commit because signing_key is nil") msg + is_nil(committer) -> Logger.debug("Not signing commit in synthesize_commit because committer is nil") msg + true -> msg - |> GitHub.Signature.add_timestamp(DateTime.utc_now()) - |> GitHub.Signature.sign!(signing_key) + |> GitHub.Signature.add_timestamp(DateTime.utc_now()) + |> GitHub.Signature.sign!(signing_key) end repo_conn diff --git a/lib/github/github/signature.ex b/lib/github/github/signature.ex index d9af10f10..6f8e839e2 100644 --- a/lib/github/github/signature.ex +++ b/lib/github/github/signature.ex @@ -6,33 +6,34 @@ defmodule BorsNG.GitHub.Signature do """ @type tcommit_no_ts :: %{ - parents: [binary], - tree: binary, - message: binary, - author: %{name: binary, email: binary}, - committer: %{name: binary, email: binary} - } + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary}, + committer: %{name: binary, email: binary} + } @type tcommit :: %{ - parents: [binary], - tree: binary, - message: binary, - author: %{name: binary, email: binary, date: binary}, - committer: %{name: binary, email: binary, date: binary} - } + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary, date: binary}, + committer: %{name: binary, email: binary, date: binary} + } @type tcommit_sig :: %{ - parents: [binary], - tree: binary, - message: binary, - author: %{name: binary, email: binary, date: binary}, - committer: %{name: binary, email: binary, date: binary}, - signature: binary - } - - @spec add_timestamp(tcommit_no_ts, DateTime.t) :: tcommit + parents: [binary], + tree: binary, + message: binary, + author: %{name: binary, email: binary, date: binary}, + committer: %{name: binary, email: binary, date: binary}, + signature: binary + } + + @spec add_timestamp(tcommit_no_ts, DateTime.t()) :: tcommit def add_timestamp(commit, dt) do ts = DateTime.to_iso8601(dt) + commit |> Map.put(:author, Map.put(commit[:author], :date, ts)) |> Map.put(:committer, Map.put(commit[:committer], :date, ts)) @@ -44,13 +45,17 @@ defmodule BorsNG.GitHub.Signature do author_ts = DateTime.to_unix(author_date, :second) |> Integer.to_string() {:ok, committer_date, _} = DateTime.from_iso8601(commit[:committer][:date]) committer_ts = DateTime.to_unix(committer_date, :second) |> Integer.to_string() + gpg_sig = case Map.fetch(commit, :signature) do {:ok, sig} -> - lines = String.split(sig, "\n") + lines = + String.split(sig, "\n") |> Enum.intersperse("\n ") |> Enum.to_list() + ["gpgsig ", lines, "\n"] + :error -> [] end @@ -58,11 +63,27 @@ defmodule BorsNG.GitHub.Signature do IO.iodata_to_binary([ ["tree ", commit[:tree], "\n"], Enum.map(commit[:parents], fn parent -> ["parent ", parent, "\n"] end), - ["author ", commit[:author][:name], " <", commit[:author][:email], "> ", author_ts, " +0000\n"], - ["committer ", commit[:committer][:name], " <", commit[:committer][:email], "> ", committer_ts, " +0000\n"], + [ + "author ", + commit[:author][:name], + " <", + commit[:author][:email], + "> ", + author_ts, + " +0000\n" + ], + [ + "committer ", + commit[:committer][:name], + " <", + commit[:committer][:email], + "> ", + committer_ts, + " +0000\n" + ], gpg_sig, "\n", - commit[:message], + commit[:message] ]) end @@ -71,23 +92,37 @@ defmodule BorsNG.GitHub.Signature do Logger.info("Signing commit #{inspect(commit)} with key #{inspect(key_id)}") path = System.find_executable("gpg") + if is_nil(path) do - throw :missing_gpg + throw(:missing_gpg) end commit_to_sign = format_commit(commit) - Logger.debug("Commit to sign: #{inspect commit_to_sign}") + Logger.debug("Commit to sign: #{inspect(commit_to_sign)}") tmp_dir = System.tmp_dir!() tmp_filename = Path.join(tmp_dir, "bors_commit_signing.#{commit[:tree]}.txt") sig_filename = Path.join(tmp_dir, "bors_commit_signing.#{commit[:tree]}.txt.asc") + try do _ = File.rm(sig_filename) File.write!(tmp_filename, commit_to_sign, [:write, :binary, :sync]) - args = ["--batch", "--with-colons", "--status-fd", "2", "--armor", "--local-user", key_id, "--detach-sign", tmp_filename] + + args = [ + "--batch", + "--with-colons", + "--status-fd", + "2", + "--armor", + "--local-user", + key_id, + "--detach-sign", + tmp_filename + ] + Logger.debug("Calling #{path} #{Enum.join(args, " ")}") {output, 0} = System.cmd(path, args) - Logger.debug("Output from gpg: #{inspect output}") + Logger.debug("Output from gpg: #{inspect(output)}") sig = File.read!(sig_filename) Map.put(commit, :signature, sig) after diff --git a/lib/worker/batcher.ex b/lib/worker/batcher.ex index bada0e7ef..b819e5d05 100644 --- a/lib/worker/batcher.ex +++ b/lib/worker/batcher.ex @@ -395,16 +395,19 @@ defmodule BorsNG.Worker.Batcher do batch.into_branch ) - toml = repo_conn + toml = + repo_conn |> Batcher.GetBorsToml.get(base.commit) |> case do - {:ok, toml} -> toml - {:error, message} -> - message = Batcher.Message.generate_bors_toml_error(message) - patches = Enum.map(patch_links, & &1.patch) - send_message(repo_conn, patches, {:config, message}) - nil - end + {:ok, toml} -> + toml + + {:error, message} -> + message = Batcher.Message.generate_bors_toml_error(message) + patches = Enum.map(patch_links, & &1.patch) + send_message(repo_conn, patches, {:config, message}) + nil + end tbase = %{ tree: base.tree, @@ -996,7 +999,11 @@ defmodule BorsNG.Worker.Batcher do end Logger.info( - "Code review status: Label Check #{passed_label} Passed Status: #{no_error_status and no_waiting_status and no_unset_status} Passed Review: #{passed_review} CODEOWNERS: #{code_owners_approved} Passed Up-To-Date Review: #{passed_up_to_date_review}" + "Code review status: Label Check #{passed_label} Passed Status: #{ + no_error_status and no_waiting_status and no_unset_status + } Passed Review: #{passed_review} CODEOWNERS: #{code_owners_approved} Passed Up-To-Date Review: #{ + passed_up_to_date_review + }" ) case {passed_label, no_error_status, no_waiting_status, no_unset_status, passed_review, diff --git a/lib/worker/batcher/bors_toml.ex b/lib/worker/batcher/bors_toml.ex index 29a9d68ee..fd6ca1508 100644 --- a/lib/worker/batcher/bors_toml.ex +++ b/lib/worker/batcher/bors_toml.ex @@ -92,9 +92,9 @@ defmodule BorsNG.Worker.Batcher.BorsToml do c = to_map(committer) {%{ - name: Map.get(c, "name", nil), - email: Map.get(c, "email", nil) - }, Map.get(c, "signing_key", nil)} + name: Map.get(c, "name", nil), + email: Map.get(c, "email", nil) + }, Map.get(c, "signing_key", nil)} end toml = %BorsNG.Worker.Batcher.BorsToml{ @@ -127,7 +127,7 @@ defmodule BorsNG.Worker.Batcher.BorsToml do committer: committer, commit_title: Map.get(toml, "commit_title", "Merge ${PR_REFS}"), update_base_for_deletes: Map.get(toml, "update_base_for_deletes", false), - signing_key: signing_key, + signing_key: signing_key } case toml do diff --git a/test/github_signature_test.exs b/test/github_signature_test.exs index 60bc32b87..19210087b 100644 --- a/test/github_signature_test.exs +++ b/test/github_signature_test.exs @@ -6,25 +6,31 @@ defmodule BorsNG.GitHub.GitHubSignatureTest do test "can gpg-sign a commit" do key_id = Confex.fetch_env!(:bors, :test_gpg_key_id) + cond do is_nil(System.find_executable("gpg")) -> Logger.info("Skipping GPG signing test because gpg is not installed") + key_id == "" -> - Logger.info("Skipping GPG signing test because test key was not set (see `config/test.exs`)") + Logger.info( + "Skipping GPG signing test because test key was not set (see `config/test.exs`)" + ) + true -> date = DateTime.utc_now() + commit_to_sign = %{ tree: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", parents: ["bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"], author: %{ name: "Author Name", email: "author@example.com", - date: DateTime.to_iso8601(date), + date: DateTime.to_iso8601(date) }, committer: %{ name: "Committer Name", email: "committer@example.com", - date: DateTime.to_iso8601(date), + date: DateTime.to_iso8601(date) }, message: "Example commit" } @@ -37,6 +43,7 @@ defmodule BorsNG.GitHub.GitHubSignatureTest do git = System.find_executable("git") tmp_dir = Path.join(System.tmp_dir!(), "git-signature-test.#{Enum.random(10000..99999)}") :ok = File.mkdir!(tmp_dir) + try do # create empty git repo Logger.debug("Creating temporary git repository at #{tmp_dir}") @@ -45,13 +52,18 @@ defmodule BorsNG.GitHub.GitHubSignatureTest do Logger.debug("Inserting raw commit object") raw_obj_path = Path.join(tmp_dir, "raw-commit.txt") :ok = File.write!(raw_obj_path, raw_with_sig, [:write, :binary, :sync]) - {raw_hash, 0} = System.cmd( - git, ["hash-object", "-t", "commit", "-w", raw_obj_path], - cd: tmp_dir, stderr_to_stdout: true - ) + + {raw_hash, 0} = + System.cmd( + git, + ["hash-object", "-t", "commit", "-w", raw_obj_path], + cd: tmp_dir, + stderr_to_stdout: true + ) + hash = String.trim(raw_hash) # verify commit - Logger.debug("Verifying commit #{inspect hash}") + Logger.debug("Verifying commit #{inspect(hash)}") {_, 0} = System.cmd(git, ["verify-commit", "--verbose", hash], cd: tmp_dir) after File.rm_rf!(tmp_dir) From 4111f436e45bdc3b31f7ef919ec447e8ef4d6dd3 Mon Sep 17 00:00:00 2001 From: Cassie Meharry Date: Tue, 28 Sep 2021 18:46:22 +0000 Subject: [PATCH 3/6] Another round of formatting --- lib/worker/batcher.ex | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/worker/batcher.ex b/lib/worker/batcher.ex index b819e5d05..ed5fad28f 100644 --- a/lib/worker/batcher.ex +++ b/lib/worker/batcher.ex @@ -999,11 +999,7 @@ defmodule BorsNG.Worker.Batcher do end Logger.info( - "Code review status: Label Check #{passed_label} Passed Status: #{ - no_error_status and no_waiting_status and no_unset_status - } Passed Review: #{passed_review} CODEOWNERS: #{code_owners_approved} Passed Up-To-Date Review: #{ - passed_up_to_date_review - }" + "Code review status: Label Check #{passed_label} Passed Status: #{no_error_status and no_waiting_status and no_unset_status} Passed Review: #{passed_review} CODEOWNERS: #{code_owners_approved} Passed Up-To-Date Review: #{passed_up_to_date_review}" ) case {passed_label, no_error_status, no_waiting_status, no_unset_status, passed_review, From 5c5773395f62ccb253e7f45418bf88666bb369eb Mon Sep 17 00:00:00 2001 From: Cassie Meharry Date: Tue, 28 Sep 2021 18:53:44 +0000 Subject: [PATCH 4/6] Fix GitHub mock server to account for extra arg in synthesize_commit --- lib/github/github/server_mock.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/github/github/server_mock.ex b/lib/github/github/server_mock.ex index 8e5a6e6d2..fe7c8a8a1 100644 --- a/lib/github/github/server_mock.ex +++ b/lib/github/github/server_mock.ex @@ -366,7 +366,7 @@ defmodule BorsNG.GitHub.ServerMock do parents: parents, commit_message: commit_message, committer: _committer - }}, + }, _signing_key}, state ) do with {:ok, repo} <- Map.fetch(state, repo_conn), From 21591dc7b40652e979b46dc6b217a6f34063324f Mon Sep 17 00:00:00 2001 From: Cassie Meharry Date: Tue, 28 Sep 2021 19:06:05 +0000 Subject: [PATCH 5/6] Don't double up errors when bors.toml is missing --- lib/worker/batcher.ex | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/worker/batcher.ex b/lib/worker/batcher.ex index ed5fad28f..40c776898 100644 --- a/lib/worker/batcher.ex +++ b/lib/worker/batcher.ex @@ -403,9 +403,6 @@ defmodule BorsNG.Worker.Batcher do toml {:error, message} -> - message = Batcher.Message.generate_bors_toml_error(message) - patches = Enum.map(patch_links, & &1.patch) - send_message(repo_conn, patches, {:config, message}) nil end @@ -421,11 +418,7 @@ defmodule BorsNG.Worker.Batcher do commit_message: "[ci skip][skip ci][skip netlify]", committer: nil }, - if is_nil(toml) do - nil - else - toml.signing_key - end + toml && toml.signing_key ) } From 3f9190da2e68ef9a74ff6c3fc9dbd89e190df40e Mon Sep 17 00:00:00 2001 From: Alex Kondratiev Date: Fri, 7 Oct 2022 19:14:47 -0400 Subject: [PATCH 6/6] Docker compose added --- .env_armhf | 1 + Dockerfile | 12 ++++++++---- docker-compose.yml | 31 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 .env_armhf create mode 100644 docker-compose.yml diff --git a/.env_armhf b/.env_armhf new file mode 100644 index 000000000..a800bcf80 --- /dev/null +++ b/.env_armhf @@ -0,0 +1 @@ +DOCKERIZE_ARCH=armhf diff --git a/Dockerfile b/Dockerfile index 976f08835..56e89ee40 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG ELIXIR_VERSION=1.12.0 +ARG ELIXIR_VERSION=1.13.0 ARG SOURCE_COMMIT FROM elixir:${ELIXIR_VERSION} as builder @@ -41,10 +41,14 @@ RUN if [ -d .git ]; then \ #### FROM debian:buster-slim -RUN apt-get update -q && apt-get --no-install-recommends install -y git-core libssl1.1 curl apt-utils ca-certificates +RUN apt-get update -q && \ + apt-get --no-install-recommends install -y \ + git-core libssl1.1 curl apt-utils ca-certificates gpg -ENV DOCKERIZE_VERSION=v0.6.0 -RUN curl -Ls https://github.com/bors-ng/dockerize/releases/download/v0.7.9/dockerize-linux-amd64-v0.7.9.tar.gz | \ +ARG DOCKERIZE_VERSION=v0.7.9 +ARG DOCKERIZE_ARCH=amd64 + +RUN curl -Ls https://github.com/bors-ng/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-linux-${DOCKERIZE_ARCH}-${DOCKERIZE_VERSION}.tar.gz | \ tar xzv -C /usr/local/bin ADD ./script/docker-entrypoint /usr/local/bin/bors-ng-entrypoint diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..ff5b48b8e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +version: "2" +services: + bors: + build: + context: . + dockerfile: ./Dockerfile + args: + - DOCKERIZE_ARCH=$DOCKERIZE_ARCH + image: bors-ng:local + ports: + - "4000:4000" + tty: true + env_file: + - .env_docker + restart: always + depends_on: + - postgres + postgres: + image: postgres:10.5 + restart: always + volumes: + - db_data:/var/lib/postgresql/data + environment: + # Make sure the [censored] password here matches the one in the DATABASE_URL + POSTGRES_PASSWORD: "7vMibEOXo1kp3bQImeTmwA" + POSTGRES_DB: "bors" +volumes: + db_data: +networks: + default: + driver: bridge