diff --git a/BUILD.bazel b/BUILD.bazel index 7d94cfec9c..dd741321af 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -83,6 +83,7 @@ py_test( ".bazelrc", ".forgejo/workflows/elixir-integration-sr-core.yml", ".forgejo/workflows/main.yml", + ".github/workflows/elixir-integration-sr-core.yml", "Makefile", "buildbuddy.yaml", "buildbuddy_setup_fixture_env.sh", diff --git a/CHANGELOG b/CHANGELOG index fa32ca4ad6..03865ccc89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,50 @@ +# ServiceRadar v1.4.33 + +Device risk scoring from NVD + KEV + CWE, Findings UI with KEV floor, and +an EventWriter pull-inflight fix so traces and OTLP metrics stop going +silent after a long-lived core. Also ships multi-arch web-ng/core-elx, +moves lint/check CI onto GitHub ARC, and points Settings first-party +plugin/add-on and agent-release import at GitHub Releases instead of +Forgejo. + +## Whats New + +**1.4.33** +- Inventory risk: compose NVD and CISA/VulnCheck KEV into one CVE finding + with CWE context, a KEV floor of 90 on the Findings overlay, and a + periodic DeviceRiskAssessmentWorker that writes `ocsf_devices.risk_score` + through DeviceRiskReducer only. Endpoint inventory scores KEV at 90 per + payload; device-level Score.compute floors KEV at 70 and folds CWE. + IOC exposure is listed on the device. (PRs #5008, #3591) +- EventWriter: expire stale JetStream pull inflight so a hung fetch no + longer parks the otel-traces / otel-metrics / logs durables (last + delivery ages out, unprocessed piles up, Observability goes empty while + the log-collector is still receiving OTLP). (PR #3764) +- Egress: Finch HTTP (Bumblebee, advisory feeds, and other Req clients) + goes through SERVICERADAR_EGRESS_PROXY. The default Finch connect + options no longer crash the Bumblebee s7 integration shard. (PRs + #5003, #5007) +- Images: web-ng and core-elx now publish multi-arch OCI indexes. (PR + #5001) +- Build: Rust crates vendor as .crate archives; OpenSSL is built + hermetically in Bazel. The native add-on version gate no longer + requires a MODULE.bazel.lock hash that rules_rs cannot satisfy. (PR + #5002) +- CI: lint and check workflows run on GitHub ARC. SRQL fixture TLS is + issued with cert-manager and a live CA. Bootstrap scratch DROP + cancellation no longer fails core s7. The cache-proxy config test now + ships the GitHub integration workflow in its runfiles. (PRs #5010, + #3768, #5005) +- Plugins: Settings first-party Wasm plugin and native add-on import + now reads GitHub Releases (`github.com/carverauto/serviceradar`) plus + Harbor OCI, not Forgejo. `ForgejoOciClient` is gone; the shared + transport is `FirstPartyReleaseClient`. `GitHubImporter` is unchanged + and still fetches source-tree `plugin.yaml`/`plugin.wasm`. Agent + release import (`ReleaseSourceImporter` and Settings → Agents) now + uses the same GitHub Releases API; Forgejo URLs are rejected. +- Web UI: boolean device-fact keys in composite checks are a combobox, + not free text. (PR #4997) + # ServiceRadar v1.4.32 Stops core from OOM-reloading leftover provider CIDR snapshots (the demo diff --git a/VERSION b/VERSION index 00bbe72aea..9baec2fdfe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.32 +1.4.33 diff --git a/docs/docs/cloud-quickstart.md b/docs/docs/cloud-quickstart.md index a257835ce5..52d9728f9f 100644 --- a/docs/docs/cloud-quickstart.md +++ b/docs/docs/cloud-quickstart.md @@ -241,7 +241,7 @@ automatically — there is no separate certificate step. Release assets (DEB, RPM, and signed agent runtime artifacts): -**[https://code.carverauto.dev/carverauto/serviceradar/releases](https://code.carverauto.dev/carverauto/serviceradar/releases)** +**[https://github.com/carverauto/serviceradar/releases](https://github.com/carverauto/serviceradar/releases)** The product UI links the same page from **Settings → Agent Deploy**. Prefer the latest stable release train for production. diff --git a/docs/docs/edge-agent-onboarding.md b/docs/docs/edge-agent-onboarding.md index e06a19de21..d2445f2d26 100644 --- a/docs/docs/edge-agent-onboarding.md +++ b/docs/docs/edge-agent-onboarding.md @@ -6,7 +6,7 @@ title: Edge Agent Onboarding Edge onboarding is intentionally simple: -1. Install `serviceradar-agent` on the host (RPM/DEB from the [releases page](https://code.carverauto.dev/carverauto/serviceradar/releases)). +1. Install `serviceradar-agent` on the host (RPM/DEB from the [releases page](https://github.com/carverauto/serviceradar/releases)). 2. In the UI, create an agent package. 3. Copy/paste the enroll command on the host. @@ -59,7 +59,7 @@ That is it. The agent enrolls, receives config, and starts streaming results. Download the latest `serviceradar-agent` package from the ServiceRadar releases page and install it on the target host: -- Releases: [code.carverauto.dev/carverauto/serviceradar/releases](https://code.carverauto.dev/carverauto/serviceradar/releases) +- Releases: [github.com/carverauto/serviceradar/releases](https://github.com/carverauto/serviceradar/releases) - Debian/Ubuntu: install the `.deb` - RHEL/Alma/Rocky: install the `.rpm` diff --git a/elixir/web-ng/.dialyzer_ignore.exs b/elixir/web-ng/.dialyzer_ignore.exs index cdb5be5042..e14c5ef72f 100644 --- a/elixir/web-ng/.dialyzer_ignore.exs +++ b/elixir/web-ng/.dialyzer_ignore.exs @@ -54,7 +54,7 @@ "The pattern variable _ can never match the type, because it is covered by previous clauses."}, {"lib/serviceradar_web_ng/dashboards/frame_runner.ex", :pattern_match_cov}, {"lib/serviceradar_web_ng/plugins/first_party_importer.ex", "The guard clause can never succeed."}, - {"lib/serviceradar_web_ng/plugins/forgejo_oci_client.ex", "The guard clause can never succeed."}, + {"lib/serviceradar_web_ng/plugins/first_party_release_client.ex", "The guard clause can never succeed."}, {"lib/serviceradar_web_ng/plugins/github_importer.ex", "The pattern can never match the type {:error, {:invalid_manifest, [binary()]}}."}, {"lib/serviceradar_web_ng/plugins/github_importer.ex", "Function dashboard_renderer_path/2 will never be called."}, diff --git a/elixir/web-ng/config/config.exs b/elixir/web-ng/config/config.exs index e5543efd26..6b64ebbeb4 100644 --- a/elixir/web-ng/config/config.exs +++ b/elixir/web-ng/config/config.exs @@ -236,7 +236,7 @@ config :serviceradar_web_ng, :client_ip, trusted_proxy_cidrs: [] config :serviceradar_web_ng, :first_party_plugin_import, - repo_url: "https://code.carverauto.dev/carverauto/serviceradar", + repo_url: "https://github.com/carverauto/serviceradar", index_asset_name: "serviceradar-wasm-plugin-index.json", auto_sync_enabled: false, sync_release_limit: 10, @@ -259,7 +259,7 @@ config :serviceradar_web_ng, :first_party_plugin_import, config :serviceradar_web_ng, :god_view_enabled, false config :serviceradar_web_ng, :native_addon_import, - repo_url: "https://code.carverauto.dev/carverauto/serviceradar", + repo_url: "https://github.com/carverauto/serviceradar", index_asset_name: "serviceradar-native-addon-index.json", auto_sync_enabled: false, sync_release_limit: 10, diff --git a/elixir/web-ng/lib/serviceradar_web_ng/edge/release_source_importer.ex b/elixir/web-ng/lib/serviceradar_web_ng/edge/release_source_importer.ex index 5c917ebba0..f18b28004b 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/edge/release_source_importer.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/edge/release_source_importer.ex @@ -10,8 +10,17 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do @default_recent_release_limit 5 @max_recent_release_scan_limit 50 @max_asset_redirects 5 - @default_provider "forgejo" - @forgejo_host "code.carverauto.dev" + @default_provider "github" + @github_host "github.com" + @github_api_host "api.github.com" + @default_repo_url "https://github.com/carverauto/serviceradar" + @github_asset_hosts [ + @github_host, + @github_api_host, + "objects.githubusercontent.com", + "release-assets.githubusercontent.com", + "github-releases.githubusercontent.com" + ] @type import_attrs :: %{optional(:provider) => String.t(), optional(String.t()) => String.t()} @spec default_manifest_asset_name() :: String.t() @@ -20,6 +29,9 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do @spec default_signature_asset_name() :: String.t() def default_signature_asset_name, do: @default_signature_asset_name + @spec default_repo_url() :: String.t() + def default_repo_url, do: @default_repo_url + @spec list_recent_releases(import_attrs(), pos_integer()) :: {:ok, [map()]} | {:error, String.t()} def list_recent_releases(attrs, limit \\ @default_recent_release_limit) @@ -94,14 +106,12 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do def import(_attrs), do: {:error, "Release import settings are invalid"} defp selected_provider(attrs) when is_map(attrs) do - attrs - |> Map.get("provider", Map.get(attrs, :provider)) - |> normalize_provider() - |> case do - nil -> @default_provider - provider -> provider + raw = Map.get(attrs, "provider") || Map.get(attrs, :provider) || @default_provider + + case normalize_provider(raw) do + "github" -> {:ok, "github"} + _other -> {:error, "GitHub is the only supported release provider"} end - |> validate_provider() end defp import_repo(attrs) when is_map(attrs) do @@ -112,24 +122,20 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do end end - defp validate_provider("forgejo"), do: {:ok, "forgejo"} - - defp validate_provider(_provider), do: {:error, "Forgejo is the only supported release provider"} - - defp parse_repo_url("forgejo", url) do - with {:ok, %URI{scheme: "https", host: @forgejo_host} = uri} <- parse_uri(url), + defp parse_repo_url("github", url) do + with {:ok, %URI{scheme: "https", host: @github_host} = uri} <- parse_uri(url), {:ok, owner, repo} <- repo_owner_and_name(uri.path) do {:ok, %{ - provider: "forgejo", + provider: "github", repo_url: "https://#{host_port(uri)}/#{owner}/#{repo}", - api_base_url: "https://#{host_port(uri)}/api/v1", + api_base_url: "https://#{@github_api_host}", owner: owner, repo: repo }} else _ -> - {:error, "Forgejo repository URL must look like https://code.carverauto.dev//"} + {:error, "GitHub repository URL must look like https://github.com//"} end end @@ -343,9 +349,16 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do end end - defp normalize_provider(value) when is_binary(value), do: value |> String.trim() |> String.downcase() + defp normalize_provider(value) when is_binary(value) do + case value |> String.trim() |> String.downcase() do + "" -> nil + normalized -> normalized + end + end - defp normalize_provider(value) when is_atom(value), do: value |> Atom.to_string() |> normalize_provider() + defp normalize_provider(value) when is_atom(value) and value not in [nil, false, true] do + value |> Atom.to_string() |> normalize_provider() + end defp normalize_provider(_value), do: nil @@ -358,8 +371,8 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do defp normalize_string(value), do: value |> to_string() |> normalize_string() - defp api_headers("forgejo") do - [{"user-agent", "serviceradar"}, {"accept", "application/json"} | auth_headers("forgejo")] + defp api_headers("github") do + [{"user-agent", "serviceradar"}, {"accept", "application/vnd.github+json"} | auth_headers("github")] end defp asset_headers(provider, url) do @@ -372,11 +385,12 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do end end - defp auth_headers("forgejo") do - case Application.get_env(:serviceradar_web_ng, :agent_release_import_forgejo_token) || - System.get_env("FORGEJO_TOKEN") do + defp auth_headers("github") do + case Application.get_env(:serviceradar_web_ng, :agent_release_import_github_token) || + System.get_env("GITHUB_TOKEN") || + System.get_env("GH_TOKEN") do nil -> [] - token -> [{"authorization", "token #{token}"}] + token -> [{"authorization", "Bearer #{token}"}] end end @@ -414,24 +428,30 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporter do end defp validate_url(url) do - case ReleaseFetchPolicy.validate(url) do - {:ok, %URI{scheme: "https"} = uri} -> {:ok, uri} - {:error, _reason} = error -> error - _ -> {:error, :disallowed_url} + case URI.parse(String.trim(to_string(url))) do + %URI{scheme: "https", host: host} = uri when host in @github_asset_hosts -> + {:ok, uri} + + _ -> + case ReleaseFetchPolicy.validate(url) do + {:ok, %URI{scheme: "https"} = uri} -> {:ok, uri} + {:error, _reason} = error -> error + _ -> {:error, :disallowed_url} + end end end - defp trusted_api_host?("forgejo", host), do: host == @forgejo_host + defp trusted_api_host?("github", host), do: host == @github_api_host defp trusted_api_host?(_, _host), do: false - defp trusted_asset_host?("forgejo", host), do: host == @forgejo_host + defp trusted_asset_host?("github", host), do: host in @github_asset_hosts defp trusted_asset_host?(_, _host), do: false defp auth_host?(provider, url) do case URI.parse(url) do %URI{host: host} when is_binary(host) -> case provider do - "forgejo" -> host == @forgejo_host + "github" -> host in [@github_host, @github_api_host] _ -> false end diff --git a/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_importer.ex b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_importer.ex index 451cbaa344..1251b18866 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_importer.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_importer.ex @@ -1,18 +1,18 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporter do @moduledoc """ - Discovers and imports first-party Wasm plugin bundles from Forgejo releases. + Discovers and imports first-party Wasm plugin bundles from GitHub Releases. - HTTP/OCI/Cosign/URL transport is the shared `ForgejoOciClient` (imported below); - this module keeps only the Wasm-bundle-specific discovery, verification, and - result-shaping logic. The `default_repo_url/0` import is excepted so this module - can re-export it as its own public accessor. + HTTP/OCI/Cosign/URL transport is the shared `FirstPartyReleaseClient` + (imported below); this module keeps only the Wasm-bundle-specific discovery, + verification, and result-shaping logic. The `default_repo_url/0` import is + excepted so this module can re-export it as its own public accessor. """ - import ServiceRadarWebNG.Plugins.ForgejoOciClient, except: [default_repo_url: 0] + import ServiceRadarWebNG.Plugins.FirstPartyReleaseClient, except: [default_repo_url: 0] alias ServiceRadar.Plugins.DisplayContract alias ServiceRadar.Plugins.Manifest - alias ServiceRadarWebNG.Plugins.ForgejoOciClient + alias ServiceRadarWebNG.Plugins.FirstPartyReleaseClient alias ServiceRadarWebNG.Plugins.Storage alias ServiceRadarWebNG.Plugins.UploadSignature @@ -32,7 +32,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporter do def default_index_asset_name, do: @default_index_asset_name @spec default_repo_url() :: String.t() - def default_repo_url, do: ForgejoOciClient.default_repo_url() + def default_repo_url, do: FirstPartyReleaseClient.default_repo_url() @spec list_recent_plugins(map(), pos_integer()) :: {:ok, [map()]} | {:error, String.t()} def list_recent_plugins(attrs \\ %{}, limit \\ @default_recent_release_limit) @@ -85,11 +85,11 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporter do def list_recent_plugins_with_summary(_attrs, _limit), do: {:error, "Plugin import settings are invalid"} @doc """ - Lists Wasm plugins from one exact Forgejo release. + Lists Wasm plugins from one exact GitHub release. Automatic synchronization uses this path so the catalog is anchored to the immutable ServiceRadar release currently running, rather than depending on the - ordering or completeness of Forgejo's recent-release feed. + ordering or completeness of GitHub's recent-release feed. """ @spec list_release_plugins(map(), String.t()) :: {:ok, [map()]} | {:error, term()} def list_release_plugins(attrs, release_tag) when is_map(attrs) do @@ -535,7 +535,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporter do defp source_metadata(repo, release, entry, fetched, now) do %{ - "source" => "first_party_forgejo_release", + "source" => "first_party_github_release", "repo_url" => repo.repo_url, "release_tag" => normalize_string(Map.get(release, "tag_name")), "release_name" => normalize_string(Map.get(release, "name")), @@ -561,7 +561,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporter do defp configured_repo_url do config = Application.get_env(:serviceradar_web_ng, :first_party_plugin_import, []) - Keyword.get(config, :repo_url, ForgejoOciClient.default_repo_url()) + Keyword.get(config, :repo_url, FirstPartyReleaseClient.default_repo_url()) end defp index_asset_name(attrs) do diff --git a/elixir/web-ng/lib/serviceradar_web_ng/plugins/forgejo_oci_client.ex b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_release_client.ex similarity index 87% rename from elixir/web-ng/lib/serviceradar_web_ng/plugins/forgejo_oci_client.ex rename to elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_release_client.ex index ea33e3d31d..c451c9f2c3 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/plugins/forgejo_oci_client.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_release_client.ex @@ -1,7 +1,7 @@ -defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do +defmodule ServiceRadarWebNG.Plugins.FirstPartyReleaseClient do @moduledoc """ - Shared transport for importing first-party artifacts from the trusted Forgejo - release host and the Carver OCI registry. Extracted from `FirstPartyImporter` + Shared transport for importing first-party artifacts from GitHub Releases + and the Carver OCI registry. Extracted from `FirstPartyImporter` (issue 3425) so both the Wasm plugin importer and the native add-on importer reuse one HTTP/OCI/cosign client instead of duplicating it. @@ -14,7 +14,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do Injection seams (unchanged from FirstPartyImporter so existing config + tests keep working): `:first_party_plugin_import_http_client` (HTTP client, default `Req`), `:first_party_plugin_cosign_verifier` (default `CosignVerifier`), - `:first_party_plugin_import_forgejo_token` / `FORGEJO_TOKEN`, and + `:first_party_plugin_import_github_token` / `GITHUB_TOKEN`, and `:first_party_plugin_import` (`:repo_url`, `:registry_docker_config_json/file`). """ @@ -22,13 +22,23 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do alias ServiceRadarWebNG.Plugins.CosignVerifier alias ServiceRadarWebNG.Plugins.Storage - @forgejo_host "code.carverauto.dev" - @default_repo_url "https://code.carverauto.dev/carverauto/serviceradar" + Module.register_attribute(__MODULE__, :sobelow_skip, accumulate: true) + + @github_host "github.com" + @github_api_host "api.github.com" + @default_repo_url "https://github.com/carverauto/serviceradar" @oci_registry "registry.carverauto.dev" + @github_asset_hosts [ + @github_host, + @github_api_host, + "objects.githubusercontent.com", + "release-assets.githubusercontent.com", + "github-releases.githubusercontent.com" + ] @max_asset_redirects 5 - @doc "The trusted Forgejo host." - def forgejo_host, do: @forgejo_host + @doc "The trusted GitHub web host." + def github_host, do: @github_host @doc "The default first-party repository URL." def default_repo_url, do: @default_repo_url @@ -36,22 +46,22 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do # --- repo parsing ------------------------------------------------------------- def parse_repo_url(url) when is_binary(url) do - with %URI{scheme: "https", host: @forgejo_host} = uri <- URI.parse(String.trim(url)), + with %URI{scheme: "https", host: @github_host} = uri <- URI.parse(String.trim(url)), {:ok, owner, repo} <- repo_owner_and_name(uri.path) do {:ok, %{ - provider: "forgejo", + provider: "github", repo_url: "https://#{host_port(uri)}/#{owner}/#{repo}", - api_base_url: "https://#{host_port(uri)}/api/v1", + api_base_url: "https://#{@github_api_host}", owner: owner, repo: repo }} else - _ -> {:error, "Forgejo repository URL must look like https://code.carverauto.dev//"} + _ -> {:error, "GitHub repository URL must look like https://github.com//"} end end - def parse_repo_url(_url), do: {:error, "Forgejo repository URL is required"} + def parse_repo_url(_url), do: {:error, "GitHub repository URL is required"} defp repo_owner_and_name(path) when is_binary(path) do case path |> String.split("/", trim: true) |> Enum.take(2) do @@ -79,7 +89,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do url = "#{repo.api_base_url}/repos/#{repo.owner}/#{repo.repo}/releases/tags/#{URI.encode(tag)}" with {:ok, request_url} <- validate_provider_api_url(repo, url), - {:ok, response} <- request(request_url, headers: api_headers("forgejo"), decode_body: true) do + {:ok, response} <- request(request_url, headers: api_headers("github"), decode_body: true) do case response do %Req.Response{status: 200, body: body} when is_map(body) -> {:ok, body} %Req.Response{status: 404} -> {:error, "Release tag #{tag} was not found"} @@ -92,7 +102,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do url = "#{repo.api_base_url}/repos/#{repo.owner}/#{repo.repo}/releases?per_page=#{normalize_limit(limit)}" with {:ok, request_url} <- validate_provider_api_url(repo, url), - {:ok, response} <- request(request_url, headers: api_headers("forgejo"), decode_body: true) do + {:ok, response} <- request(request_url, headers: api_headers("github"), decode_body: true) do case response do %Req.Response{status: 200, body: body} when is_list(body) -> {:ok, body} %Req.Response{status: 200} -> {:error, "Plugin release browser returned an unexpected payload"} @@ -173,7 +183,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do def fetch_oci_manifest(repo, ref) do url = "https://#{ref.registry}/v2/#{ref.repository}/manifests/#{ref.reference}" - headers = [{"accept", "application/vnd.oci.image.manifest.v1+json"} | asset_headers("forgejo", url)] + headers = [{"accept", "application/vnd.oci.image.manifest.v1+json"} | asset_headers("github", url)] with {:ok, request_url} <- validate_provider_asset_url(repo, url), {:ok, response} <- request_oci(request_url, ref, headers: headers, decode_body: true) do @@ -200,7 +210,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do end defp fetch_oci_blob_binary(repo, ref, url, remaining_redirects) do - case request_oci(url, ref, headers: asset_headers("forgejo", url), decode_body: false) do + case request_oci(url, ref, headers: asset_headers("github", url), decode_body: false) do {:ok, %Req.Response{status: 200, body: body}} when is_binary(body) -> {:ok, body} @@ -360,6 +370,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do |> decode_docker_auth(registry) end + @sobelow_skip ["Traversal.FileModule"] defp registry_docker_config_payload(config) do cond do payload = Keyword.get(config, :registry_docker_config_json) -> @@ -433,7 +444,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do end def fetch_url_binary(repo, url, remaining_redirects) do - case request(url, headers: asset_headers("forgejo", url), decode_body: false) do + case request(url, headers: asset_headers(url), decode_body: false) do {:ok, %Req.Response{status: 200, body: body}} when is_binary(body) -> {:ok, body} @@ -478,31 +489,34 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do [connect_options: [timeout: 5_000], receive_timeout: 10_000, redirect: false] end - defp api_headers("forgejo") do - [{"user-agent", "serviceradar"}, {"accept", "application/json"} | auth_headers("forgejo")] + defp api_headers("github") do + [{"user-agent", "serviceradar"}, {"accept", "application/vnd.github+json"} | auth_headers()] end - defp asset_headers(_provider, url) do + defp asset_headers("github", url), do: asset_headers(url) + + defp asset_headers(url) do headers = [{"user-agent", "serviceradar"}] if auth_host?(url) do - headers ++ auth_headers("forgejo") + headers ++ auth_headers() else headers end end - defp auth_headers("forgejo") do - case Application.get_env(:serviceradar_web_ng, :first_party_plugin_import_forgejo_token) || - System.get_env("FORGEJO_TOKEN") do + defp auth_headers do + case Application.get_env(:serviceradar_web_ng, :first_party_plugin_import_github_token) || + System.get_env("GITHUB_TOKEN") || + System.get_env("GH_TOKEN") do nil -> [] - token -> [{"authorization", "token #{token}"}] + token -> [{"authorization", "Bearer #{token}"}] end end defp auth_host?(url) do case URI.parse(url) do - %URI{host: @forgejo_host} -> true + %URI{host: host} when host in [@github_host, @github_api_host] -> true _ -> false end end @@ -511,7 +525,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do def validate_provider_api_url(_repo, url) do with {:ok, uri} <- validate_url(url), - true <- uri.host == @forgejo_host do + true <- uri.host == @github_api_host do {:ok, URI.to_string(uri)} else false -> {:error, "plugin import provider URL is not trusted"} @@ -521,7 +535,7 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do def validate_provider_asset_url(_repo, url) do with {:ok, uri} <- validate_url(url), - true <- uri.host in [@forgejo_host, @oci_registry] do + true <- uri.host in [@oci_registry | @github_asset_hosts] do {:ok, URI.to_string(uri)} else false -> {:error, "plugin import asset URL is not trusted"} @@ -530,10 +544,17 @@ defmodule ServiceRadarWebNG.Plugins.ForgejoOciClient do end def validate_url(url) do - case OutboundURLPolicy.validate_https_public_url(url) do - {:ok, %URI{scheme: "https"} = uri} -> {:ok, uri} - {:error, _reason} = error -> error - _ -> {:error, :disallowed_url} + case URI.parse(String.trim(to_string(url))) do + %URI{scheme: "https", host: host} = uri + when host in [@oci_registry | @github_asset_hosts] -> + {:ok, uri} + + _ -> + case OutboundURLPolicy.validate_https_public_url(url) do + {:ok, %URI{scheme: "https"} = uri} -> {:ok, uri} + {:error, _reason} = error -> error + _ -> {:error, :disallowed_url} + end end end diff --git a/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_sync_worker.ex b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_sync_worker.ex index e3fdfec7c4..0d74e1191a 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_sync_worker.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/plugins/first_party_sync_worker.ex @@ -1,6 +1,6 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartySyncWorker do @moduledoc """ - Periodically imports verified first-party Wasm plugin packages from Forgejo releases. + Periodically imports verified first-party Wasm plugin packages from GitHub Releases. """ use Oban.Worker, diff --git a/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_importer.ex b/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_importer.ex index 943c0718d3..ca99daa8da 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_importer.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_importer.ex @@ -1,6 +1,6 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporter do @moduledoc """ - Imports a first-party native add-on from a trusted Forgejo release into a staged + Imports a first-party native add-on from a trusted GitHub release into a staged `AddonPackage` (issue 3425, add-native-addon-build-signing §4.1). The web-ng counterpart to `FirstPartyImporter`: it owns transport + discovery trust (OCI + Cosign) and delegates per-arch artifact trust + persistence to the core @@ -14,7 +14,8 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporter do `config.schema.json` and the assembled per-arch artifacts go to `Core.import_entry/4`, which verifies each tarball's agent-release ed25519 signature, mirrors it (`NativeAddonArtifactMirror`), and creates the staged - `AddonPackage`. All HTTP/OCI/Cosign/URL transport is the shared `ForgejoOciClient`. + `AddonPackage`. All HTTP/OCI/Cosign/URL transport is the shared + `FirstPartyReleaseClient`. """ alias ServiceRadar.Actors.SystemActor @@ -23,7 +24,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporter do alias ServiceRadar.Plugins.NativeAddonArtifactMirror alias ServiceRadar.Plugins.NativeAddonImporter, as: Core alias ServiceRadar.Plugins.RetiredNativeAddons - alias ServiceRadarWebNG.Plugins.ForgejoOciClient, as: Client + alias ServiceRadarWebNG.Plugins.FirstPartyReleaseClient, as: Client Module.register_attribute(__MODULE__, :sobelow_skip, accumulate: true) @@ -84,11 +85,11 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporter do def list_recent_addons_with_summary(_attrs, _limit), do: {:error, :invalid_attributes} @doc """ - Lists native add-ons from one exact Forgejo release. + Lists native add-ons from one exact GitHub release. Automatic synchronization uses this path so the catalog is anchored to the immutable ServiceRadar release currently running, rather than depending on the - ordering or completeness of Forgejo's recent-release feed. + ordering or completeness of GitHub's recent-release feed. """ @spec list_release_addons(map(), String.t()) :: {:ok, [map()]} | {:error, term()} def list_release_addons(attrs, release_tag) when is_map(attrs) do diff --git a/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_sync_worker.ex b/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_sync_worker.ex index cbfe14ee83..6b155e9510 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_sync_worker.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng/plugins/native_addon_sync_worker.ex @@ -1,6 +1,6 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonSyncWorker do @moduledoc """ - Periodically imports verified first-party native add-on packages from Forgejo releases. + Periodically imports verified first-party native add-on packages from GitHub Releases. """ use Oban.Worker, diff --git a/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/addon_package_live/index.ex b/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/addon_package_live/index.ex index 60ed0bc76b..72094324f7 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/addon_package_live/index.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/addon_package_live/index.ex @@ -1787,7 +1787,7 @@ defmodule ServiceRadarWebNGWeb.Admin.AddonPackageLive.Index do defp first_party_repo_url do config = Application.get_env(:serviceradar_web_ng, :native_addon_import, []) - Keyword.get(config, :repo_url, "https://code.carverauto.dev/carverauto/serviceradar") + Keyword.get(config, :repo_url, "https://github.com/carverauto/serviceradar") end defp first_party_sync_limit do diff --git a/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/plugin_package_live/index.ex b/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/plugin_package_live/index.ex index 574cb26c01..81f37d2df5 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/plugin_package_live/index.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng_web/live/admin/plugin_package_live/index.ex @@ -2896,7 +2896,7 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLive.Index do "Showing #{length(visible_plugins)} first-party plugin entry(s) from #{selected_release_status_label(visible_plugins)}. Loaded #{length(all_plugins)} entry(s) from #{summary.indexed_releases} indexed release(s)." summary.indexed_releases == 0 -> - "Scanned #{summary.scanned_releases} recent Forgejo release(s), but none had #{summary.index_asset_name}. Publish the Wasm plugin import index to a release before importing." + "Scanned #{summary.scanned_releases} recent GitHub release(s), but none had #{summary.index_asset_name}. Publish the Wasm plugin import index to a release before importing." true -> "Scanned #{summary.indexed_releases} indexed release(s), but no import-ready plugin entries were found." diff --git a/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/deploy.ex b/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/deploy.ex index 6ee993b5ce..1d5fea6ea7 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/deploy.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/deploy.ex @@ -124,12 +124,12 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Deploy do
<.icon name="hero-document-arrow-down" class="size-4" /> <.link - href="https://code.carverauto.dev/carverauto/serviceradar/releases" + href="https://github.com/carverauto/serviceradar/releases" target="_blank" rel="noopener" class="text-sr-brand hover:underline" > - Download releases from Forgejo + Download releases from GitHub
diff --git a/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/releases.ex b/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/releases.ex index 5db828a9db..7bff197c01 100644 --- a/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/releases.ex +++ b/elixir/web-ng/lib/serviceradar_web_ng_web/live/settings/agents_live/releases.ex @@ -636,13 +636,13 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do
<.ui_panel> <:header> -
Import Forgejo Release
+
Import GitHub Release

- Use the Forgejo release as the source of truth for production rollouts. The + Use the GitHub release as the source of truth for production rollouts. The release must include a signed manifest asset and signature asset so ServiceRadar - can publish the catalog entry directly from code.carverauto.dev. + can publish the catalog entry directly from github.com.

<.form @@ -661,7 +661,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do <.input field={@release_import_form[:repo_url]} label="Repository URL" - placeholder="https://code.carverauto.dev/carverauto/serviceradar" + placeholder="https://github.com/carverauto/serviceradar" class="md:col-span-2" required /> @@ -684,7 +684,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do Recent Repository Releases
- Showing the latest {@visible_release_limit} agent releases from the selected Forgejo repository. + Showing the latest {@visible_release_limit} agent releases from the selected GitHub repository.
@@ -793,7 +793,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do
Keep the manual publish path below for local development and one-off testing - when you do not want to push a signed release through Forgejo. Use the + when you do not want to push a signed release through GitHub. Use the field below when you want to import a specific tag that is not in the recent list.
@@ -1540,8 +1540,8 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do defp release_import_form(params \\ %{}) do to_form( %{ - "provider" => Map.get(params, "provider", "forgejo"), - "repo_url" => Map.get(params, "repo_url", "https://code.carverauto.dev/carverauto/serviceradar"), + "provider" => Map.get(params, "provider", "github"), + "repo_url" => Map.get(params, "repo_url", ReleaseSourceImporter.default_repo_url()), "release_tag" => Map.get(params, "release_tag", ""), "manifest_asset_name" => Map.get( @@ -1600,13 +1600,13 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do defp normalize_rollout_form(_other, releases), do: rollout_form(%{}, releases) defp selected_import_provider(params) when is_map(params) do - case Map.get(params, "provider") || Map.get(params, :provider) || "forgejo" do - "forgejo" -> {:ok, "forgejo"} - _ -> {:error, "Forgejo is the only supported release provider"} + case Map.get(params, "provider") || Map.get(params, :provider) || "github" do + "github" -> {:ok, "github"} + _ -> {:error, "GitHub is the only supported release provider"} end end - defp selected_import_provider(_params), do: {:ok, "forgejo"} + defp selected_import_provider(_params), do: {:ok, "github"} defp maybe_reload_recent_repo_releases(socket, previous_params, params) do if repo_source_params_changed?(previous_params, params) do @@ -1964,6 +1964,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsLive.Releases do end end + defp release_provider_label("github"), do: "GitHub Releases" defp release_provider_label("forgejo"), do: "Forgejo Releases" defp release_provider_label(_provider), do: "Repository Release" diff --git a/elixir/web-ng/test/app_domain/edge/release_source_importer_test.exs b/elixir/web-ng/test/app_domain/edge/release_source_importer_test.exs index 87bf320e12..f0332753fe 100644 --- a/elixir/web-ng/test/app_domain/edge/release_source_importer_test.exs +++ b/elixir/web-ng/test/app_domain/edge/release_source_importer_test.exs @@ -3,6 +3,9 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do alias ServiceRadarWebNG.Edge.ReleaseSourceImporter + @moduletag :unit + @moduletag :db_free + @manifest %{ "version" => "1.2.3", "artifacts" => [ @@ -12,7 +15,7 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do "format" => "tar.gz", "entrypoint" => "serviceradar-agent", "url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-linux-amd64.tar.gz", + "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-linux-amd64.tar.gz", "sha256" => String.duplicate("a", 64) } ] @@ -23,14 +26,14 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do def manifest_json, do: Jason.encode!(@manifest) def signature, do: @signature - defmodule ForgejoClient do + defmodule GitHubClient do @moduledoc false alias ServiceRadarWebNG.Edge.ReleaseSourceImporterTest def get(url, _opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> {:ok, %Req.Response{ status: 200, @@ -39,7 +42,7 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do "tag_name" => "netprobe-v0.2.9", "name" => "Native add-on netprobe 0.2.9", "body" => "Add-on only release", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/netprobe-v0.2.9", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/netprobe-v0.2.9", "published_at" => "2026-03-29T20:00:00Z", "assets" => [ %{"name" => "serviceradar-native-addon-index.json"}, @@ -50,7 +53,7 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do "tag_name" => "v1.2.4", "name" => "ServiceRadar 1.2.4", "body" => "Newest release", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.2.4", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.2.4", "published_at" => "2026-03-28T20:00:00Z", "assets" => [ %{"name" => "serviceradar-agent-release-manifest.json"}, @@ -61,7 +64,7 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do "tag_name" => "v1.2.3", "name" => "ServiceRadar 1.2.3", "body" => "Missing manifest asset", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.2.3", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.2.3", "published_at" => "2026-03-27T20:00:00Z", "assets" => [ %{"name" => "serviceradar-agent-release-manifest.sig"} @@ -70,25 +73,25 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do ] }} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> {:ok, %Req.Response{ status: 200, body: %{ "tag_name" => "v1.2.3", "name" => "ServiceRadar 1.2.3", - "body" => "Forgejo release notes", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.2.3", + "body" => "GitHub release notes", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.2.3", "assets" => [ %{ "name" => "serviceradar-agent-release-manifest.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-release-manifest.json" + "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-release-manifest.json" }, %{ "name" => "serviceradar-agent-release-manifest.sig", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-release-manifest.sig" + "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-agent-release-manifest.sig" } ] } @@ -106,49 +109,6 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do end end - defmodule ForgejoClient do - @moduledoc false - - alias ServiceRadarWebNG.Edge.ReleaseSourceImporterTest - - def get(url, _opts) do - cond do - String.contains?(url, "/repos/acme/serviceradar/releases/tags/") -> - {:ok, - %Req.Response{ - status: 200, - body: %{ - "tag_name" => "v9.9.9", - "name" => "Forgejo Release", - "body" => "Forgejo release notes", - "html_url" => "https://code.carverauto.dev/acme/serviceradar/releases/tag/v9.9.9", - "assets" => [ - %{ - "name" => "custom-manifest.json", - "browser_download_url" => - "https://code.carverauto.dev/acme/serviceradar/releases/download/v9.9.9/custom-manifest.json" - }, - %{ - "name" => "custom-manifest.sig", - "browser_download_url" => - "https://code.carverauto.dev/acme/serviceradar/releases/download/v9.9.9/custom-manifest.sig" - } - ] - } - }} - - String.ends_with?(url, "/custom-manifest.json") -> - {:ok, %Req.Response{status: 200, body: ReleaseSourceImporterTest.manifest_json()}} - - String.ends_with?(url, "/custom-manifest.sig") -> - {:ok, %Req.Response{status: 200, body: ReleaseSourceImporterTest.signature()}} - - true -> - {:ok, %Req.Response{status: 404, body: ""}} - end - end - end - setup do original_client = Application.get_env(:serviceradar_web_ng, :agent_release_import_http_client) @@ -163,58 +123,58 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do :ok end - test "imports a Forgejo release manifest and signature" do - Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, ForgejoClient) + test "imports a GitHub release manifest and signature" do + Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, GitHubClient) assert {:ok, attrs} = ReleaseSourceImporter.import(%{ - "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar", + "repo_url" => "https://github.com/carverauto/serviceradar", "release_tag" => "v1.2.3" }) assert attrs.version == "1.2.3" assert attrs.signature == @signature - assert attrs.release_notes == "Forgejo release notes" + assert attrs.release_notes == "GitHub release notes" assert attrs.manifest == @manifest - assert get_in(attrs, [:metadata, "source", "provider"]) == "forgejo" + assert get_in(attrs, [:metadata, "source", "provider"]) == "github" assert get_in(attrs, [:metadata, "source", "repo_url"]) == - "https://code.carverauto.dev/carverauto/serviceradar" + "https://github.com/carverauto/serviceradar" end - test "rejects Forgejo repository URLs on untrusted hosts" do - assert {:error, "Forgejo repository URL must look like https://code.carverauto.dev//"} = + test "rejects repository URLs on untrusted hosts" do + assert {:error, "GitHub repository URL must look like https://github.com//"} = ReleaseSourceImporter.import(%{ "repo_url" => "https://forgejo.example.com/acme/serviceradar", "release_tag" => "v9.9.9" }) end - test "rejects GitHub repository URLs for agent release import" do - assert {:error, "Forgejo repository URL must look like https://code.carverauto.dev//"} = + test "rejects Forgejo repository URLs for agent release import" do + assert {:error, "GitHub repository URL must look like https://github.com//"} = ReleaseSourceImporter.import(%{ - "repo_url" => "https://github.com/carverauto/serviceradar", + "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar", "release_tag" => "v1.2.3" }) end test "returns a helpful error when the release asset is missing" do - Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, ForgejoClient) + Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, GitHubClient) assert {:error, "Release asset missing.sig was not found"} = ReleaseSourceImporter.import(%{ - "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar", + "repo_url" => "https://github.com/carverauto/serviceradar", "release_tag" => "v1.2.3", "signature_asset_name" => "missing.sig" }) end test "lists recent releases with import readiness" do - Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, ForgejoClient) + Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, GitHubClient) assert {:ok, [latest, previous]} = ReleaseSourceImporter.list_recent_releases(%{ - "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar" + "repo_url" => "https://github.com/carverauto/serviceradar" }) assert latest.tag == "v1.2.4" @@ -229,11 +189,11 @@ defmodule ServiceRadarWebNG.Edge.ReleaseSourceImporterTest do end test "recent release browser ignores add-on only releases" do - Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, ForgejoClient) + Application.put_env(:serviceradar_web_ng, :agent_release_import_http_client, GitHubClient) assert {:ok, releases} = ReleaseSourceImporter.list_recent_releases(%{ - "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar" + "repo_url" => "https://github.com/carverauto/serviceradar" }) refute Enum.any?(releases, &(&1.tag == "netprobe-v0.2.9")) diff --git a/elixir/web-ng/test/app_domain/plugins/first_party_importer_test.exs b/elixir/web-ng/test/app_domain/plugins/first_party_importer_test.exs index 38e3f15d01..bbd83aae8a 100644 --- a/elixir/web-ng/test/app_domain/plugins/first_party_importer_test.exs +++ b/elixir/web-ng/test/app_domain/plugins/first_party_importer_test.exs @@ -8,7 +8,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do @moduletag :unit @moduletag :db_free - @repo_url "https://code.carverauto.dev/carverauto/serviceradar" + @repo_url "https://github.com/carverauto/serviceradar" @manifest_yaml """ id: hello-wasm name: Hello Wasm @@ -47,14 +47,14 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do ] } - defmodule ForgejoClient do + defmodule GitHubReleaseClient do @moduledoc false alias ServiceRadarWebNG.Plugins.FirstPartyImporterTest def get(url, _opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> releases = if Process.get(:first_party_releases_without_index) do [%{"tag_name" => "v1.2.3", "assets" => []}] @@ -64,7 +64,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do {:ok, %Req.Response{status: 200, body: releases}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> {:ok, %Req.Response{status: 200, body: FirstPartyImporterTest.release()}} String.ends_with?(url, "/serviceradar-wasm-plugin-index.json") -> @@ -101,11 +101,11 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do def get(url, opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> - ForgejoClient.get(url, []) + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> + GitHubReleaseClient.get(url, []) - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> - ForgejoClient.get(url, []) + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.2.3") -> + GitHubReleaseClient.get(url, []) String.ends_with?(url, "/serviceradar-wasm-plugin-index.json") -> {:ok, %Req.Response{status: 200, body: Jason.encode!(FirstPartyImporterTest.oci_index())}} @@ -179,7 +179,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do trusted_upload_signing_keys: %{"test-signer" => Base.encode64(public_key)} ) - Application.put_env(:serviceradar_web_ng, :first_party_plugin_import_http_client, ForgejoClient) + Application.put_env(:serviceradar_web_ng, :first_party_plugin_import_http_client, GitHubReleaseClient) Application.put_env(:serviceradar_web_ng, :plugin_storage, backend: :filesystem, @@ -210,7 +210,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do :ok end - test "lists import-ready plugins from the Forgejo release index" do + test "lists import-ready plugins from the GitHub release index" do assert {:ok, [plugin]} = FirstPartyImporter.list_recent_plugins(%{"repo_url" => @repo_url}, 10) assert plugin.plugin_id == "hello-wasm" assert plugin.version == "1.2.3" @@ -327,7 +327,7 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do end test "rejects untrusted repository URLs" do - assert {:error, "Forgejo repository URL must look like https://code.carverauto.dev//"} = + assert {:error, "GitHub repository URL must look like https://github.com//"} = FirstPartyImporter.list_recent_plugins(%{"repo_url" => "https://example.com/repo"}, 10) end @@ -398,12 +398,12 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do %{ "tag_name" => "v1.2.3", "name" => "ServiceRadar v1.2.3", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.2.3", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.2.3", "assets" => [ %{ "name" => "serviceradar-wasm-plugin-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-wasm-plugin-index.json" + "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/serviceradar-wasm-plugin-index.json" } ] } @@ -417,9 +417,9 @@ defmodule ServiceRadarWebNG.Plugins.FirstPartyImporterTest do "plugin_id" => "hello-wasm", "name" => "Hello Wasm", "version" => "1.2.3", - "bundle_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/hello-wasm.zip", + "bundle_url" => "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/hello-wasm.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.2.3/hello-wasm.upload-signature.json", + "https://github.com/carverauto/serviceradar/releases/download/v1.2.3/hello-wasm.upload-signature.json", "bundle_digest" => Process.get(:first_party_bundle_digest_override) || Storage.sha256(bundle()), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-hello-wasm:v1.2.3" } diff --git a/elixir/web-ng/test/app_domain/plugins/native_addon_importer_test.exs b/elixir/web-ng/test/app_domain/plugins/native_addon_importer_test.exs index eceedfffc1..0b312baaec 100644 --- a/elixir/web-ng/test/app_domain/plugins/native_addon_importer_test.exs +++ b/elixir/web-ng/test/app_domain/plugins/native_addon_importer_test.exs @@ -1,7 +1,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do @moduledoc """ End-to-end test for the web-ng native add-on import orchestration (issue 3425, - add-native-addon-build-signing §4.1). A fake `ForgejoOciClient` HTTP backend + add-native-addon-build-signing §4.1). A fake `FirstPartyReleaseClient` HTTP backend serves a release, the `serviceradar-native-addon-index.json` asset, the OCI manifest, and the bundle + per-arch tarball/signature blobs by digest; Cosign and the datasvc upload are stubbed. The real `ServiceRadar.Plugins.NativeAddonImporter` @@ -26,7 +26,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do require Ash.Query - @repo_url "https://code.carverauto.dev/carverauto/serviceradar" + @repo_url "https://github.com/carverauto/serviceradar" @index_asset_name "serviceradar-native-addon-index.json" @oci_repository "serviceradar/native-addon-sample" @oci_ref "registry.carverauto.dev/#{@oci_repository}:v1.0.0" @@ -61,10 +61,10 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do def get(url, _opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.0.0") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.0.0") -> {:ok, %Req.Response{status: 200, body: Process.get(:native_addon_release)}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> Process.put( :native_addon_recent_release_requests, Process.get(:native_addon_recent_release_requests, 0) + 1 @@ -906,7 +906,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do "provider-bootstrap-secret", "raw-bearer-secret", "raw-basic-secret", - "raw-forgejo-token-secret", + "raw-github-token-secret", "url-user-secret", "url-password-secret", "url-token-secret", @@ -932,7 +932,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do ~s({"api_token":"json-secret"}), "Authorization: Bearer raw-bearer-secret", "Authorization=Basic raw-basic-secret", - "Authorization: token raw-forgejo-token-secret", + "Authorization: token raw-github-token-secret", "https://url-user-secret:url-password-secret@example.test/path", "https://url-token-secret@example.test/token-only", "https://example.test/path?access_token=query-token-secret&api_key=query-api-key-secret" @@ -956,7 +956,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do assert byte_size(log) < 1_500 end - test "sync worker preserves keyed tuple context while redacting Forgejo credentials" do + test "sync worker preserves keyed tuple context while redacting GitHub credentials" do configure_sync_worker() Process.put( @@ -964,7 +964,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do {:error, {:transport, [ - {"authorization", "token FORGEJO_SENTINEL"}, + {"authorization", "token GITHUB_SENTINEL"}, {:api_token, "API_SENTINEL"} ]}} ) @@ -978,7 +978,7 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do assert log =~ "authorization" assert log =~ "api_token" assert log =~ "REDACTED" - refute log =~ "FORGEJO_SENTINEL" + refute log =~ "GITHUB_SENTINEL" refute log =~ "API_SENTINEL" assert byte_size(log) < 1_500 end @@ -1458,12 +1458,12 @@ defmodule ServiceRadarWebNG.Plugins.NativeAddonImporterTest do %{ "tag_name" => "v1.0.0", "name" => "ServiceRadar v1.0.0", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.0.0", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.0.0", "assets" => [ %{ "name" => @index_asset_name, "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.0.0/#{@index_asset_name}" + "https://github.com/carverauto/serviceradar/releases/download/v1.0.0/#{@index_asset_name}" } ] } diff --git a/elixir/web-ng/test/app_domain/plugins/packages_test.exs b/elixir/web-ng/test/app_domain/plugins/packages_test.exs index d7dc7cccaa..5bbbf6c7b8 100644 --- a/elixir/web-ng/test/app_domain/plugins/packages_test.exs +++ b/elixir/web-ng/test/app_domain/plugins/packages_test.exs @@ -19,7 +19,7 @@ defmodule ServiceRadarWebNG.Plugins.PackagesTest do require Ash.Query - @repo_url "https://code.carverauto.dev/carverauto/serviceradar" + @repo_url "https://github.com/carverauto/serviceradar" @manifest %{ "id" => "unifi-protect-camera", "name" => "UniFi Protect Camera", @@ -65,7 +65,7 @@ defmodule ServiceRadarWebNG.Plugins.PackagesTest do def get(url, _opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> Process.put( :first_party_recent_release_requests, Process.get(:first_party_recent_release_requests, 0) + 1 @@ -83,10 +83,10 @@ defmodule ServiceRadarWebNG.Plugins.PackagesTest do {:ok, %Req.Response{status: 200, body: releases}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.0.1") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.0.1") -> {:ok, %Req.Response{status: 200, body: PackagesTest.first_party_release("v1.0.1")}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.0.2") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.0.2") -> {:ok, %Req.Response{status: 200, body: PackagesTest.first_party_release("v1.0.2")}} String.contains?(url, "/download/v1.0.2/serviceradar-wasm-plugin-index.json") -> @@ -580,12 +580,12 @@ defmodule ServiceRadarWebNG.Plugins.PackagesTest do %{ "tag_name" => tag, "name" => "ServiceRadar #{tag}", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/#{tag}", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/#{tag}", "assets" => [ %{ "name" => "serviceradar-wasm-plugin-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/#{tag}/serviceradar-wasm-plugin-index.json" + "https://github.com/carverauto/serviceradar/releases/download/#{tag}/serviceradar-wasm-plugin-index.json" } ] } @@ -602,9 +602,9 @@ defmodule ServiceRadarWebNG.Plugins.PackagesTest do "name" => "First-party Dedupe", "version" => "1.0.1", "bundle_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/#{tag}/first-party-dedupe#{suffix}.zip", + "https://github.com/carverauto/serviceradar/releases/download/#{tag}/first-party-dedupe#{suffix}.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/#{tag}/first-party-dedupe#{suffix}.upload-signature.json", + "https://github.com/carverauto/serviceradar/releases/download/#{tag}/first-party-dedupe#{suffix}.upload-signature.json", "bundle_digest" => Storage.sha256(first_party_bundle(tag)), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-first-party-dedupe:v1.0.1" } diff --git a/elixir/web-ng/test/phoenix/live/admin/addon_package_live_test.exs b/elixir/web-ng/test/phoenix/live/admin/addon_package_live_test.exs index 66fce0fa6b..41555cbfe1 100644 --- a/elixir/web-ng/test/phoenix/live/admin/addon_package_live_test.exs +++ b/elixir/web-ng/test/phoenix/live/admin/addon_package_live_test.exs @@ -149,12 +149,12 @@ defmodule ServiceRadarWebNGWeb.Admin.AddonPackageLiveTest do release = %{ "tag_name" => release_tag, "name" => "ServiceRadar #{release_tag}", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/#{release_tag}", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/#{release_tag}", "assets" => [ %{ "name" => "serviceradar-native-addon-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/#{release_tag}/serviceradar-native-addon-index.json" + "https://github.com/carverauto/serviceradar/releases/download/#{release_tag}/serviceradar-native-addon-index.json" } ] } diff --git a/elixir/web-ng/test/phoenix/live/admin/plugin_package_live_test.exs b/elixir/web-ng/test/phoenix/live/admin/plugin_package_live_test.exs index af3dd5e249..a811c39f3b 100644 --- a/elixir/web-ng/test/phoenix/live/admin/plugin_package_live_test.exs +++ b/elixir/web-ng/test/phoenix/live/admin/plugin_package_live_test.exs @@ -27,8 +27,8 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do require Ash.Query - @repo_url "https://code.carverauto.dev/carverauto/serviceradar" - @external_repo_url "https://code.carverauto.dev/carverauto/serviceradar-plugin-example-inventory" + @repo_url "https://github.com/carverauto/serviceradar" + @external_repo_url "https://github.com/carverauto/serviceradar-plugin-example-inventory" @manifest_yaml """ id: live-first-party-plugin name: Live First-party Plugin @@ -54,7 +54,7 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do } @wasm "live first-party wasm payload" - defmodule ForgejoClient do + defmodule GitHubReleaseClient do @moduledoc false alias ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest @@ -63,7 +63,7 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do cond do String.contains?( url, - "/api/v1/repos/carverauto/serviceradar-plugin-example-inventory/releases?per_page=" + "api.github.com/repos/carverauto/serviceradar-plugin-example-inventory/releases?per_page=" ) -> {:ok, %Req.Response{ @@ -73,21 +73,21 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do String.contains?( url, - "/api/v1/repos/carverauto/serviceradar-plugin-example-inventory/releases/tags/v2.0.0" + "api.github.com/repos/carverauto/serviceradar-plugin-example-inventory/releases/tags/v2.0.0" ) -> {:ok, %Req.Response{status: 200, body: PluginPackageLiveTest.external_release()}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> {:ok, %Req.Response{ status: 200, body: [PluginPackageLiveTest.release(), PluginPackageLiveTest.old_release()] }} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v2.0.0") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v2.0.0") -> {:ok, %Req.Response{status: 200, body: PluginPackageLiveTest.release()}} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v1.0.0") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v1.0.0") -> {:ok, %Req.Response{status: 200, body: PluginPackageLiveTest.old_release()}} String.ends_with?(url, "/serviceradar-wasm-plugin-index.json") -> @@ -178,7 +178,7 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do Application.put_env( :serviceradar_web_ng, :first_party_plugin_import_http_client, - ForgejoClient + GitHubReleaseClient ) Application.put_env(:serviceradar_web_ng, :first_party_plugin_import, @@ -1016,12 +1016,12 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do %{ "tag_name" => "v2.0.0", "name" => "ServiceRadar v2.0.0", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v2.0.0", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v2.0.0", "assets" => [ %{ "name" => "serviceradar-wasm-plugin-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v2.0.0/serviceradar-wasm-plugin-index.json" + "https://github.com/carverauto/serviceradar/releases/download/v2.0.0/serviceradar-wasm-plugin-index.json" } ] } @@ -1031,12 +1031,12 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do %{ "tag_name" => "v1.0.0", "name" => "ServiceRadar v1.0.0", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v1.0.0", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v1.0.0", "assets" => [ %{ "name" => "serviceradar-wasm-plugin-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.0.0/serviceradar-wasm-plugin-index.json" + "https://github.com/carverauto/serviceradar/releases/download/v1.0.0/serviceradar-wasm-plugin-index.json" } ] } @@ -1046,12 +1046,12 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do %{ "tag_name" => "v2.0.0", "name" => "Example inventory plugin v2.0.0", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar-plugin-example-inventory/releases/tag/v2.0.0", + "html_url" => "https://github.com/carverauto/serviceradar-plugin-example-inventory/releases/tag/v2.0.0", "assets" => [ %{ "name" => "serviceradar-wasm-plugin-index.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/serviceradar-wasm-plugin-index.json" + "https://github.com/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/serviceradar-wasm-plugin-index.json" } ] } @@ -1066,9 +1066,9 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do "name" => "Live First-party Plugin", "version" => "2.0.0", "bundle_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v2.0.0/live-first-party-plugin.zip", + "https://github.com/carverauto/serviceradar/releases/download/v2.0.0/live-first-party-plugin.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v2.0.0/live-first-party-plugin.upload-signature.json", + "https://github.com/carverauto/serviceradar/releases/download/v2.0.0/live-first-party-plugin.upload-signature.json", "bundle_digest" => Storage.sha256(bundle()), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-live-first-party-plugin:v2.0.0" } @@ -1085,9 +1085,9 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do "name" => "Old First-party Plugin", "version" => "1.0.0", "bundle_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.0.0/old-first-party-plugin.zip", + "https://github.com/carverauto/serviceradar/releases/download/v1.0.0/old-first-party-plugin.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v1.0.0/old-first-party-plugin.upload-signature.json", + "https://github.com/carverauto/serviceradar/releases/download/v1.0.0/old-first-party-plugin.upload-signature.json", "bundle_digest" => Storage.sha256(bundle()), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-old-first-party-plugin:v1.0.0" } @@ -1104,9 +1104,9 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do "name" => "Live First-party Plugin", "version" => "2.0.0", "bundle_url" => - "https://code.carverauto.dev/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/live-first-party-plugin.zip", + "https://github.com/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/live-first-party-plugin.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/live-first-party-plugin.upload-signature.json", + "https://github.com/carverauto/serviceradar-plugin-example-inventory/releases/download/v2.0.0/live-first-party-plugin.upload-signature.json", "bundle_digest" => Storage.sha256(bundle()), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-live-first-party-plugin:v2.0.0" } @@ -1126,9 +1126,9 @@ defmodule ServiceRadarWebNGWeb.Admin.PluginPackageLiveTest do "name" => "Catalog Plugin #{suffix}", "version" => "2.0.#{index}", "bundle_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v2.0.0/catalog-plugin-#{suffix}.zip", + "https://github.com/carverauto/serviceradar/releases/download/v2.0.0/catalog-plugin-#{suffix}.zip", "upload_signature_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v2.0.0/catalog-plugin-#{suffix}.upload-signature.json", + "https://github.com/carverauto/serviceradar/releases/download/v2.0.0/catalog-plugin-#{suffix}.upload-signature.json", "bundle_digest" => Storage.sha256("catalog plugin #{suffix}"), "oci_ref" => "registry.carverauto.dev/serviceradar/wasm-plugin-catalog-#{suffix}:v2.0.#{index}" } diff --git a/elixir/web-ng/test/phoenix/live/settings/agents_releases_live_test.exs b/elixir/web-ng/test/phoenix/live/settings/agents_releases_live_test.exs index f696e4b744..a3633b259e 100644 --- a/elixir/web-ng/test/phoenix/live/settings/agents_releases_live_test.exs +++ b/elixir/web-ng/test/phoenix/live/settings/agents_releases_live_test.exs @@ -26,14 +26,14 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do def get(url, _opts) do cond do - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases?per_page=") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases?per_page=") -> {:ok, %Req.Response{ status: 200, body: recent_releases() }} - String.contains?(url, "/api/v1/repos/carverauto/serviceradar/releases/tags/v7.0.0") -> + String.contains?(url, "api.github.com/repos/carverauto/serviceradar/releases/tags/v7.0.0") -> {:ok, %Req.Response{ status: 200, @@ -41,17 +41,17 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "tag_name" => "v7.0.0", "name" => "ServiceRadar 7.0.0", "body" => "Imported release notes", - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/v7.0.0", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/v7.0.0", "assets" => [ %{ "name" => "serviceradar-agent-release-manifest.json", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v7.0.0/manifest.json" + "https://github.com/carverauto/serviceradar/releases/download/v7.0.0/manifest.json" }, %{ "name" => "serviceradar-agent-release-manifest.sig", "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v7.0.0/manifest.sig" + "https://github.com/carverauto/serviceradar/releases/download/v7.0.0/manifest.sig" } ] } @@ -83,7 +83,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "format" => "tar.gz", "entrypoint" => "serviceradar-agent", "url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent-linux-amd64.tar.gz", + "https://github.com/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent-linux-amd64.tar.gz", "sha256" => String.duplicate("a", 64) } ] @@ -142,7 +142,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "tag_name" => tag, "name" => name, "body" => body, - "html_url" => "https://code.carverauto.dev/carverauto/serviceradar/releases/tag/#{tag}", + "html_url" => "https://github.com/carverauto/serviceradar/releases/tag/#{tag}", "published_at" => "2026-03-28T20:00:00Z", "assets" => assets } @@ -151,8 +151,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do defp release_asset(tag, name, file_name) do %{ "name" => name, - "browser_download_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/#{tag}/#{file_name}" + "browser_download_url" => "https://github.com/carverauto/serviceradar/releases/download/#{tag}/#{file_name}" } end @@ -237,7 +236,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do assert html =~ "Agent Releases" assert html =~ "Publish Release" assert html =~ "Create Rollout" - assert html =~ "https://code.carverauto.dev/carverauto/serviceradar" + assert html =~ "https://github.com/carverauto/serviceradar" refute html =~ "Release Provider" end @@ -287,7 +286,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "version" => version, "signature" => signature, "artifact_url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent.tar.gz", + "https://github.com/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent.tar.gz", "artifact_sha256" => String.duplicate("a", 64), "artifact_format" => "tar.gz", "entrypoint" => "serviceradar-agent", @@ -323,7 +322,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do lv |> form("#import-release-form", %{ "release_import" => %{ - "repo_url" => "https://code.carverauto.dev/carverauto/serviceradar", + "repo_url" => "https://github.com/carverauto/serviceradar", "release_tag" => "v7.0.0", "manifest_asset_name" => "serviceradar-agent-release-manifest.json", "signature_asset_name" => "serviceradar-agent-release-manifest.sig" @@ -331,8 +330,8 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do }) |> render_submit() - assert render(lv) =~ "Imported and published agent release 7.0.0 from Forgejo Releases" - assert render(lv) =~ "Forgejo Releases" + assert render(lv) =~ "Imported and published agent release 7.0.0 from GitHub Releases" + assert render(lv) =~ "GitHub Releases" assert render(lv) =~ "carverauto/serviceradar" release = @@ -341,7 +340,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do |> Ash.read_one!(scope: scope) assert release.release_notes == "Imported release notes" - assert get_in(release.metadata, ["source", "provider"]) == "forgejo" + assert get_in(release.metadata, ["source", "provider"]) == "github" assert get_in(release.metadata, ["source", "release_tag"]) == "v7.0.0" end @@ -414,7 +413,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do |> element("button[phx-value-release_tag='v7.0.0']") |> render_click() - assert render(lv) =~ "Imported and published agent release 7.0.0 from Forgejo Releases" + assert render(lv) =~ "Imported and published agent release 7.0.0 from GitHub Releases" release = AgentRelease @@ -1690,8 +1689,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "arch" => "amd64", "format" => "tar.gz", "entrypoint" => "serviceradar-agent", - "url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent.tar.gz", + "url" => "https://github.com/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent.tar.gz", "sha256" => String.duplicate("a", 64) } ] @@ -1711,7 +1709,7 @@ defmodule ServiceRadarWebNGWeb.Settings.AgentsReleasesLiveTest do "helper_protocol_version" => "srdp-helper-v1", "compatible_agent_versions" => %{"min" => version, "max" => version}, "url" => - "https://code.carverauto.dev/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent-rdp-linux-amd64.tar.gz", + "https://github.com/carverauto/serviceradar/releases/download/v#{version}/serviceradar-agent-rdp-linux-amd64.tar.gz", "sha256" => String.duplicate("b", 64), "deployment_requirements" => %{ "helper" => "serviceradar-rdp-adapter", diff --git a/helm/serviceradar/.argocd-source-serviceradar-demo-prod.yaml b/helm/serviceradar/.argocd-source-serviceradar-demo-prod.yaml index ef7815382d..1294e77273 100644 --- a/helm/serviceradar/.argocd-source-serviceradar-demo-prod.yaml +++ b/helm/serviceradar/.argocd-source-serviceradar-demo-prod.yaml @@ -1,7 +1,7 @@ helm: parameters: - name: global.imageTag - value: v1.4.32 + value: v1.4.33 forcestring: true - name: image.name value: registry.carverauto.dev/serviceradar/serviceradar-web-ng diff --git a/helm/serviceradar/Chart.yaml b/helm/serviceradar/Chart.yaml index 0a56fe0c0a..5dc652d704 100644 --- a/helm/serviceradar/Chart.yaml +++ b/helm/serviceradar/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: serviceradar description: Helm chart for deploying the ServiceRadar type: application -version: 1.4.32 -appVersion: "1.4.32" +version: 1.4.33 +appVersion: "1.4.33" diff --git a/helm/serviceradar/templates/web.yaml b/helm/serviceradar/templates/web.yaml index 945d54bf4f..4b646c3914 100644 --- a/helm/serviceradar/templates/web.yaml +++ b/helm/serviceradar/templates/web.yaml @@ -299,7 +299,7 @@ spec: value: "true" # The ServiceRadar RELEASE this deployment corresponds to -- not the # container image tag. web-ng uses it to fetch plugin and native add-on - # assets from the matching Forgejo release, and to show a version in the + # assets from the matching GitHub release, and to show a version in the # product status UI (`deployed_release_version/0` strips the `v`). # # These were the same value until now, which only worked when deploying @@ -488,7 +488,7 @@ spec: - name: SERVICERADAR_GOD_VIEW_SNAPSHOT_COALESCE_MS value: {{ default 0 $webNgGodView.snapshotCoalesceMs | quote }} - name: SERVICERADAR_FIRST_PARTY_PLUGIN_REPO_URL - value: {{ default "https://code.carverauto.dev/carverauto/serviceradar" $webNgFirstPartyImport.repoUrl | quote }} + value: {{ default "https://github.com/carverauto/serviceradar" $webNgFirstPartyImport.repoUrl | quote }} - name: SERVICERADAR_FIRST_PARTY_PLUGIN_INDEX_ASSET value: {{ default "serviceradar-wasm-plugin-index.json" $webNgFirstPartyImport.indexAssetName | quote }} - name: SERVICERADAR_FIRST_PARTY_PLUGIN_AUTO_SYNC @@ -522,7 +522,7 @@ spec: value: {{ $webNgFirstPartyImport.registryDockerConfigFile | quote }} {{- end }} - name: SERVICERADAR_NATIVE_ADDON_REPO_URL - value: {{ default "https://code.carverauto.dev/carverauto/serviceradar" $webNgNativeAddonImport.repoUrl | quote }} + value: {{ default "https://github.com/carverauto/serviceradar" $webNgNativeAddonImport.repoUrl | quote }} - name: SERVICERADAR_NATIVE_ADDON_INDEX_ASSET value: {{ default "serviceradar-native-addon-index.json" $webNgNativeAddonImport.indexAssetName | quote }} - name: SERVICERADAR_NATIVE_ADDON_AUTO_SYNC diff --git a/helm/serviceradar/values.yaml b/helm/serviceradar/values.yaml index 3a3fab6eec..f5852f0c4e 100644 --- a/helm/serviceradar/values.yaml +++ b/helm/serviceradar/values.yaml @@ -24,7 +24,7 @@ global: imageTag: "" # The ServiceRadar RELEASE this deployment corresponds to, as a `v` # tag. Distinct from imageTag on purpose: web-ng resolves plugin and native - # add-on assets from the Forgejo release with this name, and shows it in the + # add-on assets from the GitHub release with this name, and shows it in the # product status UI. Immutable rollouts set imageTag to a `sha-`, and # no release is ever named that, so the two cannot share one value. # Empty means "use the chart appVersion", which is what you want unless you are @@ -1099,7 +1099,7 @@ webNg: snapshotBudgetMs: 2000 snapshotCoalesceMs: 0 firstPartyPluginImport: - repoUrl: "https://code.carverauto.dev/carverauto/serviceradar" + repoUrl: "https://github.com/carverauto/serviceradar" indexAssetName: "serviceradar-wasm-plugin-index.json" autoSyncEnabled: false syncReleaseLimit: 10 @@ -1127,7 +1127,7 @@ webNg: registryDockerConfigJson: "" registryDockerConfigFile: "" nativeAddonImport: - repoUrl: "https://code.carverauto.dev/carverauto/serviceradar" + repoUrl: "https://github.com/carverauto/serviceradar" indexAssetName: "serviceradar-native-addon-index.json" autoSyncEnabled: false syncReleaseLimit: 10 diff --git a/scripts/cut-release.sh b/scripts/cut-release.sh index 66ab19145d..3ce72e7f4b 100755 --- a/scripts/cut-release.sh +++ b/scripts/cut-release.sh @@ -9,8 +9,12 @@ Options: --version Release version to publish (required). Use X.Y.Z for releases, X.Y.Z-preN for pre-releases. --tag-prefix Prefix to prepend to the Git tag (must be v). - --push Push the current release branch to origin when finished. - The tag remains local until the branch is merged to staging. + --remote Git remote for tag occupancy checks and --push + (default: origin). Use github when cutting against + GitHub instead of Forgejo. + --push Push the current release branch to the chosen remote + when finished. The tag remains local until the branch + is merged to staging. --no-push Do not push any refs (default). --dry-run Print the actions without modifying the repository. --prerelease Mark as pre-release (auto-detected if version contains @@ -44,6 +48,7 @@ USAGE version="" tag_prefix="v" +remote="origin" push=false dry_run=false skip_changelog_check=false @@ -70,6 +75,15 @@ while [[ $# -gt 0 ]]; do tag_prefix="${1#*=}" shift ;; + --remote) + [[ $# -ge 2 ]] || { echo "--remote requires a value" >&2; exit 1; } + remote="$2" + shift 2 + ;; + --remote=*) + remote="${1#*=}" + shift + ;; --push) push=true shift @@ -152,20 +166,25 @@ if git show-ref --verify --quiet "refs/tags/$tag"; then exit 1 fi +if ! git remote get-url "$remote" >/dev/null 2>&1; then + echo "Unknown git remote: $remote" >&2 + exit 1 +fi + set +e -remote_tag_output=$(git ls-remote --exit-code --tags origin "refs/tags/$tag" 2>&1) +remote_tag_output=$(git ls-remote --exit-code --tags "$remote" "refs/tags/$tag" 2>&1) remote_tag_status=$? set -e case "$remote_tag_status" in 0) - echo "Refusing to cut release: origin already contains tag $tag." >&2 + echo "Refusing to cut release: $remote already contains tag $tag." >&2 exit 1 ;; 2) ;; *) - echo "Unable to verify whether origin contains tag $tag:" >&2 + echo "Unable to verify whether $remote contains tag $tag:" >&2 echo "$remote_tag_output" >&2 exit "$remote_tag_status" ;; @@ -187,8 +206,8 @@ fi print_post_merge_tag_instructions() { echo "" echo "After the release branch is merged into staging, publish the tag with:" - echo " git fetch origin refs/heads/staging:refs/remotes/origin/staging" - echo " git merge-base --is-ancestor '${tag}^{commit}' refs/remotes/origin/staging && git push origin refs/tags/$tag:refs/tags/$tag" + echo " git fetch $remote refs/heads/staging:refs/remotes/$remote/staging" + echo " git merge-base --is-ancestor '${tag}^{commit}' refs/remotes/$remote/staging && git push $remote refs/tags/$tag:refs/tags/$tag" echo "The tag push is chained to the ancestry check and will not run if it fails." } @@ -300,20 +319,20 @@ fi if [[ "$push" == "true" ]]; then if [[ "$dry_run" == "true" ]]; then echo "[dry-run] Would push the release branch only with:" - echo "[dry-run] git push origin $current_branch:refs/heads/$current_branch" + echo "[dry-run] git push $remote $current_branch:refs/heads/$current_branch" echo "[dry-run] The tag would remain local until the release branch is merged to staging." else - git push origin "$current_branch:refs/heads/$current_branch" + git push "$remote" "$current_branch:refs/heads/$current_branch" echo "Release branch pushed. Open and merge its pull request before publishing the tag." fi else echo "Branch and tag are ready locally. Push the release branch with:" if [[ -n "$current_branch" && "$current_branch" != "staging" ]]; then - echo " git push origin $current_branch:refs/heads/$current_branch" + echo " git push $remote $current_branch:refs/heads/$current_branch" else release_branch="release/$tag" echo " git switch -c $release_branch" - echo " git push origin $release_branch:refs/heads/$release_branch" + echo " git push $remote $release_branch:refs/heads/$release_branch" fi fi